diff --git a/.changeset/afraid-baboons-nail.md b/.changeset/afraid-baboons-nail.md new file mode 100644 index 00000000000..d13bacea5e2 --- /dev/null +++ b/.changeset/afraid-baboons-nail.md @@ -0,0 +1,12 @@ +--- +"chainlink": patch +--- + +VerboseLogging is now turned on by default. + +You may disable if this results in excessive log volume. Disable like so: + +``` +[Pipeline] +VerboseLogging = false +``` diff --git a/.changeset/brave-games-drop.md b/.changeset/brave-games-drop.md new file mode 100644 index 00000000000..7ca47862cb7 --- /dev/null +++ b/.changeset/brave-games-drop.md @@ -0,0 +1,5 @@ +--- +"chainlink": major +--- + +Fix kv_store migration fk cascade deletion diff --git a/.changeset/breezy-taxis-breathe.md b/.changeset/breezy-taxis-breathe.md new file mode 100644 index 00000000000..79ce1ae96bd --- /dev/null +++ b/.changeset/breezy-taxis-breathe.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Add json schema support to workflows diff --git a/.changeset/chilled-buses-reflect.md b/.changeset/chilled-buses-reflect.md new file mode 100644 index 00000000000..eccac3b7f5b --- /dev/null +++ b/.changeset/chilled-buses-reflect.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Dispatcher service for external peering diff --git a/.changeset/chilly-garlics-kneel.md b/.changeset/chilly-garlics-kneel.md new file mode 100644 index 00000000000..fc8b9425250 --- /dev/null +++ b/.changeset/chilly-garlics-kneel.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +Fix error log formatting for in memory data source cache for juels fee per coin diff --git a/.changeset/cool-apricots-compare.md b/.changeset/cool-apricots-compare.md new file mode 100644 index 00000000000..945a3ffa390 --- /dev/null +++ b/.changeset/cool-apricots-compare.md @@ -0,0 +1,9 @@ +--- +"chainlink": patch +--- + +Increase default config for postgres max open conns from 20 to 100. + +Also, add autoscaling for mercury jobs. The max open conns limit will be +automatically increased to the number of mercury jobs if this exceeds the +configured value. diff --git a/.changeset/few-swans-wonder.md b/.changeset/few-swans-wonder.md new file mode 100644 index 00000000000..d6c3be39653 --- /dev/null +++ b/.changeset/few-swans-wonder.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +small gas fix diff --git a/.changeset/fresh-oranges-brake.md b/.changeset/fresh-oranges-brake.md new file mode 100644 index 00000000000..52562ee7413 --- /dev/null +++ b/.changeset/fresh-oranges-brake.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +fix jfpc cache cleanup diff --git a/.changeset/friendly-adults-pull.md b/.changeset/friendly-adults-pull.md new file mode 100644 index 00000000000..5b74f367115 --- /dev/null +++ b/.changeset/friendly-adults-pull.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +change auto 2.3 flat fees from link to USD diff --git a/.changeset/friendly-coats-switch.md b/.changeset/friendly-coats-switch.md new file mode 100644 index 00000000000..3ae97c51519 --- /dev/null +++ b/.changeset/friendly-coats-switch.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +safeTransfer and cleanups diff --git a/.changeset/gentle-cups-carry.md b/.changeset/gentle-cups-carry.md new file mode 100644 index 00000000000..1b204dfee31 --- /dev/null +++ b/.changeset/gentle-cups-carry.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +added logic C contract to automation 2.3 diff --git a/.changeset/good-rabbits-beg.md b/.changeset/good-rabbits-beg.md new file mode 100644 index 00000000000..91b5d54150f --- /dev/null +++ b/.changeset/good-rabbits-beg.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +implement offchain settlement for NOPs payment diff --git a/.changeset/hot-pets-sneeze.md b/.changeset/hot-pets-sneeze.md new file mode 100644 index 00000000000..b60e7d7cde8 --- /dev/null +++ b/.changeset/hot-pets-sneeze.md @@ -0,0 +1,12 @@ +--- +"chainlink": minor +--- + +- Misc VRF V2+ contract changes + - Reuse struct RequestCommitmentV2Plus from VRFTypes + - Fix interface name IVRFCoordinatorV2PlusFulfill in BatchVRFCoordinatorV2Plus to avoid confusion with IVRFCoordinatorV2Plus.sol + - Remove unused errors + - Rename variables for readability + - Fix comments + - Minor gas optimisation (++i) +- Fix integration tests diff --git a/.changeset/hungry-impalas-jog.md b/.changeset/hungry-impalas-jog.md new file mode 100644 index 00000000000..efa23edabb2 --- /dev/null +++ b/.changeset/hungry-impalas-jog.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +Added a tx simulation feature to the chain client to enable testing for zk out-of-counter (OOC) errors diff --git a/.changeset/hungry-seas-attend.md b/.changeset/hungry-seas-attend.md new file mode 100644 index 00000000000..1b6af484f8f --- /dev/null +++ b/.changeset/hungry-seas-attend.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +refactor foundry tests for auto 2.3 diff --git a/.changeset/kind-crabs-begin.md b/.changeset/kind-crabs-begin.md new file mode 100644 index 00000000000..4718b21f126 --- /dev/null +++ b/.changeset/kind-crabs-begin.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +Helper VRF CLI command diff --git a/.changeset/large-flowers-agree.md b/.changeset/large-flowers-agree.md new file mode 100644 index 00000000000..9f12ab42a65 --- /dev/null +++ b/.changeset/large-flowers-agree.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +Update keyvalue store to be compatible with the interface required in chainlink common diff --git a/.changeset/large-games-applaud.md b/.changeset/large-games-applaud.md new file mode 100644 index 00000000000..c6c0b3bf6f9 --- /dev/null +++ b/.changeset/large-games-applaud.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +VRFV2PlusWrapper contract: subID param added to the constructor, removed migrate() method diff --git a/.changeset/large-oranges-warn.md b/.changeset/large-oranges-warn.md new file mode 100644 index 00000000000..db29d9b5d77 --- /dev/null +++ b/.changeset/large-oranges-warn.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Adds prometheus metrics for automation streams error handling diff --git a/.changeset/lazy-cooks-agree.md b/.changeset/lazy-cooks-agree.md new file mode 100644 index 00000000000..923d2404428 --- /dev/null +++ b/.changeset/lazy-cooks-agree.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Chainlink Functions contracts v1.3 audit findings diff --git a/.changeset/little-hats-worry.md b/.changeset/little-hats-worry.md new file mode 100644 index 00000000000..eb3e86e153a --- /dev/null +++ b/.changeset/little-hats-worry.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +Change LimitTransfer gasLimit type from uint32 to uint64 diff --git a/.changeset/little-plums-grow.md b/.changeset/little-plums-grow.md new file mode 100644 index 00000000000..fa362d2dc59 --- /dev/null +++ b/.changeset/little-plums-grow.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +improve foundry tests and fix nits diff --git a/.changeset/modern-candles-begin.md b/.changeset/modern-candles-begin.md new file mode 100644 index 00000000000..933c1749d03 --- /dev/null +++ b/.changeset/modern-candles-begin.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +billing overrides diff --git a/.changeset/moody-ligers-walk.md b/.changeset/moody-ligers-walk.md new file mode 100644 index 00000000000..c93bf8517ee --- /dev/null +++ b/.changeset/moody-ligers-walk.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Add new pipeline for testing EVM node compatibility on go-ethereum dependency bump diff --git a/.changeset/nasty-humans-promise.md b/.changeset/nasty-humans-promise.md new file mode 100644 index 00000000000..8a366df1bae --- /dev/null +++ b/.changeset/nasty-humans-promise.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +add pending request counter for vrf v2.5 coordinator diff --git a/.changeset/nasty-penguins-smash.md b/.changeset/nasty-penguins-smash.md new file mode 100644 index 00000000000..620e8068e08 --- /dev/null +++ b/.changeset/nasty-penguins-smash.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Add GetFilters function to the log_poller diff --git a/.changeset/odd-mugs-divide.md b/.changeset/odd-mugs-divide.md new file mode 100644 index 00000000000..8498593c6eb --- /dev/null +++ b/.changeset/odd-mugs-divide.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Set LINK native feed in VRFV2PlusWrapper to immutable diff --git a/.changeset/odd-mugs-end.md b/.changeset/odd-mugs-end.md new file mode 100644 index 00000000000..7dba6199ce7 --- /dev/null +++ b/.changeset/odd-mugs-end.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +address TODOs and docs for 2.3 diff --git a/.changeset/polite-jeans-knock.md b/.changeset/polite-jeans-knock.md new file mode 100644 index 00000000000..69ec1715211 --- /dev/null +++ b/.changeset/polite-jeans-knock.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Remote Trigger diff --git a/.changeset/poor-melons-vanish.md b/.changeset/poor-melons-vanish.md new file mode 100644 index 00000000000..3b6d901b157 --- /dev/null +++ b/.changeset/poor-melons-vanish.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +Add the `pool_rpc_node_highest_finalized_block` metric that tracks the highest finalized block seen per RPC. If `FinalityTagEnabled = true`, a positive `NodePool.FinalizedBlockPollInterval` is needed to collect the metric. If the finality tag is not enabled, the metric is populated with a calculated latest finalized block based on the latest head and finality depth. diff --git a/.changeset/popular-buckets-hang.md b/.changeset/popular-buckets-hang.md new file mode 100644 index 00000000000..a80b4c90052 --- /dev/null +++ b/.changeset/popular-buckets-hang.md @@ -0,0 +1,18 @@ +--- +"chainlink": patch +--- + +Add new config option Pipeline.VerboseLogging + +VerboseLogging enables detailed logging of pipeline execution steps. This is +disabled by default because it increases log volume for pipeline runs, but can +be useful for debugging failed runs without relying on the UI or database. +Consider enabling this if you disabled run saving by setting MaxSuccessfulRuns +to zero. + +Set it like the following example: + +``` +[Pipeline] +VerboseLogging = true +``` diff --git a/.changeset/quick-berries-sin.md b/.changeset/quick-berries-sin.md new file mode 100644 index 00000000000..e8c348a3561 --- /dev/null +++ b/.changeset/quick-berries-sin.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +fix bug in auto2.3 withdrawERC20Fees diff --git a/.changeset/rude-beds-change.md b/.changeset/rude-beds-change.md new file mode 100644 index 00000000000..baf3e04216a --- /dev/null +++ b/.changeset/rude-beds-change.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +more auto 2.3 tests diff --git a/.changeset/rude-falcons-beg.md b/.changeset/rude-falcons-beg.md new file mode 100644 index 00000000000..4957d31c407 --- /dev/null +++ b/.changeset/rude-falcons-beg.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Calculate blockRate and logLimit defaults in the log provider based on chain ID diff --git a/.changeset/rude-paws-cross.md b/.changeset/rude-paws-cross.md new file mode 100644 index 00000000000..395a6d76244 --- /dev/null +++ b/.changeset/rude-paws-cross.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +L1Oracle handles OP Stack Ecotone encoded l1 gas price diff --git a/.changeset/selfish-timers-matter.md b/.changeset/selfish-timers-matter.md new file mode 100644 index 00000000000..cb598191ccc --- /dev/null +++ b/.changeset/selfish-timers-matter.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Refactor Log and TxStore ORMs diff --git a/.changeset/shaggy-pots-pretend.md b/.changeset/shaggy-pots-pretend.md new file mode 100644 index 00000000000..644986ddb56 --- /dev/null +++ b/.changeset/shaggy-pots-pretend.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +Add error log if juels fee per coin cache is over 24h old and lower other logs severity in cache to warn diff --git a/.changeset/shiny-forks-clap.md b/.changeset/shiny-forks-clap.md new file mode 100644 index 00000000000..4718b21f126 --- /dev/null +++ b/.changeset/shiny-forks-clap.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +Helper VRF CLI command diff --git a/.changeset/shy-jobs-speak.md b/.changeset/shy-jobs-speak.md new file mode 100644 index 00000000000..1b1c3b4c91b --- /dev/null +++ b/.changeset/shy-jobs-speak.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +use common interface for v2.3 diff --git a/.changeset/silent-pets-sip.md b/.changeset/silent-pets-sip.md new file mode 100644 index 00000000000..ba2417f0922 --- /dev/null +++ b/.changeset/silent-pets-sip.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Exposing information about LogPoller finality violation via Healthy method. It's raised whenever LogPoller sees reorg deeper than the finality diff --git a/.changeset/silly-weeks-serve.md b/.changeset/silly-weeks-serve.md new file mode 100644 index 00000000000..0f7386e69fe --- /dev/null +++ b/.changeset/silly-weeks-serve.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +update starknet relayer to fix nonce issue. introduces optional api-key for starknet toml config. diff --git a/.changeset/silver-months-glow.md b/.changeset/silver-months-glow.md new file mode 100644 index 00000000000..195525353fc --- /dev/null +++ b/.changeset/silver-months-glow.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Fixed a race condition bug around EVM nonce management, which could cause the Node to skip a nonce and get stuck. diff --git a/.changeset/small-beers-perform.md b/.changeset/small-beers-perform.md new file mode 100644 index 00000000000..a420116a44e --- /dev/null +++ b/.changeset/small-beers-perform.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Making LogPoller's replay more robust by backfilling up to finalized block and processing rest in the main loop diff --git a/.changeset/smart-kids-sip.md b/.changeset/smart-kids-sip.md new file mode 100644 index 00000000000..f5e290c5530 --- /dev/null +++ b/.changeset/smart-kids-sip.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +native support diff --git a/.changeset/smooth-monkeys-help.md b/.changeset/smooth-monkeys-help.md new file mode 100644 index 00000000000..23e44dd3032 --- /dev/null +++ b/.changeset/smooth-monkeys-help.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +upgraded transmission to 0.8.19 diff --git a/.changeset/smooth-suits-provide.md b/.changeset/smooth-suits-provide.md new file mode 100644 index 00000000000..aefafb54ad3 --- /dev/null +++ b/.changeset/smooth-suits-provide.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +docs: remove repeated words in documentation and comments diff --git a/.changeset/spicy-horses-poke.md b/.changeset/spicy-horses-poke.md new file mode 100644 index 00000000000..982d425782d --- /dev/null +++ b/.changeset/spicy-horses-poke.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Updating prometheus metrics for Automation log triggers diff --git a/.changeset/stale-sloths-drive.md b/.changeset/stale-sloths-drive.md new file mode 100644 index 00000000000..e0394de0404 --- /dev/null +++ b/.changeset/stale-sloths-drive.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +update solc version for vrf v2.5 coordinators diff --git a/.changeset/strange-swans-compare.md b/.changeset/strange-swans-compare.md new file mode 100644 index 00000000000..a5690cc5d93 --- /dev/null +++ b/.changeset/strange-swans-compare.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +remove trailing slash diff --git a/.changeset/stupid-ducks-call.md b/.changeset/stupid-ducks-call.md new file mode 100644 index 00000000000..9aae500e3fd --- /dev/null +++ b/.changeset/stupid-ducks-call.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +increase num optimizations to 500 for vrf v2.5 coordinator diff --git a/.changeset/tasty-bobcats-hammer.md b/.changeset/tasty-bobcats-hammer.md new file mode 100644 index 00000000000..69ffb6c1bcb --- /dev/null +++ b/.changeset/tasty-bobcats-hammer.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +Remove noisy log poller warning in VRFv2 & VRFv2+ listener loops diff --git a/.changeset/ten-waves-wonder.md b/.changeset/ten-waves-wonder.md new file mode 100644 index 00000000000..301a48109a8 --- /dev/null +++ b/.changeset/ten-waves-wonder.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Remove pg from evm tests diff --git a/.changeset/thick-apes-reply.md b/.changeset/thick-apes-reply.md new file mode 100644 index 00000000000..83a0232d7bb --- /dev/null +++ b/.changeset/thick-apes-reply.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +bug fixes in s_reserveAmount accounting diff --git a/.changeset/thin-coats-joke.md b/.changeset/thin-coats-joke.md new file mode 100644 index 00000000000..0cb6a0851e2 --- /dev/null +++ b/.changeset/thin-coats-joke.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +fix withdraw LINK bug in auto 2.3 diff --git a/.changeset/tiny-rabbits-crave.md b/.changeset/tiny-rabbits-crave.md new file mode 100644 index 00000000000..55b6f71c523 --- /dev/null +++ b/.changeset/tiny-rabbits-crave.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +Handle zkSync specific known transaction error diff --git a/.changeset/tiny-suns-end.md b/.changeset/tiny-suns-end.md new file mode 100644 index 00000000000..3bdd12ea362 --- /dev/null +++ b/.changeset/tiny-suns-end.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +add test for billing override diff --git a/.changeset/twenty-zebras-joke.md b/.changeset/twenty-zebras-joke.md new file mode 100644 index 00000000000..354d112e468 --- /dev/null +++ b/.changeset/twenty-zebras-joke.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +enable gas tests for auto 2.3 diff --git a/.changeset/wet-turtles-provide.md b/.changeset/wet-turtles-provide.md new file mode 100644 index 00000000000..6a26eb52d12 --- /dev/null +++ b/.changeset/wet-turtles-provide.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +Copy common transmitter methods into FunctionsContractTransmitter to enable product specific modification diff --git a/.changeset/wicked-gorillas-sniff.md b/.changeset/wicked-gorillas-sniff.md new file mode 100644 index 00000000000..7efb85aa18e --- /dev/null +++ b/.changeset/wicked-gorillas-sniff.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +VRFV2PlusWrapper config refactor diff --git a/.changeset/wicked-suits-watch.md b/.changeset/wicked-suits-watch.md new file mode 100644 index 00000000000..b4caf929a7a --- /dev/null +++ b/.changeset/wicked-suits-watch.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +Extracted Gas Limit Multiplier from gas estimators to WrappedEvmEstimator. \ No newline at end of file diff --git a/.changeset/witty-jeans-wave.md b/.changeset/witty-jeans-wave.md new file mode 100644 index 00000000000..e2a386384ab --- /dev/null +++ b/.changeset/witty-jeans-wave.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +Remove 0.6 and 0.7 Solidity source code diff --git a/.changeset/young-deers-itch.md b/.changeset/young-deers-itch.md new file mode 100644 index 00000000000..8486595c4d0 --- /dev/null +++ b/.changeset/young-deers-itch.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +pay deactivated transmitters in offchain settlement diff --git a/.dockerignore b/.dockerignore index 4bbd79b7a96..c7f58621aa2 100644 --- a/.dockerignore +++ b/.dockerignore @@ -30,3 +30,6 @@ codeship-*.yml dockercfg credentials.env gcr_creds.env + +go.work +go.work.sum \ No newline at end of file diff --git a/.github/actions/build-chainlink-image/action.yml b/.github/actions/build-chainlink-image/action.yml index 75a5147248a..39eab30120b 100644 --- a/.github/actions/build-chainlink-image/action.yml +++ b/.github/actions/build-chainlink-image/action.yml @@ -24,7 +24,7 @@ runs: steps: - name: Check if image exists id: check-image - uses: smartcontractkit/chainlink-github-actions/docker/image-exists@5bee84d30d90295010bda68b0cd46be3a1eea917 # v2.3.8 + uses: smartcontractkit/chainlink-github-actions/docker/image-exists@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: repository: chainlink tag: ${{ inputs.git_commit_sha }}${{ inputs.tag_suffix }} @@ -32,7 +32,7 @@ runs: AWS_ROLE_TO_ASSUME: ${{ inputs.AWS_ROLE_TO_ASSUME }} - name: Build Image if: steps.check-image.outputs.exists == 'false' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-image@5bee84d30d90295010bda68b0cd46be3a1eea917 # v2.3.8 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-image@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: cl_repo: smartcontractkit/chainlink cl_ref: ${{ inputs.git_commit_sha }} diff --git a/.github/actions/build-sign-publish-chainlink/action.yml b/.github/actions/build-sign-publish-chainlink/action.yml index 5bcbf205c1b..7ed0c911b83 100644 --- a/.github/actions/build-sign-publish-chainlink/action.yml +++ b/.github/actions/build-sign-publish-chainlink/action.yml @@ -105,7 +105,7 @@ runs: - if: inputs.publish == 'true' # Log in to AWS for publish to ECR name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 + uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 with: role-to-assume: ${{ inputs.aws-role-to-assume }} role-duration-seconds: ${{ inputs.aws-role-duration-seconds }} @@ -113,16 +113,16 @@ runs: - if: inputs.publish == 'true' name: Login to ECR - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 with: registry: ${{ inputs.ecr-hostname }} - name: Setup Docker Buildx - uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 + uses: docker/setup-buildx-action@2b51285047da1547ffb1b2203d8be4c0af6b1f20 # v3.2.0 - name: Generate docker metadata for root image id: meta-root - uses: docker/metadata-action@dbef88086f6cef02e264edb7dbf63250c17cef6c # v5.5.0 + uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1 env: DOCKER_METADATA_PR_HEAD_SHA: "true" with: @@ -137,14 +137,14 @@ runs: # To avoid rate limiting from Docker Hub, we login with a paid user account. - name: Login to Docker Hub if: inputs.dockerhub_username && inputs.dockerhub_password - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 with: username: ${{ inputs.dockerhub_username }} password: ${{ inputs.dockerhub_password }} - name: Build and push root docker image id: buildpush-root - uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0 + uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0 with: push: ${{ inputs.publish }} context: . @@ -166,7 +166,7 @@ runs: - name: Generate docker metadata for non-root image id: meta-nonroot - uses: docker/metadata-action@dbef88086f6cef02e264edb7dbf63250c17cef6c # v5.5.0 + uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1 env: DOCKER_METADATA_PR_HEAD_SHA: "true" with: @@ -180,14 +180,14 @@ runs: # To avoid rate limiting from Docker Hub, we login with a paid user account. - name: Login to Docker Hub if: inputs.dockerhub_username && inputs.dockerhub_password - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 with: username: ${{ inputs.dockerhub_username }} password: ${{ inputs.dockerhub_password }} - name: Build and push non-root docker image id: buildpush-nonroot - uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0 + uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0 with: push: ${{ inputs.publish }} context: . @@ -227,7 +227,7 @@ runs: - if: inputs.sign-images == 'true' name: Install cosign - uses: sigstore/cosign-installer@11086d25041f77fe8fe7b9ea4e48e3b9192b8f19 # v3.1.2 + uses: sigstore/cosign-installer@e1523de7571e31dbe865fd2e80c5c7c23ae71eb4 # v3.4.0 with: cosign-release: "v1.6.0" diff --git a/.github/actions/build-test-image/action.yml b/.github/actions/build-test-image/action.yml index 7fe002a82b2..57151960268 100644 --- a/.github/actions/build-test-image/action.yml +++ b/.github/actions/build-test-image/action.yml @@ -34,7 +34,7 @@ runs: # Base Test Image Logic - name: Get CTF Version id: version - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/mod-version@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/mod-version@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: go-project-path: ./integration-tests module-name: github.com/smartcontractkit/chainlink-testing-framework @@ -51,7 +51,7 @@ runs: echo "short_sha=${short_sha}" >> "$GITHUB_OUTPUT" - name: Checkout chainlink-testing-framework if: steps.version.outputs.is_semantic == 'false' - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: repository: smartcontractkit/chainlink-testing-framework ref: main @@ -71,7 +71,7 @@ runs: - name: Check if test base image exists if: steps.version.outputs.is_semantic == 'false' id: check-base-image - uses: smartcontractkit/chainlink-github-actions/docker/image-exists@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/docker/image-exists@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: repository: ${{ inputs.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ inputs.QA_AWS_REGION }}.amazonaws.com/test-base-image tag: ${{ steps.long_sha.outputs.long_sha }} @@ -79,7 +79,7 @@ runs: AWS_ROLE_TO_ASSUME: ${{ inputs.QA_AWS_ROLE_TO_ASSUME }} - name: Build Base Image if: steps.version.outputs.is_semantic == 'false' && steps.check-base-image.outputs.exists == 'false' - uses: smartcontractkit/chainlink-github-actions/docker/build-push@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/docker/build-push@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 env: BASE_IMAGE_NAME: ${{ inputs.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ inputs.QA_AWS_REGION }}.amazonaws.com/test-base-image:${{ steps.long_sha.outputs.long_sha }} with: @@ -92,7 +92,7 @@ runs: # Test Runner Logic - name: Check if image exists id: check-image - uses: smartcontractkit/chainlink-github-actions/docker/image-exists@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/docker/image-exists@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: repository: ${{ inputs.repository }} tag: ${{ inputs.tag }} @@ -100,7 +100,7 @@ runs: AWS_ROLE_TO_ASSUME: ${{ inputs.QA_AWS_ROLE_TO_ASSUME }} - name: Build and Publish Test Runner if: steps.check-image.outputs.exists == 'false' - uses: smartcontractkit/chainlink-github-actions/docker/build-push@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/docker/build-push@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: tags: | ${{ inputs.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ inputs.QA_AWS_REGION }}.amazonaws.com/${{ inputs.repository }}:${{ inputs.tag }} diff --git a/.github/actions/delete-deployments/action.yml b/.github/actions/delete-deployments/action.yml index f2595b41022..537e4498596 100644 --- a/.github/actions/delete-deployments/action.yml +++ b/.github/actions/delete-deployments/action.yml @@ -33,7 +33,7 @@ runs: with: version: ^8.0.0 - - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 + - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 with: node-version: "18" cache: "pnpm" diff --git a/.github/actions/golangci-lint/action.yml b/.github/actions/golangci-lint/action.yml index d0fd87774cc..3542c865959 100644 --- a/.github/actions/golangci-lint/action.yml +++ b/.github/actions/golangci-lint/action.yml @@ -32,7 +32,7 @@ inputs: runs: using: composite steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Setup Go uses: ./.github/actions/setup-go with: @@ -48,7 +48,7 @@ runs: shell: bash run: go build ./... - name: golangci-lint - uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 + uses: golangci/golangci-lint-action@3cfe3a4abbb849e10058ce4af15d205b6da42804 # v4.0.0 with: version: v1.55.2 # We already cache these directories in setup-go @@ -58,16 +58,21 @@ runs: only-new-issues: false # disabled for PRs due to unreliability args: --out-format colored-line-number,checkstyle:golangci-lint-report.xml working-directory: ${{ inputs.go-directory }} + - name: Print lint report artifact + if: failure() + shell: bash + run: cat ${{ inputs.go-directory }}/golangci-lint-report.xml - name: Store lint report artifact if: always() - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 with: name: golangci-lint-report path: ${{ inputs.go-directory }}/golangci-lint-report.xml - name: Collect Metrics if: always() - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: chainlink-golang-ci basic-auth: ${{ inputs.gc-basic-auth }} hostname: ${{ inputs.gc-host }} org-id: ${{ inputs.gc-org-id }} diff --git a/.github/actions/goreleaser-build-sign-publish/action.yml b/.github/actions/goreleaser-build-sign-publish/action.yml index b8760e34dc1..f4b2111bea5 100644 --- a/.github/actions/goreleaser-build-sign-publish/action.yml +++ b/.github/actions/goreleaser-build-sign-publish/action.yml @@ -68,7 +68,7 @@ runs: using: composite steps: - name: Setup docker buildx - uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 + uses: docker/setup-buildx-action@2b51285047da1547ffb1b2203d8be4c0af6b1f20 # v3.2.0 - name: Set up qemu uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0 - name: Setup go @@ -89,12 +89,12 @@ runs: version: ${{ inputs.zig-version }} - name: Setup cosign if: inputs.enable-cosign == 'true' - uses: sigstore/cosign-installer@9614fae9e5c5eddabb09f90a270fcb487c9f7149 # v3.3.0 + uses: sigstore/cosign-installer@e1523de7571e31dbe865fd2e80c5c7c23ae71eb4 # v3.4.0 with: cosign-release: ${{ inputs.cosign-version }} - name: Login to docker registry if: inputs.enable-docker-publish == 'true' - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 with: registry: ${{ inputs.docker-registry }} - name: Goreleaser release diff --git a/.github/actions/notify-slack-jobs-result/action.yml b/.github/actions/notify-slack-jobs-result/action.yml index 63840cfa393..f5df87bb909 100644 --- a/.github/actions/notify-slack-jobs-result/action.yml +++ b/.github/actions/notify-slack-jobs-result/action.yml @@ -36,9 +36,10 @@ runs: # I feel like there's some clever, fully jq way to do this, but I ain't got the motivation to figure it out echo "Querying test results at https://api.github.com/repos/${{inputs.github_repository}}/actions/runs/${{ inputs.workflow_run_id }}/jobs" + # we can get a maximum of 100 jobs per page, after that we need to start using pagination PARSED_RESULTS=$(curl \ -H "Authorization: Bearer ${{ inputs.github_token }}" \ - 'https://api.github.com/repos/${{inputs.github_repository}}/actions/runs/${{ inputs.workflow_run_id }}/jobs' \ + 'https://api.github.com/repos/${{inputs.github_repository}}/actions/runs/${{ inputs.workflow_run_id }}/jobs?per_page=100' \ | jq -r --arg pattern "${{ inputs.github_job_name_regex }}" '.jobs[] | select(.name | test($pattern)) as $job | $job.steps[] @@ -59,9 +60,9 @@ runs: echo all_success=$ALL_SUCCESS >> $GITHUB_OUTPUT - FORMATTED_RESULTS=$(echo $PARSED_RESULTS | jq -s '[.[] - | { - conclusion: .conclusion, + FORMATTED_RESULTS=$(echo $PARSED_RESULTS | jq -s '[.[] + | { + conclusion: .conclusion, cap: .cap, html_url: .html_url } @@ -80,7 +81,7 @@ runs: echo results=$CLEAN_RESULTS >> $GITHUB_OUTPUT - name: Post Results - uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0 env: SLACK_BOT_TOKEN: ${{ inputs.slack_bot_token }} with: diff --git a/.github/actions/setup-create-base64-config/action.yml b/.github/actions/setup-create-base64-config/action.yml index d68d4f7b12f..447f5be42cb 100644 --- a/.github/actions/setup-create-base64-config/action.yml +++ b/.github/actions/setup-create-base64-config/action.yml @@ -35,6 +35,10 @@ inputs: description: Grafana URL grafanaDashboardUrl: description: Grafana dashboard URL + ethExecutionClient: + description: Ethereum execution client to use (geth, besu, nethermind or erigon) + customEthClientDockerImage: + description: custom docker image to use for eth client (e.g. hyperledger/besu:21.10.0) runs: using: composite @@ -58,6 +62,8 @@ runs: LOGSTREAM_LOG_TARGETS: ${{ inputs.logstreamLogTargets }} GRAFANA_URL: ${{ inputs.grafanaUrl }} GRAFANA_DASHBOARD_URL: ${{ inputs.grafanaDashboardUrl }} + ETH_EXECUTION_CLIENT: ${{ inputs.ethExecutionClient }} + CUSTOM_ETH_CLIENT_DOCKER_IMAGE: ${{ inputs.customEthClientDockerImage }} run: | echo ::add-mask::$CHAINLINK_IMAGE function convert_to_toml_array() { @@ -88,6 +94,21 @@ runs: test_log_collect=false fi + custom_images="" + ethereum_version="" + + if [ -n "$CUSTOM_ETH_CLIENT_DOCKER_IMAGE" ]; then + ethereum_version="ethereum_version=\"\"" + custom_images+="[PrivateEthereumNetwork.CustomDockerImages]" + custom_images+=$'\n'"execution_layer=\"$CUSTOM_ETH_CLIENT_DOCKER_IMAGE\"" + fi + + if [ -n "$ETH_EXECUTION_CLIENT" ]; then + execution_layer="$ETH_EXECUTION_CLIENT" + else + execution_layer="geth" + fi + cat << EOF > config.toml [Network] selected_networks=$selected_networks @@ -118,6 +139,12 @@ runs: [Logging.Grafana] base_url="$GRAFANA_URL" dashboard_url="$GRAFANA_DASHBOARD_URL" + + [PrivateEthereumNetwork] + execution_layer="$execution_layer" + $ethereum_version + + $custom_images EOF BASE64_CONFIG_OVERRIDE=$(cat config.toml | base64 -w 0) diff --git a/.github/actions/setup-go/action.yml b/.github/actions/setup-go/action.yml index 405a5dfe954..6514f533ef0 100644 --- a/.github/actions/setup-go/action.yml +++ b/.github/actions/setup-go/action.yml @@ -26,7 +26,7 @@ runs: - name: Get branch name if: ${{ inputs.only-modules == 'false' }} id: branch-name - uses: tj-actions/branch-names@2e5354c6733793113f416314375826df030ada23 #v6.5 + uses: tj-actions/branch-names@6871f53176ad61624f978536bbf089c574dc19a2 # v8.0.1 - name: Set go cache keys shell: bash @@ -40,7 +40,7 @@ runs: shell: bash run: echo "path=./${{ inputs.go-module-file }}" >> $GITHUB_OUTPUT - - uses: actions/cache@v3 + - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 name: Cache Go Modules with: path: | @@ -51,7 +51,7 @@ runs: restore-keys: | ${{ runner.os }}-gomod-${{ inputs.cache-version }}- - - uses: actions/cache@v3 + - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 if: ${{ inputs.only-modules == 'false' }} name: Cache Go Build Outputs with: diff --git a/.github/actions/setup-hardhat/action.yaml b/.github/actions/setup-hardhat/action.yaml index 3b52a4b8c51..189c8210024 100644 --- a/.github/actions/setup-hardhat/action.yaml +++ b/.github/actions/setup-hardhat/action.yaml @@ -11,13 +11,13 @@ runs: using: composite steps: - name: Cache Compilers - uses: actions/cache@v3 + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: ~/.cache/hardhat-nodejs/ key: contracts-compilers-${{ runner.os }}-${{ inputs.cache-version }}-${{ hashFiles('contracts/pnpm-lock.yaml', 'contracts/hardhat.config.ts') }} - name: Cache contracts build outputs - uses: actions/cache@v3 + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: | contracts/cache/ diff --git a/.github/actions/setup-nodejs/action.yaml b/.github/actions/setup-nodejs/action.yaml index e0bdaebe99e..ed4c1d22e8b 100644 --- a/.github/actions/setup-nodejs/action.yaml +++ b/.github/actions/setup-nodejs/action.yaml @@ -11,7 +11,7 @@ runs: with: version: ^7.0.0 - - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 + - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 with: node-version: "16" cache: "pnpm" diff --git a/.github/actions/setup-solana/action.yml b/.github/actions/setup-solana/action.yml index c50ccd58352..41c67a94197 100644 --- a/.github/actions/setup-solana/action.yml +++ b/.github/actions/setup-solana/action.yml @@ -3,7 +3,7 @@ description: Setup solana CLI runs: using: composite steps: - - uses: actions/cache@v3 + - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 id: cache name: Cache solana CLI with: diff --git a/.github/actions/setup-wasmd/action.yml b/.github/actions/setup-wasmd/action.yml index 46fb84ba3ef..3e3846a70eb 100644 --- a/.github/actions/setup-wasmd/action.yml +++ b/.github/actions/setup-wasmd/action.yml @@ -3,7 +3,7 @@ description: Setup Cosmos wasmd, used for integration tests runs: using: composite steps: - - uses: actions/cache@v3 + - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 id: cache name: Cache wasmd-build with: diff --git a/.github/actions/split-tests/action.yaml b/.github/actions/split-tests/action.yaml index 684fd6a2bd7..633e897db54 100644 --- a/.github/actions/split-tests/action.yaml +++ b/.github/actions/split-tests/action.yaml @@ -11,11 +11,11 @@ outputs: runs: using: composite steps: - - uses: pnpm/action-setup@c3b53f6a16e57305370b4ae5a540c2077a1d50dd #v2.2.4 + - uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0 with: version: ^7.0.0 - - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 + - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 with: node-version: "16" cache: "pnpm" diff --git a/.github/actions/version-file-bump/action.yml b/.github/actions/version-file-bump/action.yml index 2c9b95a6898..2875234cf17 100644 --- a/.github/actions/version-file-bump/action.yml +++ b/.github/actions/version-file-bump/action.yml @@ -8,7 +8,7 @@ inputs: outputs: result: value: ${{ steps.compare.outputs.result }} - description: 'Result of the comparison' + description: "Result of the comparison" runs: using: composite steps: @@ -31,12 +31,26 @@ runs: current_version=$(head -n1 ./VERSION) echo "current_version=${current_version}" | tee -a "$GITHUB_OUTPUT" - name: Compare semantic versions - uses: smartcontractkit/chainlink-github-actions/semver-compare@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/semver-compare@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 id: compare with: version1: ${{ steps.get-current-version.outputs.current_version }} operator: eq version2: ${{ steps.get-latest-version.outputs.latest_version }} + # The follow two steps are temp until we migrate to use version from package.json as the source of truth + - name: Get package version + id: get-package-version + shell: bash + run: | + package_version=$(jq -r '.version' ./package.json) + echo "package_version=${package_version}" | tee -a "$GITHUB_OUTPUT" + - name: Diff versions + uses: smartcontractkit/chainlink-github-actions/semver-compare@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 + id: diff + with: + version1: ${{ steps.get-current-version.outputs.current_version }} + operator: eq + version2: ${{ steps.get-package-version.outputs.package_version }} - name: Fail if version not bumped # XXX: The reason we are not checking if the current is greater than the # latest release is to account for hot fixes which may have been branched @@ -44,8 +58,13 @@ runs: shell: bash env: VERSION_NOT_BUMPED: ${{ steps.compare.outputs.result }} + VERSION_SAME: ${{ steps.diff.outputs.result }} run: | if [[ "${VERSION_NOT_BUMPED:-}" = "true" ]]; then echo "Version file not bumped since last release. Please bump the ./VERSION file in the root of the repo and commit the change." exit 1 fi + if [[ "${VERSION_SAME:-}" = "false" ]]; then + echo "The version in the VERSION file is not the same as the version in package.json file. Please fix by running `pnpm changeset version`." + exit 1 + fi diff --git a/.github/scripts/crib/pr-comment-crib-env.js b/.github/scripts/crib/pr-comment-crib-env.js index 38283038ed1..d569587baff 100755 --- a/.github/scripts/crib/pr-comment-crib-env.js +++ b/.github/scripts/crib/pr-comment-crib-env.js @@ -12,8 +12,10 @@ function generateSubdomains(subdomainPrefix, prNumber) { "node4", "node5", "node6", - "geth-http", - "geth-ws", + "geth-1337-http", + "geth-1337-ws", + "geth-2337-http", + "geth-2337-ws", "mockserver", ]; return subDomainSuffixes.map( diff --git a/.github/tracing/tempo.yaml b/.github/tracing/tempo.yaml index e61f744f78b..aa8c0ecbf0f 100644 --- a/.github/tracing/tempo.yaml +++ b/.github/tracing/tempo.yaml @@ -19,6 +19,6 @@ storage: trace: backend: local # backend configuration to use wal: - path: /tmp/tempo/wal # where to store the the wal locally + path: /tmp/tempo/wal # where to store the wal locally local: path: /tmp/tempo/blocks \ No newline at end of file diff --git a/.github/workflows/automation-benchmark-tests.yml b/.github/workflows/automation-benchmark-tests.yml index c81e46d9930..97e8e623138 100644 --- a/.github/workflows/automation-benchmark-tests.yml +++ b/.github/workflows/automation-benchmark-tests.yml @@ -25,7 +25,7 @@ jobs: id-token: write contents: read name: Automation Benchmark Test - runs-on: ubuntu20.04-16cores-64GB + runs-on: ubuntu22.04-16cores-64GB env: SLACK_API_KEY: ${{ secrets.QA_SLACK_API_KEY }} SLACK_CHANNEL: C03KJ5S7KEK @@ -33,7 +33,7 @@ jobs: REF_NAME: ${{ github.head_ref || github.ref_name }} steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ env.REF_NAME }} - name: Get Slack config and mask base64 config @@ -66,7 +66,7 @@ jobs: QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} suites: benchmark chaos reorg load - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 env: DETACH_RUNNER: true TEST_SUITE: benchmark @@ -89,8 +89,9 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: automation-benchmark-build-test-image org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} diff --git a/.github/workflows/automation-load-tests.yml b/.github/workflows/automation-load-tests.yml index 82a1bba6d67..a784be51c63 100644 --- a/.github/workflows/automation-load-tests.yml +++ b/.github/workflows/automation-load-tests.yml @@ -21,7 +21,7 @@ jobs: id-token: write contents: read name: Automation Load Test - runs-on: ubuntu20.04-16cores-64GB + runs-on: ubuntu22.04-16cores-64GB env: SLACK_API_KEY: ${{ secrets.QA_SLACK_API_KEY }} SLACK_CHANNEL: C03KJ5S7KEK @@ -29,7 +29,7 @@ jobs: REF_NAME: ${{ github.head_ref || github.ref_name }} steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ env.REF_NAME }} - name: Get Slack config and mask base64 config @@ -82,7 +82,7 @@ jobs: QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} suites: benchmark chaos reorg load - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 env: RR_CPU: 4000m RR_MEM: 4Gi @@ -107,8 +107,9 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: automation-load-test org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} diff --git a/.github/workflows/automation-nightly-tests.yml b/.github/workflows/automation-nightly-tests.yml index 0427fe5b47d..2b7e2c1fdfc 100644 --- a/.github/workflows/automation-nightly-tests.yml +++ b/.github/workflows/automation-nightly-tests.yml @@ -17,19 +17,20 @@ jobs: id-token: write contents: read name: Build Chainlink Image - runs-on: ubuntu20.04-16cores-64GB + runs-on: ubuntu22.04-16cores-64GB steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: automation-nightly-build-chainlink org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} this-job-name: Build Chainlink Image continue-on-error: true - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Build Chainlink Image @@ -59,28 +60,31 @@ jobs: matrix: tests: - name: Upgrade 2.0 + id: upgrade-2-0 suite: smoke nodes: 1 - os: ubuntu20.04-8cores-32GB + os: ubuntu22.04-8cores-32GB network: SIMULATED command: -run ^TestAutomationNodeUpgrade/registry_2_0 ./smoke - name: Upgrade 2.1 + id: upgrade-2-1 suite: smoke nodes: 5 - os: ubuntu20.04-8cores-32GB + os: ubuntu22.04-8cores-32GB network: SIMULATED command: -run ^TestAutomationNodeUpgrade/registry_2_1 ./smoke - name: Upgrade 2.2 + id: upgrade-2-2 suite: smoke nodes: 5 - os: ubuntu20.04-8cores-32GB + os: ubuntu22.04-8cores-32GB network: SIMULATED command: -run ^TestAutomationNodeUpgrade/registry_2_2 ./smoke runs-on: ${{ matrix.tests.os }} name: Automation ${{ matrix.tests.name }} Test steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ github.head_ref || github.ref_name }} - name: Prepare Base64 TOML override @@ -92,7 +96,7 @@ jobs: upgradeImage: ${{ env.CHAINLINK_IMAGE }} upgradeVersion: ${{ github.sha }} - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 env: TEST_SUITE: ${{ matrix.tests.suite }} with: @@ -109,7 +113,7 @@ jobs: QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - name: Upload test log - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 if: failure() with: name: test-log-${{ matrix.tests.name }} @@ -119,8 +123,9 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: automation-nightly-upgrade-tests-${{ matrix.tests.id }} org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} diff --git a/.github/workflows/automation-ondemand-tests.yml b/.github/workflows/automation-ondemand-tests.yml index 830fb09186c..398bce02417 100644 --- a/.github/workflows/automation-ondemand-tests.yml +++ b/.github/workflows/automation-ondemand-tests.yml @@ -51,26 +51,27 @@ jobs: dockerfile: plugins/chainlink.Dockerfile tag-suffix: -plugins name: Build Chainlink Image ${{ matrix.image.name }} - runs-on: ubuntu20.04-16cores-64GB + runs-on: ubuntu22.04-16cores-64GB steps: - name: Collect Metrics if: inputs.chainlinkImage == '' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: automation-on-demand-build-chainlink org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} this-job-name: Build Chainlink Image ${{ matrix.image.name }} continue-on-error: true - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ github.head_ref || github.ref_name }} - name: Check if image exists if: inputs.chainlinkImage == '' id: check-image - uses: smartcontractkit/chainlink-github-actions/docker/image-exists@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/docker/image-exists@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: repository: chainlink tag: ${{ github.sha }}${{ matrix.image.tag-suffix }} @@ -78,7 +79,7 @@ jobs: AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - name: Build Image if: steps.check-image.outputs.exists == 'false' && inputs.chainlinkImage == '' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-image@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-image@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: cl_repo: smartcontractkit/chainlink cl_ref: ${{ github.sha }} @@ -98,19 +99,20 @@ jobs: id-token: write contents: read name: Build Test Image - runs-on: ubuntu20.04-16cores-64GB + runs-on: ubuntu22.04-16cores-64GB steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: automation-on-demand-build-test-image org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} this-job-name: Build Test Image continue-on-error: true - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ github.head_ref || github.ref_name }} - name: Build Test Image @@ -138,6 +140,7 @@ jobs: matrix: tests: - name: chaos + id: chaos suite: chaos nodes: 15 os: ubuntu-latest @@ -146,6 +149,7 @@ jobs: network: SIMULATED command: -run ^TestAutomationChaos$ ./chaos - name: reorg + id: reorg suite: reorg nodes: 5 os: ubuntu-latest @@ -154,28 +158,31 @@ jobs: network: SIMULATED_NONDEV command: -run ^TestAutomationReorg$ ./reorg - name: upgrade 2.0 + id: upgrade-2.0 type: upgrade suite: smoke nodes: 1 - os: ubuntu20.04-8cores-32GB + os: ubuntu22.04-8cores-32GB enabled: true pyroscope_env: ci-automation-on-demand-upgrade network: SIMULATED command: -run ^TestAutomationNodeUpgrade/registry_2_0 ./smoke - name: upgrade 2.1 + id: upgrade-2.1 type: upgrade suite: smoke nodes: 5 - os: ubuntu20.04-8cores-32GB + os: ubuntu22.04-8cores-32GB enabled: true pyroscope_env: ci-automation-on-demand-upgrade network: SIMULATED command: -run ^TestAutomationNodeUpgrade/registry_2_1 ./smoke - name: upgrade 2.2 + id: upgrade-2.2 type: upgrade suite: smoke nodes: 5 - os: ubuntu20.04-8cores-32GB + os: ubuntu22.04-8cores-32GB enabled: true pyroscope_env: ci-automation-on-demand-upgrade network: SIMULATED @@ -184,7 +191,7 @@ jobs: name: Automation On Demand ${{ matrix.tests.name }} Test steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ github.head_ref || github.ref_name }} - name: Determine build to use @@ -258,7 +265,7 @@ jobs: echo ::add-mask::$BASE64_CONFIG_OVERRIDE echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 if: ${{ matrix.tests.enabled == true }} env: TEST_SUITE: ${{ matrix.tests.suite }} @@ -276,7 +283,7 @@ jobs: QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - name: Upload test log - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 if: failure() with: name: test-log-${{ matrix.tests.name }} @@ -286,8 +293,9 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: automation-on-demand-tests-${{ matrix.tests.id }} org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} diff --git a/.github/workflows/bash-scripts.yml b/.github/workflows/bash-scripts.yml index 9fe2a0e60e4..e9b7265c962 100644 --- a/.github/workflows/bash-scripts.yml +++ b/.github/workflows/bash-scripts.yml @@ -11,8 +11,8 @@ jobs: bash-scripts-src: ${{ steps.bash-scripts.outputs.src }} steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 id: bash-scripts with: filters: | @@ -25,7 +25,7 @@ jobs: needs: [changes] steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Run ShellCheck if: needs.changes.outputs.bash-scripts-src == 'true' uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # v2.0.0 diff --git a/.github/workflows/build-publish-develop.yml b/.github/workflows/build-publish-develop.yml index 48cc5df80f3..def6aca189a 100644 --- a/.github/workflows/build-publish-develop.yml +++ b/.github/workflows/build-publish-develop.yml @@ -31,7 +31,7 @@ jobs: name: push-chainlink-develop ${{ matrix.image.name }} steps: - name: Checkout repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ env.GIT_REF }} # When this is ran from manual workflow_dispatch, the github.sha may be @@ -55,11 +55,55 @@ jobs: dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} git-commit-sha: ${{ steps.git-ref.outputs.checked-out || github.sha }} + + - name: Setup GAP + # Don't run for plugins. + if: matrix.image.name == '' + uses: smartcontractkit/.github/actions/setup-gap@1bc7ce34fa81fffcb4a6eb0e4e12e59d94d0fc8f # setup-gap@0.2.0 + with: + aws-region: ${{ secrets.AWS_REGION }} + aws-role-arn: ${{ secrets.AWS_OIDC_CRIB_ROLE_ARN_SAND }} + api-gateway-host: ${{ secrets.AWS_API_GW_HOST_K8S_SAND }} + use-k8s: "true" + k8s-cluster-name: ${{ secrets.AWS_EKS_CLUSTER_NAME_SAND }} + use-private-ecr-registry: true + ecr-private-registry: ${{ secrets.AWS_ACCOUNT_ID_PROD }} + metrics-job-name: push-chainlink-develop ${{ matrix.image.name }} + gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }} + gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} + gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} + + # A mutable image tag is used for these CRIBs and it was just built/published + # from this workflow. The deployment has an `imagePullPolicy: Always` set, so + # we need to restart the deployments to pick up the new image. + - name: Restart K8s Deployments for CRIBs + # Don't run for plugins. + if: matrix.image.name == '' + shell: bash + run: | + set -euo pipefail + # Removes the "smartcontractkit/" (org name) prefix. + REPO_NAME_ONLY="${GITHUB_REPOSITORY##*/}" + K8S_NAMESPACE="crib-${REPO_NAME_ONLY}-develop" + + deployment_node_names=$(kubectl --namespace "${K8S_NAMESPACE}" \ + get deployments \ + -l "app=${K8S_NAMESPACE}" \ + -o custom-columns=:metadata.name --no-headers) + + IFS=$'\n' read -r -d '' -a deployment_names_arr <<< "$deployment_node_names" || : + for name in "${deployment_names_arr[@]}"; do + echo "Restarting deployment: $name" + kubectl --namespace "${K8S_NAMESPACE}" \ + rollout restart "deployment/${name}" + done + - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: build-chainlink-develop org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} diff --git a/.github/workflows/build-publish-pr.yml b/.github/workflows/build-publish-pr.yml index b7b06e149e2..17118e9a8cd 100644 --- a/.github/workflows/build-publish-pr.yml +++ b/.github/workflows/build-publish-pr.yml @@ -21,7 +21,7 @@ jobs: ECR_IMAGE_NAME: crib-chainlink-untrusted steps: - name: Checkout repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Git Short SHA shell: bash @@ -32,7 +32,7 @@ jobs: - name: Check if image exists id: check-image - uses: smartcontractkit/chainlink-github-actions/docker/image-exists@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/docker/image-exists@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: repository: ${{ env.ECR_IMAGE_NAME}} tag: sha-${{ env.GIT_SHORT_SHA }} @@ -53,56 +53,12 @@ jobs: dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} - - name: Get PR labels - id: pr-labels - env: - GH_TOKEN: ${{ github.token }} - PR_NUMBER: ${{ github.event.number }} - run: | - RESPONSE=$(gh pr view ${PR_NUMBER} --json labels) - # Check if the labels command was successful - if [[ $? -ne 0 ]]; then - echo "Error fetching labels" - exit 1 - fi - echo "RESPONSE=${RESPONSE}" - LABELS=$(echo "$RESPONSE" | jq -r '.labels | map(.name) | join(", ")') - # Check if any labels were found - if [[ -z "${LABELS:-}" ]]; then - echo "No labels found" - else - echo "labels=${LABELS}" | tee -a "${GITHUB_OUTPUT}" - fi - - - name: Setup GAP - if: contains(steps.pr-labels.outputs.labels, 'crib') - uses: smartcontractkit/.github/actions/setup-gap@main - with: - aws-region: ${{ secrets.AWS_REGION }} - aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_PUBLISH_PR_ARN }} - api-gateway-host: ${{ secrets.AWS_API_GW_HOST_ARGO_SAND }} - use-argocd: "true" - argocd-user: ${{ secrets.ARGOCD_USER_SAND }} - argocd-pass: ${{ secrets.ARGOCD_PASS_SAND }} - - # Run an Argo CD sync after the image is built. - - name: Argo CD App Sync - if: contains(steps.pr-labels.outputs.labels, 'crib') - shell: bash - env: - PR_NUMBER: ${{ github.event.number }} - run: | - argocd app sync \ - --plaintext \ - --grpc-web \ - --async \ - "crib-chainlink-${PR_NUMBER}" - - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: build-chainlink-pr org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml index 123ecb5f83f..d243a75467e 100644 --- a/.github/workflows/build-publish.yml +++ b/.github/workflows/build-publish.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Checkout repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Check for VERSION file bump on tags # Avoids checking VERSION file bump on forks. if: ${{ github.repository == 'smartcontractkit/chainlink' && startsWith(github.ref, 'refs/tags/v') }} @@ -33,7 +33,7 @@ jobs: contents: read steps: - name: Checkout repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Build, sign and publish chainlink image uses: ./.github/actions/build-sign-publish-chainlink @@ -53,8 +53,9 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: build-chainlink-publish org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c4983bfac06..215b9026620 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Checkout repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Build chainlink image uses: ./.github/actions/build-sign-publish-chainlink @@ -23,8 +23,9 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: build-chainlink org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} diff --git a/.github/workflows/changeset.yml b/.github/workflows/changeset.yml index f077cee1285..e625ec50923 100644 --- a/.github/workflows/changeset.yml +++ b/.github/workflows/changeset.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 id: files-changed with: @@ -34,27 +34,50 @@ jobs: - '!core/**/*.json' - '!core/chainlink.goreleaser.Dockerfile' - '!core/chainlink.Dockerfile' + contracts: + - contracts/**/*.sol + - '!contracts/**/*.t.sol' core-changeset: - added: '.changeset/**' + contracts-changeset: + - added: 'contracts/.changeset/**' - name: Make a comment - uses: unsplash/comment-on-pr@ffe8f97ccc63ce12c3c23c6885b169db67958d3b # v1.3.0 + uses: thollander/actions-comment-pull-request@fabd468d3a1a0b97feee5f6b9e499eab0dd903f6 # v2.5.0 if: ${{ (steps.files-changed.outputs.core == 'true' || steps.files-changed.outputs.shared == 'true') && steps.files-changed.outputs.core-changeset == 'false' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - msg: "I see you updated files related to core. Please run `pnpm changeset` to add a changeset." - check_for_duplicate_msg: true - - name: Check for new changeset + message: "I see you updated files related to `core`. Please run `pnpm changeset` in the root directory to add a changeset." + reactions: eyes + comment_tag: changeset-core + - name: Make a comment + uses: thollander/actions-comment-pull-request@fabd468d3a1a0b97feee5f6b9e499eab0dd903f6 # v2.5.0 + if: ${{ steps.files-changed.outputs.contracts == 'true' && steps.files-changed.outputs.contracts-changeset == 'false' }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + message: | + I see you updated files related to `contracts`. Please run `pnpm changeset` in the `contracts` directory to add a changeset. + reactions: eyes + comment_tag: changeset-contracts + - name: Check for new changeset for core if: ${{ (steps.files-changed.outputs.core == 'true' || steps.files-changed.outputs.shared == 'true') && steps.files-changed.outputs.core-changeset == 'false' }} shell: bash run: | - echo "Please run pnpm changeset to add a changeset." + echo "Please run pnpm changeset to add a changeset for core." + exit 1 + - name: Check for new changeset for contracts + if: ${{ steps.files-changed.outputs.contracts == 'true' && steps.files-changed.outputs.contracts-changeset == 'false' }} + shell: bash + run: | + echo "Please run pnpm changeset to add a changeset for contracts." exit 1 - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: chainlink-changesets org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml index 35536a26d1e..3d2f8cf6fda 100644 --- a/.github/workflows/ci-core.yml +++ b/.github/workflows/ci-core.yml @@ -1,7 +1,8 @@ name: CI Core +run-name: CI Core ${{ inputs.distinct_run_name && inputs.distinct_run_name || '' }} concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: ${{ github.workflow }}-${{ github.ref }}-${{ inputs.distinct_run_name }} cancel-in-progress: true # Run on key branches to make sure integration is good, otherwise run on all PR's @@ -15,6 +16,17 @@ on: pull_request: schedule: - cron: "0 0 * * *" + workflow_dispatch: + inputs: + distinct_run_name: + description: 'A unique identifier for this run, used when running from other repos' + required: false + type: string + evm-ref: + description: The chainlink-evm reference to use when testing against a specific version for compatibliity + required: false + default: "" + type: string jobs: @@ -23,28 +35,32 @@ jobs: permissions: pull-requests: read outputs: - changes: ${{ steps.changes.outputs.changes }} + changes: ${{ steps.ignore-filter.outputs.changes || steps.changes.outputs.changes }} runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: repository: smartcontractkit/chainlink - - uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 id: changes with: filters: | changes: - '!integration-tests/**' + - name: Ignore Filter On Workflow Dispatch + if: ${{ github.event_name == 'workflow_dispatch' }} + id: ignore-filter + run: echo "changes=true" >> $GITHUB_OUTPUT golangci: # We don't directly merge dependabot PRs, so let's not waste the resources - if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' && github.actor != 'dependabot[bot]' }} + if: ${{ (github.event_name == 'pull_request' || github.event_name == 'schedule') && github.actor != 'dependabot[bot]' }} name: lint - runs-on: ubuntu20.04-8cores-32GB + runs-on: ubuntu22.04-8cores-32GB needs: [filter] steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Golang Lint uses: ./.github/actions/golangci-lint if: ${{ needs.filter.outputs.changes == 'true' }} @@ -65,17 +81,23 @@ jobs: strategy: fail-fast: false matrix: - cmd: ["go_core_tests", "go_core_race_tests", "go_core_fuzz"] - name: Core Tests (${{ matrix.cmd }}) + type: + - cmd: go_core_tests + id: core_unit + - cmd: go_core_race_tests + id: core_race + - cmd: go_core_fuzz + id: core_fuzz + name: Core Tests (${{ matrix.type.cmd }}) # We don't directly merge dependabot PRs, so let's not waste the resources if: github.actor != 'dependabot[bot]' needs: [filter] - runs-on: ubuntu20.04-64cores-256GB + runs-on: ubuntu-latest-64cores-256GB env: CL_DATABASE_URL: postgresql://postgres:postgres@localhost:5432/chainlink_test?sslmode=disable steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Setup node if: ${{ needs.filter.outputs.changes == 'true' }} uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 @@ -102,6 +124,10 @@ jobs: - name: Download Go vendor packages if: ${{ needs.filter.outputs.changes == 'true' }} run: go mod download + - name: Replace chainlink-evm deps + if: ${{ needs.filter.outputs.changes == 'true' && inputs.evm-ref != ''}} + shell: bash + run: go get github.com/smartcontractkit/chainlink-evm@${{ inputs.evm-ref }} - name: Build binary if: ${{ needs.filter.outputs.changes == 'true' }} run: go build -o chainlink.test . @@ -134,15 +160,15 @@ jobs: env: OUTPUT_FILE: ./output.txt USE_TEE: false - run: ./tools/bin/${{ matrix.cmd }} ./... + run: ./tools/bin/${{ matrix.type.cmd }} ./... - name: Print Filtered Test Results - if: ${{ failure() && matrix.cmd == 'go_core_tests' && needs.filter.outputs.changes == 'true' }} - uses: smartcontractkit/chainlink-github-actions/go/go-test-results-parsing@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + if: ${{ failure() && matrix.type.cmd == 'go_core_tests' && needs.filter.outputs.changes == 'true' }} + uses: smartcontractkit/chainlink-github-actions/go/go-test-results-parsing@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: results-file: ./output.txt output-file: ./output-short.txt - name: Print Races - if: ${{ failure() && matrix.cmd == 'go_core_race_tests' && needs.filter.outputs.changes == 'true' }} + if: ${{ failure() && matrix.type.cmd == 'go_core_race_tests' && needs.filter.outputs.changes == 'true' }} run: find race.* | xargs cat - name: Print postgres logs if: ${{ always() && needs.filter.outputs.changes == 'true' }} @@ -150,9 +176,9 @@ jobs: working-directory: ./.github/actions/setup-postgres - name: Store logs artifacts if: ${{ needs.filter.outputs.changes == 'true' && always() }} - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 with: - name: ${{ matrix.cmd }}_logs + name: ${{ matrix.type.cmd }}_logs path: | ./output.txt ./output-short.txt @@ -160,7 +186,7 @@ jobs: ./coverage.txt ./postgres_logs.txt - name: Notify Slack - if: ${{ failure() && matrix.cmd == 'go_core_race_tests' && (github.event_name == 'merge_group' || github.event.branch == 'develop') && needs.filter.outputs.changes == 'true' }} + if: ${{ failure() && matrix.type.cmd == 'go_core_race_tests' && (github.event_name == 'merge_group' || github.event.branch == 'develop') && needs.filter.outputs.changes == 'true' }} uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0 env: SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} @@ -170,12 +196,13 @@ jobs: - name: Collect Metrics if: ${{ needs.filter.outputs.changes == 'true' && always() }} id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: ${{ matrix.type.id }} org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} - this-job-name: Core Tests (${{ matrix.cmd }}) + this-job-name: Core Tests (${{ matrix.type.cmd }}) test-results-file: '{"testType":"go","filePath":"./output.txt"}' continue-on-error: true @@ -188,7 +215,7 @@ jobs: CL_DATABASE_URL: postgresql://postgres:postgres@localhost:5432/chainlink_test?sslmode=disable steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Setup node if: ${{ needs.filter.outputs.changes == 'true' }} uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 @@ -209,6 +236,10 @@ jobs: - name: Download Go vendor packages if: ${{ needs.filter.outputs.changes == 'true' }} run: go mod download + - name: Replace chainlink-evm deps + if: ${{ needs.filter.outputs.changes == 'true' && inputs.evm-ref != ''}} + shell: bash + run: go get github.com/smartcontractkit/chainlink-evm@${{ inputs.evm-ref }} - name: Build binary if: ${{ needs.filter.outputs.changes == 'true' }} run: go build -o chainlink.test . @@ -217,7 +248,7 @@ jobs: run: ./chainlink.test local db preparetest - name: Load test outputs if: ${{ needs.filter.outputs.changes == 'true' }} - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 with: path: ./artifacts - name: Build flakey test runner @@ -247,7 +278,7 @@ jobs: `ls -R ./artifacts/go_core_tests*/output.txt` - name: Store logs artifacts if: ${{ needs.filter.outputs.changes == 'true' && always() }} - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 with: name: flakey_test_runner_logs path: | @@ -260,11 +291,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 # fetches all history for all tags and branches to provide more metadata for sonar reports - name: Download all workflow run artifacts - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 - name: Set SonarQube Report Paths id: sonarqube_report_paths shell: bash @@ -284,8 +315,9 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: ci-core-sonarqube org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -295,7 +327,7 @@ jobs: clean: name: Clean Go Tidy & Generate if: ${{ !contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') && github.actor != 'dependabot[bot]' }} - runs-on: ubuntu20.04-8cores-32GB + runs-on: ubuntu22.04-8cores-32GB defaults: run: shell: bash @@ -305,7 +337,7 @@ jobs: run: | echo "## \`skip-smoke-tests\` label is active, skipping E2E smoke tests" >>$GITHUB_STEP_SUMMARY exit 0 - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 - name: Setup Go @@ -325,8 +357,9 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: ci-core-generate org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} diff --git a/.github/workflows/ci-scripts.yml b/.github/workflows/ci-scripts.yml index f44967d5e20..78c26ff258e 100644 --- a/.github/workflows/ci-scripts.yml +++ b/.github/workflows/ci-scripts.yml @@ -9,7 +9,7 @@ jobs: if: ${{ github.event_name == 'pull_request' }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Golang Lint uses: ./.github/actions/golangci-lint with: @@ -25,7 +25,7 @@ jobs: if: ${{ github.event_name == 'pull_request' }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Setup Go uses: ./.github/actions/setup-go with: @@ -38,8 +38,9 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: ci-test-scripts org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} diff --git a/.github/workflows/client-compatibility-tests.yml b/.github/workflows/client-compatibility-tests.yml index 5aead952b3e..65f6524259d 100644 --- a/.github/workflows/client-compatibility-tests.yml +++ b/.github/workflows/client-compatibility-tests.yml @@ -25,15 +25,16 @@ jobs: steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: client-compatablility-build-chainlink org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} this-job-name: Build Chainlink Image continue-on-error: true - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Build Chainlink Image @@ -55,19 +56,20 @@ jobs: steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: client-compatablility-build-tests org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} this-job-name: Build Tests Binary continue-on-error: true - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Build Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-tests@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-tests@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_download_vendor_packages_command: cd ./integration-tests && go mod download token: ${{ secrets.GITHUB_TOKEN }} @@ -151,7 +153,7 @@ jobs: name: Client Compatibility Test ${{ matrix.name }} steps: - name: Download Tests Binary - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 with: name: tests - name: Prepare Base64 TOML config @@ -205,7 +207,7 @@ jobs: key_secret="$PYROSCOPE_KEY" [PrivateEthereumNetwork] - consensus_type="pos" + ethereum_version="eth2" consensus_layer="prysm" execution_layer="$execution_layer" wait_for_finalization=false @@ -224,7 +226,7 @@ jobs: echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV touch .root_dir - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_command_to_run: ./tests -test.timeout ${{ matrix.timeout }} -test.run ${{ matrix.test }} binary_name: tests @@ -317,7 +319,7 @@ jobs: product: [ocr, ocr2] steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Post Test Results to Slack diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index faf35dc7a40..c084fd11ea3 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -22,7 +22,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Set up Go if: ${{ matrix.language == 'go' }} @@ -45,8 +45,9 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: chainlink-codeql org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} diff --git a/.github/workflows/delete-deployments.yml b/.github/workflows/delete-deployments.yml index 6c2aa8482f1..fd6b6c90b14 100644 --- a/.github/workflows/delete-deployments.yml +++ b/.github/workflows/delete-deployments.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Clean up integration environment uses: ./.github/actions/delete-deployments @@ -24,8 +24,9 @@ jobs: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: chainlink-delete-deployments org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} diff --git a/.github/workflows/dependency-check.yml b/.github/workflows/dependency-check.yml index 1f820cb2bbf..40a04c1a335 100644 --- a/.github/workflows/dependency-check.yml +++ b/.github/workflows/dependency-check.yml @@ -11,8 +11,8 @@ jobs: changes: ${{ steps.changes.outputs.src }} steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 id: changes with: filters: | @@ -25,7 +25,7 @@ jobs: needs: [changes] steps: - name: Check out code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Set up Go if: needs.changes.outputs.src == 'true' @@ -40,15 +40,16 @@ jobs: - name: Check vulnerabilities if: needs.changes.outputs.src == 'true' - uses: sonatype-nexus-community/nancy-github-action@main + uses: sonatype-nexus-community/nancy-github-action@726e338312e68ecdd4b4195765f174d3b3ce1533 # v1.0.3 with: nancyVersion: "v1.0.39" - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: dependency-vulnerability-check org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} diff --git a/.github/workflows/evm-version-compatibility-tests.yml b/.github/workflows/evm-version-compatibility-tests.yml new file mode 100644 index 00000000000..2f8eaf2b678 --- /dev/null +++ b/.github/workflows/evm-version-compatibility-tests.yml @@ -0,0 +1,340 @@ +name: EVM Node Version Compatibility Tests +on: + merge_group: + pull_request: + push: + tags: + - "*" + workflow_dispatch: + inputs: + base64_test_list: + description: Base64 encoded test list (same format as ./integration-tests/evm_node_compatibility_test_list.json) + required: false + type: string + +env: + CHAINLINK_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink + INTERNAL_DOCKER_REPO: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com + MOD_CACHE_VERSION: 2 + +jobs: + + # Check if go.mod has changed + check-dependency-bump: + runs-on: ubuntu-latest + outputs: + dependency_changed: ${{ steps.changes.outputs.dependency_changed }} + steps: + - name: Checkout code + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + with: + fetch-depth: 0 + - name: Check for go.mod changes + id: changes + run: | + git fetch origin ${{ github.base_ref }} + # if no match is found then grep exits with code 1, but if there is a match it exits with code 0 + DEPENDENCY_CHANGED=$(git diff origin/${{ github.base_ref }}...HEAD -- go.mod | grep -q 'github.com/ethereum/go-ethereum'; echo $?) + PR_VERSION=$(grep 'github.com/ethereum/go-ethereum' go.mod | awk '{print $2}') + + # here 0 means a match was found, 1 means no match was found + if [ "$DEPENDENCY_CHANGED" -eq 0 ]; then + # Dependency was changed in the PR, now compare with the base branch + git fetch origin ${{ github.base_ref }} + BASE_VERSION=$(git show origin/${{ github.base_ref }}:go.mod | grep 'github.com/ethereum/go-ethereum' | awk '{print $2}') + + echo "Base branch version: $BASE_VERSION" + echo "PR branch version: $PR_VERSION" + + echo "Dependency version changed in the PR compared to the base branch." + echo "dependency_changed=true" >> $GITHUB_OUTPUT + else + echo "No changes to ethereum/go-ethereum dependency in the PR." + echo "PR branch version: $PR_VERSION" + echo "dependency_changed=false" >> $GITHUB_OUTPUT + fi + + # Build Test Dependencies + + build-chainlink: + if: needs.check-dependency-bump.outputs.dependency_changed == 'true' || github.event_name == 'workflow_dispatch' + needs: [check-dependency-bump] + environment: integration + permissions: + id-token: write + contents: read + name: Build Chainlink Image + runs-on: ubuntu-latest + steps: + - name: Collect Metrics + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 + with: + id: evm-build-chainlink + org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} + basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} + this-job-name: Build Chainlink Image + continue-on-error: true + - name: Checkout the repo + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + with: + ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} + - name: Build Chainlink Image + uses: ./.github/actions/build-chainlink-image + with: + tag_suffix: "" + dockerfile: core/chainlink.Dockerfile + git_commit_sha: ${{ github.sha }} + AWS_REGION: ${{ secrets.QA_AWS_REGION }} + AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + + build-tests: + if: needs.check-dependency-bump.outputs.dependency_changed == 'true' || github.event_name == 'workflow_dispatch' + needs: [check-dependency-bump] + environment: integration + permissions: + id-token: write + contents: read + name: Build Tests Binary + runs-on: ubuntu-latest + steps: + - name: Collect Metrics + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 + with: + id: evm-build-tests + org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} + basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} + this-job-name: Build Tests Binary + continue-on-error: true + - name: Checkout the repo + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + with: + ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} + - name: Build Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-tests@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 + with: + test_download_vendor_packages_command: cd ./integration-tests && go mod download + token: ${{ secrets.GITHUB_TOKEN }} + go_mod_path: ./integration-tests/go.mod + go_tags: embed + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + binary_name: tests + + build-test-matrix: + if: needs.check-dependency-bump.outputs.dependency_changed == 'true' || github.event_name == 'workflow_dispatch' + needs: [check-dependency-bump] + runs-on: ubuntu-latest + name: Build Test Matrix + outputs: + matrix: ${{ env.JOB_MATRIX_JSON }} + steps: + - name: Checkout the repo + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + - name: Setup environment variables + run: | + echo "BASE64_TEST_LIST=${{ github.event.inputs.base64_test_list }}" >> $GITHUB_ENV + - name: Decode Base64 Test List Input if Set + id: decode-base64-test-list + if: env.BASE64_TEST_LIST != '' + run: | + echo "Decoding base64 test list..." + DECODED_BASE64_TEST_LIST=$(echo $BASE64_TEST_LIST | base64 -d) + echo $DECODED_BASE64_TEST_LIST + cd ./integration-tests + echo $DECODED_BASE64_TEST_LIST >> ./evm_node_compatibility_test_list.json + - name: Override Test List If Present + if: env.BASE64_TEST_LIST == '' + id: build-test-matrix-list + run: | + cd ./integration-tests + cp ./smoke/evm_node_compatibility_test_list.json . + - name: Create Test Matrix + id: create-test-matrix-list + run: | + cd ./integration-tests + JOB_MATRIX_JSON=$(./scripts/buildEvmClientTestMatrixList.sh ./evm_node_compatibility_test_list.json ubuntu-latest) + echo "JOB_MATRIX_JSON=${JOB_MATRIX_JSON}" >> $GITHUB_ENV + echo $JOB_MATRIX_JSON | jq . + + # End Build Test Dependencies + + evm-node-compatiblity-matrix: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: + [check-dependency-bump, build-chainlink, build-tests, build-test-matrix] + env: + SELECTED_NETWORKS: SIMULATED + CHAINLINK_COMMIT_SHA: ${{ github.sha }} + CHAINLINK_ENV_USER: ${{ github.actor }} + TEST_LOG_LEVEL: debug + strategy: + fail-fast: false + matrix: + evm_node: ${{fromJson(needs.build-test-matrix.outputs.matrix)}} + runs-on: ${{ matrix.evm_node.os }} + name: EVM node compatibility of ${{ matrix.evm_node.product }} with ${{ matrix.evm_node.docker_image }} + steps: + - name: Collect Metrics + if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 + with: + id: evm-e2e-compatability-tests-${{ matrix.evm_node.name }} + basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} + org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} + this-job-name: EVM node compatibility ${{ matrix.evm_node.name }} ${{ matrix.evm_node.docker_image }} + test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' + continue-on-error: true + - name: Checkout the repo + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + with: + ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} + - name: Build Go Test Command + id: build-go-test-command + run: | + # if the matrix.evm_node.run is set, use it for a different command + if [ "${{ matrix.evm_node.run }}" != "" ]; then + echo "run_command=${{ matrix.evm_node.run }} ./smoke/${{ matrix.evm_node.product }}_test.go" >> "$GITHUB_OUTPUT" + else + echo "run_command=./smoke/${{ matrix.evm_node.product }}_test.go" >> "$GITHUB_OUTPUT" + fi + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + selectedNetworks: ${{ env.SELECTED_NETWORKS }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + ethExecutionClient: ${{ matrix.evm_node.eth_client }} + customEthClientDockerImage: ${{ matrix.evm_node.docker_image }} + + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 + with: + test_command_to_run: cd ./integration-tests && go test -timeout 45m -count=1 -json -test.parallel=2 ${{ steps.build-go-test-command.outputs.run_command }} 2>&1 | tee /tmp/gotest.log | gotestfmt + test_download_vendor_packages_command: cd ./integration-tests && go mod download + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + artifacts_location: ./integration-tests/smoke/logs/ + publish_check_name: ${{ matrix.evm_node.product }}-compatibility-${{ matrix.evm_node.eth_client }}-${{ matrix.evm_node.docker_image }} + token: ${{ secrets.GITHUB_TOKEN }} + go_mod_path: ./integration-tests/go.mod + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: "" + should_tidy: "false" + - name: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 + + start-slack-thread: + name: Start Slack Thread + if: ${{ always() && needs.check-dependency-bump.outputs.dependency_changed == 'true' && needs.*.result != 'skipped' && needs.*.result != 'cancelled' }} + environment: integration + outputs: + thread_ts: ${{ steps.slack.outputs.thread_ts }} + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + runs-on: ubuntu-latest + needs: [ evm-node-compatiblity-matrix] + steps: + - name: Debug Result + run: echo ${{ join(needs.*.result, ',') }} + - name: Main Slack Notification + uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0 + id: slack + with: + channel-id: ${{ secrets.QA_SLACK_CHANNEL }} + payload: | + { + "attachments": [ + { + "color": "${{ contains(join(needs.*.result, ','), 'failure') && '#C62828' || '#2E7D32' }}", + "blocks": [ + { + "type": "header", + "text": { + "type": "plain_text", + "text": "EVM Node Compatability Test Results ${{ contains(join(needs.*.result, ','), 'failure') && ':x:' || ':white_check_mark:'}}", + "emoji": true + } + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "${{ contains(join(needs.*.result, ','), 'failure') && 'Some tests failed, notifying <@U060CGGPY8H>' || 'All Good!' }}" + } + }, + { + "type": "divider" + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "<${{ github.server_url }}/${{ github.repository }}/releases/tag/${{ github.ref_name }}|${{ github.ref_name }}> | <${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}|${{ github.sha }}> | <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Run>" + } + } + ] + } + ] + } + env: + SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} + + post-test-results-to-slack: + name: Post Test Results for ${{matrix.evm_node.eth_client}} to Slack + if: ${{ always() && needs.check-dependency-bump.outputs.dependency_changed == 'true' && needs.*.result != 'skipped' && needs.*.result != 'cancelled' }} + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + runs-on: ubuntu-latest + needs: [start-slack-thread, build-test-matrix] + strategy: + fail-fast: false + matrix: + # this basically works as group by in SQL; we should update it when we update the test list JSON file + product: [automation,ocr,ocr2,vrf,vrfv2,vrfv2plus] + steps: + - name: Checkout the repo + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + with: + ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} + - name: Post Test Results to Slack + uses: ./.github/actions/notify-slack-jobs-result + with: + github_token: ${{ github.token }} + github_repository: ${{ github.repository }} + workflow_run_id: ${{ github.run_id }} + github_job_name_regex: ^EVM node compatibility of ${{ matrix.product }} with (?.*?)$ + message_title: ${{ matrix.product }} + slack_channel_id: ${{ secrets.QA_SLACK_CHANNEL }} + slack_bot_token: ${{ secrets.QA_SLACK_API_KEY }} + slack_thread_ts: ${{ needs.start-slack-thread.outputs.thread_ts }} diff --git a/.github/workflows/goreleaser-build-publish-develop.yml b/.github/workflows/goreleaser-build-publish-develop.yml index 20bf4e342d1..a7289a2d66b 100644 --- a/.github/workflows/goreleaser-build-publish-develop.yml +++ b/.github/workflows/goreleaser-build-publish-develop.yml @@ -8,7 +8,7 @@ on: jobs: push-chainlink-develop-goreleaser: runs-on: - labels: ubuntu20.04-16cores-64GB + labels: ubuntu22.04-16cores-64GB outputs: goreleaser-metadata: ${{ steps.build-sign-publish.outputs.goreleaser-metadata }} goreleaser-artifacts: ${{ steps.build-sign-publish.outputs.goreleaser-artifacts }} @@ -18,7 +18,7 @@ jobs: contents: read steps: - name: Checkout repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Configure aws credentials uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 with: @@ -39,8 +39,9 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: goreleaser-build-publish org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} diff --git a/.github/workflows/helm-chart-publish.yml b/.github/workflows/helm-chart-publish.yml index ca0ff6104a4..3705459c228 100644 --- a/.github/workflows/helm-chart-publish.yml +++ b/.github/workflows/helm-chart-publish.yml @@ -12,7 +12,7 @@ jobs: contents: read steps: - name: Checkout repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Configure aws credentials uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 @@ -23,12 +23,12 @@ jobs: - name: Get Github Token id: get-gh-token - uses: smartcontractkit/chainlink-github-actions/github-app-token-issuer@main + uses: smartcontractkit/chainlink-github-actions/github-app-token-issuer@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: url: ${{ secrets.GATI_LAMBDA_FUNCTION_URL }} - name: Install Helm - uses: azure/setup-helm@5119fcb9089d432beecbf79bb2c7915207344b78 # v3.5 + uses: azure/setup-helm@b7246b12e77f7134dc2d460a3d5bad15bbe29390 # v4.1.0 - name: Run chart-releaser uses: helm/chart-releaser-action@a917fd15b20e8b64b94d9158ad54cd6345335584 # v1.6.0 diff --git a/.github/workflows/integration-chaos-tests.yml b/.github/workflows/integration-chaos-tests.yml index 364b2ac12bb..157bf800740 100644 --- a/.github/workflows/integration-chaos-tests.yml +++ b/.github/workflows/integration-chaos-tests.yml @@ -26,10 +26,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Check if image exists id: check-image - uses: smartcontractkit/chainlink-github-actions/docker/image-exists@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/docker/image-exists@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: repository: chainlink tag: ${{ github.sha }} @@ -37,7 +37,7 @@ jobs: AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - name: Build Image if: steps.check-image.outputs.exists == 'false' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-image@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-image@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: cl_repo: smartcontractkit/chainlink cl_ref: ${{ github.sha }} @@ -52,8 +52,9 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: e2e-chaos-build-chainlink org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -69,7 +70,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Build Test Image uses: ./.github/actions/build-test-image with: @@ -79,8 +80,9 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: e2e-chaos-build-test-image org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -100,8 +102,9 @@ jobs: steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: e2e-chaos-tests org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -109,7 +112,7 @@ jobs: test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Prepare Base64 TOML config env: CHAINLINK_VERSION: ${{ github.sha }} @@ -129,7 +132,7 @@ jobs: echo ::add-mask::$BASE64_CONFIG_OVERRIDE echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_command_to_run: cd integration-tests && go test -timeout 1h -count=1 -json -test.parallel 11 ./chaos 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download @@ -143,7 +146,7 @@ jobs: QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - name: Upload test log - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 if: failure() with: name: Test Results Log diff --git a/.github/workflows/integration-staging-tests.yml b/.github/workflows/integration-staging-tests.yml index 6851a4ec3f1..d092b2bca1c 100644 --- a/.github/workflows/integration-staging-tests.yml +++ b/.github/workflows/integration-staging-tests.yml @@ -35,7 +35,7 @@ concurrency: jobs: e2e-soak-test: environment: sdlc - runs-on: ubuntu20.04-8cores-32GB + runs-on: ubuntu22.04-8cores-32GB permissions: contents: read id-token: write @@ -49,7 +49,7 @@ jobs: WASP_LOG_LEVEL: info steps: - name: Checkout code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 - name: Prepare Base64 TOML override diff --git a/.github/workflows/integration-tests-publish.yml b/.github/workflows/integration-tests-publish.yml index ab4049cdab2..459fa486c66 100644 --- a/.github/workflows/integration-tests-publish.yml +++ b/.github/workflows/integration-tests-publish.yml @@ -18,19 +18,20 @@ jobs: id-token: write contents: read name: Publish Integration Test Image - runs-on: ubuntu20.04-16cores-64GB + runs-on: ubuntu22.04-16cores-64GB steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: publish-e2e-test-image org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} this-job-name: Publish Integration Test Image continue-on-error: true - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ github.event.pull_request.head.sha || github.sha }} - name: Setup Other Tags If Not Workflow Dispatch @@ -72,19 +73,20 @@ jobs: # dockerfile: plugins/chainlink.Dockerfile # tag-suffix: -plugins name: Build Chainlink Image ${{ matrix.image.name }} - runs-on: ubuntu20.04-8cores-32GB + runs-on: ubuntu22.04-8cores-32GB steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: build-chainlink org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} this-job-name: Build Chainlink Image ${{ matrix.image.name }} continue-on-error: true - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ github.sha }} - name: Build Chainlink Image diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index c67d2a76b98..30bf663b88e 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -1,4 +1,5 @@ name: Integration Tests +run-name: Integration Tests ${{ inputs.distinct_run_name && inputs.distinct_run_name || '' }} on: merge_group: pull_request: @@ -11,40 +12,23 @@ on: description: 'The ref to checkout, defaults to the calling branch' required: false type: string - dep_evm_sha: + evm-ref: description: 'The sha of the chainlink-evm commit to use if wanted' required: false type: string - set_changes_output: - description: 'Set the changes output' - required: false - type: string - default: 'true' - workflow_call: - inputs: - cl_ref: - description: 'The ref to checkout' - required: false - type: string - default: 'develop' - dep_evm_sha: - description: 'The sha of the chainlink-evm commit to use if wanted' - required: false - type: string - set_changes_output: - description: 'Set the changes output' - required: false - type: string - default: 'true' run_solana: description: 'Run solana tests' required: false type: string default: 'false' + distinct_run_name: + description: 'A unique identifier for this run, only use from other repos' + required: false + type: string # Only run 1 of this workflow at a time per PR concurrency: - group: integration-tests-chainlink-${{ github.ref }} + group: integration-tests-chainlink-${{ github.ref }}-${{ inputs.distinct_run_name }} cancel-in-progress: true env: @@ -55,6 +39,7 @@ env: TEST_ARGS: -test.timeout 12m INTERNAL_DOCKER_REPO: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com MOD_CACHE_VERSION: 2 + COLLECTION_ID: chainlink-e2e-tests jobs: enforce-ctf-version: @@ -65,7 +50,7 @@ jobs: steps: - run: echo "${{github.event_name}}" - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: repository: smartcontractkit/chainlink ref: ${{ inputs.cl_ref }} @@ -86,7 +71,7 @@ jobs: echo "should-enforce=$SHOULD_ENFORCE" >> $GITHUB_OUTPUT - name: Enforce CTF Version if: steps.condition-check.outputs.should-enforce == 'true' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/mod-version@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/mod-version@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: go-project-path: ./integration-tests module-name: github.com/smartcontractkit/chainlink-testing-framework @@ -99,15 +84,15 @@ jobs: if: github.actor != 'dependabot[bot]' steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: repository: smartcontractkit/chainlink ref: ${{ inputs.cl_ref }} - - uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 id: changes with: filters: | - src: + changes: - '**/*.go' - '**/*go.sum' - '**/*go.mod' @@ -115,41 +100,57 @@ jobs: - '**/*Dockerfile' - 'core/**/config/**/*.toml' - 'integration-tests/**/*.toml' + - name: Ignore Filter On Workflow Dispatch + if: ${{ github.event_name == 'workflow_dispatch' }} + id: ignore-filter + run: echo "changes=true" >> $GITHUB_OUTPUT - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: ${{ env.COLLECTION_ID }}-check-paths org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} this-job-name: Check Paths That Require Tests To Run continue-on-error: true outputs: - src: ${{ inputs.set_changes_output || steps.changes.outputs.src }} + src: ${{ steps.ignore-filter.outputs.changes || steps.changes.outputs.changes }} build-lint-integration-tests: - name: Build and Lint integration-tests - runs-on: ubuntu20.04-16cores-64GB + name: Build and Lint ${{ matrix.project.name }} + runs-on: ubuntu22.04-16cores-64GB # We don't directly merge dependabot PRs, so let's not waste the resources if: github.actor != 'dependabot[bot]' strategy: matrix: project: - name: integration-tests + id: e2e path: ./integration-tests cache-id: e2e - name: load + id: load path: ./integration-tests/load cache-id: load steps: + - name: Collect Metrics + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 + with: + id: ${{ env.COLLECTION_ID }}-build-lint-${{ matrix.project.id }} + org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} + basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} + this-job-name: Build and Lint ${{ matrix.project.name }} - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: repository: smartcontractkit/chainlink ref: ${{ inputs.cl_ref }} - name: Setup Go - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-go@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-go@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_download_vendor_packages_command: cd ${{ matrix.project.path }} && go mod download go_mod_path: ${{ matrix.project.path }}/go.mod @@ -187,21 +188,22 @@ jobs: dockerfile: plugins/chainlink.Dockerfile tag-suffix: -plugins name: Build Chainlink Image ${{ matrix.image.name }} - runs-on: ubuntu20.04-16cores-64GB + runs-on: ubuntu22.04-16cores-64GB needs: [changes, enforce-ctf-version] steps: - name: Collect Metrics if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: ${{ env.COLLECTION_ID }}-build-chainlink org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} this-job-name: Build Chainlink Image ${{ matrix.image.name }} continue-on-error: true - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: repository: smartcontractkit/chainlink ref: ${{ inputs.cl_ref || github.event.pull_request.head.sha || github.event.merge_group.head_sha }} @@ -214,7 +216,7 @@ jobs: git_commit_sha: ${{ github.sha }} AWS_REGION: ${{ secrets.QA_AWS_REGION }} AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - dep_evm_sha: ${{ inputs.dep_evm_sha }} + dep_evm_sha: ${{ inputs.evm-ref }} build-test-image: if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'schedule' || contains(join(github.event.pull_request.labels.*.name, ' '), 'build-test-image') @@ -223,21 +225,22 @@ jobs: id-token: write contents: read name: Build Test Image - runs-on: ubuntu20.04-16cores-64GB + runs-on: ubuntu22.04-16cores-64GB needs: [changes] steps: - name: Collect Metrics if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: ${{ env.COLLECTION_ID }}-build-test-image org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} this-job-name: Build Test Image continue-on-error: true - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: repository: smartcontractkit/chainlink ref: ${{ inputs.cl_ref || github.event.pull_request.head.sha || github.event.merge_group.head_sha }} @@ -263,7 +266,7 @@ jobs: echo "## \`skip-smoke-tests\` label is active, skipping E2E smoke tests" >>$GITHUB_STEP_SUMMARY exit 0 - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: repository: smartcontractkit/chainlink ref: ${{ inputs.cl_ref }} @@ -325,8 +328,9 @@ jobs: - name: Collect Metrics if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: ${{ env.COLLECTION_ID }}-matrix-${{ matrix.product.name }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} @@ -334,7 +338,7 @@ jobs: test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: repository: smartcontractkit/chainlink ref: ${{ inputs.cl_ref || github.event.pull_request.head.sha || github.event.merge_group.head_sha }} @@ -368,7 +372,7 @@ jobs: ## Run this step when changes that require tests to be run are made - name: Run Tests if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=${{ matrix.product.nodes }} ${{ steps.build-go-test-command.outputs.run_command }} 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download @@ -387,10 +391,10 @@ jobs: should_tidy: "false" - name: Print failed test summary if: always() - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 eth-smoke-tests-matrix-log-poller: - if: ${{ !(contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') || github.event_name == 'workflow_dispatch') }} + if: ${{ !(contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') || github.event_name == 'workflow_dispatch') || inputs.distinct_run_name != '' }} environment: integration permissions: checks: write @@ -414,8 +418,9 @@ jobs: - name: Collect Metrics if: needs.changes.outputs.src == 'true' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: ${{ env.COLLECTION_ID }}-matrix-${{ matrix.product.name }} org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -423,7 +428,7 @@ jobs: test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: repository: smartcontractkit/chainlink ref: ${{ inputs.cl_ref || github.event.pull_request.head.sha || github.event.merge_group.head_sha }} @@ -456,7 +461,7 @@ jobs: ## Run this step when changes that require tests to be run are made - name: Run Tests if: needs.changes.outputs.src == 'true' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=${{ matrix.product.nodes }} ${{ steps.build-go-test-command.outputs.run_command }} 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download @@ -494,49 +499,60 @@ jobs: matrix: product: - name: runlog + id: runlog nodes: 2 os: ubuntu-latest pyroscope_env: "ci-smoke-runlog-evm-simulated" - name: cron + id: cron nodes: 2 os: ubuntu-latest pyroscope_env: "ci-smoke-cron-evm-simulated" - name: flux + id: flux nodes: 1 os: ubuntu-latest pyroscope_env: "ci-smoke-flux-evm-simulated" - name: ocr + id: ocr nodes: 2 os: ubuntu-latest file: ocr pyroscope_env: ci-smoke-ocr-evm-simulated - name: ocr2 + id: ocr2 nodes: 6 - os: ubuntu20.04-16cores-64GB + os: ubuntu22.04-16cores-64GB file: ocr2 pyroscope_env: ci-smoke-ocr2-evm-simulated - name: ocr2 + id: ocr2-plugins nodes: 6 - os: ubuntu20.04-16cores-64GB + os: ubuntu22.04-16cores-64GB pyroscope_env: ci-smoke-ocr2-plugins-evm-simulated tag_suffix: "-plugins" - name: vrf + id: vrf nodes: 2 os: ubuntu-latest pyroscope_env: ci-smoke-vrf-evm-simulated - name: vrfv2 + id: vrfv2 nodes: 4 os: ubuntu-latest pyroscope_env: ci-smoke-vrf2-evm-simulated - name: vrfv2plus - nodes: 5 + id: vrfv2plus + nodes: 7 os: ubuntu-latest pyroscope_env: ci-smoke-vrf2plus-evm-simulated - name: forwarder_ocr + id: forwarder_ocr nodes: 2 os: ubuntu-latest pyroscope_env: ci-smoke-forwarder-ocr-evm-simulated - name: forwarders_ocr2 + id: forwarders_ocr2 nodes: 2 os: ubuntu-latest pyroscope_env: ci-smoke-forwarder-ocr-evm-simulated @@ -549,8 +565,9 @@ jobs: - name: Collect Metrics if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: ${{ env.COLLECTION_ID }}-matrix-${{ matrix.product.id }} org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -558,7 +575,7 @@ jobs: test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: repository: smartcontractkit/chainlink ref: ${{ inputs.cl_ref || github.event.pull_request.head.sha || github.event.merge_group.head_sha }} @@ -643,7 +660,7 @@ jobs: ## Run this step when changes that require tests to be run are made - name: Run Tests if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=${{ matrix.product.nodes }} ${{ steps.build-go-test-command.outputs.run_command }} 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download @@ -664,7 +681,7 @@ jobs: # Run this step when changes that do not need the test to run are made - name: Run Setup if: needs.changes.outputs.src == 'false' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_download_vendor_packages_command: cd ./integration-tests && go mod download go_mod_path: ./integration-tests/go.mod @@ -684,13 +701,13 @@ jobs: ls -l ./integration-tests/smoke/traces - name: Upload Trace Data if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 with: name: trace-data path: ./integration-tests/smoke/traces/trace-data.json - name: Print failed test summary if: always() - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_directory: ./integration-tests/smoke/ @@ -700,7 +717,6 @@ jobs: runs-on: ubuntu-latest name: ETH Smoke Tests needs: [eth-smoke-tests-matrix, eth-smoke-tests-matrix-automation, eth-smoke-tests-matrix-log-poller] - # needs: [eth-smoke-tests-matrix] steps: - name: Check smoke test matrix status if: needs.eth-smoke-tests-matrix.result != 'success' || needs.eth-smoke-tests-matrix-automation.result != 'success' || needs.eth-smoke-tests-matrix-log-poller.result != 'success' @@ -712,8 +728,9 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: ${{ env.COLLECTION_ID }}-matrix-results org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -729,7 +746,7 @@ jobs: steps: - name: Checkout repo if: ${{ github.event_name == 'pull_request' }} - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: repository: smartcontractkit/chainlink ref: ${{ inputs.cl_ref }} @@ -744,8 +761,9 @@ jobs: - name: Collect Metrics if: ${{ github.event_name == 'pull_request' }} id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: ${{ env.COLLECTION_ID }}-env-cleanup org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -762,12 +780,12 @@ jobs: continue-on-error: true steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: repository: smartcontractkit/chainlink ref: ${{ inputs.cl_ref || github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Run Setup - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-go@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-go@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_download_vendor_packages_command: | cd ./integration-tests @@ -802,7 +820,7 @@ jobs: TEST_SUITE: migration steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: repository: smartcontractkit/chainlink ref: ${{ inputs.cl_ref || github.event.pull_request.head.sha || github.event.merge_group.head_sha }} @@ -824,7 +842,7 @@ jobs: upgradeImage: ${{ env.UPGRADE_IMAGE }} upgradeVersion: ${{ env.UPGRADE_VERSION }} - name: Run Migration Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json ./migration 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download @@ -840,7 +858,7 @@ jobs: QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - name: Upload test log - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 if: failure() with: name: test-log-${{ matrix.product.name }} @@ -850,8 +868,9 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: ${{ env.COLLECTION_ID }}-migration-tests org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -870,7 +889,7 @@ jobs: sha: ${{ steps.getsha.outputs.sha }} steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: repository: smartcontractkit/chainlink ref: ${{ inputs.cl_ref || github.event.pull_request.head.sha || github.event.merge_group.head_sha }} @@ -890,7 +909,7 @@ jobs: echo "short sha is: ${short_sha}" echo "short_sha=${short_sha}" >> "$GITHUB_OUTPUT" - name: Checkout solana - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: repository: smartcontractkit/chainlink-solana ref: develop @@ -917,7 +936,7 @@ jobs: projectserum_version: ${{ steps.psversion.outputs.projectserum_version }} steps: - name: Checkout the solana repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: repository: smartcontractkit/chainlink-solana ref: ${{ needs.get_solana_sha.outputs.sha }} @@ -940,7 +959,7 @@ jobs: steps: - name: Check if image exists id: check-image - uses: smartcontractkit/chainlink-github-actions/docker/image-exists@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/docker/image-exists@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: repository: chainlink-solana-tests tag: ${{ needs.get_solana_sha.outputs.sha }} @@ -955,7 +974,7 @@ jobs: id-token: write contents: read name: Solana Build Artifacts - runs-on: ubuntu20.04-16cores-64GB + runs-on: ubuntu22.04-16cores-64GB needs: [ changes, @@ -972,8 +991,9 @@ jobs: - name: Collect Metrics if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: ${{ env.COLLECTION_ID }}-solana-build-contracts org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -1000,7 +1020,7 @@ jobs: id-token: write contents: read name: Solana Build Test Image - runs-on: ubuntu20.04-16cores-64GB + runs-on: ubuntu22.04-16cores-64GB needs: [ solana-build-contracts, @@ -1014,8 +1034,9 @@ jobs: - name: Collect Metrics if: (needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch') && needs.solana-test-image-exists.outputs.exists == 'false' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: ${{ env.COLLECTION_ID }}-solana-build-test-image org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -1023,7 +1044,7 @@ jobs: continue-on-error: true - name: Checkout the repo if: (needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch') && needs.solana-test-image-exists.outputs.exists == 'false' - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: repository: smartcontractkit/chainlink-solana ref: ${{ needs.get_solana_sha.outputs.sha }} @@ -1048,7 +1069,7 @@ jobs: id-token: write contents: read name: Solana Smoke Tests - runs-on: ubuntu20.04-16cores-64GB + runs-on: ubuntu22.04-16cores-64GB needs: [ build-chainlink, @@ -1066,8 +1087,9 @@ jobs: - name: Collect Metrics if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: ${{ env.COLLECTION_ID }}-solana-e2e-tests org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -1075,13 +1097,13 @@ jobs: test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: repository: smartcontractkit/chainlink-solana ref: ${{ needs.get_solana_sha.outputs.sha }} - name: Run Setup if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: go_mod_path: ./integration-tests/go.mod cache_restore_only: true @@ -1125,7 +1147,7 @@ jobs: echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV - name: Run Tests if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_command_to_run: export ENV_JOB_IMAGE=${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-solana-tests:${{ needs.get_solana_sha.outputs.sha }} && make test_smoke cl_repo: ${{ env.CHAINLINK_IMAGE }} @@ -1141,7 +1163,7 @@ jobs: QA_KUBECONFIG: "" run_setup: false - name: Upload test log - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 if: failure() with: name: test-log-solana diff --git a/.github/workflows/lint-gh-workflows.yml b/.github/workflows/lint-gh-workflows.yml index 381a2a56e16..8de3ab98a2b 100644 --- a/.github/workflows/lint-gh-workflows.yml +++ b/.github/workflows/lint-gh-workflows.yml @@ -7,14 +7,15 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out Code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Run actionlint - uses: reviewdog/action-actionlint@6a38513dd4d2e818798c5c73d0870adbb82de4a4 # v1.41.0 + uses: reviewdog/action-actionlint@c6ee1eb0a5d47b2af53a203652b5dac0b6c4016e # v1.43.0 - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: lint-gh-workflows org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} diff --git a/.github/workflows/live-testnet-tests.yml b/.github/workflows/live-testnet-tests.yml index b01e171d275..174514a879f 100644 --- a/.github/workflows/live-testnet-tests.yml +++ b/.github/workflows/live-testnet-tests.yml @@ -70,15 +70,16 @@ jobs: steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: live-testnet-build-chainlink org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} this-job-name: Build Chainlink Image continue-on-error: true - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Build Chainlink Image @@ -100,19 +101,20 @@ jobs: steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: live-testnet-build-test-image org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} this-job-name: Build Tests Binary continue-on-error: true - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Build Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-tests@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-tests@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_download_vendor_packages_command: cd ./integration-tests && go mod download token: ${{ secrets.GITHUB_TOKEN }} @@ -202,7 +204,7 @@ jobs: network: [Sepolia, Optimism Sepolia, Arbitrum Sepolia, Base Sepolia, Polygon Mumbai, Avalanche Fuji, Fantom Testnet, Celo Alfajores, Linea Goerli, BSC Testnet] steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Post Test Results @@ -242,7 +244,7 @@ jobs: name: Sepolia ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 - name: Prepare Base64 TOML override @@ -266,11 +268,11 @@ jobs: wsEndpoints: ${{ secrets.QA_SEPOLIA_URLS }} fundingKeys: ${{ secrets.QA_EVM_KEYS }} - name: Download Tests Binary - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 with: name: tests - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} binary_name: tests @@ -288,7 +290,7 @@ jobs: QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - name: Print failed test summary if: always() - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_directory: "./" @@ -315,7 +317,7 @@ jobs: name: BSC Testnet ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 - name: Prepare Base64 TOML override @@ -339,11 +341,11 @@ jobs: wsEndpoints: ${{ secrets.QA_BSC_TESTNET_URLS }} fundingKeys: ${{ secrets.QA_EVM_KEYS }} - name: Download Tests Binary - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 with: name: tests - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} binary_name: tests @@ -361,7 +363,7 @@ jobs: QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - name: Print failed test summary if: always() - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_directory: "./" @@ -388,7 +390,7 @@ jobs: name: Optimism Sepolia ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 - name: Prepare Base64 TOML override @@ -412,11 +414,11 @@ jobs: wsEndpoints: ${{ secrets.QA_OPTIMISM_SEPOLIA_URLS }} fundingKeys: ${{ secrets.QA_EVM_KEYS }} - name: Download Tests Binary - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 with: name: tests - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} binary_name: tests @@ -434,7 +436,7 @@ jobs: QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - name: Print failed test summary if: always() - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_directory: "./" @@ -461,7 +463,7 @@ jobs: name: Arbitrum Sepolia ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 - name: Prepare Base64 TOML override @@ -485,11 +487,11 @@ jobs: wsEndpoints: ${{ secrets.QA_ARBITRUM_SEPOLIA_URLS }} fundingKeys: ${{ secrets.QA_EVM_KEYS }} - name: Download Tests Binary - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 with: name: tests - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} binary_name: tests @@ -507,7 +509,7 @@ jobs: QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - name: Print failed test summary if: always() - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_directory: "./" @@ -530,7 +532,7 @@ jobs: name: Base Sepolia ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 - name: Prepare Base64 TOML override @@ -554,11 +556,11 @@ jobs: wsEndpoints: ${{ secrets.QA_BASE_SEPOLIA_URLS }} fundingKeys: ${{ secrets.QA_EVM_KEYS }} - name: Download Tests Binary - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 with: name: tests - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} binary_name: tests @@ -576,7 +578,7 @@ jobs: QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - name: Print failed test summary if: always() - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_directory: "./" @@ -603,7 +605,7 @@ jobs: name: Polygon Mumbai ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 - name: Prepare Base64 TOML override @@ -627,11 +629,11 @@ jobs: wsEndpoints: ${{ secrets.QA_POLYGON_MUMBAI_URLS }} fundingKeys: ${{ secrets.QA_EVM_KEYS }} - name: Download Tests Binary - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 with: name: tests - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} binary_name: tests @@ -649,7 +651,7 @@ jobs: QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - name: Print failed test summary if: always() - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_directory: "./" @@ -676,7 +678,7 @@ jobs: name: Avalanche Fuji ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 - name: Prepare Base64 TOML override @@ -700,11 +702,11 @@ jobs: wsEndpoints: ${{ secrets.QA_AVALANCHE_FUJI_URLS }} fundingKeys: ${{ secrets.QA_EVM_KEYS }} - name: Download Tests Binary - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 with: name: tests - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} binary_name: tests @@ -722,7 +724,7 @@ jobs: QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - name: Print failed test summary if: always() - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_directory: "./" @@ -749,7 +751,7 @@ jobs: name: Fantom Testnet ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 - name: Prepare Base64 TOML override @@ -773,11 +775,11 @@ jobs: wsEndpoints: ${{ secrets.QA_FANTOM_TESTNET_URLS }} fundingKeys: ${{ secrets.QA_EVM_KEYS }} - name: Download Tests Binary - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 with: name: tests - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} binary_name: tests @@ -795,7 +797,7 @@ jobs: QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - name: Print failed test summary if: always() - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_directory: "./" @@ -818,7 +820,7 @@ jobs: name: Celo Alfajores ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 - name: Prepare Base64 TOML override @@ -842,11 +844,11 @@ jobs: wsEndpoints: ${{ secrets.QA_CELO_ALFAJORES_URLS }} fundingKeys: ${{ secrets.QA_EVM_KEYS }} - name: Download Tests Binary - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 with: name: tests - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} binary_name: tests @@ -864,7 +866,7 @@ jobs: QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - name: Print failed test summary if: always() - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_directory: "./" @@ -887,7 +889,7 @@ jobs: name: Scroll Sepolia ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 - name: Prepare Base64 TOML override @@ -911,11 +913,11 @@ jobs: wsEndpoints: ${{ secrets.QA_SCROLL_SEPOLIA_URLS }} fundingKeys: ${{ secrets.QA_EVM_KEYS }} - name: Download Tests Binary - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 with: name: tests - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} binary_name: tests @@ -933,7 +935,7 @@ jobs: QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - name: Print failed test summary if: always() - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_directory: "./" @@ -956,7 +958,7 @@ jobs: name: Linea Goerli ${{ matrix.product }} Tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 - name: Prepare Base64 TOML override @@ -980,11 +982,11 @@ jobs: wsEndpoints: ${{ secrets.QA_LINEA_GOERLI_URLS }} fundingKeys: ${{ secrets.QA_EVM_KEYS }} - name: Download Tests Binary - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 with: name: tests - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} binary_name: tests @@ -1002,6 +1004,6 @@ jobs: QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - name: Print failed test summary if: always() - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_directory: "./" diff --git a/.github/workflows/live-vrf-tests.yml b/.github/workflows/live-vrf-tests.yml index 43442bb98af..a898cbce370 100644 --- a/.github/workflows/live-vrf-tests.yml +++ b/.github/workflows/live-vrf-tests.yml @@ -43,15 +43,16 @@ jobs: steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: live-vrf-build-chainlink org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} this-job-name: Build Chainlink Image continue-on-error: true - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Build Chainlink Image @@ -77,15 +78,16 @@ jobs: steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: live-vrf-build-test-image org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} this-job-name: Build Tests Binary continue-on-error: true - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Build Network Matrix @@ -95,7 +97,7 @@ jobs: NETWORKS="${NETWORKS//,/\",\"}" echo "matrix=${NETWORKS}" >> "$GITHUB_OUTPUT" - name: Build Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-tests@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-tests@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_download_vendor_packages_command: cd ./integration-tests && go mod download token: ${{ secrets.GITHUB_TOKEN }} @@ -133,7 +135,7 @@ jobs: run: | IFS=',' read -ra ADDR <<< "${{ inputs.test_list }}" echo "test_list=${ADDR[*]}" >> $GITHUB_ENV - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 - name: Prepare Base64 TOML override @@ -154,11 +156,11 @@ jobs: wsEndpoints: ${{ secrets[env.URLS_SECRET_NAME] }} fundingKeys: ${{ secrets.QA_EVM_KEYS }} - name: Download Tests Binary - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 with: name: tests - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_command_to_run: ./tests -test.v -test.timeout 4h -test.count=1 -test.parallel=1 -test.run ${{ env.test_list }} binary_name: tests @@ -176,6 +178,6 @@ jobs: QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - name: Print failed test summary if: always() - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_directory: "./" \ No newline at end of file diff --git a/.github/workflows/on-demand-log-poller.yml b/.github/workflows/on-demand-log-poller.yml index ad3617841d3..1685c7e4556 100644 --- a/.github/workflows/on-demand-log-poller.yml +++ b/.github/workflows/on-demand-log-poller.yml @@ -11,7 +11,7 @@ jobs: test: env: REF_NAME: ${{ github.head_ref || github.ref_name }} - runs-on: ubuntu20.04-8cores-32GB + runs-on: ubuntu22.04-8cores-32GB steps: - name: Add masks and export base64 config run: | @@ -19,7 +19,7 @@ jobs: echo ::add-mask::$BASE64_CONFIG_OVERRIDE echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ env.REF_NAME }} - name: Setup Go diff --git a/.github/workflows/on-demand-ocr-soak-test.yml b/.github/workflows/on-demand-ocr-soak-test.yml index b44a3fb2d92..18e12f321a4 100644 --- a/.github/workflows/on-demand-ocr-soak-test.yml +++ b/.github/workflows/on-demand-ocr-soak-test.yml @@ -32,15 +32,16 @@ jobs: steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: on-demand-ocr-soak-test org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} this-job-name: ${{ inputs.network }} OCR Soak Test continue-on-error: true - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ env.REF_NAME }} - name: Get Slack config and mask base64 config @@ -72,7 +73,7 @@ jobs: QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 env: DETACH_RUNNER: true TEST_SUITE: soak diff --git a/.github/workflows/on-demand-vrfv2-eth2-clients-test.yml b/.github/workflows/on-demand-vrfv2-eth2-clients-test.yml index 24db1e6ffcf..c8fcb001fbb 100644 --- a/.github/workflows/on-demand-vrfv2-eth2-clients-test.yml +++ b/.github/workflows/on-demand-vrfv2-eth2-clients-test.yml @@ -11,7 +11,7 @@ jobs: vrfv2_smoke_test: name: VRFV2 Smoke Test with custom EL client client environment: integration - runs-on: ubuntu20.04-8cores-32GB + runs-on: ubuntu22.04-8cores-32GB permissions: checks: write pull-requests: write @@ -22,7 +22,7 @@ jobs: REF_NAME: ${{ github.head_ref || github.ref_name }} steps: - name: Checkout code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 - name: Mask base64 config @@ -46,7 +46,7 @@ jobs: echo "### Execution client used" >>$GITHUB_STEP_SUMMARY echo "\`${{ env.ETH2_EL_CLIENT }}\`" >>$GITHUB_STEP_SUMMARY - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -run TestVRFv2Basic ./smoke/vrfv2_test.go 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download diff --git a/.github/workflows/on-demand-vrfv2-performance-test.yml b/.github/workflows/on-demand-vrfv2-performance-test.yml index 33377f2133c..1f0cbcce864 100644 --- a/.github/workflows/on-demand-vrfv2-performance-test.yml +++ b/.github/workflows/on-demand-vrfv2-performance-test.yml @@ -19,7 +19,7 @@ jobs: vrfv2_performance_test: name: VRFV2 Performance Test environment: integration - runs-on: ubuntu20.04-8cores-32GB + runs-on: ubuntu22.04-8cores-32GB permissions: checks: write pull-requests: write @@ -38,15 +38,16 @@ jobs: steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: on-demand-vrfv2-performance-test org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} this-job-name: ${{ inputs.network }} VRFV2 Performance Test continue-on-error: true - name: Checkout code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 - name: Mask base64 config @@ -68,9 +69,9 @@ jobs: echo "### Networks on which test was run" >>$GITHUB_STEP_SUMMARY echo "\`${{ env.NETWORKS }}\`" >>$GITHUB_STEP_SUMMARY - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: - test_command_to_run: cd ./integration-tests/load && go test -v -count=1 -timeout 24h -run TestVRFV2Performance/vrfv2_performance_test ./vrfv2 + test_command_to_run: cd ./integration-tests/load && go test -v -count=1 -timeout 24h -run TestVRFV2Performance ./vrfv2 test_download_vendor_packages_command: cd ./integration-tests && go mod download cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ env.CHAINLINK_VERSION }} diff --git a/.github/workflows/on-demand-vrfv2plus-eth2-clients-test.yml b/.github/workflows/on-demand-vrfv2plus-eth2-clients-test.yml index 01777fba646..9342bff32d5 100644 --- a/.github/workflows/on-demand-vrfv2plus-eth2-clients-test.yml +++ b/.github/workflows/on-demand-vrfv2plus-eth2-clients-test.yml @@ -11,7 +11,7 @@ jobs: vrfv2plus_smoke_test: name: VRFV2Plus Smoke Test with custom EL client environment: integration - runs-on: ubuntu20.04-8cores-32GB + runs-on: ubuntu22.04-8cores-32GB permissions: checks: write pull-requests: write @@ -22,7 +22,7 @@ jobs: REF_NAME: ${{ github.head_ref || github.ref_name }} steps: - name: Checkout code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 - name: Mask base64 config @@ -46,7 +46,7 @@ jobs: echo "### Execution client used" >>$GITHUB_STEP_SUMMARY echo "\`${{ env.ETH2_EL_CLIENT }}\`" >>$GITHUB_STEP_SUMMARY - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -run ^TestVRFv2Plus$/^Link_Billing$ ./smoke/vrfv2plus_test.go 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download diff --git a/.github/workflows/on-demand-vrfv2plus-performance-test.yml b/.github/workflows/on-demand-vrfv2plus-performance-test.yml index 4240486a181..19f14d9089d 100644 --- a/.github/workflows/on-demand-vrfv2plus-performance-test.yml +++ b/.github/workflows/on-demand-vrfv2plus-performance-test.yml @@ -20,7 +20,7 @@ jobs: vrfv2plus_performance_test: name: VRFV2 Plus Performance Test environment: integration - runs-on: ubuntu20.04-8cores-32GB + runs-on: ubuntu22.04-8cores-32GB permissions: checks: write pull-requests: write @@ -39,15 +39,16 @@ jobs: steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: on-demand-vrfv2-plus-performance-test org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} this-job-name: ${{ inputs.network }} VRFV2 Plus Performance Test continue-on-error: true - name: Checkout code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 - name: Mask base64 config @@ -69,9 +70,9 @@ jobs: echo "### Networks on which test was run" >>$GITHUB_STEP_SUMMARY echo "\`${{ env.NETWORKS }}\`" >>$GITHUB_STEP_SUMMARY - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@c67a09566412d153ff7640d99f96b43aa03abc04 # v2.3.6 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: - test_command_to_run: cd ./integration-tests/load && go test -v -count=1 -timeout 24h -run TestVRFV2PlusPerformance/vrfv2plus_performance_test ./vrfv2plus + test_command_to_run: cd ./integration-tests/load && go test -v -count=1 -timeout 24h -run TestVRFV2PlusPerformance ./vrfv2plus test_download_vendor_packages_command: cd ./integration-tests && go mod download cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ env.CHAINLINK_VERSION }} diff --git a/.github/workflows/operator-ui-cd.yml b/.github/workflows/operator-ui-cd.yml deleted file mode 100644 index 7bbdc3deaef..00000000000 --- a/.github/workflows/operator-ui-cd.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Operator UI CD - -on: - push: - branches: - - develop - workflow_dispatch: - schedule: - - cron: "0 */1 * * *" # Run every hour - -jobs: - update-version: - permissions: - id-token: write - name: Update Version - runs-on: ubuntu-latest - steps: - - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Update version - id: update - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: ./operator_ui/check.sh - - - name: Assume role capable of dispatching action - uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 - with: - role-to-assume: ${{ secrets.AWS_OIDC_CHAINLINK_CI_AUTO_PR_TOKEN_ISSUER_ROLE_ARN }} - role-duration-seconds: ${{ secrets.aws-role-duration-seconds }} - role-session-name: operator-ui-cd.update-version - aws-region: ${{ secrets.AWS_REGION }} - - - name: Get Github Token - id: get-gh-token - uses: smartcontractkit/chainlink-github-actions/github-app-token-issuer@chore/update-github-app-token-issuer - with: - url: ${{ secrets.AWS_INFRA_RELENG_TOKEN_ISSUER_LAMBDA_URL }} - - - name: Open PR - uses: peter-evans/create-pull-request@b1ddad2c994a25fbc81a28b3ec0e368bb2021c50 # v6.0.0 - with: - title: Update Operator UI from ${{ steps.update.outputs.current_tag }} to ${{ steps.update.outputs.latest_tag }} - token: ${{ steps.get-gh-token.outputs.access-token }} - branch: chore/update-operator-ui - commit-message: Update Operator UI from ${{ steps.update.outputs.current_tag }} to ${{ steps.update.outputs.latest_tag }} - body: ${{ steps.update.outputs.body }} - - - name: Collect Metrics - if: always() - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 - with: - org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} - this-job-name: Update Version - continue-on-error: true diff --git a/.github/workflows/operator-ui-ci.yml b/.github/workflows/operator-ui-ci.yml index 8fbd366a346..dc944ca363c 100644 --- a/.github/workflows/operator-ui-ci.yml +++ b/.github/workflows/operator-ui-ci.yml @@ -2,6 +2,9 @@ name: Operator UI CI on: pull_request: +env: + TARGET_BRANCH_NAME: ${{ github.event.pull_request.base.ref }} + jobs: check-gql: permissions: @@ -15,8 +18,9 @@ jobs: steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: operator-ui-ci basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} @@ -33,14 +37,28 @@ jobs: - name: Get Github Token id: get-gh-token - uses: smartcontractkit/chainlink-github-actions/github-app-token-issuer@main + uses: smartcontractkit/chainlink-github-actions/github-app-token-issuer@7882cf348cd6a1f6bcf1ee8280185584ebba96e9 # v2.3.10 with: url: ${{ secrets.AWS_INFRA_RELENG_TOKEN_ISSUER_LAMBDA_URL }} + - name: Checkout repository + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + + - name: Get operator-ui tag + id: get-operator-ui-tag + shell: bash + run: | + if [[ $TARGET_BRANCH_NAME == release/* ]]; then + TAG=$(cat ./operator_ui/TAG) + echo "TAG=$TAG" >> $GITHUB_OUTPUT + else + echo "TAG=main" >> $GITHUB_OUTPUT + fi + - uses: convictional/trigger-workflow-and-wait@f69fa9eedd3c62a599220f4d5745230e237904be #v1.6.5 with: owner: smartcontractkit repo: operator-ui github_token: ${{ steps.get-gh-token.outputs.access-token }} workflow_file_name: chainlink-ci.yml - client_payload: '{"ref": "${{ github.event.pull_request.head.sha }}"}' + client_payload: '{"ref": "${{ github.event.pull_request.head.sha }}", "tag": "${{ steps.get-operator-ui-tag.outputs.TAG }}"}' diff --git a/.github/workflows/pr-labels.yml b/.github/workflows/pr-labels.yml index 1ca521fb667..ee12102f3dd 100644 --- a/.github/workflows/pr-labels.yml +++ b/.github/workflows/pr-labels.yml @@ -15,7 +15,7 @@ jobs: issues: write pull-requests: write steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0 with: diff --git a/.github/workflows/readme.yml b/.github/workflows/readme.yml deleted file mode 100644 index 54fa3d7e43d..00000000000 --- a/.github/workflows/readme.yml +++ /dev/null @@ -1,40 +0,0 @@ -# -# This action checks PRs to see if any README* files were updated. -# If none were, it will add a message to the PR asking if it would make sense to do so. -# -name: Readme - -on: pull_request - -jobs: - readme: - # For security reasons, GITHUB_TOKEN is read-only on forks, so we cannot leave comments on PRs. - # This check skips the job if it is detected we are running on a fork. - if: ${{ github.event.pull_request.head.repo.full_name == 'smartcontractkit/chainlink' }} - name: Readme checker - runs-on: ubuntu-latest - steps: - - name: Check for changed files - id: changedfiles - uses: umani/changed-files@d7f842d11479940a6036e3aacc6d35523e6ba978 # Version 4.1.0 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - pattern: '^(?!.*node_modules).*README\.md$' - - name: Make a comment - uses: unsplash/comment-on-pr@ffe8f97ccc63ce12c3c23c6885b169db67958d3b # Version 1.3.0 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - if: contains(steps.changedfiles.outputs.files_updated, 'README') != true && contains(steps.changedfiles.outputs.files_created, 'README') != true - with: - msg: "I see that you haven't updated any README files. Would it make sense to do so?" - check_for_duplicate_msg: true - - name: Collect Metrics - if: always() - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 - with: - org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} - this-job-name: Readme checker - continue-on-error: true \ No newline at end of file diff --git a/.github/workflows/sigscanner.yml b/.github/workflows/sigscanner.yml index c245380c237..f059cd28f5e 100644 --- a/.github/workflows/sigscanner.yml +++ b/.github/workflows/sigscanner.yml @@ -26,8 +26,9 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: sigscanner org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} diff --git a/.github/workflows/solidity-foundry.yml b/.github/workflows/solidity-foundry.yml index 47f9571eea3..cea16f45f16 100644 --- a/.github/workflows/solidity-foundry.yml +++ b/.github/workflows/solidity-foundry.yml @@ -12,8 +12,8 @@ jobs: changes: ${{ steps.changes.outputs.src }} steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 id: changes with: # Foundry is only used for Solidity v0.8 contracts, therefore we can ignore @@ -21,12 +21,11 @@ jobs: filters: | src: - 'contracts/src/v0.8/**/*' - - 'contracts/test/v0.8/foundry/**/*' - '.github/workflows/solidity-foundry.yml' - 'contracts/foundry.toml' - 'contracts/gas-snapshots/*.gas-snapshot' - - '.gitmodules' - 'contracts/foundry-lib' + - '.gitmodules' tests: strategy: @@ -42,7 +41,7 @@ jobs: # passing required check for PRs that don't have filtered changes. steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: submodules: recursive @@ -55,10 +54,10 @@ jobs: - name: Install Foundry if: needs.changes.outputs.changes == 'true' - uses: foundry-rs/foundry-toolchain@v1 + uses: foundry-rs/foundry-toolchain@8f1998e9878d786675189ef566a2e4bf24869773 # v1.2.0 with: # Has to match the `make foundry` version. - version: nightly-5b7e4cb3c882b28f3c32ba580de27ce7381f415a + version: nightly-de33b6af53005037b463318d2628b5cfcaf39916 - name: Run Forge build if: needs.changes.outputs.changes == 'true' @@ -91,8 +90,9 @@ jobs: - name: Collect Metrics if: needs.changes.outputs.changes == 'true' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: solidity-foundry org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} diff --git a/.github/workflows/solidity-hardhat.yml b/.github/workflows/solidity-hardhat.yml index f07c9f8fdca..7f56e8e023b 100644 --- a/.github/workflows/solidity-hardhat.yml +++ b/.github/workflows/solidity-hardhat.yml @@ -19,13 +19,13 @@ jobs: changes: ${{ steps.changes.outputs.src }} steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 id: changes with: filters: | src: - - 'contracts/src/!(v0.8/(llo-feeds|keystone|ccip)/**)/**/*' + - 'contracts/src/!(v0.8/(llo-feeds|keystone|ccip|functions|transmission)/**)/**/*' - 'contracts/test/**/*' - 'contracts/package.json' - 'contracts/pnpm-lock.yaml' @@ -40,7 +40,7 @@ jobs: splits: ${{ steps.split.outputs.splits }} steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Generate splits id: split uses: ./.github/actions/split-tests @@ -48,80 +48,15 @@ jobs: config: ./contracts/ci.json - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: solidity-split-tests org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} this-job-name: Split Solidity Tests continue-on-error: true - solidity-coverage-splits: - needs: [changes, split-tests] - if: needs.changes.outputs.changes == 'true' - name: Solidity Coverage ${{ matrix.split.id }} ${{ fromJSON('["(skipped)", ""]')[needs.changes.outputs.changes == 'true'] }} - strategy: - fail-fast: false - matrix: - split: ${{ fromJson(needs.split-tests.outputs.splits) }} - runs-on: ubuntu-latest - steps: - - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - name: Setup NodeJS - uses: ./.github/actions/setup-nodejs - - name: Setup Hardhat - uses: ./.github/actions/setup-hardhat - with: - namespace: coverage - - name: Run coverage - env: - SPLIT: ${{ matrix.split.coverageTests }} - shell: bash - run: pnpm coverage --testfiles "$SPLIT" - working-directory: contracts - - name: Push coverage - run: ./tools/bin/codecov -f ./contracts/coverage.json - - name: Rename coverage - run: mv ./contracts/coverage.json ./contracts/coverage-${{ matrix.split.idx }}.json - - name: Upload coverage - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 - with: - name: solidity-coverage-${{ matrix.split.idx }} - path: ./contracts/coverage-${{ matrix.split.idx }}.json - - name: Collect Metrics - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 - with: - org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} - this-job-name: Solidity Coverage ${{ matrix.split.id }} - continue-on-error: true - - solidity-coverage: - needs: [changes, solidity-coverage-splits] - if: needs.changes.outputs.changes == 'true' - name: Solidity Coverage ${{ fromJSON('["(skipped)", ""]')[needs.changes.outputs.changes == 'true'] }} - runs-on: ubuntu-latest - steps: - - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - name: Setup NodeJS - uses: ./.github/actions/setup-nodejs - - name: Make coverage directory - run: mkdir ./contracts/coverage-reports - - name: Download coverage - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 - with: - path: ./contracts/coverage-reports - - name: Display structure of downloaded files - run: ls -R coverage-reports - working-directory: contracts - - name: Generate merged report - run: pnpm istanbul report text text-summary - working-directory: contracts - solidity-splits: needs: [changes, split-tests] if: needs.changes.outputs.changes == 'true' @@ -133,7 +68,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Setup NodeJS uses: ./.github/actions/setup-nodejs - name: Setup Hardhat @@ -147,8 +82,9 @@ jobs: run: pnpm test -- $SPLIT - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: solidity-splits org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -173,8 +109,9 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: solidity-tests org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} diff --git a/.github/workflows/solidity.yml b/.github/workflows/solidity.yml index 904cdacfbff..d111bf3166f 100644 --- a/.github/workflows/solidity.yml +++ b/.github/workflows/solidity.yml @@ -16,8 +16,8 @@ jobs: changes: ${{ steps.changes.outputs.src }} steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 id: changes with: list-files: "csv" @@ -26,17 +26,17 @@ jobs: - 'contracts/**/*' - '.github/workflows/solidity.yml' - '.github/workflows/solidity-foundry.yml' - old_sol: - - 'contracts/src/v0.4/**/*' - - 'contracts/src/v0.5/**/*' - - 'contracts/src/v0.6/**/*' - - 'contracts/src/v0.7/**/*' + read_only_sol: + - 'contracts/src/v0.8/interfaces/**/*' + - 'contracts/src/v0.8/automation/v1_2/**/*' + - 'contracts/src/v0.8/automation/v1_3/**/*' + - 'contracts/src/v0.8/automation/v2_0/**/*' - name: Fail if read-only files have changed - if: ${{ steps.changes.outputs.old_sol == 'true' }} + if: ${{ steps.changes.outputs.read_only_sol == 'true' }} run: | echo "One or more read-only Solidity file(s) has changed." - for file in ${{ steps.changes.outputs.old_sol_files }}; do + for file in ${{ steps.changes.outputs.read_only_sol_files }}; do echo "$file was changed" done exit 1 @@ -48,7 +48,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Setup NodeJS uses: ./.github/actions/setup-nodejs - name: Run Prepublish test @@ -56,8 +56,9 @@ jobs: run: pnpm prepublishOnly - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: solidity-prepublish-test org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -71,9 +72,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Checkout diff-so-fancy - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: repository: so-fancy/diff-so-fancy ref: a673cb4d2707f64d92b86498a2f5f71c8e2643d5 # v1.4.3 @@ -101,8 +102,9 @@ jobs: run: gh pr comment -b 'Go solidity wrappers are out-of-date, regenerate them via the `make wrappers-all` command' - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: solidity-native-compile org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -120,7 +122,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Setup NodeJS if: needs.changes.outputs.changes == 'true' uses: ./.github/actions/setup-nodejs @@ -133,8 +135,9 @@ jobs: - name: Collect Metrics if: needs.changes.outputs.changes == 'true' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: solidity-lint org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} @@ -150,7 +153,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - name: Setup NodeJS if: needs.changes.outputs.changes == 'true' uses: ./.github/actions/setup-nodejs @@ -160,8 +163,9 @@ jobs: - name: Collect Metrics if: needs.changes.outputs.changes == 'true' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: solidity-prettier org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} diff --git a/.github/workflows/sync-develop-from-smartcontractkit-chainlink.yml b/.github/workflows/sync-develop-from-smartcontractkit-chainlink.yml index afdcfa156c2..c662aecf0dd 100644 --- a/.github/workflows/sync-develop-from-smartcontractkit-chainlink.yml +++ b/.github/workflows/sync-develop-from-smartcontractkit-chainlink.yml @@ -10,7 +10,7 @@ jobs: name: Sync runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: develop if: env.GITHUB_REPOSITORY != 'smartcontractkit/chainlink' @@ -30,8 +30,9 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@0281b09807758be1dcc41651e44e62b353808c47 # v2.1.0 + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 with: + id: sync-develop org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} diff --git a/.golangci.yml b/.golangci.yml index af8c27a7f8f..7f127e9524d 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -105,7 +105,7 @@ linters-settings: desc: Use gopkg.in/guregu/null.v4 instead - pkg: gopkg.in/guregu/null.v3 desc: Use gopkg.in/guregu/null.v4 instead - - pkg: https://github.com/go-gorm/gorm + - pkg: github.com/go-gorm/gorm desc: Use github.com/jmoiron/sqlx directly instead issues: exclude-rules: diff --git a/CODEOWNERS b/CODEOWNERS index b6052f1628a..65f0b58753f 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -6,8 +6,8 @@ /core @smartcontractkit/foundations # Chains -/common @smartcontractkit/integrations -/core/chains/ @smartcontractkit/integrations +/common @smartcontractkit/bix-framework +/core/chains/ @smartcontractkit/bix-framework # Services /core/services/directrequest @smartcontractkit/keepers @@ -20,10 +20,10 @@ /core/services/ocr* @smartcontractkit/foundations /core/services/periodicbackup @smartcontractkit/foundations /core/services/pg @smartcontractkit/foundations @samsondav -/core/services/pipeline @smartcontractkit/foundations @smartcontractkit/integrations +/core/services/pipeline @smartcontractkit/foundations @smartcontractkit/bix-framework /core/services/telemetry @smartcontractkit/realtime /core/services/relay/evm/mercury @smartcontractkit/mercury-team -/core/services/webhook @smartcontractkit/foundations @smartcontractkit/integrations +/core/services/webhook @smartcontractkit/foundations @smartcontractkit/bix-framework /core/services/llo @smartcontractkit/mercury-team # VRF-related services @@ -65,7 +65,7 @@ core/scripts/gateway @smartcontractkit/functions /contracts/**/*functions* @smartcontractkit/functions /contracts/**/*llo-feeds* @smartcontrackit/mercury-team /contracts/**/*vrf* @smartcontractkit/vrf-team -/contracts/**/*l2ep* @smartcontractkit/integrations +/contracts/**/*l2ep* @smartcontractkit/bix-ship # TODO: replace with a team tag when ready /contracts/**/*keystone* @archseer @bolekk @patrick-dowell @@ -75,7 +75,7 @@ core/scripts/gateway @smartcontractkit/functions /contracts/src/v0.8/l2ep @chris-de-leon-cll /contracts/src/v0.8/llo-feeds @smartcontractkit/mercury-team # TODO: mocks folder, folder should be removed and files moved to the correct folders -/contracts/src/v0.8/operatorforwarder @smartcontractkit/foundations +/contracts/src/v0.8/operatorforwarder @RensR /contracts/src/v0.8/shared @RensR # TODO: tests folder, folder should be removed and files moved to the correct folders # TODO: transmission folder, owner should be found @@ -85,6 +85,8 @@ core/scripts/gateway @smartcontractkit/functions # At the end, match any files missed by the patterns above /contracts/scripts/native_solc_compile_all_events_mock @smartcontractkit/functions +# Remove changeset files from the codeowners +/contracts/.changeset # Tests diff --git a/GNUmakefile b/GNUmakefile index 46565a2778a..6e61563316e 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -27,11 +27,13 @@ gomod: ## Ensure chainlink's go dependencies are installed. go mod download .PHONY: gomodtidy -gomodtidy: ## Run go mod tidy on all modules. +gomodtidy: gomods ## Run go mod tidy on all modules. go mod tidy cd ./core/scripts && go mod tidy cd ./integration-tests && go mod tidy cd ./integration-tests/load && go mod tidy + cd ./dashboard-lib && go mod tidy + cd ./charts/chainlink-cluster && go mod tidy .PHONY: godoc godoc: ## Install and run godoc @@ -84,8 +86,8 @@ abigen: ## Build & install abigen. ./tools/bin/build_abigen .PHONY: generate -generate: abigen codecgen mockery protoc ## Execute all go:generate commands. - go generate -x ./... +generate: abigen codecgen mockery protoc gomods ## Execute all go:generate commands. + gomods -w go generate -x ./... .PHONY: testscripts testscripts: chainlink-test ## Install and run testscript against testdata/scripts/* files. @@ -112,6 +114,10 @@ presubmit: ## Format go files and imports. gofmt -w . go mod tidy +.PHONY: gomods +gomods: ## Install gomods + go install github.com/jmank88/gomods@v0.1.0 + .PHONY: mockery mockery: $(mockery) ## Install mockery. go install github.com/vektra/mockery/v2@v2.38.0 diff --git a/charts/chainlink-cluster/dashboard/cmd/deploy.go b/charts/chainlink-cluster/dashboard/cmd/deploy.go index 9eb89ae3bd2..883c1939a6b 100644 --- a/charts/chainlink-cluster/dashboard/cmd/deploy.go +++ b/charts/chainlink-cluster/dashboard/cmd/deploy.go @@ -2,9 +2,9 @@ package main import ( "github.com/K-Phoen/grabana/dashboard" - lib "github.com/smartcontractkit/chainlink/dashboard-lib/lib" - core_don "github.com/smartcontractkit/chainlink/dashboard-lib/lib/core-don" - k8spods "github.com/smartcontractkit/chainlink/dashboard-lib/lib/k8s-pods" + lib "github.com/smartcontractkit/chainlink/dashboard-lib" + core_don "github.com/smartcontractkit/chainlink/dashboard-lib/core-don" + k8spods "github.com/smartcontractkit/chainlink/dashboard-lib/k8s-pods" waspdb "github.com/smartcontractkit/wasp/dashboard" ) @@ -17,7 +17,7 @@ func main() { db := lib.NewDashboard(DashboardName, cfg, []dashboard.Option{ dashboard.AutoRefresh("10s"), - dashboard.Tags([]string{"experimental", "generated"}), + dashboard.Tags([]string{"generated"}), }, ) db.Add( diff --git a/charts/chainlink-cluster/dashboard/tests/.gitignore b/charts/chainlink-cluster/dashboard/tests/.gitignore deleted file mode 100644 index eecb65f23fd..00000000000 --- a/charts/chainlink-cluster/dashboard/tests/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -node_modules/ -/test-results/ -/playwright-report/ -/blob-report/ -/playwright/.cache/ -.github/ diff --git a/charts/chainlink-cluster/dashboard/tests/package.json b/charts/chainlink-cluster/dashboard/tests/package.json deleted file mode 100644 index 3d4ecdd6d69..00000000000 --- a/charts/chainlink-cluster/dashboard/tests/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "tests", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": {}, - "keywords": [], - "author": "", - "license": "ISC", - "devDependencies": { - "@playwright/test": "^1.42.1", - "@types/node": "^20.11.25" - }, - "dependencies": { - "dashboard-tests": "^1.0.0" - } -} diff --git a/charts/chainlink-cluster/dashboard/tests/playwright.config.ts b/charts/chainlink-cluster/dashboard/tests/playwright.config.ts deleted file mode 100644 index 7af47550407..00000000000 --- a/charts/chainlink-cluster/dashboard/tests/playwright.config.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { defineConfig, devices } from '@playwright/test'; - -/** - * See https://playwright.dev/docs/test-configuration. - */ -export default defineConfig({ - testDir: './specs', - /* Run tests in files in parallel */ - fullyParallel: true, - /* Fail the build on CI if you accidentally left test.only in the source code. */ - forbidOnly: !!process.env.CI, - /* Retry on CI only */ - retries: process.env.CI ? 2 : 0, - /* Opt out of parallel tests on CI. */ - workers: process.env.CI ? 1 : undefined, - /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: 'html', - /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ - use: { - /* Base URL to use in actions like `await page.goto('/')`. */ - // baseURL: '', - - /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: 'on-first-retry', - }, - - projects: [ - { - name: 'chromium', - use: { ...devices['Desktop Chrome'] }, - }, - ], -}); diff --git a/charts/chainlink-cluster/dashboard/tests/pnpm-lock.yaml b/charts/chainlink-cluster/dashboard/tests/pnpm-lock.yaml deleted file mode 100644 index 4f7f1d277eb..00000000000 --- a/charts/chainlink-cluster/dashboard/tests/pnpm-lock.yaml +++ /dev/null @@ -1,57 +0,0 @@ -lockfileVersion: '6.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -devDependencies: - '@playwright/test': - specifier: ^1.42.1 - version: 1.42.1 - '@types/node': - specifier: ^20.11.25 - version: 20.11.25 - -packages: - - /@playwright/test@1.42.1: - resolution: {integrity: sha512-Gq9rmS54mjBL/7/MvBaNOBwbfnh7beHvS6oS4srqXFcQHpQCV1+c8JXWE8VLPyRDhgS3H8x8A7hztqI9VnwrAQ==} - engines: {node: '>=16'} - hasBin: true - dependencies: - playwright: 1.42.1 - dev: true - - /@types/node@20.11.25: - resolution: {integrity: sha512-TBHyJxk2b7HceLVGFcpAUjsa5zIdsPWlR6XHfyGzd0SFu+/NFgQgMAl96MSDZgQDvJAvV6BKsFOrt6zIL09JDw==} - dependencies: - undici-types: 5.26.5 - dev: true - - /fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /playwright-core@1.42.1: - resolution: {integrity: sha512-mxz6zclokgrke9p1vtdy/COWBH+eOZgYUVVU34C73M+4j4HLlQJHtfcqiqqxpP0o8HhMkflvfbquLX5dg6wlfA==} - engines: {node: '>=16'} - hasBin: true - dev: true - - /playwright@1.42.1: - resolution: {integrity: sha512-PgwB03s2DZBcNRoW+1w9E+VkLBxweib6KTXM0M3tkiT4jVxKSi6PmVJ591J+0u10LUrgxB7dLRbiJqO5s2QPMg==} - engines: {node: '>=16'} - hasBin: true - dependencies: - playwright-core: 1.42.1 - optionalDependencies: - fsevents: 2.3.2 - dev: true - - /undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - dev: true diff --git a/charts/chainlink-cluster/devspace.yaml b/charts/chainlink-cluster/devspace.yaml index f520c627b7f..d46e28572bb 100644 --- a/charts/chainlink-cluster/devspace.yaml +++ b/charts/chainlink-cluster/devspace.yaml @@ -117,6 +117,8 @@ deployments: runAsGroup: 999 web_port: 6688 p2p_port: 6690 + # extraEnvVars: + # "CL_MEDIAN_CMD": "chainlink-feeds" nodes: - name: node-1 image: ${runtime.images.app} @@ -161,7 +163,14 @@ deployments: # [WebServer.TLS] # HTTPSPort = 0 # or use overridesToml to override some part of configuration - # overridesToml: | + # overridesToml: | + # Enable Tracing + # [Tracing] + # Enabled = true + # SamplingRatio = 1.0 + # CollectorTarget = 'app-opentelemetry-collector:4317' + # TLSCertPath = '' + # Mode = 'unencrypted' - name: node-2 image: ${runtime.images.app} - name: node-3 @@ -208,8 +217,8 @@ deployments: runAsUser: 999 runAsGroup: 999 version: v1.12.0 - wsrpc-port: 8546 - httprpc-port: 8544 + wsRpcPort: 8546 + httpRpcPort: 8544 chains: - networkId: 1337 - networkId: 2337 @@ -355,6 +364,15 @@ deployments: name: mockserver port: number: 1080 + - host: ${DEVSPACE_NAMESPACE}-grafana.${DEVSPACE_INGRESS_BASE_DOMAIN} + http: + paths: + - path: / + backend: + service: + name: app-grafana + port: + number: 80 networkPolicyDefault: ingress: allowCustomCidrs: true diff --git a/charts/chainlink-cluster/go.mod b/charts/chainlink-cluster/go.mod index 3f893606f00..4a8dd43fd5f 100644 --- a/charts/chainlink-cluster/go.mod +++ b/charts/chainlink-cluster/go.mod @@ -4,200 +4,20 @@ go 1.21.7 require ( github.com/K-Phoen/grabana v0.22.1 - github.com/smartcontractkit/chainlink/dashboard-lib v0.22.1 + github.com/smartcontractkit/chainlink/dashboard-lib v0.0.0-00010101000000-000000000000 + github.com/smartcontractkit/wasp v0.4.6 ) require ( - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 // indirect github.com/K-Phoen/sdk v0.12.4 // indirect - github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver/v3 v3.2.1 // indirect - github.com/Masterminds/sprig/v3 v3.2.3 // indirect - github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect - github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect - github.com/armon/go-metrics v0.4.1 // indirect - github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/aws/aws-sdk-go v1.45.25 // indirect - github.com/beorn7/perks v1.0.1 // indirect - github.com/buger/jsonparser v1.1.1 // indirect - github.com/bytedance/sonic v1.9.1 // indirect - github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b // indirect - github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 // indirect - github.com/cespare/xxhash v1.1.0 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect - github.com/coreos/go-semver v0.3.0 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/dennwc/varint v1.0.0 // indirect - github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/dustin/go-humanize v1.0.1 // indirect - github.com/edsrzf/mmap-go v1.1.0 // indirect - github.com/emicklei/go-restful/v3 v3.10.2 // indirect - github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb // indirect - github.com/fatih/color v1.15.0 // indirect - github.com/felixge/httpsnoop v1.0.3 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.2 // indirect - github.com/gin-contrib/sse v0.1.0 // indirect - github.com/gin-gonic/gin v1.9.1 // indirect - github.com/go-kit/log v0.2.1 // indirect - github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect - github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/analysis v0.21.4 // indirect - github.com/go-openapi/errors v0.20.4 // indirect - github.com/go-openapi/jsonpointer v0.20.0 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/loads v0.21.2 // indirect - github.com/go-openapi/spec v0.20.9 // indirect - github.com/go-openapi/strfmt v0.21.7 // indirect - github.com/go-openapi/swag v0.22.4 // indirect - github.com/go-openapi/validate v0.22.1 // indirect - github.com/go-playground/locales v0.14.1 // indirect - github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.14.0 // indirect - github.com/go-redis/redis/v8 v8.11.5 // indirect - github.com/go-resty/resty/v2 v2.11.0 // indirect - github.com/goccy/go-json v0.10.2 // indirect - github.com/gogo/googleapis v1.4.1 // indirect - github.com/gogo/protobuf v1.3.3 // indirect - github.com/gogo/status v1.1.1 // indirect - github.com/golang-jwt/jwt/v4 v4.5.0 // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect - github.com/google/btree v1.1.2 // indirect - github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/go-cmp v0.6.0 // indirect - github.com/google/gofuzz v1.2.0 // indirect - github.com/google/uuid v1.3.1 // indirect - github.com/gorilla/mux v1.8.0 // indirect github.com/gosimple/slug v1.13.1 // indirect github.com/gosimple/unidecode v1.0.1 // indirect - github.com/grafana/dskit v0.0.0-20231120170505-765e343eda4f // indirect - github.com/grafana/gomemcache v0.0.0-20231023152154-6947259a0586 // indirect - github.com/grafana/loki v1.6.2-0.20231215164305-b51b7d7b5503 // indirect - github.com/grafana/loki/pkg/push v0.0.0-20231124142027-e52380921608 // indirect - github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd // indirect - github.com/hashicorp/consul/api v1.25.1 // indirect - github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-hclog v1.5.0 // indirect - github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/go-msgpack v0.5.5 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-rootcerts v1.0.2 // indirect - github.com/hashicorp/go-sockaddr v1.0.2 // indirect - github.com/hashicorp/golang-lru v0.6.0 // indirect - github.com/hashicorp/memberlist v0.5.0 // indirect - github.com/hashicorp/serf v0.10.1 // indirect - github.com/huandu/xstrings v1.3.3 // indirect - github.com/imdario/mergo v0.3.16 // indirect - github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/jpillora/backoff v1.0.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/julienschmidt/httprouter v1.3.0 // indirect - github.com/klauspost/compress v1.17.1 // indirect - github.com/klauspost/cpuid/v2 v2.2.5 // indirect - github.com/kylelemons/godebug v1.1.0 // indirect - github.com/leodido/go-urn v1.2.4 // indirect - github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect - github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect - github.com/miekg/dns v1.1.56 // indirect - github.com/mitchellh/copystructure v1.0.0 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/mitchellh/reflectwalk v1.0.1 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect - github.com/oklog/ulid v1.3.1 // indirect - github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e // indirect - github.com/opentracing-contrib/go-stdlib v1.0.0 // indirect - github.com/opentracing/opentracing-go v1.2.0 // indirect - github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect - github.com/pelletier/go-toml/v2 v2.1.0 // indirect - github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/alertmanager v0.26.0 // indirect - github.com/prometheus/client_golang v1.17.0 // indirect - github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.45.0 // indirect - github.com/prometheus/common/sigv4 v0.1.0 // indirect - github.com/prometheus/exporter-toolkit v0.10.1-0.20230714054209-2f4150c63f97 // indirect - github.com/prometheus/procfs v0.12.0 // indirect - github.com/prometheus/prometheus v0.47.2-0.20231010075449-4b9c19fe5510 // indirect github.com/rs/zerolog v1.32.0 // indirect - github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect - github.com/sercand/kuberesolver/v5 v5.1.1 // indirect - github.com/shopspring/decimal v1.2.0 // indirect - github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240227164431-18a7065e23ea // indirect - github.com/smartcontractkit/wasp v0.4.6 // indirect - github.com/soheilhy/cmux v0.1.5 // indirect - github.com/sony/gobreaker v0.5.0 // indirect - github.com/spf13/cast v1.3.1 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/objx v0.5.0 // indirect - github.com/stretchr/testify v1.8.4 // indirect - github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect - github.com/uber/jaeger-lib v2.4.1+incompatible // indirect - github.com/ugorji/go/codec v1.2.11 // indirect - go.etcd.io/etcd/api/v3 v3.5.7 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.7 // indirect - go.etcd.io/etcd/client/v3 v3.5.7 // indirect - go.mongodb.org/mongo-driver v1.12.0 // indirect - go.opentelemetry.io/collector/pdata v1.0.0-rcv0015 // indirect - go.opentelemetry.io/collector/semconv v0.81.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect - go.opentelemetry.io/otel v1.19.0 // indirect - go.opentelemetry.io/otel/metric v1.19.0 // indirect - go.opentelemetry.io/otel/trace v1.19.0 // indirect - go.uber.org/atomic v1.11.0 // indirect - go.uber.org/goleak v1.2.1 // indirect - go.uber.org/multierr v1.11.0 // indirect - go.uber.org/ratelimit v0.2.0 // indirect - go.uber.org/zap v1.26.0 // indirect - go4.org/netipx v0.0.0-20230125063823-8449b0a6169f // indirect - golang.org/x/arch v0.4.0 // indirect - golang.org/x/crypto v0.17.0 // indirect - golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect - golang.org/x/mod v0.13.0 // indirect - golang.org/x/net v0.19.0 // indirect - golang.org/x/oauth2 v0.15.0 // indirect - golang.org/x/sync v0.4.0 // indirect golang.org/x/sys v0.15.0 // indirect - golang.org/x/term v0.15.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.14.0 // indirect - google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c // indirect - google.golang.org/grpc v1.59.0 // indirect - google.golang.org/protobuf v1.32.0 // indirect - gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.28.2 // indirect - k8s.io/apimachinery v0.28.2 // indirect - k8s.io/client-go v0.28.2 // indirect - k8s.io/klog/v2 v2.100.1 // indirect - k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect - k8s.io/utils v0.0.0-20230711102312-30195339c3c7 // indirect - nhooyr.io/websocket v1.8.7 // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect ) replace ( @@ -205,6 +25,7 @@ replace ( // replicating the replace directive on cosmos SDK github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 + github.com/grafana/grafana-foundation-sdk/go => github.com/grafana/grafana-foundation-sdk/go v0.0.0-20240314112857-a7c9c6d0044c // until merged upstream: https://github.com/hashicorp/go-plugin/pull/257 github.com/hashicorp/go-plugin => github.com/smartcontractkit/go-plugin v0.0.0-20240208201424-b3b91517de16 @@ -213,5 +34,5 @@ replace ( github.com/mwitkow/grpc-proxy => github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f github.com/sercand/kuberesolver/v4 => github.com/sercand/kuberesolver/v5 v5.1.1 - github.com/smartcontractkit/chainlink/dashboard-lib => ../../dashboard + github.com/smartcontractkit/chainlink/dashboard-lib => ../../dashboard-lib ) diff --git a/charts/chainlink-cluster/go.sum b/charts/chainlink-cluster/go.sum index 28af748e7cb..d1680424a7a 100644 --- a/charts/chainlink-cluster/go.sum +++ b/charts/chainlink-cluster/go.sum @@ -1,1094 +1,37 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 h1:8q4SaHjFsClSvuVne0ID/5Ka8u3fcIHyqkLjcFpNRHQ= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= -github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 h1:OBhqkivkhkMqLPymWEppkm7vgPQY2XsHoEkaMQ0AdZY= -github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/K-Phoen/grabana v0.22.1 h1:b/O+C3H2H6VNYSeMCYUO4X4wYuwFXgBcRkvYa+fjpQA= github.com/K-Phoen/grabana v0.22.1/go.mod h1:3LTXrTzQzTKTgvKSXdRjlsJbizSOW/V23Q3iX00R5bU= github.com/K-Phoen/sdk v0.12.4 h1:j2EYuBJm3zDTD0fGKACVFWxAXtkR0q5QzfVqxmHSeGQ= github.com/K-Phoen/sdk v0.12.4/go.mod h1:qmM0wO23CtoDux528MXPpYvS4XkRWkWX6rvX9Za8EVU= -github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= -github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= -github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= -github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= -github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= -github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= -github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= -github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.45.25 h1:c4fLlh5sLdK2DCRTY1z0hyuJZU4ygxX8m1FswL6/nF4= -github.com/aws/aws-sdk-go v1.45.25/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= -github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= -github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= -github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= -github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b h1:6+ZFm0flnudZzdSE0JxlhR2hKnGPcNB35BjQf4RYQDY= -github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= -github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 h1:SjZ2GvvOononHOpK84APFuMvxqsk3tEIaKH/z4Rpu3g= -github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8/go.mod h1:uEyr4WpAH4hio6LFriaPkL938XnrvLpNPmQHBdrmbIE= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= -github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE= -github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= -github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= -github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= -github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb h1:IT4JYU7k4ikYg1SCxNI1/Tieq/NFvh6dzLdgi7eu0tM= -github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb/go.mod h1:bH6Xx7IW64qjjJq8M2u4dxNaBiDfKK+z/3eGDpXEQhc= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= -github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= -github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= -github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= -github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= -github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= -github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= -github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc= -github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo= -github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.20.4 h1:unTcVm6PispJsMECE3zWgvG4xTiKda1LIR5rCRWLG6M= -github.com/go-openapi/errors v0.20.4/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= -github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA= -github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= -github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= -github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro= -github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw= -github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= -github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= -github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8= -github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= -github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= -github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= -github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= -github.com/go-openapi/strfmt v0.21.7 h1:rspiXgNWgeUzhjo1YU01do6qsahtJNByjLVbPLNHb8k= -github.com/go-openapi/strfmt v0.21.7/go.mod h1:adeGTkxE44sPyLk0JV235VQAO/ZXUr8KAzYjclFs3ew= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= -github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU= -github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= -github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= -github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= -github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= -github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= -github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= -github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8= -github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= -github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= -github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= -github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= -github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= -github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= -github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= -github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= -github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= -github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= -github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= -github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= -github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= -github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= -github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= -github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= -github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= -github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= -github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= -github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= -github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= -github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= -github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= -github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= -github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= -github.com/gogo/status v1.1.1 h1:DuHXlSFHNKqTQ+/ACf5Vs6r4X/dH2EgIzR9Vr+H65kg= -github.com/gogo/status v1.1.1/go.mod h1:jpG3dM5QPcqu19Hg8lkUhBFBa3TcLs1DG7+2Jqci7oU= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= -github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= -github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gosimple/slug v1.13.1 h1:bQ+kpX9Qa6tHRaK+fZR0A0M2Kd7Pa5eHPPsb1JpHD+Q= github.com/gosimple/slug v1.13.1/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ= github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o= github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc= -github.com/grafana/dskit v0.0.0-20231120170505-765e343eda4f h1:gyojr97YeWZ70pKNakWv5/tKwBHuLy3icnIeCo9gQr4= -github.com/grafana/dskit v0.0.0-20231120170505-765e343eda4f/go.mod h1:8dsy5tQOkeNQyjXpm5mQsbCu3H5uzeBD35MzRQFznKU= -github.com/grafana/gomemcache v0.0.0-20231023152154-6947259a0586 h1:/of8Z8taCPftShATouOrBVy6GaTTjgQd/VfNiZp/VXQ= -github.com/grafana/gomemcache v0.0.0-20231023152154-6947259a0586/go.mod h1:PGk3RjYHpxMM8HFPhKKo+vve3DdlPUELZLSDEFehPuU= -github.com/grafana/loki v1.6.2-0.20231215164305-b51b7d7b5503 h1:gdrsYbmk8822v6qvPwZO5DC6QjnAW7uKJ9YXnoUmV8c= -github.com/grafana/loki v1.6.2-0.20231215164305-b51b7d7b5503/go.mod h1:d8seWXCEXkL42mhuIJYcGi6DxfehzoIpLrMQWJojvOo= -github.com/grafana/loki/pkg/push v0.0.0-20231124142027-e52380921608 h1:ZYk42718kSXOiIKdjZKljWLgBpzL5z1yutKABksQCMg= -github.com/grafana/loki/pkg/push v0.0.0-20231124142027-e52380921608/go.mod h1:f3JSoxBTPXX5ec4FxxeC19nTBSxoTz+cBgS3cYLMcr0= -github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd h1:PpuIBO5P3e9hpqBD0O/HjhShYuM6XE0i/lbE6J94kww= -github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A= -github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= -github.com/hashicorp/consul/api v1.25.1 h1:CqrdhYzc8XZuPnhIYZWH45toM0LB9ZeYr/gvpLVI3PE= -github.com/hashicorp/consul/api v1.25.1/go.mod h1:iiLVwR/htV7mas/sy0O+XSuEnrdBUUydemjxcUrAt4g= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= -github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= -github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= -github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= -github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= -github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= -github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= -github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4= -github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= -github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM= -github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= -github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= -github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= -github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= -github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= -github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= -github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.17.1 h1:NE3C767s2ak2bweCZo3+rdP4U/HoyVXLv/X9f2gPS5g= -github.com/klauspost/compress v1.17.1/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= -github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= -github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= -github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= -github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= -github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= -github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e h1:4cPxUYdgaGzZIT5/j0IfqOrrXmq6bG8AwvwisMXpdrg= -github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo= -github.com/opentracing-contrib/go-stdlib v1.0.0 h1:TBS7YuVotp8myLon4Pv7BtCBzOTo1DeZCld0Z63mW2w= -github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= -github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= -github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= -github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= -github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= -github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= -github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= -github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= -github.com/prometheus/alertmanager v0.26.0 h1:uOMJWfIwJguc3NaM3appWNbbrh6G/OjvaHMk22aBBYc= -github.com/prometheus/alertmanager v0.26.0/go.mod h1:rVcnARltVjavgVaNnmevxK7kOn7IZavyf0KNgHkbEpU= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= -github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= -github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4= -github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI= -github.com/prometheus/exporter-toolkit v0.10.1-0.20230714054209-2f4150c63f97 h1:oHcfzdJnM/SFppy2aUlvomk37GI33x9vgJULihE5Dt8= -github.com/prometheus/exporter-toolkit v0.10.1-0.20230714054209-2f4150c63f97/go.mod h1:LoBCZeRh+5hX+fSULNyFnagYlQG/gBsyA/deNzROkq8= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/prometheus/prometheus v0.47.2-0.20231010075449-4b9c19fe5510 h1:6ksZ7t1hNOzGPPs8DK7SvXQf6UfWzi+W5Z7PCBl8gx4= -github.com/prometheus/prometheus v0.47.2-0.20231010075449-4b9c19fe5510/go.mod h1:UC0TwJiF90m2T3iYPQBKnGu8gv3s55dF/EgpTq8gyvo= -github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4= -github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI= -github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sercand/kuberesolver/v5 v5.1.1 h1:CYH+d67G0sGBj7q5wLK61yzqJJ8gLLC8aeprPTHb6yY= -github.com/sercand/kuberesolver/v5 v5.1.1/go.mod h1:Fs1KbKhVRnB2aDWN12NjKCB+RgYMWZJ294T3BtmVCpQ= -github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240227164431-18a7065e23ea h1:ZdLmNAfKRjH8AYUvjiiDGUgiWQfq/7iNpxyTkvjx/ko= -github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240227164431-18a7065e23ea/go.mod h1:gCKC9w6XpNk6jm+XIk2psrkkfxhi421N9NSiFceXW88= github.com/smartcontractkit/wasp v0.4.6 h1:s6J8HgpxMHORl19nCpZPxc5jaVUQv8EXB6QjTuLXXnw= github.com/smartcontractkit/wasp v0.4.6/go.mod h1:+ViWdUf1ap6powiEiwPskpZfH/Q1sG29YoVav7zGOIo= -github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= -github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg= -github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= -github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= -github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= -github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= -github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= -github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= -github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= -github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= -github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= -github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.etcd.io/etcd/api/v3 v3.5.7 h1:sbcmosSVesNrWOJ58ZQFitHMdncusIifYcrBfwrlJSY= -go.etcd.io/etcd/api/v3 v3.5.7/go.mod h1:9qew1gCdDDLu+VwmeG+iFpL+QlpHTo7iubavdVDgCAA= -go.etcd.io/etcd/client/pkg/v3 v3.5.7 h1:y3kf5Gbp4e4q7egZdn5T7W9TSHUvkClN6u+Rq9mEOmg= -go.etcd.io/etcd/client/pkg/v3 v3.5.7/go.mod h1:o0Abi1MK86iad3YrWhgUsbGx1pmTS+hrORWc2CamuhY= -go.etcd.io/etcd/client/v3 v3.5.7 h1:u/OhpiuCgYY8awOHlhIhmGIGpxfBU/GZBUP3m/3/Iz4= -go.etcd.io/etcd/client/v3 v3.5.7/go.mod h1:sOWmj9DZUMyAngS7QQwCyAXXAL6WhgTOPLNS/NabQgw= -go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= -go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= -go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= -go.mongodb.org/mongo-driver v1.12.0 h1:aPx33jmn/rQuJXPQLZQ8NtfPQG8CaqgLThFtqRb0PiE= -go.mongodb.org/mongo-driver v1.12.0/go.mod h1:AZkxhPnFJUoH7kZlFkVKucV20K387miPfm7oimrSmK0= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opentelemetry.io/collector/pdata v1.0.0-rcv0015 h1:8PzrQFk3oKiT1Sd5EmNEcagdMyt1KcBy5/OyF5He5gY= -go.opentelemetry.io/collector/pdata v1.0.0-rcv0015/go.mod h1:I1PqyHJlsXjANC73tp43nDId7/jiv82NoZZ6uS0xdwM= -go.opentelemetry.io/collector/semconv v0.81.0 h1:lCYNNo3powDvFIaTPP2jDKIrBiV1T92NK4QgL/aHYXw= -go.opentelemetry.io/collector/semconv v0.81.0/go.mod h1:TlYPtzvsXyHOgr5eATi43qEMqwSmIziivJB2uctKswo= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q= -go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= -go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= -go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= -go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= -go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= -go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= -go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA= -go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= -go4.org/netipx v0.0.0-20230125063823-8449b0a6169f h1:ketMxHg+vWm3yccyYiq+uK8D3fRmna2Fcj+awpQp84s= -go4.org/netipx v0.0.0-20230125063823-8449b0a6169f/go.mod h1:tgPU4N2u9RByaTN3NC2p9xOzyFpte4jYwsIIRF7XlSc= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= -golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= -golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200324203455-a04cca1dde73/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0= -google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk= -google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a h1:myvhA4is3vrit1a6NZCWBIwN0kNEnX21DJOJX/NvIfI= -google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:SUBoKXbI1Efip18FClrQVGjWcyd0QZd8KkvdP34t7ww= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c h1:jHkCUWkseRf+W+edG5hMzr/Uh1xkDREY4caybAq4dpY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= -google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw= -k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg= -k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ= -k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU= -k8s.io/client-go v0.28.2 h1:DNoYI1vGq0slMBN/SWKMZMw0Rq+0EQW6/AK4v9+3VeY= -k8s.io/client-go v0.28.2/go.mod h1:sMkApowspLuc7omj1FOSUxSoqjr+d5Q0Yc0LOFnYFJY= -k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= -k8s.io/utils v0.0.0-20230711102312-30195339c3c7 h1:ZgnF1KZsYxWIifwSNZFZgNtWE89WI5yiP5WwlfDoIyc= -k8s.io/utils v0.0.0-20230711102312-30195339c3c7/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= -nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk= -sigs.k8s.io/structured-merge-diff/v4 v4.3.0/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/charts/chainlink-cluster/templates/chainlink-db-deployment.yaml b/charts/chainlink-cluster/templates/chainlink-db-deployment.yaml index 91924ba5005..ba72c5ff8fb 100644 --- a/charts/chainlink-cluster/templates/chainlink-db-deployment.yaml +++ b/charts/chainlink-cluster/templates/chainlink-db-deployment.yaml @@ -7,6 +7,10 @@ kind: Deployment {{ end }} metadata: name: {{ $.Release.Name }}-{{ $cfg.name }}-db + labels: + app: {{ $.Release.Name }}-db + instance: {{ $cfg.name }}-db + release: {{ $.Release.Name }} spec: {{ if $.Values.db.stateful }} serviceName: {{ $.Release.Name }}-db-${{ $cfg.name }} diff --git a/charts/chainlink-cluster/templates/chainlink-db-networkpolicy.yaml b/charts/chainlink-cluster/templates/chainlink-db-networkpolicy.yaml index 5f7e7706ced..3e4c9f49b46 100644 --- a/charts/chainlink-cluster/templates/chainlink-db-networkpolicy.yaml +++ b/charts/chainlink-cluster/templates/chainlink-db-networkpolicy.yaml @@ -15,10 +15,6 @@ spec: - podSelector: matchLabels: app: {{ $.Release.Name }} - # Allow all runner pods to access the database pods. - - podSelector: - matchLabels: - app: runner ports: - protocol: TCP port: 5432 diff --git a/charts/chainlink-cluster/templates/chainlink-node-deployment.yaml b/charts/chainlink-cluster/templates/chainlink-node-deployment.yaml index 0ce16fd475b..38676716f90 100644 --- a/charts/chainlink-cluster/templates/chainlink-node-deployment.yaml +++ b/charts/chainlink-cluster/templates/chainlink-node-deployment.yaml @@ -3,6 +3,13 @@ apiVersion: apps/v1 kind: Deployment metadata: name: {{ if eq $index 0 }}{{ $.Release.Name }}-{{ $cfg.name }}-bootstrap{{ else }}{{ $.Release.Name }}-{{ $cfg.name }}{{ end }} + labels: + app: {{ $.Release.Name }} + instance: {{ $cfg.name }} + release: {{ $.Release.Name }} + {{- range $key, $value := $.Values.labels }} + {{ $key }}: {{ $value | quote }} + {{- end }} spec: strategy: # Need to recreate the pod to deal with lease lock held by old pod. @@ -67,6 +74,10 @@ spec: value: postgresql://postgres:verylongdatabasepassword@{{ $.Release.Name }}-db-{{ $cfg.name }}/chainlink?sslmode=disable - name: CL_DEV value: "false" + {{- range $name, $value := $.Values.chainlink.extraEnvVars }} + - name: "{{ $name }}" + value: "{{ $value }}" + {{- end }} volumeMounts: - name: {{ $.Release.Name }}-{{ $cfg.name }}-cm mountPath: /etc/node-secrets-volume/ diff --git a/charts/chainlink-cluster/templates/chainlink-node-networkpolicy.yaml b/charts/chainlink-cluster/templates/chainlink-node-networkpolicy.yaml index e63759a994f..f2d0c02676e 100644 --- a/charts/chainlink-cluster/templates/chainlink-node-networkpolicy.yaml +++ b/charts/chainlink-cluster/templates/chainlink-node-networkpolicy.yaml @@ -10,12 +10,9 @@ spec: policyTypes: - Ingress ingress: - # Allow all ingress traffic between the node pods and from runner pod. + # Allow all ingress traffic between the node pods. - from: - podSelector: matchLabels: app: {{ $.Release.Name }} - - podSelector: - matchLabels: - app: runner {{- end }} \ No newline at end of file diff --git a/charts/chainlink-cluster/templates/geth-deployment.yaml b/charts/chainlink-cluster/templates/geth-deployment.yaml index c78f0851038..e8e04936ea4 100644 --- a/charts/chainlink-cluster/templates/geth-deployment.yaml +++ b/charts/chainlink-cluster/templates/geth-deployment.yaml @@ -4,6 +4,10 @@ apiVersion: apps/v1 kind: Deployment metadata: name: geth-{{ $cfg.networkId }} + labels: + app: geth + release: {{ $.Release.Name }} + instance: geth-{{ $cfg.networkId }} spec: selector: matchLabels: diff --git a/charts/chainlink-cluster/templates/geth-networkpolicy.yaml b/charts/chainlink-cluster/templates/geth-networkpolicy.yaml index 025d6184501..9e823a0431b 100644 --- a/charts/chainlink-cluster/templates/geth-networkpolicy.yaml +++ b/charts/chainlink-cluster/templates/geth-networkpolicy.yaml @@ -15,10 +15,6 @@ spec: - podSelector: matchLabels: app: {{ $.Release.Name }} - # Allow http and websocket connections from the runner pods. - - podSelector: - matchLabels: - app: runner ports: - protocol: TCP port: 8544 diff --git a/charts/chainlink-cluster/templates/mockserver-networkpolicy.yaml b/charts/chainlink-cluster/templates/mockserver-networkpolicy.yaml index 6ac4f658e37..8d167b4f924 100644 --- a/charts/chainlink-cluster/templates/mockserver-networkpolicy.yaml +++ b/charts/chainlink-cluster/templates/mockserver-networkpolicy.yaml @@ -15,10 +15,6 @@ spec: - podSelector: matchLabels: app: {{ $.Release.Name }} - # Allow http traffic from the runner pods. - - podSelector: - matchLabels: - app: runner ports: - protocol: TCP port: 1080 diff --git a/charts/chainlink-cluster/values.yaml b/charts/chainlink-cluster/values.yaml index b0866574c90..d3c1c384a2b 100644 --- a/charts/chainlink-cluster/values.yaml +++ b/charts/chainlink-cluster/values.yaml @@ -120,8 +120,8 @@ geth: runAsUser: 999 runAsGroup: 999 version: v1.12.0 - wsrpc-port: 8546 - httprpc-port: 8544 + wsRpcPort: 8546 + httpRpcPort: 8544 blocktime: 1 chains: - networkId: 1337 @@ -185,14 +185,12 @@ opentelemetry-collector: otlp: protocols: grpc: - endpoint: "0.0.0.0:4317" + endpoint: ${env:MY_POD_IP}:4317 http: - endpoint: "0.0.0.0:3100" + endpoint: ${env:MY_POD_IP}:4318 exporters: - file: - path: /tracing/trace-data.json otlp: - endpoint: tempo:4317 + endpoint: app-tempo:4317 tls: insecure: true service: @@ -202,27 +200,13 @@ opentelemetry-collector: pipelines: traces: receivers: [otlp] - exporters: [file, otlp] + exporters: [otlp] tempo: enabled: true image: tag: "1.7.2" - server: - http_listen_port: 3200 # default storage path: /var/tempo/ - readinessProbe: - httpGet: - path: /ready - port: 3200 - initialDelaySeconds: 10 - periodSeconds: 5 - livenessProbe: - httpGet: - path: /ready - port: 3200 - initialDelaySeconds: 20 - periodSeconds: 10 securityContext: runAsNonRoot: true runAsUser: 10001 @@ -232,14 +216,14 @@ tempo: trace: backend: local # backend configuration to use wal: - path: /tmp/tempo/wal # where to store the the wal locally + path: /tmp/tempo/wal # where to store the wal locally local: path: /tmp/tempo/blocks grafana: enabled: true image: - tag: 7.3.2 + tag: 10.4.1 rbac: namespaced: true datasources: @@ -250,7 +234,7 @@ grafana: type: tempo access: proxy orgId: 1 - url: http://tempo:3200 + url: http://app-tempo:3100 basicAuth: false isDefault: true version: 1 @@ -264,7 +248,7 @@ grafana: GF_AUTH_ANONYMOUS_ENABLED: "true" GF_AUTH_ANONYMOUS_ORG_ROLE: "Admin" GF_AUTH_DISABLE_LOGIN_FORM: "true" - GF_FEATURE_TOGGLES_ENABLE: "traceqlEditor" + GF_FEATURE_TOGGLES_ENABLE: "traceqlEditor tempoSearch tempoServiceGraph" ingress: enabled: false @@ -361,6 +345,16 @@ ingress: name: mockserver port: number: 1080 + - host: chainlink-grafana.local + http: + paths: + - path: / + pathType: ImplementationSpecific + backend: + service: + name: grafana + port: + number: 80 # monitoring.coreos.com/v1 PodMonitor for each node prometheusMonitor: true @@ -420,7 +414,7 @@ networkPolicies: app: tempo ports: - protocol: TCP - port: 3100 + port: 4317 # Configure the default network policy. networkPolicyDefault: diff --git a/codecov.yml b/codecov.yml index 27b4815f54c..a70f1961e36 100644 --- a/codecov.yml +++ b/codecov.yml @@ -10,8 +10,6 @@ github_checks: annotations: false ignore: - - 'contracts/src/v0.4' - - 'contracts/src/v0.5' - - 'contracts/src/v0.8' # Disabled due to solidity-coverage not reporting coverage + - 'contracts/' # Disabled due to solidity-coverage not reporting coverage - 'core/internal' - 'core/scripts' diff --git a/common/client/mock_head_test.go b/common/client/mock_head_test.go index 747770480f5..e68a047e078 100644 --- a/common/client/mock_head_test.go +++ b/common/client/mock_head_test.go @@ -51,6 +51,24 @@ func (_m *mockHead) BlockNumber() int64 { return r0 } +// IsValid provides a mock function with given fields: +func (_m *mockHead) IsValid() bool { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for IsValid") + } + + var r0 bool + if rf, ok := ret.Get(0).(func() bool); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + // newMockHead creates a new instance of mockHead. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func newMockHead(t interface { diff --git a/common/client/mock_node_client_test.go b/common/client/mock_node_client_test.go index d143ebb88a5..dfe9f32664a 100644 --- a/common/client/mock_node_client_test.go +++ b/common/client/mock_node_client_test.go @@ -144,6 +144,34 @@ func (_m *mockNodeClient[CHAIN_ID, HEAD]) IsSyncing(ctx context.Context) (bool, return r0, r1 } +// LatestFinalizedBlock provides a mock function with given fields: ctx +func (_m *mockNodeClient[CHAIN_ID, HEAD]) LatestFinalizedBlock(ctx context.Context) (HEAD, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for LatestFinalizedBlock") + } + + var r0 HEAD + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (HEAD, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) HEAD); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(HEAD) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // SetAliveLoopSub provides a mock function with given fields: _a0 func (_m *mockNodeClient[CHAIN_ID, HEAD]) SetAliveLoopSub(_a0 types.Subscription) { _m.Called(_a0) diff --git a/common/client/mocks/config.go b/common/client/mocks/config.go new file mode 100644 index 00000000000..27b717f61a0 --- /dev/null +++ b/common/client/mocks/config.go @@ -0,0 +1,30 @@ +package mocks + +import ( + "time" + + commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" +) + +type ChainConfig struct { + IsFinalityTagEnabled bool + FinalityDepthVal uint32 + NoNewHeadsThresholdVal time.Duration + ChainTypeVal commonconfig.ChainType +} + +func (t ChainConfig) ChainType() commonconfig.ChainType { + return t.ChainTypeVal +} + +func (t ChainConfig) NodeNoNewHeadsThreshold() time.Duration { + return t.NoNewHeadsThresholdVal +} + +func (t ChainConfig) FinalityDepth() uint32 { + return t.FinalityDepthVal +} + +func (t ChainConfig) FinalityTagEnabled() bool { + return t.IsFinalityTagEnabled +} diff --git a/common/client/models.go b/common/client/models.go index d0cf42a3844..66f1e9cf88b 100644 --- a/common/client/models.go +++ b/common/client/models.go @@ -18,6 +18,7 @@ const ( InsufficientFunds // Tx was rejected due to insufficient funds. ExceedsMaxFee // Attempt's fee was higher than the node's limit and got rejected. FeeOutOfValidRange // This error is returned when we use a fee price suggested from an RPC, but the network rejects the attempt due to an invalid range(mostly used by L2 chains). Retry by requesting a new suggested fee price. + OutOfCounters // The error returned when a transaction is too complex to be proven by zk circuits. This error is mainly returned by zk chains. sendTxReturnCodeLen // tracks the number of errors. Must always be last ) diff --git a/common/client/multi_node_test.go b/common/client/multi_node_test.go index 43e4127556a..9c09bd57d70 100644 --- a/common/client/multi_node_test.go +++ b/common/client/multi_node_test.go @@ -848,6 +848,14 @@ func TestMultiNode_SendTransaction_aggregateTxResults(t *testing.T) { ExpectedCriticalErr: "expected at least one response on SendTransaction", ResultsByCode: map[SendTxReturnCode][]error{}, }, + { + Name: "Zk out of counter error", + ExpectedTxResult: "not enough keccak counters to continue the execution", + ExpectedCriticalErr: "", + ResultsByCode: map[SendTxReturnCode][]error{ + OutOfCounters: {errors.New("not enough keccak counters to continue the execution")}, + }, + }, } for _, testCase := range testCases { diff --git a/common/client/node.go b/common/client/node.go index 082b1b45f99..61816be21da 100644 --- a/common/client/node.go +++ b/common/client/node.go @@ -15,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/common/types" ) @@ -43,6 +44,14 @@ type NodeConfig interface { SelectionMode() string SyncThreshold() uint32 NodeIsSyncingEnabled() bool + FinalizedBlockPollInterval() time.Duration +} + +type ChainConfig interface { + NodeNoNewHeadsThreshold() time.Duration + FinalityDepth() uint32 + FinalityTagEnabled() bool + ChainType() commonconfig.ChainType } //go:generate mockery --quiet --name Node --structname mockNode --filename "mock_node_test.go" --inpackage --case=underscore @@ -73,14 +82,14 @@ type node[ RPC NodeClient[CHAIN_ID, HEAD], ] struct { services.StateMachine - lfcLog logger.Logger - name string - id int32 - chainID CHAIN_ID - nodePoolCfg NodeConfig - noNewHeadsThreshold time.Duration - order int32 - chainFamily string + lfcLog logger.Logger + name string + id int32 + chainID CHAIN_ID + nodePoolCfg NodeConfig + chainCfg ChainConfig + order int32 + chainFamily string ws url.URL http *url.URL @@ -90,8 +99,9 @@ type node[ stateMu sync.RWMutex // protects state* fields state nodeState // Each node is tracking the last received head number and total difficulty - stateLatestBlockNumber int64 - stateLatestTotalDifficulty *big.Int + stateLatestBlockNumber int64 + stateLatestTotalDifficulty *big.Int + stateLatestFinalizedBlockNumber int64 // nodeCtx is the node lifetime's context nodeCtx context.Context @@ -113,7 +123,7 @@ func NewNode[ RPC NodeClient[CHAIN_ID, HEAD], ]( nodeCfg NodeConfig, - noNewHeadsThreshold time.Duration, + chainCfg ChainConfig, lggr logger.Logger, wsuri url.URL, httpuri *url.URL, @@ -129,7 +139,7 @@ func NewNode[ n.id = id n.chainID = chainID n.nodePoolCfg = nodeCfg - n.noNewHeadsThreshold = noNewHeadsThreshold + n.chainCfg = chainCfg n.ws = wsuri n.order = nodeOrder if httpuri != nil { diff --git a/common/client/node_lifecycle.go b/common/client/node_lifecycle.go index 20902277480..4707a60426f 100644 --- a/common/client/node_lifecycle.go +++ b/common/client/node_lifecycle.go @@ -22,6 +22,10 @@ var ( Name: "pool_rpc_node_highest_seen_block", Help: "The highest seen block for the given RPC node", }, []string{"chainID", "nodeName"}) + promPoolRPCNodeHighestFinalizedBlock = promauto.NewGaugeVec(prometheus.GaugeOpts{ + Name: "pool_rpc_node_highest_finalized_block", + Help: "The highest seen finalized block for the given RPC node", + }, []string{"chainID", "nodeName"}) promPoolRPCNodeNumSeenBlocks = promauto.NewCounterVec(prometheus.CounterOpts{ Name: "pool_rpc_node_num_seen_blocks", Help: "The total number of new blocks seen by the given RPC node", @@ -88,7 +92,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { } } - noNewHeadsTimeoutThreshold := n.noNewHeadsThreshold + noNewHeadsTimeoutThreshold := n.chainCfg.NodeNoNewHeadsThreshold() pollFailureThreshold := n.nodePoolCfg.PollFailureThreshold() pollInterval := n.nodePoolCfg.PollInterval() @@ -134,6 +138,14 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { lggr.Debug("Polling disabled") } + var pollFinalizedHeadCh <-chan time.Time + if n.chainCfg.FinalityTagEnabled() && n.nodePoolCfg.FinalizedBlockPollInterval() > 0 { + lggr.Debugw("Finalized block polling enabled") + pollT := time.NewTicker(n.nodePoolCfg.FinalizedBlockPollInterval()) + defer pollT.Stop() + pollFinalizedHeadCh = pollT.C + } + _, highestReceivedBlockNumber, _ := n.StateAndLatest() var pollFailures uint32 @@ -201,6 +213,13 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { outOfSyncT.Reset(noNewHeadsTimeoutThreshold) } n.setLatestReceived(bh.BlockNumber(), bh.BlockDifficulty()) + if !n.chainCfg.FinalityTagEnabled() { + latestFinalizedBN := max(bh.BlockNumber()-int64(n.chainCfg.FinalityDepth()), 0) + if latestFinalizedBN > n.stateLatestFinalizedBlockNumber { + promPoolRPCNodeHighestFinalizedBlock.WithLabelValues(n.chainID.String(), n.name).Set(float64(latestFinalizedBN)) + n.stateLatestFinalizedBlockNumber = latestFinalizedBN + } + } case err := <-sub.Err(): lggr.Errorw("Subscription was terminated", "err", err, "nodeState", n.State()) n.declareUnreachable() @@ -214,13 +233,33 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { lggr.Criticalf("RPC endpoint detected out of sync; %s %s", msgCannotDisable, msgDegradedState) // We don't necessarily want to wait the full timeout to check again, we should // check regularly and log noisily in this state - outOfSyncT.Reset(zombieNodeCheckInterval(n.noNewHeadsThreshold)) + outOfSyncT.Reset(zombieNodeCheckInterval(noNewHeadsTimeoutThreshold)) continue } } n.declareOutOfSync(func(num int64, td *big.Int) bool { return num < highestReceivedBlockNumber }) return + case <-pollFinalizedHeadCh: + ctx, cancel := context.WithTimeout(n.nodeCtx, n.nodePoolCfg.FinalizedBlockPollInterval()) + latestFinalized, err := n.RPC().LatestFinalizedBlock(ctx) + cancel() + if err != nil { + lggr.Warnw("Failed to fetch latest finalized block", "err", err) + continue + } + + if !latestFinalized.IsValid() { + lggr.Warn("Latest finalized block is not valid") + continue + } + + latestFinalizedBN := latestFinalized.BlockNumber() + if latestFinalizedBN > n.stateLatestFinalizedBlockNumber { + promPoolRPCNodeHighestFinalizedBlock.WithLabelValues(n.chainID.String(), n.name).Set(float64(latestFinalizedBN)) + n.stateLatestFinalizedBlockNumber = latestFinalizedBN + } } + } } @@ -316,7 +355,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td return } lggr.Debugw(msgReceivedBlock, "blockNumber", head.BlockNumber(), "blockDifficulty", head.BlockDifficulty(), "nodeState", n.State()) - case <-time.After(zombieNodeCheckInterval(n.noNewHeadsThreshold)): + case <-time.After(zombieNodeCheckInterval(n.chainCfg.NodeNoNewHeadsThreshold())): if n.nLiveNodes != nil { if l, _, _ := n.nLiveNodes(); l < 1 { lggr.Critical("RPC endpoint is still out of sync, but there are no other available nodes. This RPC node will be forcibly moved back into the live pool in a degraded state") diff --git a/common/client/node_lifecycle_test.go b/common/client/node_lifecycle_test.go index 437bc4a655b..b3c09b35000 100644 --- a/common/client/node_lifecycle_test.go +++ b/common/client/node_lifecycle_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/cometbft/cometbft/libs/rand" + prom "github.com/prometheus/client_model/go" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -17,6 +18,7 @@ import ( bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + clientMocks "github.com/smartcontractkit/chainlink/v2/common/client/mocks" "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/common/types/mocks" ) @@ -283,9 +285,11 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { t.Parallel() rpc := newMockNodeClient[types.ID, Head](t) node := newSubscribedNode(t, testNodeOpts{ - config: testNodeConfig{}, - noNewHeadsThreshold: tests.TestInterval, - rpc: rpc, + config: testNodeConfig{}, + chainConfig: clientMocks.ChainConfig{ + NoNewHeadsThresholdVal: tests.TestInterval, + }, + rpc: rpc, }) defer func() { assert.NoError(t, node.close()) }() // tries to redial in outOfSync @@ -308,10 +312,12 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { rpc := newMockNodeClient[types.ID, Head](t) lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) node := newSubscribedNode(t, testNodeOpts{ - config: testNodeConfig{}, - lggr: lggr, - noNewHeadsThreshold: tests.TestInterval, - rpc: rpc, + config: testNodeConfig{}, + lggr: lggr, + chainConfig: clientMocks.ChainConfig{ + NoNewHeadsThresholdVal: tests.TestInterval, + }, + rpc: rpc, }) defer func() { assert.NoError(t, node.close()) }() node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *big.Int) { @@ -335,10 +341,12 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { rpc.On("SetAliveLoopSub", sub).Once() lggr, observedLogs := logger.TestObserved(t, zap.ErrorLevel) node := newDialedNode(t, testNodeOpts{ - lggr: lggr, - config: testNodeConfig{}, - noNewHeadsThreshold: tests.TestInterval, - rpc: rpc, + lggr: lggr, + config: testNodeConfig{}, + chainConfig: clientMocks.ChainConfig{ + NoNewHeadsThresholdVal: tests.TestInterval, + }, + rpc: rpc, }) defer func() { assert.NoError(t, node.close()) }() // disconnects all on transfer to unreachable or outOfSync @@ -374,6 +382,128 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { return state == nodeStateAlive && block == expectedBlockNumber == bigmath.Equal(diff, expectedDiff) }) }) + t.Run("If finality tag is not enabled updates finalized block metric using finality depth and latest head", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + sub := mocks.NewSubscription(t) + sub.On("Err").Return((<-chan error)(nil)) + sub.On("Unsubscribe").Once() + const blockNumber = 1000 + const finalityDepth = 10 + const expectedBlock = 990 + rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Run(func(args mock.Arguments) { + ch := args.Get(1).(chan<- Head) + go writeHeads(t, ch, head{BlockNumber: blockNumber - 1}, head{BlockNumber: blockNumber}, head{BlockNumber: blockNumber - 1}) + }).Return(sub, nil).Once() + rpc.On("SetAliveLoopSub", sub).Once() + name := "node-" + rand.Str(5) + node := newDialedNode(t, testNodeOpts{ + config: testNodeConfig{}, + chainConfig: clientMocks.ChainConfig{FinalityDepthVal: finalityDepth}, + rpc: rpc, + name: name, + chainID: big.NewInt(1), + }) + defer func() { assert.NoError(t, node.close()) }() + node.declareAlive() + tests.AssertEventually(t, func() bool { + metric, err := promPoolRPCNodeHighestFinalizedBlock.GetMetricWithLabelValues(big.NewInt(1).String(), name) + require.NoError(t, err) + var m = &prom.Metric{} + require.NoError(t, metric.Write(m)) + return float64(expectedBlock) == m.Gauge.GetValue() + }) + }) + t.Run("Logs warning if failed to get finalized block", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + rpc.On("LatestFinalizedBlock", mock.Anything).Return(newMockHead(t), errors.New("failed to get finalized block")) + sub := mocks.NewSubscription(t) + sub.On("Err").Return((<-chan error)(nil)) + sub.On("Unsubscribe").Once() + rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Return(sub, nil).Once() + rpc.On("SetAliveLoopSub", sub).Once() + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) + node := newDialedNode(t, testNodeOpts{ + config: testNodeConfig{ + finalizedBlockPollInterval: tests.TestInterval, + }, + chainConfig: clientMocks.ChainConfig{ + IsFinalityTagEnabled: true, + }, + rpc: rpc, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + node.declareAlive() + tests.AssertLogEventually(t, observedLogs, "Failed to fetch latest finalized block") + }) + t.Run("Logs warning if latest finalized block is not valid", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + head := newMockHead(t) + head.On("IsValid").Return(false) + rpc.On("LatestFinalizedBlock", mock.Anything).Return(head, nil) + sub := mocks.NewSubscription(t) + sub.On("Err").Return((<-chan error)(nil)) + sub.On("Unsubscribe").Once() + rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Return(sub, nil).Once() + rpc.On("SetAliveLoopSub", sub).Once() + lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) + node := newDialedNode(t, testNodeOpts{ + config: testNodeConfig{ + finalizedBlockPollInterval: tests.TestInterval, + }, + chainConfig: clientMocks.ChainConfig{ + IsFinalityTagEnabled: true, + }, + rpc: rpc, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + node.declareAlive() + tests.AssertLogEventually(t, observedLogs, "Latest finalized block is not valid") + }) + t.Run("If finality tag and finalized block polling are enabled updates latest finalized block metric", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + const expectedBlock = 1101 + const finalityDepth = 10 + rpc.On("LatestFinalizedBlock", mock.Anything).Return(head{BlockNumber: expectedBlock - 1}.ToMockHead(t), nil).Once() + rpc.On("LatestFinalizedBlock", mock.Anything).Return(head{BlockNumber: expectedBlock}.ToMockHead(t), nil) + sub := mocks.NewSubscription(t) + sub.On("Err").Return((<-chan error)(nil)) + sub.On("Unsubscribe").Once() + rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Run(func(args mock.Arguments) { + ch := args.Get(1).(chan<- Head) + // ensure that "calculated" finalized head is larger than actual, to ensure we are correctly setting + // the metric + go writeHeads(t, ch, head{BlockNumber: expectedBlock*2 + finalityDepth}) + }).Return(sub, nil).Once() + rpc.On("SetAliveLoopSub", sub).Once() + name := "node-" + rand.Str(5) + node := newDialedNode(t, testNodeOpts{ + config: testNodeConfig{ + finalizedBlockPollInterval: tests.TestInterval, + }, + chainConfig: clientMocks.ChainConfig{ + FinalityDepthVal: finalityDepth, + IsFinalityTagEnabled: true, + }, + rpc: rpc, + name: name, + chainID: big.NewInt(1), + }) + defer func() { assert.NoError(t, node.close()) }() + node.declareAlive() + tests.AssertEventually(t, func() bool { + metric, err := promPoolRPCNodeHighestFinalizedBlock.GetMetricWithLabelValues(big.NewInt(1).String(), name) + require.NoError(t, err) + var m = &prom.Metric{} + require.NoError(t, metric.Write(m)) + return float64(expectedBlock) == m.Gauge.GetValue() + }) + }) } type head struct { @@ -381,11 +511,17 @@ type head struct { BlockDifficulty *big.Int } +func (h head) ToMockHead(t *testing.T) *mockHead { + m := newMockHead(t) + m.On("BlockNumber").Return(h.BlockNumber).Maybe() + m.On("BlockDifficulty").Return(h.BlockDifficulty).Maybe() + m.On("IsValid").Return(true).Maybe() + return m +} + func writeHeads(t *testing.T, ch chan<- Head, heads ...head) { for _, head := range heads { - h := newMockHead(t) - h.On("BlockNumber").Return(head.BlockNumber) - h.On("BlockDifficulty").Return(head.BlockDifficulty) + h := head.ToMockHead(t) select { case ch <- h: case <-tests.Context(t).Done(): @@ -675,10 +811,12 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { nodeChainID := types.RandomID() lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) node := newAliveNode(t, testNodeOpts{ - noNewHeadsThreshold: tests.TestInterval, - rpc: rpc, - chainID: nodeChainID, - lggr: lggr, + chainConfig: clientMocks.ChainConfig{ + NoNewHeadsThresholdVal: tests.TestInterval, + }, + rpc: rpc, + chainID: nodeChainID, + lggr: lggr, }) defer func() { assert.NoError(t, node.close()) }() node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *big.Int) { @@ -1234,7 +1372,7 @@ func TestUnit_NodeLifecycle_syncStatus(t *testing.T) { } for _, td := range []int64{totalDifficulty - syncThreshold - 1, totalDifficulty - syncThreshold, totalDifficulty, totalDifficulty + 1} { for _, testCase := range testCases { - t.Run(fmt.Sprintf("%s: selectionMode: %s: total difficulty: %d", testCase.name, selectionMode, td), func(t *testing.T) { + t.Run(fmt.Sprintf("%s: SelectionModeVal: %s: total difficulty: %d", testCase.name, selectionMode, td), func(t *testing.T) { outOfSync, liveNodes := node.syncStatus(testCase.blockNumber, big.NewInt(td)) assert.Equal(t, nodesNum, liveNodes) assert.Equal(t, testCase.outOfSync, outOfSync) @@ -1287,7 +1425,7 @@ func TestUnit_NodeLifecycle_syncStatus(t *testing.T) { } for _, hb := range []int64{highestBlock - syncThreshold - 1, highestBlock - syncThreshold, highestBlock, highestBlock + 1} { for _, testCase := range testCases { - t.Run(fmt.Sprintf("%s: selectionMode: %s: highest block: %d", testCase.name, NodeSelectionModeTotalDifficulty, hb), func(t *testing.T) { + t.Run(fmt.Sprintf("%s: SelectionModeVal: %s: highest block: %d", testCase.name, NodeSelectionModeTotalDifficulty, hb), func(t *testing.T) { outOfSync, liveNodes := node.syncStatus(hb, big.NewInt(testCase.totalDifficulty)) assert.Equal(t, nodesNum, liveNodes) assert.Equal(t, testCase.outOfSync, outOfSync) diff --git a/common/client/node_test.go b/common/client/node_test.go index c7a7a710d8f..a97f26555a9 100644 --- a/common/client/node_test.go +++ b/common/client/node_test.go @@ -7,15 +7,17 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" + clientMocks "github.com/smartcontractkit/chainlink/v2/common/client/mocks" "github.com/smartcontractkit/chainlink/v2/common/types" ) type testNodeConfig struct { - pollFailureThreshold uint32 - pollInterval time.Duration - selectionMode string - syncThreshold uint32 - nodeIsSyncingEnabled bool + pollFailureThreshold uint32 + pollInterval time.Duration + selectionMode string + syncThreshold uint32 + nodeIsSyncingEnabled bool + finalizedBlockPollInterval time.Duration } func (n testNodeConfig) PollFailureThreshold() uint32 { @@ -38,22 +40,26 @@ func (n testNodeConfig) NodeIsSyncingEnabled() bool { return n.nodeIsSyncingEnabled } +func (n testNodeConfig) FinalizedBlockPollInterval() time.Duration { + return n.finalizedBlockPollInterval +} + type testNode struct { *node[types.ID, Head, NodeClient[types.ID, Head]] } type testNodeOpts struct { - config testNodeConfig - noNewHeadsThreshold time.Duration - lggr logger.Logger - wsuri url.URL - httpuri *url.URL - name string - id int32 - chainID types.ID - nodeOrder int32 - rpc *mockNodeClient[types.ID, Head] - chainFamily string + config testNodeConfig + chainConfig clientMocks.ChainConfig + lggr logger.Logger + wsuri url.URL + httpuri *url.URL + name string + id int32 + chainID types.ID + nodeOrder int32 + rpc *mockNodeClient[types.ID, Head] + chainFamily string } func newTestNode(t *testing.T, opts testNodeOpts) testNode { @@ -77,7 +83,7 @@ func newTestNode(t *testing.T, opts testNodeOpts) testNode { opts.id = 42 } - nodeI := NewNode[types.ID, Head, NodeClient[types.ID, Head]](opts.config, opts.noNewHeadsThreshold, opts.lggr, + nodeI := NewNode[types.ID, Head, NodeClient[types.ID, Head]](opts.config, opts.chainConfig, opts.lggr, opts.wsuri, opts.httpuri, opts.name, opts.id, opts.chainID, opts.nodeOrder, opts.rpc, opts.chainFamily) return testNode{ diff --git a/common/client/types.go b/common/client/types.go index 8d7b5b71b83..a27e6a50b73 100644 --- a/common/client/types.go +++ b/common/client/types.go @@ -53,6 +53,7 @@ type RPC[ type Head interface { BlockNumber() int64 BlockDifficulty() *big.Int + IsValid() bool } // NodeClient includes all the necessary RPC methods required by a node. @@ -72,6 +73,7 @@ type NodeClient[ SetAliveLoopSub(types.Subscription) UnsubscribeAllExceptAliveLoop() IsSyncing(ctx context.Context) (bool, error) + LatestFinalizedBlock(ctx context.Context) (HEAD, error) } // clientAPI includes all the direct RPC methods required by the generalized common client to implement its own. diff --git a/common/txmgr/broadcaster.go b/common/txmgr/broadcaster.go index f56e6b0368c..a13673bf91b 100644 --- a/common/txmgr/broadcaster.go +++ b/common/txmgr/broadcaster.go @@ -5,7 +5,6 @@ import ( "database/sql" "errors" "fmt" - "slices" "sync" "time" @@ -112,13 +111,13 @@ type Broadcaster[ txStore txmgrtypes.TransactionStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, SEQ, FEE] client txmgrtypes.TransactionClient[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] txmgrtypes.TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] - sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH, SEQ] - resumeCallback ResumeCallback - chainID CHAIN_ID - config txmgrtypes.BroadcasterChainConfig - feeConfig txmgrtypes.BroadcasterFeeConfig - txConfig txmgrtypes.BroadcasterTransactionsConfig - listenerConfig txmgrtypes.BroadcasterListenerConfig + sequenceTracker txmgrtypes.SequenceTracker[ADDR, SEQ] + resumeCallback ResumeCallback + chainID CHAIN_ID + config txmgrtypes.BroadcasterChainConfig + feeConfig txmgrtypes.BroadcasterFeeConfig + txConfig txmgrtypes.BroadcasterTransactionsConfig + listenerConfig txmgrtypes.BroadcasterListenerConfig // autoSyncSequence, if set, will cause Broadcaster to fast-forward the sequence // when Start is called @@ -141,10 +140,6 @@ type Broadcaster[ initSync sync.Mutex isStarted bool - - sequenceLock sync.RWMutex - nextSequenceMap map[ADDR]SEQ - generateNextSequence types.GenerateNextSequenceFunc[SEQ] } func NewBroadcaster[ @@ -164,11 +159,10 @@ func NewBroadcaster[ listenerConfig txmgrtypes.BroadcasterListenerConfig, keystore txmgrtypes.KeyStore[ADDR, CHAIN_ID, SEQ], txAttemptBuilder txmgrtypes.TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], - sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH, SEQ], + sequenceTracker txmgrtypes.SequenceTracker[ADDR, SEQ], lggr logger.Logger, checkerFactory TransmitCheckerFactory[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], autoSyncSequence bool, - generateNextSequence types.GenerateNextSequenceFunc[SEQ], ) *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] { lggr = logger.Named(lggr, "Broadcaster") b := &Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]{ @@ -176,7 +170,6 @@ func NewBroadcaster[ txStore: txStore, client: client, TxAttemptBuilder: txAttemptBuilder, - sequenceSyncer: sequenceSyncer, chainID: client.ConfiguredChainID(), config: config, feeConfig: feeConfig, @@ -185,10 +178,10 @@ func NewBroadcaster[ ks: keystore, checkerFactory: checkerFactory, autoSyncSequence: autoSyncSequence, + sequenceTracker: sequenceTracker, } b.processUnstartedTxsImpl = b.processUnstartedTxs - b.generateNextSequence = generateNextSequence return b } @@ -222,9 +215,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) star eb.wg = sync.WaitGroup{} eb.wg.Add(len(eb.enabledAddresses)) eb.triggers = make(map[ADDR]chan struct{}) - eb.sequenceLock.Lock() - eb.nextSequenceMap = eb.loadNextSequenceMap(ctx, eb.enabledAddresses) - eb.sequenceLock.Unlock() + eb.sequenceTracker.LoadNextSequences(ctx, eb.enabledAddresses) for _, addr := range eb.enabledAddresses { triggerCh := make(chan struct{}, 1) eb.triggers[addr] = triggerCh @@ -284,46 +275,6 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Trig } } -// Load the next sequence map using the tx table or on-chain (if not found in tx table) -func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) loadNextSequenceMap(ctx context.Context, addresses []ADDR) map[ADDR]SEQ { - nextSequenceMap := make(map[ADDR]SEQ) - for _, address := range addresses { - seq, err := eb.getSequenceForAddr(ctx, address) - if err == nil { - nextSequenceMap[address] = seq - } - } - - return nextSequenceMap -} - -func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) getSequenceForAddr(ctx context.Context, address ADDR) (seq SEQ, err error) { - // Get the highest sequence from the tx table - // Will need to be incremented since this sequence is already used - seq, err = eb.txStore.FindLatestSequence(ctx, address, eb.chainID) - if err == nil { - seq = eb.generateNextSequence(seq) - return seq, nil - } - // Look for nonce on-chain if no tx found for address in TxStore or if error occurred - // Returns the nonce that should be used for the next transaction so no need to increment - seq, err = eb.client.PendingSequenceAt(ctx, address) - if err == nil { - return seq, nil - } - eb.lggr.Criticalw("failed to retrieve next sequence from on-chain for address: ", "address", address.String()) - return seq, err - -} - -func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) newSequenceSyncBackoff() backoff.Backoff { - return backoff.Backoff{ - Min: 100 * time.Millisecond, - Max: 5 * time.Second, - Jitter: true, - } -} - func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) newResendBackoff() backoff.Backoff { return backoff.Backoff{ Min: 1 * time.Second, @@ -340,7 +291,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) moni if eb.autoSyncSequence { eb.lggr.Debugw("Auto-syncing sequence", "address", addr.String()) - eb.SyncSequence(ctx, addr) + eb.sequenceTracker.SyncSequence(ctx, addr, eb.chStop) if ctx.Err() != nil { return } @@ -393,46 +344,6 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) moni } } -// syncSequence tries to sync the key sequence, retrying indefinitely until success or stop signal is sent -func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) SyncSequence(ctx context.Context, addr ADDR) { - sequenceSyncRetryBackoff := eb.newSequenceSyncBackoff() - localSequence, err := eb.GetNextSequence(ctx, addr) - // Address not found in map so skip sync - if err != nil { - eb.lggr.Criticalw("Failed to retrieve local next sequence for address", "address", addr.String(), "err", err) - return - } - - // Enter loop with retries - var attempt int - for { - select { - case <-eb.chStop: - return - case <-time.After(sequenceSyncRetryBackoff.Duration()): - attempt++ - newNextSequence, err := eb.sequenceSyncer.Sync(ctx, addr, localSequence) - if err != nil { - if attempt > 5 { - eb.lggr.Criticalw("Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) - eb.SvcErrBuffer.Append(err) - } else { - eb.lggr.Warnw("Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) - } - continue - } - // Found new sequence to use from on-chain - if localSequence.String() != newNextSequence.String() { - eb.lggr.Infow("Fast-forward sequence", "address", addr, "newNextSequence", newNextSequence, "oldNextSequence", localSequence) - // Set new sequence in the map - eb.SetNextSequence(addr, newNextSequence) - } - return - - } - } -} - // ProcessUnstartedTxs picks up and handles all txes in the queue // revive:disable:error-return func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) ProcessUnstartedTxs(ctx context.Context, addr ADDR) (retryable bool, err error) { @@ -564,7 +475,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand } lgr := etx.GetLogger(logger.With(eb.lggr, "fee", attempt.TxFee)) - lgr.Infow("Sending transaction", "txAttemptID", attempt.ID, "txHash", attempt.Hash, "meta", etx.Meta, "feeLimit", etx.FeeLimit, "attempt", attempt, "etx", etx) + lgr.Infow("Sending transaction", "txAttemptID", attempt.ID, "txHash", attempt.Hash, "meta", etx.Meta, "feeLimit", attempt.ChainSpecificFeeLimit, "callerProvidedFeeLimit", etx.FeeLimit, "attempt", attempt, "etx", etx) errType, err := eb.client.SendTransactionReturnCode(ctx, etx, attempt, lgr) if errType != client.Fatal { @@ -619,18 +530,12 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand // and hand off to the confirmer to get the receipt (or mark as // failed). observeTimeUntilBroadcast(eb.chainID, etx.CreatedAt, time.Now()) - // Check if from_address exists in map to ensure it is valid before broadcasting - var sequence SEQ - sequence, err = eb.GetNextSequence(ctx, etx.FromAddress) - if err != nil { - return err, true - } err = eb.txStore.UpdateTxAttemptInProgressToBroadcast(ctx, &etx, attempt, txmgrtypes.TxAttemptBroadcast) if err != nil { return err, true } // Increment sequence if successfully broadcasted - eb.IncrementNextSequence(etx.FromAddress, sequence) + eb.sequenceTracker.GenerateNextSequence(etx.FromAddress, *etx.Sequence) return err, true case client.Underpriced: return eb.tryAgainBumpingGas(ctx, lgr, err, etx, attempt, initialBroadcastAt) @@ -677,18 +582,12 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand // transaction to have been accepted. In this case, the right thing to // do is assume success and hand off to Confirmer - // Check if from_address exists in map to ensure it is valid before broadcasting - var sequence SEQ - sequence, err = eb.GetNextSequence(ctx, etx.FromAddress) - if err != nil { - return err, true - } err = eb.txStore.UpdateTxAttemptInProgressToBroadcast(ctx, &etx, attempt, txmgrtypes.TxAttemptBroadcast) if err != nil { return err, true } // Increment sequence if successfully broadcasted - eb.IncrementNextSequence(etx.FromAddress, sequence) + eb.sequenceTracker.GenerateNextSequence(etx.FromAddress, *etx.Sequence) return err, true } // Either the unknown error prevented the transaction from being mined, or @@ -716,7 +615,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) next return nil, fmt.Errorf("findNextUnstartedTransactionFromAddress failed: %w", err) } - sequence, err := eb.GetNextSequence(ctx, etx.FromAddress) + sequence, err := eb.sequenceTracker.GetNextSequence(ctx, etx.FromAddress) if err != nil { return nil, err } @@ -805,49 +704,6 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) save return eb.txStore.UpdateTxFatalError(ctx, etx) } -// Used to get the next usable sequence for a transaction -func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetNextSequence(ctx context.Context, address ADDR) (seq SEQ, err error) { - eb.sequenceLock.Lock() - defer eb.sequenceLock.Unlock() - // Get next sequence from map - seq, exists := eb.nextSequenceMap[address] - if exists { - return seq, nil - } - - eb.lggr.Infow("address not found in local next sequence map. Attempting to search and populate sequence.", "address", address.String()) - // Check if address is in the enabled address list - if !slices.Contains(eb.enabledAddresses, address) { - return seq, fmt.Errorf("address disabled: %s", address) - } - - // Try to retrieve next sequence from tx table or on-chain to load the map - // A scenario could exist where loading the map during startup failed (e.g. All configured RPC's are unreachable at start) - // The expectation is that the node does not fail startup so sequences need to be loaded during runtime - foundSeq, err := eb.getSequenceForAddr(ctx, address) - if err != nil { - return seq, fmt.Errorf("failed to find next sequence for address: %s", address) - } - - // Set sequence in map - eb.nextSequenceMap[address] = foundSeq - return foundSeq, nil -} - -// Used to increment the sequence in the mapping to have the next usable one available for the next transaction -func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) IncrementNextSequence(address ADDR, seq SEQ) { - eb.sequenceLock.Lock() - defer eb.sequenceLock.Unlock() - eb.nextSequenceMap[address] = eb.generateNextSequence(seq) -} - -// Used to set the next sequence explicitly to a certain value -func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) SetNextSequence(address ADDR, seq SEQ) { - eb.sequenceLock.Lock() - defer eb.sequenceLock.Unlock() - eb.nextSequenceMap[address] = seq -} - func observeTimeUntilBroadcast[CHAIN_ID types.ID](chainID CHAIN_ID, createdAt, broadcastAt time.Time) { duration := float64(broadcastAt.Sub(createdAt)) promTimeUntilBroadcast.WithLabelValues(chainID.String()).Observe(duration) diff --git a/common/txmgr/confirmer.go b/common/txmgr/confirmer.go index d76e70d9707..53e1c3c4206 100644 --- a/common/txmgr/confirmer.go +++ b/common/txmgr/confirmer.go @@ -782,7 +782,8 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) log "etxID", etx.ID, "txHash", attempt.Hash, "previousAttempt", attempt, - "feeLimit", etx.FeeLimit, + "feeLimit", attempt.ChainSpecificFeeLimit, + "callerProvidedFeeLimit", etx.FeeLimit, "maxGasPrice", ec.feeConfig.MaxFeePrice(), "sequence", etx.Sequence, } @@ -818,7 +819,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han } now := time.Now() - lggr.Debugw("Sending transaction", "txAttemptID", attempt.ID, "txHash", attempt.Hash, "meta", etx.Meta, "feeLimit", etx.FeeLimit, "attempt", attempt, "etx", etx) + lggr.Debugw("Sending transaction", "txAttemptID", attempt.ID, "txHash", attempt.Hash, "meta", etx.Meta, "feeLimit", attempt.ChainSpecificFeeLimit, "callerProvidedFeeLimit", etx.FeeLimit, "attempt", attempt, "etx", etx) errType, sendError := ec.client.SendTransactionReturnCode(ctx, etx, attempt, lggr) switch errType { @@ -878,7 +879,8 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han // fatally error. lggr.Criticalw("Invariant violation: fatal error while re-attempting transaction", "fee", attempt.TxFee, - "feeLimit", etx.FeeLimit, + "feeLimit", attempt.ChainSpecificFeeLimit, + "callerProvidedFeeLimit", etx.FeeLimit, "signedRawTx", commonhex.EnsurePrefix(hex.EncodeToString(attempt.SignedRawTx)), "blockHeight", blockHeight, ) @@ -1071,9 +1073,9 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) For continue } attempt.Tx = *etx // for logging - ec.lggr.Debugw("Sending transaction", "txAttemptID", attempt.ID, "txHash", attempt.Hash, "err", err, "meta", etx.Meta, "feeLimit", etx.FeeLimit, "attempt", attempt) + ec.lggr.Debugw("Sending transaction", "txAttemptID", attempt.ID, "txHash", attempt.Hash, "err", err, "meta", etx.Meta, "feeLimit", attempt.ChainSpecificFeeLimit, "callerProvidedFeeLimit", etx.FeeLimit, attempt) if errCode, err := ec.client.SendTransactionReturnCode(ctx, *etx, attempt, ec.lggr); errCode != client.Successful && err != nil { - ec.lggr.Errorw(fmt.Sprintf("ForceRebroadcast: failed to rebroadcast tx %v with sequence %v and gas limit %v: %s", etx.ID, *etx.Sequence, etx.FeeLimit, err.Error()), "err", err, "fee", attempt.TxFee) + ec.lggr.Errorw(fmt.Sprintf("ForceRebroadcast: failed to rebroadcast tx %v with sequence %v, gas limit %v, and caller provided fee Limit %v : %s", etx.ID, *etx.Sequence, attempt.ChainSpecificFeeLimit, etx.FeeLimit, err.Error()), "err", err, "fee", attempt.TxFee) continue } ec.lggr.Infof("ForceRebroadcast: successfully rebroadcast tx %v with hash: 0x%x", etx.ID, attempt.Hash) diff --git a/common/txmgr/mocks/tx_manager.go b/common/txmgr/mocks/tx_manager.go index 45a3675aced..37b0822941d 100644 --- a/common/txmgr/mocks/tx_manager.go +++ b/common/txmgr/mocks/tx_manager.go @@ -386,7 +386,7 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Reset( } // SendNativeToken provides a mock function with given fields: ctx, chainID, from, to, value, gasLimit -func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) SendNativeToken(ctx context.Context, chainID CHAIN_ID, from ADDR, to ADDR, value big.Int, gasLimit uint32) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { +func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) SendNativeToken(ctx context.Context, chainID CHAIN_ID, from ADDR, to ADDR, value big.Int, gasLimit uint64) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, chainID, from, to, value, gasLimit) if len(ret) == 0 { @@ -395,16 +395,16 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) SendNa var r0 txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error - if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID, ADDR, ADDR, big.Int, uint32) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID, ADDR, ADDR, big.Int, uint64) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { return rf(ctx, chainID, from, to, value, gasLimit) } - if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID, ADDR, ADDR, big.Int, uint32) txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID, ADDR, ADDR, big.Int, uint64) txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { r0 = rf(ctx, chainID, from, to, value, gasLimit) } else { r0 = ret.Get(0).(txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) } - if rf, ok := ret.Get(1).(func(context.Context, CHAIN_ID, ADDR, ADDR, big.Int, uint32) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, CHAIN_ID, ADDR, ADDR, big.Int, uint64) error); ok { r1 = rf(ctx, chainID, from, to, value, gasLimit) } else { r1 = ret.Error(1) diff --git a/common/txmgr/sequence_syncer.go b/common/txmgr/sequence_syncer.go deleted file mode 100644 index dd4d458dd74..00000000000 --- a/common/txmgr/sequence_syncer.go +++ /dev/null @@ -1,11 +0,0 @@ -package txmgr - -import ( - "context" - - "github.com/smartcontractkit/chainlink/v2/common/types" -) - -type SequenceSyncer[ADDR types.Hashable, TX_HASH types.Hashable, BLOCK_HASH types.Hashable, SEQ types.Sequence] interface { - Sync(ctx context.Context, addr ADDR, localSequence SEQ) (SEQ, error) -} diff --git a/common/txmgr/txmgr.go b/common/txmgr/txmgr.go index 2bd9ed4d2d2..fcfd023ece3 100644 --- a/common/txmgr/txmgr.go +++ b/common/txmgr/txmgr.go @@ -47,7 +47,7 @@ type TxManager[ CreateTransaction(ctx context.Context, txRequest txmgrtypes.TxRequest[ADDR, TX_HASH]) (etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) GetForwarderForEOA(eoa ADDR) (forwarder ADDR, err error) RegisterResumeCallback(fn ResumeCallback) - SendNativeToken(ctx context.Context, chainID CHAIN_ID, from, to ADDR, value big.Int, gasLimit uint32) (etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + SendNativeToken(ctx context.Context, chainID CHAIN_ID, from, to ADDR, value big.Int, gasLimit uint64) (etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) Reset(addr ADDR, abandon bool) error // Find transactions by a field in the TxMeta blob and transaction states FindTxesByMetaFieldAndStates(ctx context.Context, metaField string, metaValue string, states []txmgrtypes.TxState, chainID *big.Int) (txes []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) @@ -107,7 +107,6 @@ type Txm[ tracker *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE] fwdMgr txmgrtypes.ForwarderManager[ADDR] txAttemptBuilder txmgrtypes.TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] - sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH, SEQ] } func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) RegisterResumeCallback(fn ResumeCallback) { @@ -136,7 +135,6 @@ func NewTxm[ fwdMgr txmgrtypes.ForwarderManager[ADDR], txAttemptBuilder txmgrtypes.TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], txStore txmgrtypes.TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE], - sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH, SEQ], broadcaster *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], confirmer *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE], resender *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE], @@ -157,7 +155,6 @@ func NewTxm[ reset: make(chan reset), fwdMgr: fwdMgr, txAttemptBuilder: txAttemptBuilder, - sequenceSyncer: sequenceSyncer, broadcaster: broadcaster, confirmer: confirmer, resender: resender, @@ -552,7 +549,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) checkEnabl } // SendNativeToken creates a transaction that transfers the given value of native tokens -func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SendNativeToken(ctx context.Context, chainID CHAIN_ID, from, to ADDR, value big.Int, gasLimit uint32) (etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { +func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SendNativeToken(ctx context.Context, chainID CHAIN_ID, from, to ADDR, value big.Int, gasLimit uint64) (etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { if utils.IsZero(to) { return etx, errors.New("cannot send native token to zero address") } @@ -561,7 +558,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SendNative ToAddress: to, EncodedPayload: []byte{}, Value: value, - FeeLimit: uint64(gasLimit), + FeeLimit: gasLimit, Strategy: NewSendEveryStrategy(), } etx, err = b.pruneQueueAndCreateTxn(ctx, txRequest, chainID) @@ -645,7 +642,7 @@ func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Res } // SendNativeToken does nothing, null functionality -func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) SendNativeToken(ctx context.Context, chainID CHAIN_ID, from, to ADDR, value big.Int, gasLimit uint32) (etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { +func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) SendNativeToken(ctx context.Context, chainID CHAIN_ID, from, to ADDR, value big.Int, gasLimit uint64) (etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { return etx, errors.New(n.ErrMsg) } diff --git a/common/txmgr/types/sequence_tracker.go b/common/txmgr/types/sequence_tracker.go new file mode 100644 index 00000000000..7e824aa38cd --- /dev/null +++ b/common/txmgr/types/sequence_tracker.go @@ -0,0 +1,26 @@ +package types + +import ( + "context" + + "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/common/types" +) + +type SequenceTracker[ + // Represents an account address, in native chain format. + ADDR types.Hashable, + // Represents the sequence type for a chain. For example, nonce for EVM. + SEQ types.Sequence, +] interface { + // Load the next sequence needed for transactions for all enabled addresses + LoadNextSequences(context.Context, []ADDR) + // Get the next sequence to assign to a transaction + GetNextSequence(context.Context, ADDR) (SEQ, error) + // Signals the existing sequence has been used so generates and stores the next sequence + // Can be a no-op depending on the chain + GenerateNextSequence(ADDR, SEQ) + // Syncs the local sequence with the one on-chain in case the address as been used externally + // Can be a no-op depending on the chain + SyncSequence(context.Context, ADDR, services.StopChan) +} diff --git a/common/types/head.go b/common/types/head.go index c363fd5d0f2..4ecdb981c78 100644 --- a/common/types/head.go +++ b/common/types/head.go @@ -36,4 +36,6 @@ type Head[BLOCK_HASH Hashable] interface { // Returns the total difficulty of the block. For chains who do not have a concept of block // difficulty, return 0. BlockDifficulty() *big.Int + // IsValid returns true if the head is valid. + IsValid() bool } diff --git a/common/types/mocks/head.go b/common/types/mocks/head.go index 29b6d073656..fd5c95d472f 100644 --- a/common/types/mocks/head.go +++ b/common/types/mocks/head.go @@ -184,6 +184,24 @@ func (_m *Head[BLOCK_HASH]) HashAtHeight(blockNum int64) BLOCK_HASH { return r0 } +// IsValid provides a mock function with given fields: +func (_m *Head[BLOCK_HASH]) IsValid() bool { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for IsValid") + } + + var r0 bool + if rf, ok := ret.Get(0).(func() bool); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + // NewHead creates a new instance of Head. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewHead[BLOCK_HASH types.Hashable](t interface { diff --git a/contracts/.changeset/afraid-seahorses-yell.md b/contracts/.changeset/afraid-seahorses-yell.md new file mode 100644 index 00000000000..2d45c33320d --- /dev/null +++ b/contracts/.changeset/afraid-seahorses-yell.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": minor +--- + +Chainlink Functions contracts v1.3.0 diff --git a/contracts/.changeset/afraid-years-fix.md b/contracts/.changeset/afraid-years-fix.md new file mode 100644 index 00000000000..7048f562312 --- /dev/null +++ b/contracts/.changeset/afraid-years-fix.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +upgraded transmission to 0.8.19 diff --git a/contracts/.changeset/clever-kings-smell.md b/contracts/.changeset/clever-kings-smell.md new file mode 100644 index 00000000000..eee8eddf53a --- /dev/null +++ b/contracts/.changeset/clever-kings-smell.md @@ -0,0 +1,11 @@ +--- +"@chainlink/contracts": minor +--- + +- Misc VRF V2+ contract changes + - Reuse struct RequestCommitmentV2Plus from VRFTypes + - Fix interface name IVRFCoordinatorV2PlusFulfill in BatchVRFCoordinatorV2Plus to avoid confusion with IVRFCoordinatorV2Plus.sol + - Remove unused errors + - Rename variables for readability + - Fix comments + - Minor gas optimisation (++i) diff --git a/contracts/.changeset/curly-guests-add.md b/contracts/.changeset/curly-guests-add.md new file mode 100644 index 00000000000..1bf40fbeab6 --- /dev/null +++ b/contracts/.changeset/curly-guests-add.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": minor +--- + +improve foundry tests diff --git a/contracts/.changeset/early-hairs-wonder.md b/contracts/.changeset/early-hairs-wonder.md new file mode 100644 index 00000000000..808c89f8451 --- /dev/null +++ b/contracts/.changeset/early-hairs-wonder.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +fix bug in auto2.3 withdrawERC20Fees diff --git a/contracts/.changeset/eight-peas-glow.md b/contracts/.changeset/eight-peas-glow.md new file mode 100644 index 00000000000..03c0498abe2 --- /dev/null +++ b/contracts/.changeset/eight-peas-glow.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": minor +--- + +VRFV2PlusWrapper config refactor diff --git a/contracts/.changeset/famous-feet-rescue.md b/contracts/.changeset/famous-feet-rescue.md new file mode 100644 index 00000000000..d955046ceb9 --- /dev/null +++ b/contracts/.changeset/famous-feet-rescue.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +fix withdraw LINK bug in auto 2.3 diff --git a/contracts/.changeset/fast-maps-rush.md b/contracts/.changeset/fast-maps-rush.md new file mode 100644 index 00000000000..a9a25116758 --- /dev/null +++ b/contracts/.changeset/fast-maps-rush.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": minor +--- + +pay deactivated transmitters in offchain settlement diff --git a/contracts/.changeset/fluffy-peaches-provide.md b/contracts/.changeset/fluffy-peaches-provide.md new file mode 100644 index 00000000000..cf6f001ac2e --- /dev/null +++ b/contracts/.changeset/fluffy-peaches-provide.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +added logic C contract to automation 2.3 diff --git a/contracts/.changeset/forty-ways-ring.md b/contracts/.changeset/forty-ways-ring.md new file mode 100644 index 00000000000..620d2ca1d84 --- /dev/null +++ b/contracts/.changeset/forty-ways-ring.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +upgrade solc version to 0.8.19 for vrf v2.5 contracts diff --git a/contracts/.changeset/fresh-zoos-marry.md b/contracts/.changeset/fresh-zoos-marry.md new file mode 100644 index 00000000000..32af56e63ac --- /dev/null +++ b/contracts/.changeset/fresh-zoos-marry.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +enable gas tests for auto 2.3 diff --git a/contracts/.changeset/happy-books-taste.md b/contracts/.changeset/happy-books-taste.md new file mode 100644 index 00000000000..4b758a65a2e --- /dev/null +++ b/contracts/.changeset/happy-books-taste.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +billing overrides diff --git a/contracts/.changeset/heavy-lions-pull.md b/contracts/.changeset/heavy-lions-pull.md new file mode 100644 index 00000000000..236c4ad033e --- /dev/null +++ b/contracts/.changeset/heavy-lions-pull.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": minor +--- + +Update type and version name for VRFv2+ Wrapper diff --git a/contracts/.changeset/lazy-sheep-invite.md b/contracts/.changeset/lazy-sheep-invite.md new file mode 100644 index 00000000000..77f42295232 --- /dev/null +++ b/contracts/.changeset/lazy-sheep-invite.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": minor +--- + +implement offchain settlement for NOPs payment diff --git a/contracts/.changeset/loud-donuts-work.md b/contracts/.changeset/loud-donuts-work.md new file mode 100644 index 00000000000..e177af6fb3e --- /dev/null +++ b/contracts/.changeset/loud-donuts-work.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +rm hh coverage diff --git a/contracts/.changeset/lucky-bananas-kneel.md b/contracts/.changeset/lucky-bananas-kneel.md new file mode 100644 index 00000000000..2c2b8d5b321 --- /dev/null +++ b/contracts/.changeset/lucky-bananas-kneel.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +mv vrf foundry tests diff --git a/contracts/.changeset/lucky-eels-kiss.md b/contracts/.changeset/lucky-eels-kiss.md new file mode 100644 index 00000000000..2279cb107b9 --- /dev/null +++ b/contracts/.changeset/lucky-eels-kiss.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +VRFV2PlusWrapper contract: subID param added to the constructor, removed migrate() method diff --git a/contracts/.changeset/many-onions-run.md b/contracts/.changeset/many-onions-run.md new file mode 100644 index 00000000000..6c186c9d99c --- /dev/null +++ b/contracts/.changeset/many-onions-run.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +safeTransfer and cleanups diff --git a/contracts/.changeset/modern-horses-destroy.md b/contracts/.changeset/modern-horses-destroy.md new file mode 100644 index 00000000000..32e58da8ff3 --- /dev/null +++ b/contracts/.changeset/modern-horses-destroy.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +fix solhint issues in automation folder diff --git a/contracts/.changeset/nine-comics-bathe.md b/contracts/.changeset/nine-comics-bathe.md new file mode 100644 index 00000000000..7d8573cd784 --- /dev/null +++ b/contracts/.changeset/nine-comics-bathe.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": minor +--- + +Removed 0.6 and 0.7 Solidity source code diff --git a/contracts/.changeset/odd-experts-jump.md b/contracts/.changeset/odd-experts-jump.md new file mode 100644 index 00000000000..d82c762477c --- /dev/null +++ b/contracts/.changeset/odd-experts-jump.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +address TODOs and docs for 2.3 diff --git a/contracts/.changeset/pretty-cups-tickle.md b/contracts/.changeset/pretty-cups-tickle.md new file mode 100644 index 00000000000..a7c5625a4e1 --- /dev/null +++ b/contracts/.changeset/pretty-cups-tickle.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +auto 2.3 foundry test refactor diff --git a/contracts/.changeset/quick-vans-retire.md b/contracts/.changeset/quick-vans-retire.md new file mode 100644 index 00000000000..ad0e6859957 --- /dev/null +++ b/contracts/.changeset/quick-vans-retire.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": minor +--- + +introduce native billing support to automation registry v2.3 diff --git a/contracts/.changeset/quiet-cars-taste.md b/contracts/.changeset/quiet-cars-taste.md new file mode 100644 index 00000000000..f59f3e6d05c --- /dev/null +++ b/contracts/.changeset/quiet-cars-taste.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +more auto 2.3 tests diff --git a/contracts/.changeset/six-donuts-reply.md b/contracts/.changeset/six-donuts-reply.md new file mode 100644 index 00000000000..a9da93964be --- /dev/null +++ b/contracts/.changeset/six-donuts-reply.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +small gas fix diff --git a/contracts/.changeset/smooth-spiders-beam.md b/contracts/.changeset/smooth-spiders-beam.md new file mode 100644 index 00000000000..edf804c910b --- /dev/null +++ b/contracts/.changeset/smooth-spiders-beam.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +change auto 2.3 flat fees from link to USD diff --git a/contracts/.changeset/strange-actors-do.md b/contracts/.changeset/strange-actors-do.md new file mode 100644 index 00000000000..644e30f2a09 --- /dev/null +++ b/contracts/.changeset/strange-actors-do.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +Set LINK native feed in VRFV2PlusWrapper to immutable diff --git a/contracts/.changeset/tasty-rings-bow.md b/contracts/.changeset/tasty-rings-bow.md new file mode 100644 index 00000000000..828050c6eeb --- /dev/null +++ b/contracts/.changeset/tasty-rings-bow.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +add billing override test diff --git a/contracts/.changeset/three-spoons-clean.md b/contracts/.changeset/three-spoons-clean.md new file mode 100644 index 00000000000..f822a9cb274 --- /dev/null +++ b/contracts/.changeset/three-spoons-clean.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +use common interface for v2.3 diff --git a/contracts/.changeset/tricky-pigs-shout.md b/contracts/.changeset/tricky-pigs-shout.md new file mode 100644 index 00000000000..095fc06701c --- /dev/null +++ b/contracts/.changeset/tricky-pigs-shout.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": minor +--- + +bug fixes in s_reserveAmount accounting diff --git a/contracts/.changeset/weak-kangaroos-heal.md b/contracts/.changeset/weak-kangaroos-heal.md new file mode 100644 index 00000000000..0cba92dd998 --- /dev/null +++ b/contracts/.changeset/weak-kangaroos-heal.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +bump solhint and address issues, remove unused imports diff --git a/contracts/.changeset/wise-shrimps-perform.md b/contracts/.changeset/wise-shrimps-perform.md new file mode 100644 index 00000000000..b623b1432d3 --- /dev/null +++ b/contracts/.changeset/wise-shrimps-perform.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +support native payment diff --git a/contracts/.changeset/young-crabs-sing.md b/contracts/.changeset/young-crabs-sing.md new file mode 100644 index 00000000000..c0593d869b6 --- /dev/null +++ b/contracts/.changeset/young-crabs-sing.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": minor +--- + +removed 0.4 and 0.5 contracts diff --git a/contracts/.changeset/young-insects-punch.md b/contracts/.changeset/young-insects-punch.md new file mode 100644 index 00000000000..47d01926978 --- /dev/null +++ b/contracts/.changeset/young-insects-punch.md @@ -0,0 +1,5 @@ +--- +"@chainlink/contracts": patch +--- + +increase num optimizations to 500 for v2.5 coordinator diff --git a/contracts/.prettierignore b/contracts/.prettierignore index 856908bf116..b2c6d61c220 100644 --- a/contracts/.prettierignore +++ b/contracts/.prettierignore @@ -21,10 +21,6 @@ node_modules solc LinkToken.json typechain -src/v0.4 -src/v0.5 -src/v0.6 -src/v0.7 **/vendor # Ignore TS definition and map files diff --git a/contracts/.solcover.js b/contracts/.solcover.js deleted file mode 100644 index e3602a0b4b6..00000000000 --- a/contracts/.solcover.js +++ /dev/null @@ -1,35 +0,0 @@ -module.exports = { - skipFiles: [ - 'v0.4/', - 'v0.5/', - 'v0.6/tests', - 'v0.6/interfaces', - 'v0.6/vendor', - 'v0.7/tests', - 'v0.7/interfaces', - 'v0.7/vendor', - 'v0.8/mocks', - 'v0.8/interfaces', - 'v0.8/vendor', - 'v0.8/dev/interfaces', - 'v0.8/dev/vendor', - 'v0.8/dev/Keeper2_0/interfaces', - 'v0.8/dev/transmission', - 'v0.8/tests', - ], - istanbulReporter: ['text', 'text-summary', 'json'], - mocha: { - grep: '@skip-coverage', // Find everything with this tag - invert: true, // Run the grep's inverse set. - }, - configureYulOptimizer: true, - solcOptimizerDetails: { - peephole: false, - jumpdestRemover: false, - orderLiterals: true, - deduplicate: false, - cse: false, - constantOptimizer: false, - yul: true, - }, -} diff --git a/contracts/.solhint.json b/contracts/.solhint.json index ea220d0a030..5168d4e7838 100644 --- a/contracts/.solhint.json +++ b/contracts/.solhint.json @@ -11,6 +11,8 @@ "no-inline-assembly": "off", "contract-name-camelcase": "off", "no-unused-import": "error", + "gas-struct-packing": "warn", + "interface-starts-with-i": "warn", "func-visibility": [ "error", { diff --git a/contracts/GNUmakefile b/contracts/GNUmakefile index 751a47b3be4..4ec8057b975 100644 --- a/contracts/GNUmakefile +++ b/contracts/GNUmakefile @@ -1,6 +1,6 @@ # ALL_FOUNDRY_PRODUCTS contains a list of all products that have a foundry # profile defined and use the Foundry snapshots. -ALL_FOUNDRY_PRODUCTS = l2ep llo-feeds functions keystone shared +ALL_FOUNDRY_PRODUCTS = l2ep llo-feeds functions keystone shared transmission # To make a snapshot for a specific product, either set the `FOUNDRY_PROFILE` env var # or call the target with `FOUNDRY_PROFILE=product` @@ -43,7 +43,7 @@ mockery: $(mockery) ## Install mockery. .PHONY: foundry foundry: ## Install foundry. - foundryup --version nightly-5b7e4cb3c882b28f3c32ba580de27ce7381f415a + foundryup --version nightly-de33b6af53005037b463318d2628b5cfcaf39916 .PHONY: foundry-refresh foundry-refresh: foundry diff --git a/contracts/STYLE_GUIDE.md b/contracts/STYLE_GUIDE.md index 903832cf099..212cd979e39 100644 --- a/contracts/STYLE_GUIDE.md +++ b/contracts/STYLE_GUIDE.md @@ -64,8 +64,6 @@ uint256 networkFeeUSDCents; // good ### Structs -- All structs should be packed to have the lowest memory footprint to reduce gas usage. Even structs that will never be written to storage should be packed. - - A contract can be considered a struct; it should also be packed to reduce gas cost. - Structs should contain struct packing comments to clearly indicate the storage slot layout - Using the exact characters from the example below will ensure visually appealing struct packing comments. - Notice there is no line on the unpacked last `fee` item. @@ -378,17 +376,22 @@ function getNum() external view returns (uint64 num) { Use [custom errors](https://blog.soliditylang.org/2021/04/21/custom-errors/) instead of emitting strings. This saves contract code size and simultaneously provides more informative error messages. -rule: `custom-errors` +rule: `gas-custom-errors` ## Interfaces Interfaces should be named `IFoo` instead of `FooInterface`. This follows the patterns of popular [libraries like OpenZeppelin’s](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol#L9). -rule: `tbd` +rule: `interface-starts-with-i` ## Structs -Structs should be constructed with named arguments. This prevents accidental assignment to the wrong field and makes the code more readable. +- All structs should be packed to have the lowest memory footprint to reduce gas usage. Even structs that will never be written to storage should be packed. + - A contract can be considered a struct; it should also be packed to reduce gas cost. + +rule: `gas-struct-packing` + +- Structs should be constructed with named arguments. This prevents accidental assignment to the wrong field and makes the code more readable. ```solidity // Good diff --git a/contracts/ci.json b/contracts/ci.json index f1eff76513c..668c85fd4d4 100644 --- a/contracts/ci.json +++ b/contracts/ci.json @@ -2,23 +2,13 @@ "type": "solidity", "basePath": "./contracts/test/", "splits": [ - { - "dir": "cross-version", - "numOfSplits": 1 - }, { "dir": "v0.8", - "numOfSplits": 6, + "numOfSplits": 5, "slowTests": [ - "Cron", - "CronUpkeep", - "VRFSubscriptionBalanceMonitor", - "EthBalanceMonitor", - "KeeperRegistrar", - "KeeperRegistry1_2", - "KeeperRegistry1_3", - "KeeperRegistry2_0", - "KeeperRegistry2_1" + "CronUpkeepFactory", + "AutomationRegistry2_2", + "AutomationRegistry2_3" ] } ] diff --git a/contracts/foundry-lib/forge-std b/contracts/foundry-lib/forge-std index f73c73d2018..bb4ceea94d6 160000 --- a/contracts/foundry-lib/forge-std +++ b/contracts/foundry-lib/forge-std @@ -1 +1 @@ -Subproject commit f73c73d2018eb6a111f35e4dae7b4f27401e9421 +Subproject commit bb4ceea94d6f10eeb5b41dc2391c6c8bf8e734ef diff --git a/contracts/foundry.toml b/contracts/foundry.toml index b87f1f891ea..bbc9f395942 100644 --- a/contracts/foundry.toml +++ b/contracts/foundry.toml @@ -4,7 +4,7 @@ optimizer = true optimizer_runs = 1_000_000 src = 'src/v0.8' -test = 'test/v0.8/foundry' +test = 'test/v0.8' out = 'foundry-artifacts' cache_path = 'foundry-cache' libs = ['node_modules', 'foundry-lib'] @@ -23,38 +23,34 @@ test = 'src/v0.8/functions/tests/v1_X' gas_price = 3_000_000_000 # 3 gwei [profile.vrf] -optimizer_runs = 1000 +optimizer_runs = 1_000 src = 'src/v0.8/vrf' -test = 'test/v0.8/foundry/vrf' # skips tests for no VRF foundry tests -solc_version = '0.8.6' +test = 'src/v0.8/vrf/test' [profile.vrfv2plus_coordinator] -optimizer_runs = 50 +optimizer_runs = 500 src = 'src/v0.8/vrf' -solc_version = '0.8.6' [profile.vrfv2plus] optimizer_runs = 1_000_000 src = 'src/v0.8/vrf' -solc_version = '0.8.6' [profile.automation] -optimizer_runs = 10000 +optimizer_runs = 10_000 src = 'src/v0.8/automation' test = 'src/v0.8/automation/test' [profile.l2ep] -optimizer_runs = 1000000 +optimizer_runs = 1_000_000 src = 'src/v0.8/l2ep' test = 'src/v0.8/l2ep/test' solc_version = '0.8.19' [profile.llo-feeds] -optimizer_runs = 1000000 +optimizer_runs = 1_000_000 src = 'src/v0.8/llo-feeds' test = 'src/v0.8/llo-feeds/test' solc_version = '0.8.19' -# We cannot turn on deny_warnings = true as that will hide any CI failure [profile.keystone] solc_version = '0.8.19' @@ -62,8 +58,20 @@ src = 'src/v0.8/keystone' test = 'src/v0.8/keystone/test' optimizer_runs = 10_000 +[profile.operatorforwarder] +optimizer_runs = 1_000_000 +solc_version = '0.8.19' +src = 'src/v0.8/operatorforwarder' +test = 'src/v0.8/operatorforwarder/test' + +[profile.transmission] +optimizer_runs = 1_000_000 +solc_version = '0.8.19' +src = 'src/v0.8/transmission' +test = 'src/v0.8/transmission/test' + [profile.shared] -optimizer_runs = 1000000 +optimizer_runs = 1_000_000 src = 'src/v0.8/shared' test = 'src/v0.8/shared/test' solc_version = '0.8.19' diff --git a/contracts/gas-snapshots/functions.gas-snapshot b/contracts/gas-snapshots/functions.gas-snapshot index fb24f678bc2..c7bede2770d 100644 --- a/contracts/gas-snapshots/functions.gas-snapshot +++ b/contracts/gas-snapshots/functions.gas-snapshot @@ -1,239 +1,239 @@ -ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumGoerli() (gas: 15924776) -ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumMainnet() (gas: 15924754) -ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumSepolia() (gas: 15924770) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseGoerli() (gas: 15936218) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseMainnet() (gas: 15936195) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseSepolia() (gas: 15936167) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismGoerli() (gas: 15936118) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismMainnet() (gas: 15936107) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismSepolia() (gas: 15936151) -FunctionsBilling_Constructor:test_Constructor_Success() (gas: 14823) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumGoerli() (gas: 15910179) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumMainnet() (gas: 15910157) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumSepolia() (gas: 15910173) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseGoerli() (gas: 15921621) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseMainnet() (gas: 15921598) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseSepolia() (gas: 15921570) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismGoerli() (gas: 15921521) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismMainnet() (gas: 15921510) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismSepolia() (gas: 15921554) +FunctionsBilling_Constructor:test_Constructor_Success() (gas: 17982) FunctionsBilling_DeleteCommitment:test_DeleteCommitment_RevertIfNotRouter() (gas: 13260) FunctionsBilling_DeleteCommitment:test_DeleteCommitment_Success() (gas: 15875) -FunctionsBilling_EstimateCost:test_EstimateCost_RevertsIfGasPriceAboveCeiling() (gas: 32436) -FunctionsBilling_EstimateCost:test_EstimateCost_Success() (gas: 88199) -FunctionsBilling_EstimateCost:test_EstimateCost_SuccessLowGasPrice() (gas: 88302) -FunctionsBilling_GetAdminFeeJuels:test_GetAdminFeeJuels_Success() (gas: 18334) -FunctionsBilling_GetConfig:test_GetConfig_Success() (gas: 27553) -FunctionsBilling_GetDONFeeJuels:test_GetDONFeeJuels_Success() (gas: 40831) -FunctionsBilling_GetOperationFee:test_GetOperationFeeJuels_Success() (gas: 40211) -FunctionsBilling_GetWeiPerUnitLink:test_GetWeiPerUnitLink_Success() (gas: 29414) -FunctionsBilling_OracleWithdraw:test_OracleWithdraw_RevertIfInsufficientBalance() (gas: 70107) -FunctionsBilling_OracleWithdraw:test_OracleWithdraw_RevertWithNoBalance() (gas: 106264) -FunctionsBilling_OracleWithdraw:test_OracleWithdraw_SuccessCoordinatorOwner() (gas: 129542) -FunctionsBilling_OracleWithdraw:test_OracleWithdraw_SuccessTransmitterWithBalanceNoAmountGiven() (gas: 169241) -FunctionsBilling_OracleWithdraw:test_OracleWithdraw_SuccessTransmitterWithBalanceValidAmountGiven() (gas: 142476) +FunctionsBilling_EstimateCost:test_EstimateCost_RevertsIfGasPriceAboveCeiling() (gas: 32450) +FunctionsBilling_EstimateCost:test_EstimateCost_Success() (gas: 91058) +FunctionsBilling_EstimateCost:test_EstimateCost_SuccessLowGasPrice() (gas: 91161) +FunctionsBilling_GetAdminFeeJuels:test_GetAdminFeeJuels_Success() (gas: 18671) +FunctionsBilling_GetConfig:test_GetConfig_Success() (gas: 30213) +FunctionsBilling_GetDONFeeJuels:test_GetDONFeeJuels_Success() (gas: 41128) +FunctionsBilling_GetOperationFee:test_GetOperationFeeJuels_Success() (gas: 40548) +FunctionsBilling_GetWeiPerUnitLink:test_GetWeiPerUnitLink_Success() (gas: 29751) +FunctionsBilling_OracleWithdraw:test_OracleWithdraw_RevertIfInsufficientBalance() (gas: 70136) +FunctionsBilling_OracleWithdraw:test_OracleWithdraw_RevertWithNoBalance() (gas: 108953) +FunctionsBilling_OracleWithdraw:test_OracleWithdraw_SuccessCoordinatorOwner() (gas: 129908) +FunctionsBilling_OracleWithdraw:test_OracleWithdraw_SuccessTransmitterWithBalanceNoAmountGiven() (gas: 171930) +FunctionsBilling_OracleWithdraw:test_OracleWithdraw_SuccessTransmitterWithBalanceValidAmountGiven() (gas: 145165) FunctionsBilling_OracleWithdrawAll:test_OracleWithdrawAll_RevertIfNotOwner() (gas: 13297) -FunctionsBilling_OracleWithdrawAll:test_OracleWithdrawAll_SuccessPaysTransmittersWithBalance() (gas: 217168) +FunctionsBilling_OracleWithdrawAll:test_OracleWithdrawAll_SuccessPaysTransmittersWithBalance() (gas: 222357) FunctionsBilling_UpdateConfig:test_UpdateConfig_RevertIfNotOwner() (gas: 21521) -FunctionsBilling_UpdateConfig:test_UpdateConfig_Success() (gas: 49192) +FunctionsBilling_UpdateConfig:test_UpdateConfig_Success() (gas: 53173) FunctionsBilling__DisperseFeePool:test__DisperseFeePool_RevertIfNotSet() (gas: 8810) FunctionsBilling__FulfillAndBill:test__FulfillAndBill_RevertIfInvalidCommitment() (gas: 13375) -FunctionsBilling__FulfillAndBill:test__FulfillAndBill_Success() (gas: 185974) -FunctionsBilling__StartBilling:test__FulfillAndBill_HasUniqueGlobalRequestId() (gas: 523657) -FunctionsClient_Constructor:test_Constructor_Success() (gas: 7573) +FunctionsBilling__FulfillAndBill:test__FulfillAndBill_Success() (gas: 186305) +FunctionsBilling__StartBilling:test__FulfillAndBill_HasUniqueGlobalRequestId() (gas: 524682) +FunctionsClient_Constructor:test_Constructor_Success() (gas: 10407) FunctionsClient_HandleOracleFulfillment:test_HandleOracleFulfillment_RevertIfNotRouter() (gas: 14617) FunctionsClient_HandleOracleFulfillment:test_HandleOracleFulfillment_Success() (gas: 22917) -FunctionsClient__SendRequest:test__SendRequest_RevertIfInvalidCallbackGasLimit() (gas: 55059) -FunctionsCoordinator_Constructor:test_Constructor_Success() (gas: 12007) +FunctionsClient__SendRequest:test__SendRequest_RevertIfInvalidCallbackGasLimit() (gas: 55069) +FunctionsCoordinator_Constructor:test_Constructor_Success() (gas: 15107) FunctionsCoordinator_GetDONPublicKey:test_GetDONPublicKey_RevertIfEmpty() (gas: 15378) -FunctionsCoordinator_GetDONPublicKey:test_GetDONPublicKey_Success() (gas: 106551) +FunctionsCoordinator_GetDONPublicKey:test_GetDONPublicKey_Success() (gas: 91701) FunctionsCoordinator_GetThresholdPublicKey:test_GetThresholdPublicKey_RevertIfEmpty() (gas: 15356) -FunctionsCoordinator_GetThresholdPublicKey:test_GetThresholdPublicKey_Success() (gas: 656405) +FunctionsCoordinator_GetThresholdPublicKey:test_GetThresholdPublicKey_Success() (gas: 515779) FunctionsCoordinator_SetDONPublicKey:test_SetDONPublicKey_RevertNotOwner() (gas: 20365) -FunctionsCoordinator_SetDONPublicKey:test_SetDONPublicKey_Success() (gas: 101330) +FunctionsCoordinator_SetDONPublicKey:test_SetDONPublicKey_Success() (gas: 88980) FunctionsCoordinator_SetThresholdPublicKey:test_SetThresholdPublicKey_RevertNotOwner() (gas: 13892) -FunctionsCoordinator_SetThresholdPublicKey:test_SetThresholdPublicKey_Success() (gas: 651097) -FunctionsCoordinator_StartRequest:test_StartRequest_RevertIfNotRouter() (gas: 22770) -FunctionsCoordinator_StartRequest:test_StartRequest_Success() (gas: 150311) -FunctionsCoordinator__IsTransmitter:test__IsTransmitter_SuccessFound() (gas: 12275) -FunctionsCoordinator__IsTransmitter:test__IsTransmitter_SuccessNotFound() (gas: 20107) -FunctionsRequest_DEFAULT_BUFFER_SIZE:test_DEFAULT_BUFFER_SIZE() (gas: 246) -FunctionsRequest_EncodeCBOR:test_EncodeCBOR_Success() (gas: 223) -FunctionsRequest_REQUEST_DATA_VERSION:test_REQUEST_DATA_VERSION() (gas: 225) -FunctionsRouter_Constructor:test_Constructor_Success() (gas: 12007) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedCostExceedsCommitment() (gas: 173026) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInsufficientGas() (gas: 163498) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidCommitment() (gas: 38115) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidRequestId() (gas: 35238) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedSubscriptionBalanceInvariant() (gas: 181502) +FunctionsCoordinator_SetThresholdPublicKey:test_SetThresholdPublicKey_Success() (gas: 512971) +FunctionsCoordinator_StartRequest:test_StartRequest_RevertIfNotRouter() (gas: 22736) +FunctionsCoordinator_StartRequest:test_StartRequest_Success() (gas: 150175) +FunctionsCoordinator__IsTransmitter:test__IsTransmitter_SuccessFound() (gas: 15106) +FunctionsCoordinator__IsTransmitter:test__IsTransmitter_SuccessNotFound() (gas: 22938) +FunctionsRequest_DEFAULT_BUFFER_SIZE:test_DEFAULT_BUFFER_SIZE() (gas: 3089) +FunctionsRequest_EncodeCBOR:test_EncodeCBOR_Success() (gas: 3066) +FunctionsRequest_REQUEST_DATA_VERSION:test_REQUEST_DATA_VERSION() (gas: 3068) +FunctionsRouter_Constructor:test_Constructor_Success() (gas: 15107) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedCostExceedsCommitment() (gas: 173017) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInsufficientGas() (gas: 163489) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidCommitment() (gas: 38777) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidRequestId() (gas: 35900) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedSubscriptionBalanceInvariant() (gas: 181496) FunctionsRouter_Fulfill:test_Fulfill_RevertIfNotCommittedCoordinator() (gas: 28086) -FunctionsRouter_Fulfill:test_Fulfill_RevertIfPaused() (gas: 157064) -FunctionsRouter_Fulfill:test_Fulfill_SuccessClientNoLongerExists() (gas: 335516) -FunctionsRouter_Fulfill:test_Fulfill_SuccessFulfilled() (gas: 349140) +FunctionsRouter_Fulfill:test_Fulfill_RevertIfPaused() (gas: 157055) +FunctionsRouter_Fulfill:test_Fulfill_SuccessClientNoLongerExists() (gas: 335507) +FunctionsRouter_Fulfill:test_Fulfill_SuccessFulfilled() (gas: 349131) FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackReverts() (gas: 2628028) -FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackRunsOutOfGas() (gas: 658982) -FunctionsRouter_GetAdminFee:test_GetAdminFee_Success() (gas: 17983) -FunctionsRouter_GetAllowListId:test_GetAllowListId_Success() (gas: 12904) -FunctionsRouter_GetConfig:test_GetConfig_Success() (gas: 37159) -FunctionsRouter_GetContractById:test_GetContractById_RevertIfRouteDoesNotExist() (gas: 13849) -FunctionsRouter_GetContractById:test_GetContractById_SuccessIfRouteExists() (gas: 17373) -FunctionsRouter_GetProposedContractById:test_GetProposedContractById_RevertIfRouteDoesNotExist() (gas: 16383) -FunctionsRouter_GetProposedContractById:test_GetProposedContractById_SuccessIfRouteExists() (gas: 23935) -FunctionsRouter_GetProposedContractSet:test_GetProposedContractSet_Success() (gas: 25936) -FunctionsRouter_IsValidCallbackGasLimit:test_IsValidCallbackGasLimit_RevertGasLimitTooBig() (gas: 28103) -FunctionsRouter_IsValidCallbackGasLimit:test_IsValidCallbackGasLimit_RevertInvalidConfig() (gas: 41093) -FunctionsRouter_IsValidCallbackGasLimit:test_IsValidCallbackGasLimit_Success() (gas: 24620) +FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackRunsOutOfGas() (gas: 658973) +FunctionsRouter_GetAdminFee:test_GetAdminFee_Success() (gas: 18323) +FunctionsRouter_GetAllowListId:test_GetAllowListId_Success() (gas: 13241) +FunctionsRouter_GetConfig:test_GetConfig_Success() (gas: 40170) +FunctionsRouter_GetContractById:test_GetContractById_RevertIfRouteDoesNotExist() (gas: 13839) +FunctionsRouter_GetContractById:test_GetContractById_SuccessIfRouteExists() (gas: 17704) +FunctionsRouter_GetProposedContractById:test_GetProposedContractById_RevertIfRouteDoesNotExist() (gas: 16373) +FunctionsRouter_GetProposedContractById:test_GetProposedContractById_SuccessIfRouteExists() (gas: 24266) +FunctionsRouter_GetProposedContractSet:test_GetProposedContractSet_Success() (gas: 27289) +FunctionsRouter_IsValidCallbackGasLimit:test_IsValidCallbackGasLimit_RevertGasLimitTooBig() (gas: 28087) +FunctionsRouter_IsValidCallbackGasLimit:test_IsValidCallbackGasLimit_RevertInvalidConfig() (gas: 41095) +FunctionsRouter_IsValidCallbackGasLimit:test_IsValidCallbackGasLimit_Success() (gas: 24632) FunctionsRouter_Pause:test_Pause_RevertIfNotOwner() (gas: 13338) -FunctionsRouter_Pause:test_Pause_Success() (gas: 20344) +FunctionsRouter_Pause:test_Pause_Success() (gas: 20669) FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfEmptyAddress() (gas: 14791) FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfExceedsMaxProposal() (gas: 21693) FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfLengthMismatch() (gas: 14670) FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfNotNewContract() (gas: 19048) FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfNotOwner() (gas: 23392) FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_Success() (gas: 118479) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfConsumerNotAllowed() (gas: 59391) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfDuplicateRequestId() (gas: 217981) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfConsumerNotAllowed() (gas: 59400) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfDuplicateRequestId() (gas: 217990) FunctionsRouter_SendRequest:test_SendRequest_RevertIfEmptyData() (gas: 29426) FunctionsRouter_SendRequest:test_SendRequest_RevertIfIncorrectDonId() (gas: 57904) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 208541) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfInvalidCallbackGasLimit() (gas: 50947) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 208562) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfInvalidCallbackGasLimit() (gas: 50953) FunctionsRouter_SendRequest:test_SendRequest_RevertIfInvalidDonId() (gas: 25082) FunctionsRouter_SendRequest:test_SendRequest_RevertIfNoSubscription() (gas: 29132) FunctionsRouter_SendRequest:test_SendRequest_RevertIfPaused() (gas: 34291) -FunctionsRouter_SendRequest:test_SendRequest_Success() (gas: 317671) -FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfConsumerNotAllowed() (gas: 65887) +FunctionsRouter_SendRequest:test_SendRequest_Success() (gas: 226521) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfConsumerNotAllowed() (gas: 65896) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfEmptyData() (gas: 36012) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfIncorrectDonId() (gas: 29896) -FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfInvalidCallbackGasLimit() (gas: 57533) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfInvalidCallbackGasLimit() (gas: 57539) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfInvalidDonId() (gas: 27503) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfNoSubscription() (gas: 35717) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfPaused() (gas: 40810) -FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_Success() (gas: 324108) -FunctionsRouter_SendRequestToProposed:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 214989) -FunctionsRouter_SetAllowListId:test_SetAllowListId_Success() (gas: 30688) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_Success() (gas: 232958) +FunctionsRouter_SendRequestToProposed:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 215010) +FunctionsRouter_SetAllowListId:test_SetAllowListId_Success() (gas: 33531) FunctionsRouter_SetAllowListId:test_UpdateConfig_RevertIfNotOwner() (gas: 13403) FunctionsRouter_Unpause:test_Unpause_RevertIfNotOwner() (gas: 13293) -FunctionsRouter_Unpause:test_Unpause_Success() (gas: 77400) +FunctionsRouter_Unpause:test_Unpause_Success() (gas: 77725) FunctionsRouter_UpdateConfig:test_UpdateConfig_RevertIfNotOwner() (gas: 24437) -FunctionsRouter_UpdateConfig:test_UpdateConfig_Success() (gas: 60676) +FunctionsRouter_UpdateConfig:test_UpdateConfig_Success() (gas: 63353) FunctionsRouter_UpdateContracts:test_UpdateContracts_RevertIfNotOwner() (gas: 13336) -FunctionsRouter_UpdateContracts:test_UpdateContracts_Success() (gas: 38732) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfNotAllowedSender() (gas: 60414) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfPaused() (gas: 61031) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderBecomesBlocked() (gas: 139404) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderIsNotNewOwner() (gas: 62781) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_Success() (gas: 239409) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumers() (gas: 138025) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumersAfterConfigUpdate() (gas: 164969) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNoSubscription() (gas: 12946) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNotAllowedSender() (gas: 102448) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNotSubscriptionOwner() (gas: 87199) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfPaused() (gas: 18094) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_Success() (gas: 95524) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNoSubscription() (gas: 15041) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotAllowedSender() (gas: 102524) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotSubscriptionOwner() (gas: 89309) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPaused() (gas: 20148) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPendingRequests() (gas: 218493) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitAllBalanceAsDeposit() (gas: 114541) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitSomeBalanceAsDeposit() (gas: 125867) -FunctionsSubscriptions_CancelSubscription_ReceiveDeposit:test_CancelSubscription_SuccessRecieveDeposit() (gas: 75017) -FunctionsSubscriptions_Constructor:test_Constructor_Success() (gas: 7654) -FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfNotAllowedSender() (gas: 28704) +FunctionsRouter_UpdateContracts:test_UpdateContracts_Success() (gas: 39269) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfNotAllowedSender() (gas: 60413) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfPaused() (gas: 61040) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderBecomesBlocked() (gas: 139706) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderIsNotNewOwner() (gas: 62780) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_Success() (gas: 240035) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumers() (gas: 138033) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumersAfterConfigUpdate() (gas: 164977) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNoSubscription() (gas: 12955) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNotAllowedSender() (gas: 102450) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNotSubscriptionOwner() (gas: 87205) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfPaused() (gas: 18100) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_Success() (gas: 96221) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNoSubscription() (gas: 15053) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotAllowedSender() (gas: 102529) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotSubscriptionOwner() (gas: 89318) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPaused() (gas: 20157) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPendingRequests() (gas: 218446) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitAllBalanceAsDeposit() (gas: 115656) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitSomeBalanceAsDeposit() (gas: 126964) +FunctionsSubscriptions_CancelSubscription_ReceiveDeposit:test_CancelSubscription_SuccessRecieveDeposit() (gas: 75369) +FunctionsSubscriptions_Constructor:test_Constructor_Success() (gas: 10488) +FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfNotAllowedSender() (gas: 28688) FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfPaused() (gas: 17994) -FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_Success() (gas: 351858) -FunctionsSubscriptions_GetConsumer:test_GetConsumer_Success() (gas: 16226) -FunctionsSubscriptions_GetFlags:test_GetFlags_SuccessInvalidSubscription() (gas: 13101) -FunctionsSubscriptions_GetFlags:test_GetFlags_SuccessValidSubscription() (gas: 40903) -FunctionsSubscriptions_GetSubscription:test_GetSubscription_Success() (gas: 30937) -FunctionsSubscriptions_GetSubscriptionCount:test_GetSubscriptionCount_Success() (gas: 12968) +FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_Success() (gas: 353899) +FunctionsSubscriptions_GetConsumer:test_GetConsumer_Success() (gas: 17256) +FunctionsSubscriptions_GetFlags:test_GetFlags_SuccessInvalidSubscription() (gas: 13438) +FunctionsSubscriptions_GetFlags:test_GetFlags_SuccessValidSubscription() (gas: 41243) +FunctionsSubscriptions_GetSubscription:test_GetSubscription_Success() (gas: 32968) +FunctionsSubscriptions_GetSubscriptionCount:test_GetSubscriptionCount_Success() (gas: 13305) FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_RevertIfEndIsAfterLastSubscription() (gas: 16547) -FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_RevertIfStartIsAfterEnd() (gas: 13459) -FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_Success() (gas: 59592) -FunctionsSubscriptions_GetTotalBalance:test_GetTotalBalance_Success() (gas: 15010) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoCalldata() (gas: 39939) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription() (gas: 42404) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNotLink() (gas: 13441) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfPaused() (gas: 47347) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success() (gas: 81490) -FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfAmountMoreThanBalance() (gas: 20745) +FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_RevertIfStartIsAfterEnd() (gas: 13465) +FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_Success() (gas: 65990) +FunctionsSubscriptions_GetTotalBalance:test_GetTotalBalance_Success() (gas: 15347) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoCalldata() (gas: 39908) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription() (gas: 42382) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNotLink() (gas: 13419) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfPaused() (gas: 47325) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success() (gas: 84314) +FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfAmountMoreThanBalance() (gas: 20766) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfBalanceInvariant() (gas: 189) -FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfNoAmount() (gas: 15638) -FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfPaused() (gas: 20856) -FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_SuccessPaysRecipient() (gas: 59732) -FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_SuccessSetsBalanceToZero() (gas: 57701) +FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfNoAmount() (gas: 15641) +FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfPaused() (gas: 20859) +FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_SuccessPaysRecipient() (gas: 60075) +FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_SuccessSetsBalanceToZero() (gas: 57716) FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_RevertIfNoSubscription() (gas: 12818) FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_RevertIfNotOwner() (gas: 15549) -FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_Success() (gas: 54867) +FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_Success() (gas: 55141) FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessDeletesSubscription() (gas: 49607) -FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessSubOwnerRefunded() (gas: 50896) -FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessWhenRequestInFlight() (gas: 186697) -FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfAmountMoreThanBalance() (gas: 17924) +FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessSubOwnerRefunded() (gas: 53166) +FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessWhenRequestInFlight() (gas: 186649) +FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfAmountMoreThanBalance() (gas: 17945) FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfBalanceInvariant() (gas: 210) FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfNotOwner() (gas: 15555) -FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessIfNoAmount() (gas: 30996) -FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessIfRecipientAddressZero() (gas: 28809) -FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessPaysRecipient() (gas: 31092) -FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessSetsBalanceToZero() (gas: 31569) -FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessFalseIfNoPendingRequests() (gas: 14981) -FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessTrueIfPendingRequests() (gas: 200618) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfEmptyNewOwner() (gas: 27655) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfInvalidNewOwner() (gas: 57797) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNoSubscription() (gas: 15001) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNotAllowedSender() (gas: 119770) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNotSubscriptionOwner() (gas: 17960) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfPaused() (gas: 20128) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_Success() (gas: 68240) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_SuccessChangeProposedOwner() (gas: 82837) +FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessIfNoAmount() (gas: 33839) +FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessIfRecipientAddressZero() (gas: 31649) +FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessPaysRecipient() (gas: 33935) +FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessSetsBalanceToZero() (gas: 31584) +FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessFalseIfNoPendingRequests() (gas: 17818) +FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessTrueIfPendingRequests() (gas: 203439) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfEmptyNewOwner() (gas: 27664) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfInvalidNewOwner() (gas: 57815) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNoSubscription() (gas: 15013) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNotAllowedSender() (gas: 119775) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNotSubscriptionOwner() (gas: 17969) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfPaused() (gas: 20137) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_Success() (gas: 68596) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_SuccessChangeProposedOwner() (gas: 83539) FunctionsSubscriptions_RecoverFunds:test_OwnerCancelSubscription_RevertIfNotOwner() (gas: 15554) -FunctionsSubscriptions_RecoverFunds:test_RecoverFunds_Success() (gas: 41111) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfInvalidConsumer() (gas: 30304) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNoSubscription() (gas: 15019) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotAllowedSender() (gas: 102439) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotSubscriptionOwner() (gas: 87245) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPaused() (gas: 18049) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPendingRequests() (gas: 216026) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_Success() (gas: 42023) -FunctionsSubscriptions_SetFlags:test_SetFlags_RevertIfNoSubscription() (gas: 12891) +FunctionsSubscriptions_RecoverFunds:test_RecoverFunds_Success() (gas: 41376) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfInvalidConsumer() (gas: 30310) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNoSubscription() (gas: 15031) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotAllowedSender() (gas: 102444) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotSubscriptionOwner() (gas: 87254) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPaused() (gas: 18058) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPendingRequests() (gas: 215971) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_Success() (gas: 42088) +FunctionsSubscriptions_SetFlags:test_SetFlags_RevertIfNoSubscription() (gas: 12888) FunctionsSubscriptions_SetFlags:test_SetFlags_RevertIfNotOwner() (gas: 15684) -FunctionsSubscriptions_SetFlags:test_SetFlags_Success() (gas: 35594) +FunctionsSubscriptions_SetFlags:test_SetFlags_Success() (gas: 38434) FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertIfPaused() (gas: 25955) FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertIfTimeoutNotExceeded() (gas: 25261) FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertInvalidRequest() (gas: 28242) -FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_Success() (gas: 57732) -FunctionsSubscriptions_createSubscription:test_CreateSubscription_RevertIfNotAllowedSender() (gas: 26434) +FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_Success() (gas: 58416) +FunctionsSubscriptions_createSubscription:test_CreateSubscription_RevertIfNotAllowedSender() (gas: 26418) FunctionsSubscriptions_createSubscription:test_CreateSubscription_RevertIfPaused() (gas: 15759) -FunctionsSubscriptions_createSubscription:test_CreateSubscription_Success() (gas: 152708) +FunctionsSubscriptions_createSubscription:test_CreateSubscription_Success() (gas: 153701) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:testAcceptTermsOfService_InvalidSigner_vuln() (gas: 94913) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfAcceptorIsNotSender() (gas: 25859) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfBlockedSender() (gas: 88990) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfInvalidSigner() (gas: 23619) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfRecipientContractIsNotSender() (gas: 1866552) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfRecipientIsNotSender() (gas: 26025) -FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForContract() (gas: 1946628) -FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForSelf() (gas: 103533) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForContract() (gas: 1946965) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForSelf() (gas: 104509) FunctionsTermsOfServiceAllowList_BlockSender:test_BlockSender_RevertIfNotOwner() (gas: 15491) -FunctionsTermsOfServiceAllowList_BlockSender:test_BlockSender_Success() (gas: 96662) -FunctionsTermsOfServiceAllowList_Constructor:test_Constructor_Success() (gas: 12253) -FunctionsTermsOfServiceAllowList_GetAllAllowedSenders:test_GetAllAllowedSenders_Success() (gas: 19199) -FunctionsTermsOfServiceAllowList_GetAllowedSendersCount:test_GetAllowedSendersCount_Success() (gas: 12995) -FunctionsTermsOfServiceAllowList_GetAllowedSendersInRange:test_GetAllowedSendersInRange_RevertIfAllowedSendersIsEmpty() (gas: 13158901) -FunctionsTermsOfServiceAllowList_GetAllowedSendersInRange:test_GetAllowedSendersInRange_RevertIfEndIsAfterLastAllowedSender() (gas: 16571) -FunctionsTermsOfServiceAllowList_GetAllowedSendersInRange:test_GetAllowedSendersInRange_RevertIfStartIsAfterEnd() (gas: 13301) -FunctionsTermsOfServiceAllowList_GetAllowedSendersInRange:test_GetAllowedSendersInRange_Success() (gas: 20448) -FunctionsTermsOfServiceAllowList_GetBlockedSendersCount:test_GetBlockedSendersCount_Success() (gas: 12931) -FunctionsTermsOfServiceAllowList_GetBlockedSendersInRange:test_GetBlockedSendersInRange_RevertIfAllowedSendersIsEmpty() (gas: 13158905) +FunctionsTermsOfServiceAllowList_BlockSender:test_BlockSender_Success() (gas: 97541) +FunctionsTermsOfServiceAllowList_Constructor:test_Constructor_Success() (gas: 15345) +FunctionsTermsOfServiceAllowList_GetAllAllowedSenders:test_GetAllAllowedSenders_Success() (gas: 19243) +FunctionsTermsOfServiceAllowList_GetAllowedSendersCount:test_GetAllowedSendersCount_Success() (gas: 13332) +FunctionsTermsOfServiceAllowList_GetAllowedSendersInRange:test_GetAllowedSendersInRange_RevertIfAllowedSendersIsEmpty() (gas: 13161056) +FunctionsTermsOfServiceAllowList_GetAllowedSendersInRange:test_GetAllowedSendersInRange_RevertIfEndIsAfterLastAllowedSender() (gas: 16554) +FunctionsTermsOfServiceAllowList_GetAllowedSendersInRange:test_GetAllowedSendersInRange_RevertIfStartIsAfterEnd() (gas: 13284) +FunctionsTermsOfServiceAllowList_GetAllowedSendersInRange:test_GetAllowedSendersInRange_Success() (gas: 20312) +FunctionsTermsOfServiceAllowList_GetBlockedSendersCount:test_GetBlockedSendersCount_Success() (gas: 13268) +FunctionsTermsOfServiceAllowList_GetBlockedSendersInRange:test_GetBlockedSendersInRange_RevertIfAllowedSendersIsEmpty() (gas: 13161066) FunctionsTermsOfServiceAllowList_GetBlockedSendersInRange:test_GetBlockedSendersInRange_RevertIfEndIsAfterLastAllowedSender() (gas: 16549) FunctionsTermsOfServiceAllowList_GetBlockedSendersInRange:test_GetBlockedSendersInRange_RevertIfStartIsAfterEnd() (gas: 13367) -FunctionsTermsOfServiceAllowList_GetBlockedSendersInRange:test_GetBlockedSendersInRange_Success() (gas: 18493) -FunctionsTermsOfServiceAllowList_GetConfig:test_GetConfig_Success() (gas: 15751) -FunctionsTermsOfServiceAllowList_GetMessage:test_GetMessage_Success() (gas: 11593) -FunctionsTermsOfServiceAllowList_HasAccess:test_HasAccess_FalseWhenEnabled() (gas: 15969) -FunctionsTermsOfServiceAllowList_HasAccess:test_HasAccess_TrueWhenDisabled() (gas: 23560) -FunctionsTermsOfServiceAllowList_IsBlockedSender:test_IsBlockedSender_SuccessFalse() (gas: 15445) -FunctionsTermsOfServiceAllowList_IsBlockedSender:test_IsBlockedSender_SuccessTrue() (gas: 86643) +FunctionsTermsOfServiceAllowList_GetBlockedSendersInRange:test_GetBlockedSendersInRange_Success() (gas: 18537) +FunctionsTermsOfServiceAllowList_GetConfig:test_GetConfig_Success() (gas: 16388) +FunctionsTermsOfServiceAllowList_GetMessage:test_GetMessage_Success() (gas: 11918) +FunctionsTermsOfServiceAllowList_HasAccess:test_HasAccess_FalseWhenEnabled() (gas: 16257) +FunctionsTermsOfServiceAllowList_HasAccess:test_HasAccess_TrueWhenDisabled() (gas: 23848) +FunctionsTermsOfServiceAllowList_IsBlockedSender:test_IsBlockedSender_SuccessFalse() (gas: 15776) +FunctionsTermsOfServiceAllowList_IsBlockedSender:test_IsBlockedSender_SuccessTrue() (gas: 86974) FunctionsTermsOfServiceAllowList_UnblockSender:test_UnblockSender_RevertIfNotOwner() (gas: 13502) FunctionsTermsOfServiceAllowList_UnblockSender:test_UnblockSender_Success() (gas: 96216) -FunctionsTermsOfServiceAllowList_UpdateConfig:test_UpdateConfig_RevertIfNotOwner() (gas: 13824) -FunctionsTermsOfServiceAllowList_UpdateConfig:test_UpdateConfig_Success() (gas: 22183) +FunctionsTermsOfServiceAllowList_UpdateConfig:test_UpdateConfig_RevertIfNotOwner() (gas: 13812) +FunctionsTermsOfServiceAllowList_UpdateConfig:test_UpdateConfig_Success() (gas: 22817) Gas_AcceptTermsOfService:test_AcceptTermsOfService_Gas() (gas: 84702) -Gas_AddConsumer:test_AddConsumer_Gas() (gas: 79131) +Gas_AddConsumer:test_AddConsumer_Gas() (gas: 79140) Gas_CreateSubscription:test_CreateSubscription_Gas() (gas: 73419) Gas_FulfillRequest_DuplicateRequestID:test_FulfillRequest_DuplicateRequestID_MaximumGas() (gas: 20717) Gas_FulfillRequest_DuplicateRequestID:test_FulfillRequest_DuplicateRequestID_MinimumGas() (gas: 20157) Gas_FulfillRequest_Success:test_FulfillRequest_Success_MaximumGas() (gas: 501825) Gas_FulfillRequest_Success:test_FulfillRequest_Success_MinimumGas() (gas: 203029) -Gas_FundSubscription:test_FundSubscription_Gas() (gas: 38546) +Gas_FundSubscription:test_FundSubscription_Gas() (gas: 38524) Gas_SendRequest:test_SendRequest_MaximumGas() (gas: 1003809) Gas_SendRequest:test_SendRequest_MinimumGas() (gas: 181701) \ No newline at end of file diff --git a/contracts/gas-snapshots/keystone.gas-snapshot b/contracts/gas-snapshots/keystone.gas-snapshot index be23de1fc62..6797bd77e20 100644 --- a/contracts/gas-snapshots/keystone.gas-snapshot +++ b/contracts/gas-snapshots/keystone.gas-snapshot @@ -1,2 +1,2 @@ -KeystoneForwarderTest:test_abi_partial_decoding_works() (gas: 2068) -KeystoneForwarderTest:test_it_works() (gas: 993848) \ No newline at end of file +KeystoneForwarderTest:test_abi_partial_decoding_works() (gas: 5123) +KeystoneForwarderTest:test_it_works() (gas: 996215) \ No newline at end of file diff --git a/contracts/gas-snapshots/l2ep.gas-snapshot b/contracts/gas-snapshots/l2ep.gas-snapshot index fdc9ec9b22c..324cacfc024 100644 --- a/contracts/gas-snapshots/l2ep.gas-snapshot +++ b/contracts/gas-snapshots/l2ep.gas-snapshot @@ -1,146 +1,146 @@ -ArbitrumCrossDomainForwarder_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 37312) +ArbitrumCrossDomainForwarder_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 37613) ArbitrumCrossDomainForwarder_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 12963) -ArbitrumCrossDomainForwarder_Constructor:test_InitialState() (gas: 18431) -ArbitrumCrossDomainForwarder_Forward:test_Forward() (gas: 47601) -ArbitrumCrossDomainForwarder_Forward:test_ForwardRevert() (gas: 22151) -ArbitrumCrossDomainForwarder_Forward:test_NotCallableByUnknownAddress() (gas: 16048) -ArbitrumCrossDomainForwarder_TransferL1Ownership:test_CallableByL1Owner() (gas: 41408) +ArbitrumCrossDomainForwarder_Constructor:test_InitialState() (gas: 22196) +ArbitrumCrossDomainForwarder_Forward:test_Forward() (gas: 47867) +ArbitrumCrossDomainForwarder_Forward:test_ForwardRevert() (gas: 22181) +ArbitrumCrossDomainForwarder_Forward:test_NotCallableByUnknownAddress() (gas: 16056) +ArbitrumCrossDomainForwarder_TransferL1Ownership:test_CallableByL1Owner() (gas: 41430) ArbitrumCrossDomainForwarder_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 19312) -ArbitrumCrossDomainForwarder_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 18323) -ArbitrumCrossDomainForwarder_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 13200) -ArbitrumCrossDomainGovernor_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 37312) +ArbitrumCrossDomainForwarder_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 18671) +ArbitrumCrossDomainForwarder_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 13219) +ArbitrumCrossDomainGovernor_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 37613) ArbitrumCrossDomainGovernor_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 12963) -ArbitrumCrossDomainGovernor_Constructor:test_InitialState() (gas: 18454) -ArbitrumCrossDomainGovernor_Forward:test_CallableByL2Owner() (gas: 49720) -ArbitrumCrossDomainGovernor_Forward:test_Forward() (gas: 47658) +ArbitrumCrossDomainGovernor_Constructor:test_InitialState() (gas: 22219) +ArbitrumCrossDomainGovernor_Forward:test_CallableByL2Owner() (gas: 49980) +ArbitrumCrossDomainGovernor_Forward:test_Forward() (gas: 47918) ArbitrumCrossDomainGovernor_Forward:test_ForwardRevert() (gas: 24348) -ArbitrumCrossDomainGovernor_Forward:test_NotCallableByUnknownAddress() (gas: 18247) +ArbitrumCrossDomainGovernor_Forward:test_NotCallableByUnknownAddress() (gas: 18255) ArbitrumCrossDomainGovernor_ForwardDelegate:test_BubbleUpRevert() (gas: 19386) -ArbitrumCrossDomainGovernor_ForwardDelegate:test_CallableByCrossDomainMessengerAddressOrL1Owner() (gas: 60617) -ArbitrumCrossDomainGovernor_ForwardDelegate:test_CallableByL2Owner() (gas: 62723) -ArbitrumCrossDomainGovernor_ForwardDelegate:test_NotCallableByUnknownAddress() (gas: 18237) -ArbitrumCrossDomainGovernor_ForwardDelegate:test_RevertsBatchWhenOneCallFails() (gas: 64110) -ArbitrumCrossDomainGovernor_TransferL1Ownership:test_CallableByL1Owner() (gas: 41408) +ArbitrumCrossDomainGovernor_ForwardDelegate:test_CallableByCrossDomainMessengerAddressOrL1Owner() (gas: 60874) +ArbitrumCrossDomainGovernor_ForwardDelegate:test_CallableByL2Owner() (gas: 62980) +ArbitrumCrossDomainGovernor_ForwardDelegate:test_NotCallableByUnknownAddress() (gas: 18245) +ArbitrumCrossDomainGovernor_ForwardDelegate:test_RevertsBatchWhenOneCallFails() (gas: 64379) +ArbitrumCrossDomainGovernor_TransferL1Ownership:test_CallableByL1Owner() (gas: 41430) ArbitrumCrossDomainGovernor_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 19312) -ArbitrumCrossDomainGovernor_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 18323) -ArbitrumCrossDomainGovernor_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 13200) -ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetAnswer() (gas: 92118) -ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetRoundData() (gas: 92673) -ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetTimestamp() (gas: 92039) -ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestAnswer() (gas: 89813) -ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRound() (gas: 89705) -ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRoundData() (gas: 90246) -ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestTimestamp() (gas: 89690) -ArbitrumSequencerUptimeFeed_AggregatorV3Interface:test_AggregatorV3Interface() (gas: 98825) -ArbitrumSequencerUptimeFeed_AggregatorV3Interface:test_Return0WhenRoundDoesNotExistYet() (gas: 18309) -ArbitrumSequencerUptimeFeed_Constants:test_InitialState() (gas: 5684) -ArbitrumSequencerUptimeFeed_GasCosts:test_GasCosts() (gas: 97495) -ArbitrumSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() (gas: 602711) -ArbitrumSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() (gas: 573802) -ArbitrumSequencerUptimeFeed_UpdateStatus:test_IgnoreOutOfOrderUpdates() (gas: 98976) -ArbitrumSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddr() (gas: 15416) -ArbitrumSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndNoTimeChange() (gas: 113269) -ArbitrumSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndTimeChange() (gas: 113329) -ArbitrumValidator_Validate:test_PostSequencerOffline() (gas: 69068) -OptimismCrossDomainForwarder_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 46888) -OptimismCrossDomainForwarder_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22155) -OptimismCrossDomainForwarder_Constructor:test_InitialState() (gas: 18266) -OptimismCrossDomainForwarder_Forward:test_Forward() (gas: 58025) -OptimismCrossDomainForwarder_Forward:test_ForwardRevert() (gas: 32546) -OptimismCrossDomainForwarder_Forward:test_NotCallableByUnknownAddress() (gas: 13859) -OptimismCrossDomainForwarder_TransferL1Ownership:test_CallableByL1Owner() (gas: 48886) -OptimismCrossDomainForwarder_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28767) -OptimismCrossDomainForwarder_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16134) -OptimismCrossDomainForwarder_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11011) -OptimismCrossDomainGovernor_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 46888) -OptimismCrossDomainGovernor_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22155) -OptimismCrossDomainGovernor_Constructor:test_InitialState() (gas: 18289) -OptimismCrossDomainGovernor_Forward:test_CallableByL2Owner() (gas: 47557) -OptimismCrossDomainGovernor_Forward:test_Forward() (gas: 58096) -OptimismCrossDomainGovernor_Forward:test_ForwardRevert() (gas: 32627) -OptimismCrossDomainGovernor_Forward:test_NotCallableByUnknownAddress() (gas: 16061) -OptimismCrossDomainGovernor_ForwardDelegate:test_BubbleUpRevert() (gas: 29181) -OptimismCrossDomainGovernor_ForwardDelegate:test_CallableByCrossDomainMessengerAddressOrL1Owner() (gas: 72695) -OptimismCrossDomainGovernor_ForwardDelegate:test_CallableByL2Owner() (gas: 72685) -OptimismCrossDomainGovernor_ForwardDelegate:test_NotCallableByUnknownAddress() (gas: 16051) -OptimismCrossDomainGovernor_ForwardDelegate:test_RevertsBatchWhenOneCallFails() (gas: 75908) -OptimismCrossDomainGovernor_TransferL1Ownership:test_CallableByL1Owner() (gas: 48886) -OptimismCrossDomainGovernor_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28767) -OptimismCrossDomainGovernor_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16134) -OptimismCrossDomainGovernor_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11011) -OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetAnswer() (gas: 59095) -OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetRoundData() (gas: 59635) -OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetTimestamp() (gas: 58950) -OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestAnswer() (gas: 56887) -OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRound() (gas: 56773) -OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRoundData() (gas: 57309) -OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestTimestamp() (gas: 56740) -OptimismSequencerUptimeFeed_AggregatorV3Interface:test_AggregatorV3Interface() (gas: 65617) +ArbitrumCrossDomainGovernor_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 18671) +ArbitrumCrossDomainGovernor_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 13219) +ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetAnswer() (gas: 92790) +ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetRoundData() (gas: 93351) +ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetTimestamp() (gas: 92711) +ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestAnswer() (gas: 90485) +ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRound() (gas: 90377) +ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRoundData() (gas: 90924) +ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestTimestamp() (gas: 90362) +ArbitrumSequencerUptimeFeed_AggregatorV3Interface:test_AggregatorV3Interface() (gas: 104994) +ArbitrumSequencerUptimeFeed_AggregatorV3Interface:test_Return0WhenRoundDoesNotExistYet() (gas: 20033) +ArbitrumSequencerUptimeFeed_Constants:test_InitialState() (gas: 8530) +ArbitrumSequencerUptimeFeed_GasCosts:test_GasCosts() (gas: 99865) +ArbitrumSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() (gas: 604414) +ArbitrumSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() (gas: 574476) +ArbitrumSequencerUptimeFeed_UpdateStatus:test_IgnoreOutOfOrderUpdates() (gas: 99662) +ArbitrumSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddr() (gas: 15424) +ArbitrumSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndNoTimeChange() (gas: 114647) +ArbitrumSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndTimeChange() (gas: 114707) +ArbitrumValidator_Validate:test_PostSequencerOffline() (gas: 69086) +OptimismCrossDomainForwarder_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 47206) +OptimismCrossDomainForwarder_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22160) +OptimismCrossDomainForwarder_Constructor:test_InitialState() (gas: 22031) +OptimismCrossDomainForwarder_Forward:test_Forward() (gas: 58281) +OptimismCrossDomainForwarder_Forward:test_ForwardRevert() (gas: 32560) +OptimismCrossDomainForwarder_Forward:test_NotCallableByUnknownAddress() (gas: 13867) +OptimismCrossDomainForwarder_TransferL1Ownership:test_CallableByL1Owner() (gas: 48910) +OptimismCrossDomainForwarder_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28775) +OptimismCrossDomainForwarder_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16482) +OptimismCrossDomainForwarder_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11030) +OptimismCrossDomainGovernor_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 47206) +OptimismCrossDomainGovernor_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22160) +OptimismCrossDomainGovernor_Constructor:test_InitialState() (gas: 22054) +OptimismCrossDomainGovernor_Forward:test_CallableByL2Owner() (gas: 47823) +OptimismCrossDomainGovernor_Forward:test_Forward() (gas: 58352) +OptimismCrossDomainGovernor_Forward:test_ForwardRevert() (gas: 32641) +OptimismCrossDomainGovernor_Forward:test_NotCallableByUnknownAddress() (gas: 16069) +OptimismCrossDomainGovernor_ForwardDelegate:test_BubbleUpRevert() (gas: 29189) +OptimismCrossDomainGovernor_ForwardDelegate:test_CallableByCrossDomainMessengerAddressOrL1Owner() (gas: 72942) +OptimismCrossDomainGovernor_ForwardDelegate:test_CallableByL2Owner() (gas: 72924) +OptimismCrossDomainGovernor_ForwardDelegate:test_NotCallableByUnknownAddress() (gas: 16059) +OptimismCrossDomainGovernor_ForwardDelegate:test_RevertsBatchWhenOneCallFails() (gas: 76167) +OptimismCrossDomainGovernor_TransferL1Ownership:test_CallableByL1Owner() (gas: 48910) +OptimismCrossDomainGovernor_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28775) +OptimismCrossDomainGovernor_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16482) +OptimismCrossDomainGovernor_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11030) +OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetAnswer() (gas: 59785) +OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetRoundData() (gas: 60331) +OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetTimestamp() (gas: 59640) +OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestAnswer() (gas: 57577) +OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRound() (gas: 57463) +OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRoundData() (gas: 58005) +OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestTimestamp() (gas: 57430) +OptimismSequencerUptimeFeed_AggregatorV3Interface:test_AggregatorV3Interface() (gas: 71804) OptimismSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetAnswerWhenRoundDoesNotExistYet() (gas: 17679) OptimismSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetRoundDataWhenRoundDoesNotExistYet() (gas: 17897) OptimismSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetTimestampWhenRoundDoesNotExistYet() (gas: 17603) -OptimismSequencerUptimeFeed_Constructor:test_InitialState() (gas: 21078) -OptimismSequencerUptimeFeed_GasCosts:test_GasCosts() (gas: 67197) -OptimismSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() (gas: 597640) -OptimismSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() (gas: 573807) -OptimismSequencerUptimeFeed_UpdateStatus:test_IgnoreOutOfOrderUpdates() (gas: 66532) -OptimismSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddr() (gas: 13200) -OptimismSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddrAndNotL1SenderAddr() (gas: 23607) -OptimismSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenNoChange() (gas: 74035) -OptimismSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndNoTimeChange() (gas: 96155) -OptimismSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndTimeChange() (gas: 96215) -OptimismValidator_SetGasLimit:test_CorrectlyUpdatesTheGasLimit() (gas: 15503) +OptimismSequencerUptimeFeed_Constructor:test_InitialState() (gas: 22110) +OptimismSequencerUptimeFeed_GasCosts:test_GasCosts() (gas: 69567) +OptimismSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() (gas: 601843) +OptimismSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() (gas: 574481) +OptimismSequencerUptimeFeed_UpdateStatus:test_IgnoreOutOfOrderUpdates() (gas: 67230) +OptimismSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddr() (gas: 13214) +OptimismSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddrAndNotL1SenderAddr() (gas: 23632) +OptimismSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenNoChange() (gas: 77137) +OptimismSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndNoTimeChange() (gas: 97545) +OptimismSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndTimeChange() (gas: 97605) +OptimismValidator_SetGasLimit:test_CorrectlyUpdatesTheGasLimit() (gas: 18695) OptimismValidator_Validate:test_PostSequencerOffline() (gas: 74813) OptimismValidator_Validate:test_PostSequencerStatusWhenThereIsNotStatusChange() (gas: 74869) -OptimismValidator_Validate:test_RevertsIfCalledByAnAccountWithNoAccess() (gas: 15563) -ScrollCrossDomainForwarder_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 46988) -ScrollCrossDomainForwarder_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22207) -ScrollCrossDomainForwarder_Constructor:test_InitialState() (gas: 17930) -ScrollCrossDomainForwarder_Forward:test_Forward() (gas: 58092) -ScrollCrossDomainForwarder_Forward:test_ForwardRevert() (gas: 32619) -ScrollCrossDomainForwarder_Forward:test_NotCallableByUnknownAddress() (gas: 13859) -ScrollCrossDomainForwarder_TransferL1Ownership:test_CallableByL1Owner() (gas: 48952) -ScrollCrossDomainForwarder_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28833) -ScrollCrossDomainForwarder_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16134) -ScrollCrossDomainForwarder_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11011) -ScrollCrossDomainGovernor_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 46988) -ScrollCrossDomainGovernor_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22207) -ScrollCrossDomainGovernor_Constructor:test_InitialState() (gas: 17953) -ScrollCrossDomainGovernor_Forward:test_CallableByL2Owner() (gas: 47552) -ScrollCrossDomainGovernor_Forward:test_Forward() (gas: 58158) -ScrollCrossDomainGovernor_Forward:test_ForwardRevert() (gas: 32697) -ScrollCrossDomainGovernor_Forward:test_NotCallableByUnknownAddress() (gas: 16058) -ScrollCrossDomainGovernor_ForwardDelegate:test_BubbleUpRevert() (gas: 29248) -ScrollCrossDomainGovernor_ForwardDelegate:test_CallableByCrossDomainMessengerAddressOrL1Owner() (gas: 72756) -ScrollCrossDomainGovernor_ForwardDelegate:test_CallableByL2Owner() (gas: 72746) -ScrollCrossDomainGovernor_ForwardDelegate:test_NotCallableByUnknownAddress() (gas: 16048) -ScrollCrossDomainGovernor_ForwardDelegate:test_RevertsBatchWhenOneCallFails() (gas: 75970) -ScrollCrossDomainGovernor_TransferL1Ownership:test_CallableByL1Owner() (gas: 48952) -ScrollCrossDomainGovernor_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28833) -ScrollCrossDomainGovernor_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16134) -ScrollCrossDomainGovernor_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11011) -ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetAnswer() (gas: 57250) -ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetRoundData() (gas: 57780) -ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetTimestamp() (gas: 57105) -ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestAnswer() (gas: 54888) -ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRound() (gas: 54768) -ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRoundData() (gas: 55473) -ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestTimestamp() (gas: 54758) -ScrollSequencerUptimeFeed_AggregatorV3Interface:test_AggregatorV3Interface() (gas: 63903) +OptimismValidator_Validate:test_RevertsIfCalledByAnAccountWithNoAccess() (gas: 15571) +ScrollCrossDomainForwarder_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 47300) +ScrollCrossDomainForwarder_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22212) +ScrollCrossDomainForwarder_Constructor:test_InitialState() (gas: 21707) +ScrollCrossDomainForwarder_Forward:test_Forward() (gas: 58348) +ScrollCrossDomainForwarder_Forward:test_ForwardRevert() (gas: 32618) +ScrollCrossDomainForwarder_Forward:test_NotCallableByUnknownAddress() (gas: 13867) +ScrollCrossDomainForwarder_TransferL1Ownership:test_CallableByL1Owner() (gas: 48976) +ScrollCrossDomainForwarder_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28841) +ScrollCrossDomainForwarder_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16482) +ScrollCrossDomainForwarder_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11030) +ScrollCrossDomainGovernor_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 47300) +ScrollCrossDomainGovernor_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22212) +ScrollCrossDomainGovernor_Constructor:test_InitialState() (gas: 21730) +ScrollCrossDomainGovernor_Forward:test_CallableByL2Owner() (gas: 47818) +ScrollCrossDomainGovernor_Forward:test_Forward() (gas: 58414) +ScrollCrossDomainGovernor_Forward:test_ForwardRevert() (gas: 32696) +ScrollCrossDomainGovernor_Forward:test_NotCallableByUnknownAddress() (gas: 16066) +ScrollCrossDomainGovernor_ForwardDelegate:test_BubbleUpRevert() (gas: 29250) +ScrollCrossDomainGovernor_ForwardDelegate:test_CallableByCrossDomainMessengerAddressOrL1Owner() (gas: 73009) +ScrollCrossDomainGovernor_ForwardDelegate:test_CallableByL2Owner() (gas: 72991) +ScrollCrossDomainGovernor_ForwardDelegate:test_NotCallableByUnknownAddress() (gas: 16056) +ScrollCrossDomainGovernor_ForwardDelegate:test_RevertsBatchWhenOneCallFails() (gas: 76235) +ScrollCrossDomainGovernor_TransferL1Ownership:test_CallableByL1Owner() (gas: 48976) +ScrollCrossDomainGovernor_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28841) +ScrollCrossDomainGovernor_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16482) +ScrollCrossDomainGovernor_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11030) +ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetAnswer() (gas: 57940) +ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetRoundData() (gas: 58476) +ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetTimestamp() (gas: 57795) +ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestAnswer() (gas: 55578) +ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRound() (gas: 55458) +ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRoundData() (gas: 56169) +ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestTimestamp() (gas: 55448) +ScrollSequencerUptimeFeed_AggregatorV3Interface:test_AggregatorV3Interface() (gas: 70090) ScrollSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetAnswerWhenRoundDoesNotExistYet() (gas: 17675) ScrollSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetRoundDataWhenRoundDoesNotExistYet() (gas: 17893) ScrollSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetTimestampWhenRoundDoesNotExistYet() (gas: 17599) -ScrollSequencerUptimeFeed_Constructor:test_InitialState() (gas: 102485) -ScrollSequencerUptimeFeed_GasCosts:test_GasCosts() (gas: 64888) -ScrollSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() (gas: 597491) -ScrollSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() (gas: 573807) -ScrollSequencerUptimeFeed_UpdateStatus:test_IgnoreOutOfOrderUpdates() (gas: 64417) -ScrollSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddr() (gas: 13200) -ScrollSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddrAndNotL1SenderAddr() (gas: 23607) -ScrollSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenNoChange() (gas: 71618) -ScrollSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndNoTimeChange() (gas: 92018) -ScrollSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndTimeChange() (gas: 92078) -ScrollValidator_SetGasLimit:test_CorrectlyUpdatesTheGasLimit() (gas: 15637) -ScrollValidator_Validate:test_PostSequencerOffline() (gas: 78367) -ScrollValidator_Validate:test_PostSequencerStatusWhenThereIsNotStatusChange() (gas: 78423) -ScrollValidator_Validate:test_RevertsIfCalledByAnAccountWithNoAccess() (gas: 15569) \ No newline at end of file +ScrollSequencerUptimeFeed_Constructor:test_InitialState() (gas: 103508) +ScrollSequencerUptimeFeed_GasCosts:test_GasCosts() (gas: 67258) +ScrollSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() (gas: 601694) +ScrollSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() (gas: 574481) +ScrollSequencerUptimeFeed_UpdateStatus:test_IgnoreOutOfOrderUpdates() (gas: 65115) +ScrollSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddr() (gas: 13214) +ScrollSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddrAndNotL1SenderAddr() (gas: 23632) +ScrollSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenNoChange() (gas: 74720) +ScrollSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndNoTimeChange() (gas: 93408) +ScrollSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndTimeChange() (gas: 93468) +ScrollValidator_SetGasLimit:test_CorrectlyUpdatesTheGasLimit() (gas: 18829) +ScrollValidator_Validate:test_PostSequencerOffline() (gas: 78349) +ScrollValidator_Validate:test_PostSequencerStatusWhenThereIsNotStatusChange() (gas: 78411) +ScrollValidator_Validate:test_RevertsIfCalledByAnAccountWithNoAccess() (gas: 15571) \ No newline at end of file diff --git a/contracts/gas-snapshots/llo-feeds.gas-snapshot b/contracts/gas-snapshots/llo-feeds.gas-snapshot index ec037aafb87..0162809e90d 100644 --- a/contracts/gas-snapshots/llo-feeds.gas-snapshot +++ b/contracts/gas-snapshots/llo-feeds.gas-snapshot @@ -1,158 +1,158 @@ -ByteUtilTest:test_readAddress() (gas: 542) -ByteUtilTest:test_readAddressMultiWord() (gas: 540) +ByteUtilTest:test_readAddress() (gas: 3388) +ByteUtilTest:test_readAddressMultiWord() (gas: 3386) ByteUtilTest:test_readAddressWithEmptyArray() (gas: 3274) ByteUtilTest:test_readAddressWithNotEnoughBytes() (gas: 3314) -ByteUtilTest:test_readUint192Max() (gas: 485) -ByteUtilTest:test_readUint192Min() (gas: 508) -ByteUtilTest:test_readUint192MultiWord() (gas: 486) +ByteUtilTest:test_readUint192Max() (gas: 3326) +ByteUtilTest:test_readUint192Min() (gas: 3349) +ByteUtilTest:test_readUint192MultiWord() (gas: 3327) ByteUtilTest:test_readUint192WithEmptyArray() (gas: 3274) ByteUtilTest:test_readUint192WithNotEnoughBytes() (gas: 3314) -ByteUtilTest:test_readUint256Max() (gas: 502) -ByteUtilTest:test_readUint256Min() (gas: 546) -ByteUtilTest:test_readUint256MultiWord() (gas: 500) +ByteUtilTest:test_readUint256Max() (gas: 3343) +ByteUtilTest:test_readUint256Min() (gas: 3387) +ByteUtilTest:test_readUint256MultiWord() (gas: 3341) ByteUtilTest:test_readUint256WithEmptyArray() (gas: 3296) ByteUtilTest:test_readUint256WithNotEnoughBytes() (gas: 3293) -ByteUtilTest:test_readUint32Max() (gas: 507) -ByteUtilTest:test_readUint32Min() (gas: 487) -ByteUtilTest:test_readUint32MultiWord() (gas: 552) +ByteUtilTest:test_readUint32Max() (gas: 3348) +ByteUtilTest:test_readUint32Min() (gas: 3328) +ByteUtilTest:test_readUint32MultiWord() (gas: 3393) ByteUtilTest:test_readUint32WithEmptyArray() (gas: 3253) ByteUtilTest:test_readUint32WithNotEnoughBytes() (gas: 3272) -ByteUtilTest:test_readZeroAddress() (gas: 519) -FeeManagerProcessFeeTest:test_DiscountIsAppliedForNative() (gas: 52288) -FeeManagerProcessFeeTest:test_DiscountIsReturnedForNative() (gas: 52241) -FeeManagerProcessFeeTest:test_DiscountIsReturnedForNativeWithSurcharge() (gas: 78446) -FeeManagerProcessFeeTest:test_V1PayloadVerifies() (gas: 26980) -FeeManagerProcessFeeTest:test_V1PayloadVerifiesAndReturnsChange() (gas: 57895) -FeeManagerProcessFeeTest:test_V2PayloadVerifies() (gas: 116094) -FeeManagerProcessFeeTest:test_V2PayloadWithoutQuoteFails() (gas: 27395) -FeeManagerProcessFeeTest:test_V2PayloadWithoutZeroFee() (gas: 70370) -FeeManagerProcessFeeTest:test_WithdrawERC20() (gas: 71617) -FeeManagerProcessFeeTest:test_WithdrawNonAdminAddr() (gas: 56261) -FeeManagerProcessFeeTest:test_WithdrawUnwrappedNative() (gas: 25322) -FeeManagerProcessFeeTest:test_baseFeeIsAppliedForLink() (gas: 14347) -FeeManagerProcessFeeTest:test_baseFeeIsAppliedForNative() (gas: 17285) -FeeManagerProcessFeeTest:test_correctDiscountIsAppliedWhenBothTokensAreDiscounted() (gas: 90297) -FeeManagerProcessFeeTest:test_discountAIsNotAppliedWhenSetForOtherUsers() (gas: 56177) -FeeManagerProcessFeeTest:test_discountFeeRoundsDownWhenUneven() (gas: 52490) -FeeManagerProcessFeeTest:test_discountIsAppliedForLink() (gas: 49279) -FeeManagerProcessFeeTest:test_discountIsAppliedWith100PercentSurcharge() (gas: 78538) -FeeManagerProcessFeeTest:test_discountIsNoLongerAppliedAfterRemoving() (gas: 45940) -FeeManagerProcessFeeTest:test_discountIsNotAppliedForInvalidTokenAddress() (gas: 17546) -FeeManagerProcessFeeTest:test_discountIsNotAppliedToOtherFeeds() (gas: 54247) -FeeManagerProcessFeeTest:test_discountIsReturnedForLink() (gas: 49254) -FeeManagerProcessFeeTest:test_emptyQuoteRevertsWithError() (gas: 12152) -FeeManagerProcessFeeTest:test_eventIsEmittedAfterSurchargeIsSet() (gas: 41348) -FeeManagerProcessFeeTest:test_eventIsEmittedIfNotEnoughLink() (gas: 172747) -FeeManagerProcessFeeTest:test_eventIsEmittedUponWithdraw() (gas: 68984) -FeeManagerProcessFeeTest:test_feeIsUpdatedAfterDiscountIsRemoved() (gas: 49186) -FeeManagerProcessFeeTest:test_feeIsUpdatedAfterNewDiscountIsApplied() (gas: 66985) -FeeManagerProcessFeeTest:test_feeIsUpdatedAfterNewSurchargeIsApplied() (gas: 63666) -FeeManagerProcessFeeTest:test_feeIsZeroWith100PercentDiscount() (gas: 51688) -FeeManagerProcessFeeTest:test_getBaseRewardWithLinkQuote() (gas: 14364) -FeeManagerProcessFeeTest:test_getLinkFeeIsRoundedUp() (gas: 49472) -FeeManagerProcessFeeTest:test_getLinkRewardIsSameAsFee() (gas: 54936) -FeeManagerProcessFeeTest:test_getLinkRewardWithNativeQuoteAndSurchargeWithLinkDiscount() (gas: 82400) -FeeManagerProcessFeeTest:test_getRewardWithLinkDiscount() (gas: 49297) -FeeManagerProcessFeeTest:test_getRewardWithLinkQuoteAndLinkDiscount() (gas: 49300) -FeeManagerProcessFeeTest:test_getRewardWithNativeQuote() (gas: 17305) -FeeManagerProcessFeeTest:test_getRewardWithNativeQuoteAndSurcharge() (gas: 50487) -FeeManagerProcessFeeTest:test_linkAvailableForPaymentReturnsLinkBalance() (gas: 52419) -FeeManagerProcessFeeTest:test_nativeSurcharge0Percent() (gas: 30497) -FeeManagerProcessFeeTest:test_nativeSurcharge100Percent() (gas: 50512) -FeeManagerProcessFeeTest:test_nativeSurchargeCannotExceed100Percent() (gas: 17167) -FeeManagerProcessFeeTest:test_nativeSurchargeEventIsEmittedOnUpdate() (gas: 41394) -FeeManagerProcessFeeTest:test_noFeeIsAppliedWhenReportHasZeroFee() (gas: 51511) -FeeManagerProcessFeeTest:test_noFeeIsAppliedWhenReportHasZeroFeeAndDiscountAndSurchargeIsSet() (gas: 77739) -FeeManagerProcessFeeTest:test_nonAdminProxyUserCannotProcessFee() (gas: 21881) -FeeManagerProcessFeeTest:test_nonAdminUserCanNotSetDiscount() (gas: 19835) -FeeManagerProcessFeeTest:test_payLinkDeficit() (gas: 193861) -FeeManagerProcessFeeTest:test_payLinkDeficitOnlyCallableByAdmin() (gas: 17405) -FeeManagerProcessFeeTest:test_payLinkDeficitPaysAllFeesProcessed() (gas: 213908) -FeeManagerProcessFeeTest:test_payLinkDeficitTwice() (gas: 198228) -FeeManagerProcessFeeTest:test_processFeeAsProxy() (gas: 116432) -FeeManagerProcessFeeTest:test_processFeeDefaultReportsStillVerifiesWithEmptyQuote() (gas: 27468) -FeeManagerProcessFeeTest:test_processFeeEmitsEventIfNotEnoughLink() (gas: 161843) -FeeManagerProcessFeeTest:test_processFeeIfSubscriberIsSelf() (gas: 27822) -FeeManagerProcessFeeTest:test_processFeeNative() (gas: 172464) -FeeManagerProcessFeeTest:test_processFeeUsesCorrectDigest() (gas: 117392) -FeeManagerProcessFeeTest:test_processFeeWithDefaultReportPayloadAndQuoteStillVerifies() (gas: 29542) -FeeManagerProcessFeeTest:test_processFeeWithDiscountEmitsEvent() (gas: 241293) -FeeManagerProcessFeeTest:test_processFeeWithInvalidReportVersionFailsToDecode() (gas: 28517) -FeeManagerProcessFeeTest:test_processFeeWithNoDiscountDoesNotEmitEvent() (gas: 166406) -FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNative() (gas: 179998) -FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeLinkAddress() (gas: 131461) -FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeLinkAddressExcessiveFee() (gas: 155390) -FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeShortFunds() (gas: 92630) -FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeWithExcessiveFee() (gas: 186961) -FeeManagerProcessFeeTest:test_processFeeWithWithCorruptQuotePayload() (gas: 70681) -FeeManagerProcessFeeTest:test_processFeeWithWithEmptyQuotePayload() (gas: 27733) -FeeManagerProcessFeeTest:test_processFeeWithWithZeroQuotePayload() (gas: 27783) -FeeManagerProcessFeeTest:test_processFeeWithZeroLinkNonZeroNativeWithLinkQuote() (gas: 32973) -FeeManagerProcessFeeTest:test_processFeeWithZeroLinkNonZeroNativeWithNativeQuote() (gas: 152363) -FeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkReturnsChange() (gas: 53470) -FeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkWithLinkQuote() (gas: 116343) -FeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkWithNativeQuote() (gas: 35744) -FeeManagerProcessFeeTest:test_processMultipleLinkReports() (gas: 221473) -FeeManagerProcessFeeTest:test_processMultipleUnwrappedNativeReports() (gas: 255314) -FeeManagerProcessFeeTest:test_processMultipleV1Reports() (gas: 74137) -FeeManagerProcessFeeTest:test_processMultipleWrappedNativeReports() (gas: 238439) -FeeManagerProcessFeeTest:test_processV1V2V3Reports() (gas: 206233) -FeeManagerProcessFeeTest:test_processV1V2V3ReportsWithUnwrapped() (gas: 247907) -FeeManagerProcessFeeTest:test_reportWithNoExpiryOrFeeReturnsZero() (gas: 10770) -FeeManagerProcessFeeTest:test_setDiscountOver100Percent() (gas: 19548) -FeeManagerProcessFeeTest:test_subscriberDiscountEventIsEmittedOnUpdate() (gas: 46259) -FeeManagerProcessFeeTest:test_surchargeFeeRoundsUpWhenUneven() (gas: 50864) -FeeManagerProcessFeeTest:test_surchargeIsApplied() (gas: 50745) -FeeManagerProcessFeeTest:test_surchargeIsAppliedForNativeFeeWithDiscount() (gas: 78900) -FeeManagerProcessFeeTest:test_surchargeIsNoLongerAppliedAfterRemoving() (gas: 46514) -FeeManagerProcessFeeTest:test_surchargeIsNotAppliedForLinkFee() (gas: 49587) -FeeManagerProcessFeeTest:test_surchargeIsNotAppliedWith100PercentDiscount() (gas: 77896) -FeeManagerProcessFeeTest:test_testRevertIfReportHasExpired() (gas: 14908) -RewardManagerClaimTest:test_claimAllRecipients() (gas: 275763) -RewardManagerClaimTest:test_claimMultipleRecipients() (gas: 153308) -RewardManagerClaimTest:test_claimRewardsWithDuplicatePoolIdsDoesNotPayoutTwice() (gas: 328345) -RewardManagerClaimTest:test_claimSingleRecipient() (gas: 88340) -RewardManagerClaimTest:test_claimUnevenAmountRoundsDown() (gas: 313549) -RewardManagerClaimTest:test_claimUnregisteredPoolId() (gas: 34461) -RewardManagerClaimTest:test_claimUnregisteredRecipient() (gas: 40491) +ByteUtilTest:test_readZeroAddress() (gas: 3365) +FeeManagerProcessFeeTest:test_DiscountIsAppliedForNative() (gas: 52645) +FeeManagerProcessFeeTest:test_DiscountIsReturnedForNative() (gas: 52595) +FeeManagerProcessFeeTest:test_DiscountIsReturnedForNativeWithSurcharge() (gas: 78808) +FeeManagerProcessFeeTest:test_V1PayloadVerifies() (gas: 26974) +FeeManagerProcessFeeTest:test_V1PayloadVerifiesAndReturnsChange() (gas: 58904) +FeeManagerProcessFeeTest:test_V2PayloadVerifies() (gas: 116750) +FeeManagerProcessFeeTest:test_V2PayloadWithoutQuoteFails() (gas: 27389) +FeeManagerProcessFeeTest:test_V2PayloadWithoutZeroFee() (gas: 70364) +FeeManagerProcessFeeTest:test_WithdrawERC20() (gas: 72682) +FeeManagerProcessFeeTest:test_WithdrawNonAdminAddr() (gas: 56286) +FeeManagerProcessFeeTest:test_WithdrawUnwrappedNative() (gas: 26387) +FeeManagerProcessFeeTest:test_baseFeeIsAppliedForLink() (gas: 17190) +FeeManagerProcessFeeTest:test_baseFeeIsAppliedForNative() (gas: 20128) +FeeManagerProcessFeeTest:test_correctDiscountIsAppliedWhenBothTokensAreDiscounted() (gas: 91011) +FeeManagerProcessFeeTest:test_discountAIsNotAppliedWhenSetForOtherUsers() (gas: 56534) +FeeManagerProcessFeeTest:test_discountFeeRoundsDownWhenUneven() (gas: 52847) +FeeManagerProcessFeeTest:test_discountIsAppliedForLink() (gas: 49636) +FeeManagerProcessFeeTest:test_discountIsAppliedWith100PercentSurcharge() (gas: 78903) +FeeManagerProcessFeeTest:test_discountIsNoLongerAppliedAfterRemoving() (gas: 46511) +FeeManagerProcessFeeTest:test_discountIsNotAppliedForInvalidTokenAddress() (gas: 17560) +FeeManagerProcessFeeTest:test_discountIsNotAppliedToOtherFeeds() (gas: 54604) +FeeManagerProcessFeeTest:test_discountIsReturnedForLink() (gas: 49608) +FeeManagerProcessFeeTest:test_emptyQuoteRevertsWithError() (gas: 12163) +FeeManagerProcessFeeTest:test_eventIsEmittedAfterSurchargeIsSet() (gas: 41356) +FeeManagerProcessFeeTest:test_eventIsEmittedIfNotEnoughLink() (gas: 173756) +FeeManagerProcessFeeTest:test_eventIsEmittedUponWithdraw() (gas: 69009) +FeeManagerProcessFeeTest:test_feeIsUpdatedAfterDiscountIsRemoved() (gas: 49757) +FeeManagerProcessFeeTest:test_feeIsUpdatedAfterNewDiscountIsApplied() (gas: 67699) +FeeManagerProcessFeeTest:test_feeIsUpdatedAfterNewSurchargeIsApplied() (gas: 64368) +FeeManagerProcessFeeTest:test_feeIsZeroWith100PercentDiscount() (gas: 52045) +FeeManagerProcessFeeTest:test_getBaseRewardWithLinkQuote() (gas: 17207) +FeeManagerProcessFeeTest:test_getLinkFeeIsRoundedUp() (gas: 49829) +FeeManagerProcessFeeTest:test_getLinkRewardIsSameAsFee() (gas: 55641) +FeeManagerProcessFeeTest:test_getLinkRewardWithNativeQuoteAndSurchargeWithLinkDiscount() (gas: 82765) +FeeManagerProcessFeeTest:test_getRewardWithLinkDiscount() (gas: 49654) +FeeManagerProcessFeeTest:test_getRewardWithLinkQuoteAndLinkDiscount() (gas: 49657) +FeeManagerProcessFeeTest:test_getRewardWithNativeQuote() (gas: 20148) +FeeManagerProcessFeeTest:test_getRewardWithNativeQuoteAndSurcharge() (gas: 50838) +FeeManagerProcessFeeTest:test_linkAvailableForPaymentReturnsLinkBalance() (gas: 53192) +FeeManagerProcessFeeTest:test_nativeSurcharge0Percent() (gas: 30848) +FeeManagerProcessFeeTest:test_nativeSurcharge100Percent() (gas: 50863) +FeeManagerProcessFeeTest:test_nativeSurchargeCannotExceed100Percent() (gas: 17175) +FeeManagerProcessFeeTest:test_nativeSurchargeEventIsEmittedOnUpdate() (gas: 41402) +FeeManagerProcessFeeTest:test_noFeeIsAppliedWhenReportHasZeroFee() (gas: 51868) +FeeManagerProcessFeeTest:test_noFeeIsAppliedWhenReportHasZeroFeeAndDiscountAndSurchargeIsSet() (gas: 78104) +FeeManagerProcessFeeTest:test_nonAdminProxyUserCannotProcessFee() (gas: 21895) +FeeManagerProcessFeeTest:test_nonAdminUserCanNotSetDiscount() (gas: 19849) +FeeManagerProcessFeeTest:test_payLinkDeficit() (gas: 194429) +FeeManagerProcessFeeTest:test_payLinkDeficitOnlyCallableByAdmin() (gas: 17413) +FeeManagerProcessFeeTest:test_payLinkDeficitPaysAllFeesProcessed() (gas: 214755) +FeeManagerProcessFeeTest:test_payLinkDeficitTwice() (gas: 198803) +FeeManagerProcessFeeTest:test_processFeeAsProxy() (gas: 117088) +FeeManagerProcessFeeTest:test_processFeeDefaultReportsStillVerifiesWithEmptyQuote() (gas: 27462) +FeeManagerProcessFeeTest:test_processFeeEmitsEventIfNotEnoughLink() (gas: 163205) +FeeManagerProcessFeeTest:test_processFeeIfSubscriberIsSelf() (gas: 27827) +FeeManagerProcessFeeTest:test_processFeeNative() (gas: 173826) +FeeManagerProcessFeeTest:test_processFeeUsesCorrectDigest() (gas: 118379) +FeeManagerProcessFeeTest:test_processFeeWithDefaultReportPayloadAndQuoteStillVerifies() (gas: 29536) +FeeManagerProcessFeeTest:test_processFeeWithDiscountEmitsEvent() (gas: 241353) +FeeManagerProcessFeeTest:test_processFeeWithInvalidReportVersionFailsToDecode() (gas: 28511) +FeeManagerProcessFeeTest:test_processFeeWithNoDiscountDoesNotEmitEvent() (gas: 166753) +FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNative() (gas: 181691) +FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeLinkAddress() (gas: 131466) +FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeLinkAddressExcessiveFee() (gas: 157072) +FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeShortFunds() (gas: 92635) +FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeWithExcessiveFee() (gas: 188654) +FeeManagerProcessFeeTest:test_processFeeWithWithCorruptQuotePayload() (gas: 70675) +FeeManagerProcessFeeTest:test_processFeeWithWithEmptyQuotePayload() (gas: 27727) +FeeManagerProcessFeeTest:test_processFeeWithWithZeroQuotePayload() (gas: 27777) +FeeManagerProcessFeeTest:test_processFeeWithZeroLinkNonZeroNativeWithLinkQuote() (gas: 32967) +FeeManagerProcessFeeTest:test_processFeeWithZeroLinkNonZeroNativeWithNativeQuote() (gas: 153725) +FeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkReturnsChange() (gas: 53795) +FeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkWithLinkQuote() (gas: 116999) +FeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkWithNativeQuote() (gas: 35738) +FeeManagerProcessFeeTest:test_processMultipleLinkReports() (gas: 223133) +FeeManagerProcessFeeTest:test_processMultipleUnwrappedNativeReports() (gas: 256996) +FeeManagerProcessFeeTest:test_processMultipleV1Reports() (gas: 74793) +FeeManagerProcessFeeTest:test_processMultipleWrappedNativeReports() (gas: 239801) +FeeManagerProcessFeeTest:test_processV1V2V3Reports() (gas: 207915) +FeeManagerProcessFeeTest:test_processV1V2V3ReportsWithUnwrapped() (gas: 249580) +FeeManagerProcessFeeTest:test_reportWithNoExpiryOrFeeReturnsZero() (gas: 13613) +FeeManagerProcessFeeTest:test_setDiscountOver100Percent() (gas: 19562) +FeeManagerProcessFeeTest:test_subscriberDiscountEventIsEmittedOnUpdate() (gas: 46261) +FeeManagerProcessFeeTest:test_surchargeFeeRoundsUpWhenUneven() (gas: 51215) +FeeManagerProcessFeeTest:test_surchargeIsApplied() (gas: 51096) +FeeManagerProcessFeeTest:test_surchargeIsAppliedForNativeFeeWithDiscount() (gas: 79265) +FeeManagerProcessFeeTest:test_surchargeIsNoLongerAppliedAfterRemoving() (gas: 47076) +FeeManagerProcessFeeTest:test_surchargeIsNotAppliedForLinkFee() (gas: 49938) +FeeManagerProcessFeeTest:test_surchargeIsNotAppliedWith100PercentDiscount() (gas: 78261) +FeeManagerProcessFeeTest:test_testRevertIfReportHasExpired() (gas: 14919) +RewardManagerClaimTest:test_claimAllRecipients() (gas: 277131) +RewardManagerClaimTest:test_claimMultipleRecipients() (gas: 154341) +RewardManagerClaimTest:test_claimRewardsWithDuplicatePoolIdsDoesNotPayoutTwice() (gas: 330086) +RewardManagerClaimTest:test_claimSingleRecipient() (gas: 89024) +RewardManagerClaimTest:test_claimUnevenAmountRoundsDown() (gas: 315289) +RewardManagerClaimTest:test_claimUnregisteredPoolId() (gas: 35145) +RewardManagerClaimTest:test_claimUnregisteredRecipient() (gas: 41182) RewardManagerClaimTest:test_eventIsEmittedUponClaim() (gas: 86069) -RewardManagerClaimTest:test_eventIsNotEmittedUponUnsuccessfulClaim() (gas: 24700) -RewardManagerClaimTest:test_recipientsClaimMultipleDeposits() (gas: 383222) -RewardManagerClaimTest:test_singleRecipientClaimMultipleDeposits() (gas: 136295) -RewardManagerNoRecipientSet:test_claimAllRecipientsAfterRecipientsSet() (gas: 489377) -RewardManagerPayRecipientsTest:test_addFundsToPoolAsNonOwnerOrFeeManager() (gas: 11428) -RewardManagerPayRecipientsTest:test_addFundsToPoolAsOwner() (gas: 53876) -RewardManagerPayRecipientsTest:test_payAllRecipients() (gas: 249472) +RewardManagerClaimTest:test_eventIsNotEmittedUponUnsuccessfulClaim() (gas: 25031) +RewardManagerClaimTest:test_recipientsClaimMultipleDeposits() (gas: 386675) +RewardManagerClaimTest:test_singleRecipientClaimMultipleDeposits() (gas: 137685) +RewardManagerNoRecipientSet:test_claimAllRecipientsAfterRecipientsSet() (gas: 492113) +RewardManagerPayRecipientsTest:test_addFundsToPoolAsNonOwnerOrFeeManager() (gas: 11437) +RewardManagerPayRecipientsTest:test_addFundsToPoolAsOwner() (gas: 53894) +RewardManagerPayRecipientsTest:test_payAllRecipients() (gas: 250840) RewardManagerPayRecipientsTest:test_payAllRecipientsFromNonAdminUser() (gas: 20475) -RewardManagerPayRecipientsTest:test_payAllRecipientsFromRecipientInPool() (gas: 249718) -RewardManagerPayRecipientsTest:test_payAllRecipientsWithAdditionalInvalidRecipient() (gas: 260922) -RewardManagerPayRecipientsTest:test_payAllRecipientsWithAdditionalUnregisteredRecipient() (gas: 264058) -RewardManagerPayRecipientsTest:test_payRecipientWithInvalidPool() (gas: 28549) -RewardManagerPayRecipientsTest:test_payRecipientsEmptyRecipientList() (gas: 24970) -RewardManagerPayRecipientsTest:test_payRecipientsWithInvalidPoolId() (gas: 31055) -RewardManagerPayRecipientsTest:test_paySingleRecipient() (gas: 84354) -RewardManagerPayRecipientsTest:test_paySubsetOfRecipientsInPool() (gas: 197451) -RewardManagerRecipientClaimDifferentWeightsTest:test_allRecipientsClaimingReceiveExpectedAmount() (gas: 279425) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimAllRecipientsMultiplePools() (gas: 509891) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimAllRecipientsSinglePool() (gas: 281811) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimEmptyPoolWhenSecondPoolContainsFunds() (gas: 291640) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimMultipleRecipientsMultiplePools() (gas: 261591) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimMultipleRecipientsSinglePool() (gas: 153438) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimSingleRecipientMultiplePools() (gas: 131915) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimSingleUniqueRecipient() (gas: 105314) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimUnevenAmountRoundsDown() (gas: 576291) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimUnregisteredRecipient() (gas: 63557) -RewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorAndTotalPoolsEqual() (gas: 10202) +RewardManagerPayRecipientsTest:test_payAllRecipientsFromRecipientInPool() (gas: 251086) +RewardManagerPayRecipientsTest:test_payAllRecipientsWithAdditionalInvalidRecipient() (gas: 262290) +RewardManagerPayRecipientsTest:test_payAllRecipientsWithAdditionalUnregisteredRecipient() (gas: 265775) +RewardManagerPayRecipientsTest:test_payRecipientWithInvalidPool() (gas: 28891) +RewardManagerPayRecipientsTest:test_payRecipientsEmptyRecipientList() (gas: 25312) +RewardManagerPayRecipientsTest:test_payRecipientsWithInvalidPoolId() (gas: 31397) +RewardManagerPayRecipientsTest:test_paySingleRecipient() (gas: 84696) +RewardManagerPayRecipientsTest:test_paySubsetOfRecipientsInPool() (gas: 198477) +RewardManagerRecipientClaimDifferentWeightsTest:test_allRecipientsClaimingReceiveExpectedAmount() (gas: 280793) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimAllRecipientsMultiplePools() (gas: 512369) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimAllRecipientsSinglePool() (gas: 283589) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimEmptyPoolWhenSecondPoolContainsFunds() (gas: 293418) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimMultipleRecipientsMultiplePools() (gas: 263015) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimMultipleRecipientsSinglePool() (gas: 154507) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimSingleRecipientMultiplePools() (gas: 132623) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimSingleUniqueRecipient() (gas: 106022) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimUnevenAmountRoundsDown() (gas: 579532) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimUnregisteredRecipient() (gas: 64626) +RewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorAndTotalPoolsEqual() (gas: 13051) RewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorCannotBeGreaterThanTotalPools() (gas: 12680) -RewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorSingleResult() (gas: 19606) -RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInBothPools() (gas: 29052) -RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInBothPoolsWhereAlreadyClaimed() (gas: 147218) -RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInNoPools() (gas: 18532) -RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInSinglePool() (gas: 24569) -RewardManagerRecipientClaimMultiplePoolsTest:test_recipientsClaimMultipleDeposits() (gas: 387672) -RewardManagerRecipientClaimMultiplePoolsTest:test_singleRecipientClaimMultipleDeposits() (gas: 136332) -RewardManagerRecipientClaimUnevenWeightTest:test_allRecipientsClaimingReceiveExpectedAmount() (gas: 198399) -RewardManagerRecipientClaimUnevenWeightTest:test_allRecipientsClaimingReceiveExpectedAmountWithSmallDeposit() (gas: 218269) +RewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorSingleResult() (gas: 22448) +RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInBothPools() (gas: 32225) +RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInBothPoolsWhereAlreadyClaimed() (gas: 148553) +RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInNoPools() (gas: 21705) +RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInSinglePool() (gas: 27742) +RewardManagerRecipientClaimMultiplePoolsTest:test_recipientsClaimMultipleDeposits() (gas: 391245) +RewardManagerRecipientClaimMultiplePoolsTest:test_singleRecipientClaimMultipleDeposits() (gas: 137770) +RewardManagerRecipientClaimUnevenWeightTest:test_allRecipientsClaimingReceiveExpectedAmount() (gas: 199454) +RewardManagerRecipientClaimUnevenWeightTest:test_allRecipientsClaimingReceiveExpectedAmountWithSmallDeposit() (gas: 219327) RewardManagerSetRecipientsTest:test_eventIsEmittedUponSetRecipients() (gas: 191729) RewardManagerSetRecipientsTest:test_setRecipientContainsDuplicateRecipients() (gas: 126082) RewardManagerSetRecipientsTest:test_setRewardRecipientFromManagerAddress() (gas: 193880) @@ -165,19 +165,19 @@ RewardManagerSetRecipientsTest:test_setRewardRecipients() (gas: 185589) RewardManagerSetRecipientsTest:test_setRewardRecipientsIsEmpty() (gas: 87113) RewardManagerSetRecipientsTest:test_setSingleRewardRecipient() (gas: 110371) RewardManagerSetupTest:test_eventEmittedUponFeeManagerUpdate() (gas: 21388) -RewardManagerSetupTest:test_eventEmittedUponFeePaid() (gas: 259121) +RewardManagerSetupTest:test_eventEmittedUponFeePaid() (gas: 259132) RewardManagerSetupTest:test_rejectsZeroLinkAddressOnConstruction() (gas: 59411) RewardManagerSetupTest:test_setFeeManagerZeroAddress() (gas: 17038) -RewardManagerUpdateRewardRecipientsMultiplePoolsTest:test_updatePrimaryRecipientWeights() (gas: 373525) -RewardManagerUpdateRewardRecipientsTest:test_eventIsEmittedUponUpdateRecipients() (gas: 279119) +RewardManagerUpdateRewardRecipientsMultiplePoolsTest:test_updatePrimaryRecipientWeights() (gas: 376628) +RewardManagerUpdateRewardRecipientsTest:test_eventIsEmittedUponUpdateRecipients() (gas: 280487) RewardManagerUpdateRewardRecipientsTest:test_onlyAdminCanUpdateRecipients() (gas: 19749) -RewardManagerUpdateRewardRecipientsTest:test_partialUpdateRecipientWeights() (gas: 218898) -RewardManagerUpdateRewardRecipientsTest:test_updateAllRecipientsWithSameAddressAndWeight() (gas: 272941) +RewardManagerUpdateRewardRecipientsTest:test_partialUpdateRecipientWeights() (gas: 220972) +RewardManagerUpdateRewardRecipientsTest:test_updateAllRecipientsWithSameAddressAndWeight() (gas: 274309) RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsToSubset() (gas: 254232) RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsWithExcessiveWeight() (gas: 259219) -RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsWithSameAddressAndWeight() (gas: 148890) +RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsWithSameAddressAndWeight() (gas: 149916) RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsWithUnderWeightSet() (gas: 259293) -RewardManagerUpdateRewardRecipientsTest:test_updateRecipientWeights() (gas: 369006) +RewardManagerUpdateRewardRecipientsTest:test_updateRecipientWeights() (gas: 372109) RewardManagerUpdateRewardRecipientsTest:test_updateRecipientWithNewZeroAddress() (gas: 270780) RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsContainsDuplicateRecipients() (gas: 288575) RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentLargerSet() (gas: 407876) @@ -186,95 +186,95 @@ RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentSet() (g RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentSetWithInvalidWeights() (gas: 312122) RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsUpdateAndRemoveExistingForLargerSet() (gas: 399699) RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsUpdateAndRemoveExistingForSmallerSet() (gas: 289513) -VerificationdeactivateConfigWhenThereAreMultipleDigestsTest:test_correctlyRemovesAMiddleDigest() (gas: 24177) -VerificationdeactivateConfigWhenThereAreMultipleDigestsTest:test_correctlyRemovesTheFirstDigest() (gas: 24144) -VerificationdeactivateConfigWhenThereAreMultipleDigestsTest:test_correctlyUnsetsDigestsInSequence() (gas: 44109) +VerificationdeactivateConfigWhenThereAreMultipleDigestsTest:test_correctlyRemovesAMiddleDigest() (gas: 27017) +VerificationdeactivateConfigWhenThereAreMultipleDigestsTest:test_correctlyRemovesTheFirstDigest() (gas: 26984) +VerificationdeactivateConfigWhenThereAreMultipleDigestsTest:test_correctlyUnsetsDigestsInSequence() (gas: 45102) VerificationdeactivateConfigWhenThereAreMultipleDigestsTest:test_revertsIfCalledByNonOwner() (gas: 15016) VerificationdeactivateConfigWhenThereAreMultipleDigestsTest:test_revertsIfRemovingAnEmptyDigest() (gas: 10907) VerificationdeactivateConfigWhenThereAreMultipleDigestsTest:test_revertsIfRemovingAnNonExistentDigest() (gas: 13381) VerifierActivateConfigTest:test_revertsIfDigestIsEmpty() (gas: 10984) VerifierActivateConfigTest:test_revertsIfDigestNotSet() (gas: 13394) -VerifierActivateConfigTest:test_revertsIfNotOwner() (gas: 17171) -VerifierActivateConfigWithDeactivatedConfigTest:test_allowsVerification() (gas: 97164) +VerifierActivateConfigTest:test_revertsIfNotOwner() (gas: 17182) +VerifierActivateConfigWithDeactivatedConfigTest:test_allowsVerification() (gas: 97175) VerifierActivateFeedTest:test_revertsIfNoFeedExistsActivate() (gas: 13179) VerifierActivateFeedTest:test_revertsIfNoFeedExistsDeactivate() (gas: 13157) -VerifierActivateFeedTest:test_revertsIfNotOwnerActivateFeed() (gas: 17098) -VerifierActivateFeedTest:test_revertsIfNotOwnerDeactivateFeed() (gas: 17153) -VerifierBulkVerifyBillingReport:test_verifyMultiVersions() (gas: 475585) -VerifierBulkVerifyBillingReport:test_verifyMultiVersionsReturnsVerifiedReports() (gas: 681857) -VerifierBulkVerifyBillingReport:test_verifyWithBulkLink() (gas: 556863) -VerifierBulkVerifyBillingReport:test_verifyWithBulkNative() (gas: 560460) -VerifierBulkVerifyBillingReport:test_verifyWithBulkNativeUnwrapped() (gas: 567951) -VerifierBulkVerifyBillingReport:test_verifyWithBulkNativeUnwrappedReturnsChange() (gas: 574957) +VerifierActivateFeedTest:test_revertsIfNotOwnerActivateFeed() (gas: 17109) +VerifierActivateFeedTest:test_revertsIfNotOwnerDeactivateFeed() (gas: 17164) +VerifierBulkVerifyBillingReport:test_verifyMultiVersions() (gas: 476595) +VerifierBulkVerifyBillingReport:test_verifyMultiVersionsReturnsVerifiedReports() (gas: 474853) +VerifierBulkVerifyBillingReport:test_verifyWithBulkLink() (gas: 557541) +VerifierBulkVerifyBillingReport:test_verifyWithBulkNative() (gas: 560806) +VerifierBulkVerifyBillingReport:test_verifyWithBulkNativeUnwrapped() (gas: 568629) +VerifierBulkVerifyBillingReport:test_verifyWithBulkNativeUnwrappedReturnsChange() (gas: 575635) VerifierConstructorTest:test_revertsIfInitializedWithEmptyVerifierProxy() (gas: 59960) -VerifierConstructorTest:test_setsTheCorrectProperties() (gas: 1808155) -VerifierDeactivateFeedWithVerifyTest:test_currentReportAllowsVerification() (gas: 192062) -VerifierDeactivateFeedWithVerifyTest:test_currentReportFailsVerification() (gas: 113377) -VerifierDeactivateFeedWithVerifyTest:test_previousReportAllowsVerification() (gas: 99613) -VerifierDeactivateFeedWithVerifyTest:test_previousReportFailsVerification() (gas: 69932) -VerifierProxyAccessControlledVerificationTest:test_proxiesToTheVerifierIfHasAccess() (gas: 205796) -VerifierProxyAccessControlledVerificationTest:test_revertsIfNoAccess() (gas: 112334) -VerifierProxyConstructorTest:test_correctlySetsTheCorrectAccessControllerInterface() (gas: 1482522) -VerifierProxyConstructorTest:test_correctlySetsTheOwner() (gas: 1462646) -VerifierProxyConstructorTest:test_correctlySetsVersion() (gas: 6873) -VerifierProxyInitializeVerifierTest:test_revertsIfDigestAlreadySet() (gas: 54108) -VerifierProxyInitializeVerifierTest:test_revertsIfNotCorrectVerifier() (gas: 13595) -VerifierProxyInitializeVerifierTest:test_revertsIfNotOwner() (gas: 17157) -VerifierProxyInitializeVerifierTest:test_revertsIfVerifierAlreadyInitialized() (gas: 42025) -VerifierProxyInitializeVerifierTest:test_revertsIfZeroAddress() (gas: 10948) -VerifierProxyInitializeVerifierTest:test_setFeeManagerWhichDoesntHonourIERC165Interface() (gas: 13815) -VerifierProxyInitializeVerifierTest:test_setFeeManagerWhichDoesntHonourInterface() (gas: 16301) -VerifierProxyInitializeVerifierTest:test_setFeeManagerZeroAddress() (gas: 10947) -VerifierProxyInitializeVerifierTest:test_updatesVerifierIfVerifier() (gas: 53406) -VerifierProxySetAccessControllerTest:test_emitsTheCorrectEvent() (gas: 35340) -VerifierProxySetAccessControllerTest:test_revertsIfCalledByNonOwner() (gas: 15061) -VerifierProxySetAccessControllerTest:test_successfullySetsNewAccessController() (gas: 32032) -VerifierProxySetAccessControllerTest:test_successfullySetsNewAccessControllerIsEmpty() (gas: 12131) -VerifierProxyUnsetVerifierTest:test_revertsIfDigestDoesNotExist() (gas: 13141) -VerifierProxyUnsetVerifierTest:test_revertsIfNotAdmin() (gas: 14965) -VerifierProxyUnsetVerifierWithPreviouslySetVerifierTest:test_correctlyUnsetsVerifier() (gas: 12720) -VerifierProxyUnsetVerifierWithPreviouslySetVerifierTest:test_emitsAnEventAfterUnsettingVerifier() (gas: 17965) -VerifierProxyVerifyTest:test_proxiesToTheCorrectVerifier() (gas: 201609) -VerifierProxyVerifyTest:test_revertsIfNoVerifierConfigured() (gas: 117256) -VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlySetsConfigWhenDigestsAreRemoved() (gas: 538898) -VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlyUpdatesDigestsOnMultipleVerifiersInTheProxy() (gas: 964730) -VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlyUpdatesTheDigestInTheProxy() (gas: 520482) +VerifierConstructorTest:test_setsTheCorrectProperties() (gas: 1813269) +VerifierDeactivateFeedWithVerifyTest:test_currentReportAllowsVerification() (gas: 192073) +VerifierDeactivateFeedWithVerifyTest:test_currentReportFailsVerification() (gas: 113388) +VerifierDeactivateFeedWithVerifyTest:test_previousReportAllowsVerification() (gas: 99624) +VerifierDeactivateFeedWithVerifyTest:test_previousReportFailsVerification() (gas: 69943) +VerifierProxyAccessControlledVerificationTest:test_proxiesToTheVerifierIfHasAccess() (gas: 208529) +VerifierProxyAccessControlledVerificationTest:test_revertsIfNoAccess() (gas: 112345) +VerifierProxyConstructorTest:test_correctlySetsTheCorrectAccessControllerInterface() (gas: 1485359) +VerifierProxyConstructorTest:test_correctlySetsTheOwner() (gas: 1465483) +VerifierProxyConstructorTest:test_correctlySetsVersion() (gas: 9701) +VerifierProxyInitializeVerifierTest:test_revertsIfDigestAlreadySet() (gas: 54133) +VerifierProxyInitializeVerifierTest:test_revertsIfNotCorrectVerifier() (gas: 13613) +VerifierProxyInitializeVerifierTest:test_revertsIfNotOwner() (gas: 17168) +VerifierProxyInitializeVerifierTest:test_revertsIfVerifierAlreadyInitialized() (gas: 42047) +VerifierProxyInitializeVerifierTest:test_revertsIfZeroAddress() (gas: 10956) +VerifierProxyInitializeVerifierTest:test_setFeeManagerWhichDoesntHonourIERC165Interface() (gas: 13823) +VerifierProxyInitializeVerifierTest:test_setFeeManagerWhichDoesntHonourInterface() (gas: 16290) +VerifierProxyInitializeVerifierTest:test_setFeeManagerZeroAddress() (gas: 10933) +VerifierProxyInitializeVerifierTest:test_updatesVerifierIfVerifier() (gas: 54086) +VerifierProxySetAccessControllerTest:test_emitsTheCorrectEvent() (gas: 35348) +VerifierProxySetAccessControllerTest:test_revertsIfCalledByNonOwner() (gas: 15069) +VerifierProxySetAccessControllerTest:test_successfullySetsNewAccessController() (gas: 34921) +VerifierProxySetAccessControllerTest:test_successfullySetsNewAccessControllerIsEmpty() (gas: 15020) +VerifierProxyUnsetVerifierTest:test_revertsIfDigestDoesNotExist() (gas: 13149) +VerifierProxyUnsetVerifierTest:test_revertsIfNotAdmin() (gas: 14973) +VerifierProxyUnsetVerifierWithPreviouslySetVerifierTest:test_correctlyUnsetsVerifier() (gas: 15555) +VerifierProxyUnsetVerifierWithPreviouslySetVerifierTest:test_emitsAnEventAfterUnsettingVerifier() (gas: 17961) +VerifierProxyVerifyTest:test_proxiesToTheCorrectVerifier() (gas: 204342) +VerifierProxyVerifyTest:test_revertsIfNoVerifierConfigured() (gas: 117264) +VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlySetsConfigWhenDigestsAreRemoved() (gas: 542302) +VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlyUpdatesDigestsOnMultipleVerifiersInTheProxy() (gas: 967768) +VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlyUpdatesTheDigestInTheProxy() (gas: 523251) VerifierSetConfigFromSourceTest:test_revertsIfCalledByNonOwner() (gas: 183217) -VerifierSetConfigTest:test_correctlyUpdatesTheConfig() (gas: 1057925) +VerifierSetConfigTest:test_correctlyUpdatesTheConfig() (gas: 1062438) VerifierSetConfigTest:test_revertsIfCalledByNonOwner() (gas: 182986) VerifierSetConfigTest:test_revertsIfDuplicateSigners() (gas: 251561) VerifierSetConfigTest:test_revertsIfFaultToleranceIsZero() (gas: 176543) VerifierSetConfigTest:test_revertsIfNotEnoughSigners() (gas: 15828) VerifierSetConfigTest:test_revertsIfSetWithTooManySigners() (gas: 22213) VerifierSetConfigTest:test_revertsIfSignerContainsZeroAddress() (gas: 228034) -VerifierSetConfigWhenThereAreMultipleDigestsTest:test_correctlySetsConfigWhenDigestsAreRemoved() (gas: 538647) -VerifierSetConfigWhenThereAreMultipleDigestsTest:test_correctlyUpdatesDigestsOnMultipleVerifiersInTheProxy() (gas: 964219) -VerifierSetConfigWhenThereAreMultipleDigestsTest:test_correctlyUpdatesTheDigestInTheProxy() (gas: 520222) -VerifierSupportsInterfaceTest:test_falseIfIsNotCorrectInterface() (gas: 5590) -VerifierSupportsInterfaceTest:test_trueIfIsCorrectInterface() (gas: 5633) -VerifierTestBillingReport:test_verifyWithLink() (gas: 274948) -VerifierTestBillingReport:test_verifyWithNative() (gas: 315650) -VerifierTestBillingReport:test_verifyWithNativeUnwrapped() (gas: 317898) -VerifierTestBillingReport:test_verifyWithNativeUnwrappedReturnsChange() (gas: 324966) -VerifierVerifyMultipleConfigDigestTest:test_canVerifyNewerReportsWithNewerConfigs() (gas: 131228) -VerifierVerifyMultipleConfigDigestTest:test_canVerifyOlderReportsWithOlderConfigs() (gas: 187132) -VerifierVerifyMultipleConfigDigestTest:test_revertsIfAReportIsVerifiedWithAnExistingButIncorrectDigest() (gas: 88205) -VerifierVerifyMultipleConfigDigestTest:test_revertsIfVerifyingWithAnUnsetDigest() (gas: 128062) -VerifierVerifySingleConfigDigestTest:test_emitsAnEventIfReportVerified() (gas: 186945) -VerifierVerifySingleConfigDigestTest:test_returnsThePriceAndBlockNumIfReportVerified() (gas: 187114) -VerifierVerifySingleConfigDigestTest:test_revertsIfConfigDigestNotSet() (gas: 116130) -VerifierVerifySingleConfigDigestTest:test_revertsIfDuplicateSignersHaveSigned() (gas: 182315) -VerifierVerifySingleConfigDigestTest:test_revertsIfMismatchedSignatureLength() (gas: 53037) -VerifierVerifySingleConfigDigestTest:test_revertsIfReportHasUnconfiguredFeedID() (gas: 103976) +VerifierSetConfigWhenThereAreMultipleDigestsTest:test_correctlySetsConfigWhenDigestsAreRemoved() (gas: 542051) +VerifierSetConfigWhenThereAreMultipleDigestsTest:test_correctlyUpdatesDigestsOnMultipleVerifiersInTheProxy() (gas: 967257) +VerifierSetConfigWhenThereAreMultipleDigestsTest:test_correctlyUpdatesTheDigestInTheProxy() (gas: 522991) +VerifierSupportsInterfaceTest:test_falseIfIsNotCorrectInterface() (gas: 8421) +VerifierSupportsInterfaceTest:test_trueIfIsCorrectInterface() (gas: 8464) +VerifierTestBillingReport:test_verifyWithLink() (gas: 275293) +VerifierTestBillingReport:test_verifyWithNative() (gas: 316326) +VerifierTestBillingReport:test_verifyWithNativeUnwrapped() (gas: 318574) +VerifierTestBillingReport:test_verifyWithNativeUnwrappedReturnsChange() (gas: 325642) +VerifierVerifyMultipleConfigDigestTest:test_canVerifyNewerReportsWithNewerConfigs() (gas: 133961) +VerifierVerifyMultipleConfigDigestTest:test_canVerifyOlderReportsWithOlderConfigs() (gas: 189865) +VerifierVerifyMultipleConfigDigestTest:test_revertsIfAReportIsVerifiedWithAnExistingButIncorrectDigest() (gas: 88216) +VerifierVerifyMultipleConfigDigestTest:test_revertsIfVerifyingWithAnUnsetDigest() (gas: 128073) +VerifierVerifySingleConfigDigestTest:test_emitsAnEventIfReportVerified() (gas: 186956) +VerifierVerifySingleConfigDigestTest:test_returnsThePriceAndBlockNumIfReportVerified() (gas: 189847) +VerifierVerifySingleConfigDigestTest:test_revertsIfConfigDigestNotSet() (gas: 116141) +VerifierVerifySingleConfigDigestTest:test_revertsIfDuplicateSignersHaveSigned() (gas: 182326) +VerifierVerifySingleConfigDigestTest:test_revertsIfMismatchedSignatureLength() (gas: 53108) +VerifierVerifySingleConfigDigestTest:test_revertsIfReportHasUnconfiguredFeedID() (gas: 103987) VerifierVerifySingleConfigDigestTest:test_revertsIfVerifiedByNonProxy() (gas: 100992) -VerifierVerifySingleConfigDigestTest:test_revertsIfVerifiedWithIncorrectAddresses() (gas: 184066) -VerifierVerifySingleConfigDigestTest:test_revertsIfWrongNumberOfSigners() (gas: 110031) -VerifierVerifySingleConfigDigestTest:test_setsTheCorrectEpoch() (gas: 194270) -Verifier_accessControlledVerify:testVerifyWithAccessControl_gas() (gas: 212066) -Verifier_bulkVerifyWithFee:testBulkVerifyProxyWithLinkFeeSuccess_gas() (gas: 519378) -Verifier_bulkVerifyWithFee:testBulkVerifyProxyWithNativeFeeSuccess_gas() (gas: 542797) -Verifier_setConfig:testSetConfigSuccess_gas() (gas: 922684) -Verifier_verify:testVerifyProxySuccess_gas() (gas: 198731) -Verifier_verify:testVerifySuccess_gas() (gas: 186725) -Verifier_verifyWithFee:testVerifyProxyWithLinkFeeSuccess_gas() (gas: 238888) -Verifier_verifyWithFee:testVerifyProxyWithNativeFeeSuccess_gas() (gas: 257388) \ No newline at end of file +VerifierVerifySingleConfigDigestTest:test_revertsIfVerifiedWithIncorrectAddresses() (gas: 184077) +VerifierVerifySingleConfigDigestTest:test_revertsIfWrongNumberOfSigners() (gas: 110042) +VerifierVerifySingleConfigDigestTest:test_setsTheCorrectEpoch() (gas: 194592) +Verifier_accessControlledVerify:testVerifyWithAccessControl_gas() (gas: 212077) +Verifier_bulkVerifyWithFee:testBulkVerifyProxyWithLinkFeeSuccess_gas() (gas: 519389) +Verifier_bulkVerifyWithFee:testBulkVerifyProxyWithNativeFeeSuccess_gas() (gas: 542808) +Verifier_setConfig:testSetConfigSuccess_gas() (gas: 922616) +Verifier_verify:testVerifyProxySuccess_gas() (gas: 198742) +Verifier_verify:testVerifySuccess_gas() (gas: 186736) +Verifier_verifyWithFee:testVerifyProxyWithLinkFeeSuccess_gas() (gas: 238899) +Verifier_verifyWithFee:testVerifyProxyWithNativeFeeSuccess_gas() (gas: 257399) \ No newline at end of file diff --git a/contracts/gas-snapshots/operatorforwarder.gas-snapshot b/contracts/gas-snapshots/operatorforwarder.gas-snapshot new file mode 100644 index 00000000000..964c1a91b8d --- /dev/null +++ b/contracts/gas-snapshots/operatorforwarder.gas-snapshot @@ -0,0 +1,2 @@ +Operator_cancelRequest:test_Success(uint96) (runs: 256, μ: 306103, ~: 306096) +Operator_cancelRequest:test_afterSuccessfulRequestSucess(uint96) (runs: 256, μ: 384781, ~: 389554) \ No newline at end of file diff --git a/contracts/gas-snapshots/shared.gas-snapshot b/contracts/gas-snapshots/shared.gas-snapshot index 6f307d257f5..c41c633749c 100644 --- a/contracts/gas-snapshots/shared.gas-snapshot +++ b/contracts/gas-snapshots/shared.gas-snapshot @@ -1,48 +1,48 @@ -BurnMintERC677_approve:testApproveSuccess() (gas: 55248) +BurnMintERC677_approve:testApproveSuccess() (gas: 55512) BurnMintERC677_approve:testInvalidAddressReverts() (gas: 10663) -BurnMintERC677_burn:testBasicBurnSuccess() (gas: 164342) +BurnMintERC677_burn:testBasicBurnSuccess() (gas: 173939) BurnMintERC677_burn:testBurnFromZeroAddressReverts() (gas: 47201) BurnMintERC677_burn:testExceedsBalanceReverts() (gas: 21841) BurnMintERC677_burn:testSenderNotBurnerReverts() (gas: 13359) -BurnMintERC677_burnFrom:testBurnFromSuccess() (gas: 57658) +BurnMintERC677_burnFrom:testBurnFromSuccess() (gas: 57923) BurnMintERC677_burnFrom:testExceedsBalanceReverts() (gas: 35864) BurnMintERC677_burnFrom:testInsufficientAllowanceReverts() (gas: 21849) BurnMintERC677_burnFrom:testSenderNotBurnerReverts() (gas: 13359) -BurnMintERC677_burnFromAlias:testBurnFromSuccess() (gas: 57684) +BurnMintERC677_burnFromAlias:testBurnFromSuccess() (gas: 57949) BurnMintERC677_burnFromAlias:testExceedsBalanceReverts() (gas: 35880) BurnMintERC677_burnFromAlias:testInsufficientAllowanceReverts() (gas: 21869) BurnMintERC677_burnFromAlias:testSenderNotBurnerReverts() (gas: 13379) -BurnMintERC677_constructor:testConstructorSuccess() (gas: 1669109) -BurnMintERC677_decreaseApproval:testDecreaseApprovalSuccess() (gas: 28537) -BurnMintERC677_grantMintAndBurnRoles:testGrantMintAndBurnRolesSuccess() (gas: 120071) -BurnMintERC677_grantRole:testGrantBurnAccessSuccess() (gas: 52724) -BurnMintERC677_grantRole:testGrantManySuccess() (gas: 935521) -BurnMintERC677_grantRole:testGrantMintAccessSuccess() (gas: 93605) -BurnMintERC677_increaseApproval:testIncreaseApprovalSuccess() (gas: 40911) -BurnMintERC677_mint:testBasicMintSuccess() (gas: 149365) +BurnMintERC677_constructor:testConstructorSuccess() (gas: 1672809) +BurnMintERC677_decreaseApproval:testDecreaseApprovalSuccess() (gas: 31069) +BurnMintERC677_grantMintAndBurnRoles:testGrantMintAndBurnRolesSuccess() (gas: 121324) +BurnMintERC677_grantRole:testGrantBurnAccessSuccess() (gas: 53460) +BurnMintERC677_grantRole:testGrantManySuccess() (gas: 937759) +BurnMintERC677_grantRole:testGrantMintAccessSuccess() (gas: 94340) +BurnMintERC677_increaseApproval:testIncreaseApprovalSuccess() (gas: 44076) +BurnMintERC677_mint:testBasicMintSuccess() (gas: 149699) BurnMintERC677_mint:testMaxSupplyExceededReverts() (gas: 50385) BurnMintERC677_mint:testSenderNotMinterReverts() (gas: 11195) -BurnMintERC677_supportsInterface:testConstructorSuccess() (gas: 8685) +BurnMintERC677_supportsInterface:testConstructorSuccess() (gas: 12476) BurnMintERC677_transfer:testInvalidAddressReverts() (gas: 10639) -BurnMintERC677_transfer:testTransferSuccess() (gas: 39462) -CallWithExactGas__callWithExactGas:test_CallWithExactGasReceiverErrorSuccess() (gas: 66918) -CallWithExactGas__callWithExactGas:test_CallWithExactGasSafeReturnDataExactGas() (gas: 22615) +BurnMintERC677_transfer:testTransferSuccess() (gas: 42299) +CallWithExactGas__callWithExactGas:test_CallWithExactGasReceiverErrorSuccess() (gas: 67209) +CallWithExactGas__callWithExactGas:test_CallWithExactGasSafeReturnDataExactGas() (gas: 18324) CallWithExactGas__callWithExactGas:test_NoContractReverts() (gas: 11559) -CallWithExactGas__callWithExactGas:test_NoGasForCallExactCheckReverts() (gas: 12908) -CallWithExactGas__callWithExactGas:test_NotEnoughGasForCallReverts() (gas: 13361) -CallWithExactGas__callWithExactGas:test_callWithExactGasSuccess(bytes,bytes4) (runs: 256, μ: 15477, ~: 15418) -CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractExactGasSuccess() (gas: 19147) -CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractReceiverErrorSuccess() (gas: 67096) -CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractSuccess(bytes,bytes4) (runs: 256, μ: 15675, ~: 15616) -CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_NoContractSuccess() (gas: 9816) -CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_NoGasForCallExactCheckReturnFalseSuccess() (gas: 9578) -CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_NotEnoughGasForCallReturnsFalseSuccess() (gas: 9890) -CallWithExactGas__callWithExactGasSafeReturnData:test_CallWithExactGasSafeReturnDataExactGas() (gas: 19017) -CallWithExactGas__callWithExactGasSafeReturnData:test_NoContractReverts() (gas: 13949) -CallWithExactGas__callWithExactGasSafeReturnData:test_NoGasForCallExactCheckReverts() (gas: 13239) -CallWithExactGas__callWithExactGasSafeReturnData:test_NotEnoughGasForCallReverts() (gas: 13670) -OpStackBurnMintERC677_constructor:testConstructorSuccess() (gas: 1739317) -OpStackBurnMintERC677_interfaceCompatibility:testBurnCompatibility() (gas: 263373) +CallWithExactGas__callWithExactGas:test_NoGasForCallExactCheckReverts() (gas: 15788) +CallWithExactGas__callWithExactGas:test_NotEnoughGasForCallReverts() (gas: 16241) +CallWithExactGas__callWithExactGas:test_callWithExactGasSuccess(bytes,bytes4) (runs: 256, μ: 15812, ~: 15752) +CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractExactGasSuccess() (gas: 20116) +CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractReceiverErrorSuccess() (gas: 67721) +CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractSuccess(bytes,bytes4) (runs: 256, μ: 16322, ~: 16262) +CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_NoContractSuccess() (gas: 12962) +CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_NoGasForCallExactCheckReturnFalseSuccess() (gas: 13005) +CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_NotEnoughGasForCallReturnsFalseSuccess() (gas: 13317) +CallWithExactGas__callWithExactGasSafeReturnData:test_CallWithExactGasSafeReturnDataExactGas() (gas: 20331) +CallWithExactGas__callWithExactGasSafeReturnData:test_NoContractReverts() (gas: 13917) +CallWithExactGas__callWithExactGasSafeReturnData:test_NoGasForCallExactCheckReverts() (gas: 16116) +CallWithExactGas__callWithExactGasSafeReturnData:test_NotEnoughGasForCallReverts() (gas: 16547) +OpStackBurnMintERC677_constructor:testConstructorSuccess() (gas: 1743649) +OpStackBurnMintERC677_interfaceCompatibility:testBurnCompatibility() (gas: 298649) OpStackBurnMintERC677_interfaceCompatibility:testMintCompatibility() (gas: 137957) -OpStackBurnMintERC677_interfaceCompatibility:testStaticFunctionsCompatibility() (gas: 10622) -OpStackBurnMintERC677_supportsInterface:testConstructorSuccess() (gas: 8961) \ No newline at end of file +OpStackBurnMintERC677_interfaceCompatibility:testStaticFunctionsCompatibility() (gas: 13781) +OpStackBurnMintERC677_supportsInterface:testConstructorSuccess() (gas: 12752) \ No newline at end of file diff --git a/contracts/gas-snapshots/transmission.gas-snapshot b/contracts/gas-snapshots/transmission.gas-snapshot new file mode 100644 index 00000000000..1588faf7b9a --- /dev/null +++ b/contracts/gas-snapshots/transmission.gas-snapshot @@ -0,0 +1,4 @@ +EIP_712_1014_4337:testEIP712EIP4337AndCreateSmartContractAccount() (gas: 910982) +EIP_712_1014_4337:testEIP712EIP4337AndCreateSmartContractAccountWithPaymaster() (gas: 2287249) +EIP_712_1014_4337:testEIP712EIP4337AndCreateSmartContractAccountWithPaymasterForVRFRequest() (gas: 2877786) +EIP_712_1014_4337:testEIP712EIP4337WithExistingSmartContractAccount() (gas: 879722) \ No newline at end of file diff --git a/contracts/hardhat.config.ts b/contracts/hardhat.config.ts index 6a0b36ad0c7..d3dad625928 100644 --- a/contracts/hardhat.config.ts +++ b/contracts/hardhat.config.ts @@ -1,13 +1,8 @@ -import '@nomiclabs/hardhat-ethers' -import '@nomiclabs/hardhat-etherscan' -import '@nomiclabs/hardhat-waffle' -import '@openzeppelin/hardhat-upgrades' +import '@nomicfoundation/hardhat-ethers' +import '@nomicfoundation/hardhat-verify' +import '@nomicfoundation/hardhat-chai-matchers' import '@typechain/hardhat' import 'hardhat-abi-exporter' -import 'hardhat-contract-sizer' -import 'hardhat-gas-reporter' -import 'solidity-coverage' -import 'hardhat-ignore-warnings' import { subtask } from 'hardhat/config' import { TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS } from 'hardhat/builtin-tasks/task-names' @@ -60,30 +55,10 @@ let config = { }, solidity: { compilers: [ - { - version: '0.4.24', - settings: COMPILER_SETTINGS, - }, - { - version: '0.5.0', - settings: COMPILER_SETTINGS, - }, - { - version: '0.6.6', - settings: COMPILER_SETTINGS, - }, - { - version: '0.7.6', - settings: COMPILER_SETTINGS, - }, { version: '0.8.6', settings: COMPILER_SETTINGS, }, - { - version: '0.8.15', - settings: COMPILER_SETTINGS, - }, { version: '0.8.16', settings: COMPILER_SETTINGS, @@ -107,11 +82,11 @@ let config = { }, }, 'src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol': { - version: '0.8.6', + version: '0.8.19', settings: { optimizer: { enabled: true, - runs: 50, // see native_solc_compile_all_vrf + runs: 500, // see native_solc_compile_all_vrf }, metadata: { bytecodeHash: 'none', @@ -120,18 +95,10 @@ let config = { }, }, }, - contractSizer: { - alphaSort: true, - runOnCompile: false, - disambiguatePaths: false, - }, mocha: { - timeout: 100000, + timeout: 150000, forbidOnly: Boolean(process.env.CI), }, - gasReporter: { - enabled: Boolean(process.env.REPORT_GAS), - }, warnings: !process.env.HIDE_WARNINGS, } diff --git a/contracts/package.json b/contracts/package.json index 40296ad2cfb..926b62a1a07 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -18,7 +18,7 @@ "prepublishOnly": "pnpm compile && ./scripts/prepublish_generate_abi_folder", "publish-beta": "pnpm publish --tag beta", "publish-prod": "npm dist-tag add @chainlink/contracts@1.0.0 latest", - "solhint": "solhint --max-warnings 20 \"./src/v0.8/**/*.sol\"" + "solhint": "solhint --max-warnings 85 \"./src/v0.8/**/*.sol\"" }, "files": [ "src/v0.8", @@ -37,59 +37,49 @@ "@ethersproject/bignumber": "~5.7.0", "@ethersproject/contracts": "~5.7.0", "@ethersproject/providers": "~5.7.2", - "@ethersproject/random": "~5.7.0", + "@nomicfoundation/hardhat-chai-matchers": "^1.0.6", + "@nomicfoundation/hardhat-ethers": "^3.0.5", "@nomicfoundation/hardhat-network-helpers": "^1.0.9", - "@nomiclabs/hardhat-ethers": "^2.2.3", - "@nomiclabs/hardhat-etherscan": "^3.1.7", - "@nomiclabs/hardhat-waffle": "2.0.6", - "@openzeppelin/hardhat-upgrades": "1.28.0", - "@openzeppelin/test-helpers": "^0.5.16", + "@nomicfoundation/hardhat-verify": "^2.0.5", "@typechain/ethers-v5": "^7.2.0", "@typechain/hardhat": "^7.0.0", "@types/cbor": "5.0.1", - "@types/chai": "^4.3.11", + "@types/chai": "^4.3.14", "@types/debug": "^4.1.12", "@types/deep-equal-in-any-order": "^1.0.3", "@types/mocha": "^10.0.6", - "@types/node": "^16.18.80", + "@types/node": "^16.18.91", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", "abi-to-sol": "^0.6.6", "cbor": "^5.2.0", "chai": "^4.3.10", "debug": "^4.3.4", + "deep-equal-in-any-order": "^2.0.6", "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", - "deep-equal-in-any-order": "^2.0.6", "eslint-plugin-prettier": "^5.1.3", - "ethereum-waffle": "^3.4.4", "ethers": "~5.7.2", - "hardhat": "~2.19.2", + "hardhat": "~2.20.1", "hardhat-abi-exporter": "^2.10.1", - "hardhat-contract-sizer": "^2.10.0", - "hardhat-gas-reporter": "^1.0.9", "hardhat-ignore-warnings": "^0.2.6", - "istanbul": "^0.4.5", - "moment": "^2.29.4", + "moment": "^2.30.1", "prettier": "^3.2.5", "prettier-plugin-solidity": "1.3.1", - "rlp": "^2.2.7", - "solhint": "^4.1.1", + "solhint": "^4.5.2", "solhint-plugin-chainlink-solidity": "git+https://github.com/smartcontractkit/chainlink-solhint-rules.git#v1.2.1", "solhint-plugin-prettier": "^0.1.0", - "solidity-coverage": "^0.8.5", "ts-node": "^10.9.2", - "tslib": "^2.6.2", "typechain": "^8.2.1", - "typescript": "^5.3.3" + "typescript": "^5.4.3" }, "dependencies": { + "@changesets/changelog-github": "^0.4.8", + "@changesets/cli": "~2.26.2", "@eth-optimism/contracts": "0.6.0", - "@scroll-tech/contracts": "0.1.0", "@openzeppelin/contracts": "4.9.3", "@openzeppelin/contracts-upgradeable": "4.9.3", - "@changesets/changelog-github": "^0.4.8", - "@changesets/cli": "~2.26.2", - "semver": "^7.5.4" + "@scroll-tech/contracts": "0.1.0", + "semver": "^7.6.0" } } diff --git a/contracts/pnpm-lock.yaml b/contracts/pnpm-lock.yaml index ea7e2922b06..ec23afcc564 100644 --- a/contracts/pnpm-lock.yaml +++ b/contracts/pnpm-lock.yaml @@ -27,8 +27,8 @@ dependencies: specifier: 0.1.0 version: 0.1.0 semver: - specifier: ^7.5.4 - version: 7.5.4 + specifier: ^7.6.0 + version: 7.6.0 devDependencies: '@ethereum-waffle/mock-contract': @@ -46,39 +46,30 @@ devDependencies: '@ethersproject/providers': specifier: ~5.7.2 version: 5.7.2 - '@ethersproject/random': - specifier: ~5.7.0 - version: 5.7.0 + '@nomicfoundation/hardhat-chai-matchers': + specifier: ^1.0.6 + version: 1.0.6(@nomiclabs/hardhat-ethers@2.2.3)(chai@4.4.1)(ethers@5.7.2)(hardhat@2.20.1) + '@nomicfoundation/hardhat-ethers': + specifier: ^3.0.5 + version: 3.0.5(ethers@5.7.2)(hardhat@2.20.1) '@nomicfoundation/hardhat-network-helpers': specifier: ^1.0.9 - version: 1.0.10(hardhat@2.19.2) - '@nomiclabs/hardhat-ethers': - specifier: ^2.2.3 - version: 2.2.3(ethers@5.7.2)(hardhat@2.19.2) - '@nomiclabs/hardhat-etherscan': - specifier: ^3.1.7 - version: 3.1.8(hardhat@2.19.2) - '@nomiclabs/hardhat-waffle': - specifier: 2.0.6 - version: 2.0.6(@nomiclabs/hardhat-ethers@2.2.3)(@types/sinon-chai@3.2.8)(ethereum-waffle@3.4.4)(ethers@5.7.2)(hardhat@2.19.2) - '@openzeppelin/hardhat-upgrades': - specifier: 1.28.0 - version: 1.28.0(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.8)(ethers@5.7.2)(hardhat@2.19.2) - '@openzeppelin/test-helpers': - specifier: ^0.5.16 - version: 0.5.16(bn.js@4.12.0) + version: 1.0.10(hardhat@2.20.1) + '@nomicfoundation/hardhat-verify': + specifier: ^2.0.5 + version: 2.0.5(hardhat@2.20.1) '@typechain/ethers-v5': specifier: ^7.2.0 - version: 7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.3.2)(typescript@5.3.3) + version: 7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.3.2)(typescript@5.4.3) '@typechain/hardhat': specifier: ^7.0.0 - version: 7.0.0(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@typechain/ethers-v5@7.2.0)(ethers@5.7.2)(hardhat@2.19.2)(typechain@8.3.2) + version: 7.0.0(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@typechain/ethers-v5@7.2.0)(ethers@5.7.2)(hardhat@2.20.1)(typechain@8.3.2) '@types/cbor': specifier: 5.0.1 version: 5.0.1 '@types/chai': - specifier: ^4.3.11 - version: 4.3.11 + specifier: ^4.3.14 + version: 4.3.14 '@types/debug': specifier: ^4.1.12 version: 4.1.12 @@ -89,14 +80,14 @@ devDependencies: specifier: ^10.0.6 version: 10.0.6 '@types/node': - specifier: ^16.18.80 - version: 16.18.80 + specifier: ^16.18.91 + version: 16.18.91 '@typescript-eslint/eslint-plugin': specifier: ^6.21.0 - version: 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.3.3) + version: 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.4.3) '@typescript-eslint/parser': specifier: ^6.21.0 - version: 6.21.0(eslint@8.56.0)(typescript@5.3.3) + version: 6.21.0(eslint@8.57.0)(typescript@5.4.3) abi-to-sol: specifier: ^0.6.6 version: 0.6.6 @@ -105,7 +96,7 @@ devDependencies: version: 5.2.0 chai: specifier: ^4.3.10 - version: 4.3.10 + version: 4.4.1 debug: specifier: ^4.3.4 version: 4.3.4(supports-color@8.1.1) @@ -114,73 +105,52 @@ devDependencies: version: 2.0.6 eslint: specifier: ^8.56.0 - version: 8.56.0 + version: 8.57.0 eslint-config-prettier: specifier: ^9.1.0 - version: 9.1.0(eslint@8.56.0) + version: 9.1.0(eslint@8.57.0) eslint-plugin-prettier: specifier: ^5.1.3 - version: 5.1.3(eslint-config-prettier@9.1.0)(eslint@8.56.0)(prettier@3.2.5) - ethereum-waffle: - specifier: ^3.4.4 - version: 3.4.4(typescript@5.3.3) + version: 5.1.3(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.2.5) ethers: specifier: ~5.7.2 version: 5.7.2 hardhat: - specifier: ~2.19.2 - version: 2.19.2(ts-node@10.9.2)(typescript@5.3.3) + specifier: ~2.20.1 + version: 2.20.1(ts-node@10.9.2)(typescript@5.4.3) hardhat-abi-exporter: specifier: ^2.10.1 - version: 2.10.1(hardhat@2.19.2) - hardhat-contract-sizer: - specifier: ^2.10.0 - version: 2.10.0(hardhat@2.19.2) - hardhat-gas-reporter: - specifier: ^1.0.9 - version: 1.0.9(hardhat@2.19.2) + version: 2.10.1(hardhat@2.20.1) hardhat-ignore-warnings: specifier: ^0.2.6 - version: 0.2.9 - istanbul: - specifier: ^0.4.5 - version: 0.4.5 + version: 0.2.11 moment: - specifier: ^2.29.4 - version: 2.29.4 + specifier: ^2.30.1 + version: 2.30.1 prettier: specifier: ^3.2.5 version: 3.2.5 prettier-plugin-solidity: specifier: 1.3.1 version: 1.3.1(prettier@3.2.5) - rlp: - specifier: ^2.2.7 - version: 2.2.7 solhint: - specifier: ^4.1.1 - version: 4.1.1 + specifier: ^4.5.2 + version: 4.5.2 solhint-plugin-chainlink-solidity: specifier: git+https://github.com/smartcontractkit/chainlink-solhint-rules.git#v1.2.1 version: github.com/smartcontractkit/chainlink-solhint-rules/1b4c0c2663fcd983589d4f33a2e73908624ed43c solhint-plugin-prettier: specifier: ^0.1.0 version: 0.1.0(prettier-plugin-solidity@1.3.1)(prettier@3.2.5) - solidity-coverage: - specifier: ^0.8.5 - version: 0.8.5(hardhat@2.19.2) ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@16.18.80)(typescript@5.3.3) - tslib: - specifier: ^2.6.2 - version: 2.6.2 + version: 10.9.2(@types/node@16.18.91)(typescript@5.4.3) typechain: specifier: ^8.2.1 - version: 8.3.2(typescript@5.3.3) + version: 8.3.2(typescript@5.4.3) typescript: - specifier: ^5.3.3 - version: 5.3.3 + specifier: ^5.4.3 + version: 5.4.3 packages: @@ -189,36 +159,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /@aws-crypto/sha256-js@1.2.2: - resolution: {integrity: sha512-Nr1QJIbW/afYYGzYvrF70LtaHrIRtd4TNAglX8BvlfxJLZ45SAmueIKYl5tWoNBPzp65ymXGFK0Bb1vZUpuc9g==} - dependencies: - '@aws-crypto/util': 1.2.2 - '@aws-sdk/types': 3.468.0 - tslib: 1.14.1 - dev: true - - /@aws-crypto/util@1.2.2: - resolution: {integrity: sha512-H8PjG5WJ4wz0UXAFXeJjWCW1vkvIJ3qUUD+rGRwJ2/hj+xT58Qle2MTql/2MGzkU+1JLAFuR6aJpLAjHwhmwwg==} - dependencies: - '@aws-sdk/types': 3.468.0 - '@aws-sdk/util-utf8-browser': 3.259.0 - tslib: 1.14.1 - dev: true - - /@aws-sdk/types@3.468.0: - resolution: {integrity: sha512-rx/9uHI4inRbp2tw3Y4Ih4PNZkVj32h7WneSg3MVgVjAoVD5Zti9KhS5hkvsBxfgmQmg0AQbE+b1sy5WGAgntA==} - engines: {node: '>=14.0.0'} - dependencies: - '@smithy/types': 2.7.0 - tslib: 2.6.2 - dev: true - - /@aws-sdk/util-utf8-browser@3.259.0: - resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} - dependencies: - tslib: 2.6.2 - dev: true - /@babel/code-frame@7.18.6: resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} engines: {node: '>=6.9.0'} @@ -237,50 +177,11 @@ packages: chalk: 2.4.2 js-tokens: 4.0.0 - /@babel/runtime@7.19.0: - resolution: {integrity: sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==} - engines: {node: '>=6.9.0'} - dependencies: - regenerator-runtime: 0.13.9 - dev: true - /@babel/runtime@7.24.0: resolution: {integrity: sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.1 - dev: false - - /@chainsafe/as-sha256@0.3.1: - resolution: {integrity: sha512-hldFFYuf49ed7DAakWVXSJODuq3pzJEguD8tQ7h+sGkM18vja+OFoJI9krnGmgzyuZC2ETX0NOIcCTy31v2Mtg==} - dev: true - - /@chainsafe/persistent-merkle-tree@0.4.2: - resolution: {integrity: sha512-lLO3ihKPngXLTus/L7WHKaw9PnNJWizlOF1H9NNzHP6Xvh82vzg9F2bzkXhYIFshMZ2gTCEz8tq6STe7r5NDfQ==} - dependencies: - '@chainsafe/as-sha256': 0.3.1 - dev: true - - /@chainsafe/persistent-merkle-tree@0.5.0: - resolution: {integrity: sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==} - dependencies: - '@chainsafe/as-sha256': 0.3.1 - dev: true - - /@chainsafe/ssz@0.10.2: - resolution: {integrity: sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==} - dependencies: - '@chainsafe/as-sha256': 0.3.1 - '@chainsafe/persistent-merkle-tree': 0.5.0 - dev: true - - /@chainsafe/ssz@0.9.4: - resolution: {integrity: sha512-77Qtg2N1ayqs4Bg/wvnWfg5Bta7iy7IRh8XqXh7oNMeP2HBbBwx8m6yTpA8p0EHItWPEBkgZd5S5/LSlp3GXuQ==} - dependencies: - '@chainsafe/as-sha256': 0.3.1 - '@chainsafe/persistent-merkle-tree': 0.4.2 - case: 1.6.3 - dev: true /@changesets/apply-release-plan@6.1.4: resolution: {integrity: sha512-FMpKF1fRlJyCZVYHr3CbinpZZ+6MwvOtWUuO8uo+svcATEoc1zRDcj23pAurJ2TZ/uVz1wFHH6K3NlACy0PLew==} @@ -297,7 +198,7 @@ packages: outdent: 0.5.0 prettier: 2.8.8 resolve-from: 5.0.0 - semver: 7.5.4 + semver: 7.6.0 dev: false /@changesets/assemble-release-plan@5.2.4: @@ -308,7 +209,7 @@ packages: '@changesets/get-dependents-graph': 1.3.6 '@changesets/types': 5.2.1 '@manypkg/get-packages': 1.1.3 - semver: 7.5.4 + semver: 7.6.0 dev: false /@changesets/changelog-git@0.1.14: @@ -360,7 +261,7 @@ packages: p-limit: 2.3.0 preferred-pm: 3.1.3 resolve-from: 5.0.0 - semver: 7.5.4 + semver: 7.6.0 spawndamnit: 2.0.0 term-size: 2.2.1 tty-table: 4.2.3 @@ -391,7 +292,7 @@ packages: '@manypkg/get-packages': 1.1.3 chalk: 2.4.2 fs-extra: 7.0.1 - semver: 7.5.4 + semver: 7.6.0 dev: false /@changesets/get-github-info@0.5.2: @@ -485,13 +386,6 @@ packages: prettier: 2.8.8 dev: false - /@colors/colors@1.5.0: - resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} - engines: {node: '>=0.1.90'} - requiresBuild: true - dev: true - optional: true - /@cspotcode/source-map-support@0.8.1: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} @@ -499,57 +393,13 @@ packages: '@jridgewell/trace-mapping': 0.3.9 dev: true - /@ensdomains/address-encoder@0.1.9: - resolution: {integrity: sha512-E2d2gP4uxJQnDu2Kfg1tHNspefzbLT8Tyjrm5sEuim32UkU2sm5xL4VXtgc2X33fmPEw9+jUMpGs4veMbf+PYg==} - dependencies: - bech32: 1.1.4 - blakejs: 1.2.1 - bn.js: 4.12.0 - bs58: 4.0.1 - crypto-addr-codec: 0.1.7 - nano-base32: 1.0.1 - ripemd160: 2.0.2 - dev: true - - /@ensdomains/ens@0.4.5: - resolution: {integrity: sha512-JSvpj1iNMFjK6K+uVl4unqMoa9rf5jopb8cya5UGBWz23Nw8hSNT7efgUx4BTlAPAgpNlEioUfeTyQ6J9ZvTVw==} - deprecated: Please use @ensdomains/ens-contracts - dependencies: - bluebird: 3.7.2 - eth-ens-namehash: 2.0.8 - solc: 0.4.26 - testrpc: 0.0.1 - web3-utils: 1.8.0 - dev: true - - /@ensdomains/ensjs@2.1.0: - resolution: {integrity: sha512-GRbGPT8Z/OJMDuxs75U/jUNEC0tbL0aj7/L/QQznGYKm/tiasp+ndLOaoULy9kKJFC0TBByqfFliEHDgoLhyog==} - dependencies: - '@babel/runtime': 7.19.0 - '@ensdomains/address-encoder': 0.1.9 - '@ensdomains/ens': 0.4.5 - '@ensdomains/resolver': 0.2.4 - content-hash: 2.5.2 - eth-ens-namehash: 2.0.8 - ethers: 5.7.2 - js-sha3: 0.8.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - dev: true - - /@ensdomains/resolver@0.2.4: - resolution: {integrity: sha512-bvaTH34PMCbv6anRa9I/0zjLJgY4EuznbEMgbV77JBCQ9KNC46rzi0avuxpOfu+xDjPEtSFGqVEOr5GlUSGudA==} - deprecated: Please use @ensdomains/ens-contracts - dev: true - - /@eslint-community/eslint-utils@4.4.0(eslint@8.56.0): + /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 8.56.0 + eslint: 8.57.0 eslint-visitor-keys: 3.4.3 dev: true @@ -575,8 +425,8 @@ packages: - supports-color dev: true - /@eslint/js@8.56.0: - resolution: {integrity: sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==} + /@eslint/js@8.57.0: + resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true @@ -612,60 +462,12 @@ packages: '@ethersproject/transactions': 5.7.0 '@ethersproject/web': 5.7.1 bufio: 1.0.7 - chai: 4.3.10 + chai: 4.4.1 transitivePeerDependencies: - bufferutil - utf-8-validate dev: false - /@ethereum-waffle/chai@3.4.4: - resolution: {integrity: sha512-/K8czydBtXXkcM9X6q29EqEkc5dN3oYenyH2a9hF7rGAApAJUpH8QBtojxOY/xQ2up5W332jqgxwp0yPiYug1g==} - engines: {node: '>=10.0'} - dependencies: - '@ethereum-waffle/provider': 3.4.4 - ethers: 5.7.2 - transitivePeerDependencies: - - bufferutil - - encoding - - supports-color - - utf-8-validate - dev: true - - /@ethereum-waffle/compiler@3.4.4(typescript@5.3.3): - resolution: {integrity: sha512-RUK3axJ8IkD5xpWjWoJgyHclOeEzDLQFga6gKpeGxiS/zBu+HB0W2FvsrrLalTFIaPw/CGYACRBSIxqiCqwqTQ==} - engines: {node: '>=10.0'} - dependencies: - '@resolver-engine/imports': 0.3.3 - '@resolver-engine/imports-fs': 0.3.3 - '@typechain/ethers-v5': 2.0.0(ethers@5.7.2)(typechain@3.0.0) - '@types/mkdirp': 0.5.2 - '@types/node-fetch': 2.6.2 - ethers: 5.7.2 - mkdirp: 0.5.6 - node-fetch: 2.6.7 - solc: 0.6.12 - ts-generator: 0.1.1 - typechain: 3.0.0(typescript@5.3.3) - transitivePeerDependencies: - - bufferutil - - encoding - - supports-color - - typescript - - utf-8-validate - dev: true - - /@ethereum-waffle/ens@3.4.4: - resolution: {integrity: sha512-0m4NdwWxliy3heBYva1Wr4WbJKLnwXizmy5FfSSr5PMbjI7SIGCdCB59U7/ZzY773/hY3bLnzLwvG5mggVjJWg==} - engines: {node: '>=10.0'} - dependencies: - '@ensdomains/ens': 0.4.5 - '@ensdomains/resolver': 0.2.4 - ethers: 5.7.2 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - dev: true - /@ethereum-waffle/mock-contract@3.4.4: resolution: {integrity: sha512-Mp0iB2YNWYGUV+VMl5tjPsaXKbKo8MDH9wSJ702l9EBjdxFf/vBvnMBAC1Fub1lLtmD0JHtp1pq+mWzg/xlLnA==} engines: {node: '>=10.0'} @@ -677,52 +479,6 @@ packages: - utf-8-validate dev: true - /@ethereum-waffle/provider@3.4.4: - resolution: {integrity: sha512-GK8oKJAM8+PKy2nK08yDgl4A80mFuI8zBkE0C9GqTRYQqvuxIyXoLmJ5NZU9lIwyWVv5/KsoA11BgAv2jXE82g==} - engines: {node: '>=10.0'} - dependencies: - '@ethereum-waffle/ens': 3.4.4 - ethers: 5.7.2 - ganache-core: 2.13.2 - patch-package: 6.4.7 - postinstall-postinstall: 2.1.0 - transitivePeerDependencies: - - bufferutil - - encoding - - supports-color - - utf-8-validate - dev: true - - /@ethereumjs/common@2.6.5: - resolution: {integrity: sha512-lRyVQOeCDaIVtgfbowla32pzeDv2Obr8oR8Put5RdUBNRGr1VGPGQNGP6elWIpgK3YdpzqTOh4GyUGOureVeeA==} - dependencies: - crc-32: 1.2.2 - ethereumjs-util: 7.1.5 - dev: true - - /@ethereumjs/tx@3.5.2: - resolution: {integrity: sha512-gQDNJWKrSDGu2w7w0PzVXVBNMzb7wwdDOmOqczmhNjqFxFuIbhVJDwiGEnxFNC2/b8ifcZzY7MLcluizohRzNw==} - dependencies: - '@ethereumjs/common': 2.6.5 - ethereumjs-util: 7.1.5 - dev: true - - /@ethersproject/abi@5.0.0-beta.153: - resolution: {integrity: sha512-aXweZ1Z7vMNzJdLpR1CZUAIgnwjrZeUSvN9syCwlBaEBUFJmFY+HHnfuTI5vIhVs/mRkfJVrbEyl51JZQqyjAg==} - requiresBuild: true - dependencies: - '@ethersproject/address': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/hash': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.0.6 - '@ethersproject/properties': 5.7.0 - '@ethersproject/strings': 5.7.0 - dev: true - optional: true - /@ethersproject/abi@5.7.0: resolution: {integrity: sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==} dependencies: @@ -1008,11 +764,11 @@ packages: '@ethersproject/properties': 5.7.0 '@ethersproject/strings': 5.7.0 - /@humanwhocodes/config-array@0.11.13: - resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} + /@humanwhocodes/config-array@0.11.14: + resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} dependencies: - '@humanwhocodes/object-schema': 2.0.1 + '@humanwhocodes/object-schema': 2.0.2 debug: 4.3.4(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: @@ -1024,8 +780,8 @@ packages: engines: {node: '>=12.22'} dev: true - /@humanwhocodes/object-schema@2.0.1: - resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} + /@humanwhocodes/object-schema@2.0.2: + resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} dev: true /@jridgewell/resolve-uri@3.1.1: @@ -1101,171 +857,240 @@ packages: '@nodelib/fs.scandir': 2.1.5 fastq: 1.6.0 - /@nomicfoundation/ethereumjs-block@5.0.2: - resolution: {integrity: sha512-hSe6CuHI4SsSiWWjHDIzWhSiAVpzMUcDRpWYzN0T9l8/Rz7xNn3elwVOJ/tAyS0LqL6vitUD78Uk7lQDXZun7Q==} - engines: {node: '>=14'} + /@nomicfoundation/ethereumjs-block@5.0.4: + resolution: {integrity: sha512-AcyacJ9eX/uPEvqsPiB+WO1ymE+kyH48qGGiGV+YTojdtas8itUTW5dehDSOXEEItWGbbzEJ4PRqnQZlWaPvDw==} + engines: {node: '>=18'} dependencies: - '@nomicfoundation/ethereumjs-common': 4.0.2 - '@nomicfoundation/ethereumjs-rlp': 5.0.2 - '@nomicfoundation/ethereumjs-trie': 6.0.2 - '@nomicfoundation/ethereumjs-tx': 5.0.2 - '@nomicfoundation/ethereumjs-util': 9.0.2 + '@nomicfoundation/ethereumjs-common': 4.0.4 + '@nomicfoundation/ethereumjs-rlp': 5.0.4 + '@nomicfoundation/ethereumjs-trie': 6.0.4 + '@nomicfoundation/ethereumjs-tx': 5.0.4 + '@nomicfoundation/ethereumjs-util': 9.0.4 ethereum-cryptography: 0.1.3 - ethers: 5.7.2 transitivePeerDependencies: - - bufferutil - - utf-8-validate + - c-kzg dev: true - /@nomicfoundation/ethereumjs-blockchain@7.0.2: - resolution: {integrity: sha512-8UUsSXJs+MFfIIAKdh3cG16iNmWzWC/91P40sazNvrqhhdR/RtGDlFk2iFTGbBAZPs2+klZVzhRX8m2wvuvz3w==} - engines: {node: '>=14'} + /@nomicfoundation/ethereumjs-blockchain@7.0.4: + resolution: {integrity: sha512-jYsd/kwzbmpnxx86tXsYV8wZ5xGvFL+7/P0c6OlzpClHsbFzeF41KrYA9scON8Rg6bZu3ZTv6JOAgj3t7USUfg==} + engines: {node: '>=18'} dependencies: - '@nomicfoundation/ethereumjs-block': 5.0.2 - '@nomicfoundation/ethereumjs-common': 4.0.2 - '@nomicfoundation/ethereumjs-ethash': 3.0.2 - '@nomicfoundation/ethereumjs-rlp': 5.0.2 - '@nomicfoundation/ethereumjs-trie': 6.0.2 - '@nomicfoundation/ethereumjs-tx': 5.0.2 - '@nomicfoundation/ethereumjs-util': 9.0.2 - abstract-level: 1.0.3 + '@nomicfoundation/ethereumjs-block': 5.0.4 + '@nomicfoundation/ethereumjs-common': 4.0.4 + '@nomicfoundation/ethereumjs-ethash': 3.0.4 + '@nomicfoundation/ethereumjs-rlp': 5.0.4 + '@nomicfoundation/ethereumjs-trie': 6.0.4 + '@nomicfoundation/ethereumjs-tx': 5.0.4 + '@nomicfoundation/ethereumjs-util': 9.0.4 debug: 4.3.4(supports-color@8.1.1) ethereum-cryptography: 0.1.3 - level: 8.0.0 - lru-cache: 5.1.1 - memory-level: 1.0.0 + lru-cache: 10.2.0 transitivePeerDependencies: - - bufferutil + - c-kzg - supports-color - - utf-8-validate dev: true - /@nomicfoundation/ethereumjs-common@4.0.2: - resolution: {integrity: sha512-I2WGP3HMGsOoycSdOTSqIaES0ughQTueOsddJ36aYVpI3SN8YSusgRFLwzDJwRFVIYDKx/iJz0sQ5kBHVgdDwg==} + /@nomicfoundation/ethereumjs-common@4.0.4: + resolution: {integrity: sha512-9Rgb658lcWsjiicr5GzNCjI1llow/7r0k50dLL95OJ+6iZJcVbi15r3Y0xh2cIO+zgX0WIHcbzIu6FeQf9KPrg==} dependencies: - '@nomicfoundation/ethereumjs-util': 9.0.2 - crc-32: 1.2.2 + '@nomicfoundation/ethereumjs-util': 9.0.4 + transitivePeerDependencies: + - c-kzg dev: true - /@nomicfoundation/ethereumjs-ethash@3.0.2: - resolution: {integrity: sha512-8PfoOQCcIcO9Pylq0Buijuq/O73tmMVURK0OqdjhwqcGHYC2PwhbajDh7GZ55ekB0Px197ajK3PQhpKoiI/UPg==} - engines: {node: '>=14'} + /@nomicfoundation/ethereumjs-ethash@3.0.4: + resolution: {integrity: sha512-xvIrwIMl9sSaiYKRem68+O7vYdj7Q2XWv5P7JXiIkn83918QzWHvqbswTRsH7+r6X1UEvdsURRnZbvZszEjAaQ==} + engines: {node: '>=18'} dependencies: - '@nomicfoundation/ethereumjs-block': 5.0.2 - '@nomicfoundation/ethereumjs-rlp': 5.0.2 - '@nomicfoundation/ethereumjs-util': 9.0.2 - abstract-level: 1.0.3 - bigint-crypto-utils: 3.1.8 + '@nomicfoundation/ethereumjs-block': 5.0.4 + '@nomicfoundation/ethereumjs-rlp': 5.0.4 + '@nomicfoundation/ethereumjs-util': 9.0.4 + bigint-crypto-utils: 3.3.0 ethereum-cryptography: 0.1.3 transitivePeerDependencies: - - bufferutil - - utf-8-validate + - c-kzg dev: true - /@nomicfoundation/ethereumjs-evm@2.0.2: - resolution: {integrity: sha512-rBLcUaUfANJxyOx9HIdMX6uXGin6lANCulIm/pjMgRqfiCRMZie3WKYxTSd8ZE/d+qT+zTedBF4+VHTdTSePmQ==} - engines: {node: '>=14'} + /@nomicfoundation/ethereumjs-evm@2.0.4(@nomicfoundation/ethereumjs-verkle@0.0.2): + resolution: {integrity: sha512-lTyZZi1KpeMHzaO6cSVisR2tjiTTedjo7PcmhI/+GNFo9BmyY6QYzGeSti0sFttmjbEMioHgXxl5yrLNRg6+1w==} + engines: {node: '>=18'} dependencies: - '@ethersproject/providers': 5.7.2 - '@nomicfoundation/ethereumjs-common': 4.0.2 - '@nomicfoundation/ethereumjs-tx': 5.0.2 - '@nomicfoundation/ethereumjs-util': 9.0.2 + '@nomicfoundation/ethereumjs-common': 4.0.4 + '@nomicfoundation/ethereumjs-statemanager': 2.0.4(@nomicfoundation/ethereumjs-verkle@0.0.2) + '@nomicfoundation/ethereumjs-tx': 5.0.4 + '@nomicfoundation/ethereumjs-util': 9.0.4 + '@types/debug': 4.1.12 debug: 4.3.4(supports-color@8.1.1) ethereum-cryptography: 0.1.3 - mcl-wasm: 0.7.9 - rustbn.js: 0.2.0 + rustbn-wasm: 0.2.0 transitivePeerDependencies: - - bufferutil + - '@nomicfoundation/ethereumjs-verkle' + - c-kzg - supports-color - - utf-8-validate dev: true - /@nomicfoundation/ethereumjs-rlp@5.0.2: - resolution: {integrity: sha512-QwmemBc+MMsHJ1P1QvPl8R8p2aPvvVcKBbvHnQOKBpBztEo0omN0eaob6FeZS/e3y9NSe+mfu3nNFBHszqkjTA==} - engines: {node: '>=14'} + /@nomicfoundation/ethereumjs-rlp@5.0.4: + resolution: {integrity: sha512-8H1S3s8F6QueOc/X92SdrA4RDenpiAEqMg5vJH99kcQaCy/a3Q6fgseo75mgWlbanGJXSlAPtnCeG9jvfTYXlw==} + engines: {node: '>=18'} hasBin: true dev: true - /@nomicfoundation/ethereumjs-statemanager@2.0.2: - resolution: {integrity: sha512-dlKy5dIXLuDubx8Z74sipciZnJTRSV/uHG48RSijhgm1V7eXYFC567xgKtsKiVZB1ViTP9iFL4B6Je0xD6X2OA==} + /@nomicfoundation/ethereumjs-statemanager@2.0.4(@nomicfoundation/ethereumjs-verkle@0.0.2): + resolution: {integrity: sha512-HPDjeFrxw6llEi+BzqXkZ+KkvFnTOPczuHBtk21hRlDiuKuZz32dPzlhpRsDBGV1b5JTmRDUVqCS1lp3Gghw4Q==} + peerDependencies: + '@nomicfoundation/ethereumjs-verkle': 0.0.2 + peerDependenciesMeta: + '@nomicfoundation/ethereumjs-verkle': + optional: true dependencies: - '@nomicfoundation/ethereumjs-common': 4.0.2 - '@nomicfoundation/ethereumjs-rlp': 5.0.2 + '@nomicfoundation/ethereumjs-common': 4.0.4 + '@nomicfoundation/ethereumjs-rlp': 5.0.4 + '@nomicfoundation/ethereumjs-trie': 6.0.4 + '@nomicfoundation/ethereumjs-util': 9.0.4 + '@nomicfoundation/ethereumjs-verkle': 0.0.2 debug: 4.3.4(supports-color@8.1.1) ethereum-cryptography: 0.1.3 - ethers: 5.7.2 js-sdsl: 4.4.2 + lru-cache: 10.2.0 transitivePeerDependencies: - - bufferutil + - c-kzg - supports-color - - utf-8-validate dev: true - /@nomicfoundation/ethereumjs-trie@6.0.2: - resolution: {integrity: sha512-yw8vg9hBeLYk4YNg5MrSJ5H55TLOv2FSWUTROtDtTMMmDGROsAu+0tBjiNGTnKRi400M6cEzoFfa89Fc5k8NTQ==} - engines: {node: '>=14'} + /@nomicfoundation/ethereumjs-trie@6.0.4: + resolution: {integrity: sha512-3nSwQiFMvr2VFe/aZUyinuohYvtytUqZCUCvIWcPJ/BwJH6oQdZRB42aNFBJ/8nAh2s3OcroWpBLskzW01mFKA==} + engines: {node: '>=18'} dependencies: - '@nomicfoundation/ethereumjs-rlp': 5.0.2 - '@nomicfoundation/ethereumjs-util': 9.0.2 + '@nomicfoundation/ethereumjs-rlp': 5.0.4 + '@nomicfoundation/ethereumjs-util': 9.0.4 '@types/readable-stream': 2.3.15 ethereum-cryptography: 0.1.3 + lru-cache: 10.2.0 readable-stream: 3.6.0 + transitivePeerDependencies: + - c-kzg dev: true - /@nomicfoundation/ethereumjs-tx@5.0.2: - resolution: {integrity: sha512-T+l4/MmTp7VhJeNloMkM+lPU3YMUaXdcXgTGCf8+ZFvV9NYZTRLFekRwlG6/JMmVfIfbrW+dRRJ9A6H5Q/Z64g==} - engines: {node: '>=14'} + /@nomicfoundation/ethereumjs-tx@5.0.4: + resolution: {integrity: sha512-Xjv8wAKJGMrP1f0n2PeyfFCCojHd7iS3s/Ab7qzF1S64kxZ8Z22LCMynArYsVqiFx6rzYy548HNVEyI+AYN/kw==} + engines: {node: '>=18'} + peerDependencies: + c-kzg: ^2.1.2 + peerDependenciesMeta: + c-kzg: + optional: true dependencies: - '@chainsafe/ssz': 0.9.4 - '@ethersproject/providers': 5.7.2 - '@nomicfoundation/ethereumjs-common': 4.0.2 - '@nomicfoundation/ethereumjs-rlp': 5.0.2 - '@nomicfoundation/ethereumjs-util': 9.0.2 + '@nomicfoundation/ethereumjs-common': 4.0.4 + '@nomicfoundation/ethereumjs-rlp': 5.0.4 + '@nomicfoundation/ethereumjs-util': 9.0.4 ethereum-cryptography: 0.1.3 - transitivePeerDependencies: - - bufferutil - - utf-8-validate dev: true - /@nomicfoundation/ethereumjs-util@9.0.2: - resolution: {integrity: sha512-4Wu9D3LykbSBWZo8nJCnzVIYGvGCuyiYLIJa9XXNVt1q1jUzHdB+sJvx95VGCpPkCT+IbLecW6yfzy3E1bQrwQ==} - engines: {node: '>=14'} + /@nomicfoundation/ethereumjs-util@9.0.4: + resolution: {integrity: sha512-sLOzjnSrlx9Bb9EFNtHzK/FJFsfg2re6bsGqinFinH1gCqVfz9YYlXiMWwDM4C/L4ywuHFCYwfKTVr/QHQcU0Q==} + engines: {node: '>=18'} + peerDependencies: + c-kzg: ^2.1.2 + peerDependenciesMeta: + c-kzg: + optional: true dependencies: - '@chainsafe/ssz': 0.10.2 - '@nomicfoundation/ethereumjs-rlp': 5.0.2 + '@nomicfoundation/ethereumjs-rlp': 5.0.4 ethereum-cryptography: 0.1.3 dev: true - /@nomicfoundation/ethereumjs-vm@7.0.2: - resolution: {integrity: sha512-Bj3KZT64j54Tcwr7Qm/0jkeZXJMfdcAtRBedou+Hx0dPOSIgqaIr0vvLwP65TpHbak2DmAq+KJbW2KNtIoFwvA==} - engines: {node: '>=14'} + /@nomicfoundation/ethereumjs-verkle@0.0.2: + resolution: {integrity: sha512-bjnfZElpYGK/XuuVRmLS3yDvr+cDs85D9oonZ0YUa5A3lgFgokWMp76zXrxX2jVQ0BfHaw12y860n1+iOi6yFQ==} + engines: {node: '>=18'} + dependencies: + '@nomicfoundation/ethereumjs-rlp': 5.0.4 + '@nomicfoundation/ethereumjs-util': 9.0.4 + lru-cache: 10.2.0 + rust-verkle-wasm: 0.0.1 + transitivePeerDependencies: + - c-kzg + dev: true + + /@nomicfoundation/ethereumjs-vm@7.0.4(@nomicfoundation/ethereumjs-verkle@0.0.2): + resolution: {integrity: sha512-gsA4IhmtWHI4BofKy3kio9W+dqZQs5Ji5mLjLYxHCkat+JQBUt5szjRKra2F9nGDJ2XcI/wWb0YWUFNgln4zRQ==} + engines: {node: '>=18'} dependencies: - '@nomicfoundation/ethereumjs-block': 5.0.2 - '@nomicfoundation/ethereumjs-blockchain': 7.0.2 - '@nomicfoundation/ethereumjs-common': 4.0.2 - '@nomicfoundation/ethereumjs-evm': 2.0.2 - '@nomicfoundation/ethereumjs-rlp': 5.0.2 - '@nomicfoundation/ethereumjs-statemanager': 2.0.2 - '@nomicfoundation/ethereumjs-trie': 6.0.2 - '@nomicfoundation/ethereumjs-tx': 5.0.2 - '@nomicfoundation/ethereumjs-util': 9.0.2 + '@nomicfoundation/ethereumjs-block': 5.0.4 + '@nomicfoundation/ethereumjs-blockchain': 7.0.4 + '@nomicfoundation/ethereumjs-common': 4.0.4 + '@nomicfoundation/ethereumjs-evm': 2.0.4(@nomicfoundation/ethereumjs-verkle@0.0.2) + '@nomicfoundation/ethereumjs-rlp': 5.0.4 + '@nomicfoundation/ethereumjs-statemanager': 2.0.4(@nomicfoundation/ethereumjs-verkle@0.0.2) + '@nomicfoundation/ethereumjs-trie': 6.0.4 + '@nomicfoundation/ethereumjs-tx': 5.0.4 + '@nomicfoundation/ethereumjs-util': 9.0.4 debug: 4.3.4(supports-color@8.1.1) ethereum-cryptography: 0.1.3 - mcl-wasm: 0.7.9 - rustbn.js: 0.2.0 transitivePeerDependencies: - - bufferutil + - '@nomicfoundation/ethereumjs-verkle' + - c-kzg + - supports-color + dev: true + + /@nomicfoundation/hardhat-chai-matchers@1.0.6(@nomiclabs/hardhat-ethers@2.2.3)(chai@4.4.1)(ethers@5.7.2)(hardhat@2.20.1): + resolution: {integrity: sha512-f5ZMNmabZeZegEfuxn/0kW+mm7+yV7VNDxLpMOMGXWFJ2l/Ct3QShujzDRF9cOkK9Ui/hbDeOWGZqyQALDXVCQ==} + peerDependencies: + '@nomiclabs/hardhat-ethers': ^2.0.0 + chai: ^4.2.0 + ethers: ^5.0.0 + hardhat: ^2.9.4 + dependencies: + '@ethersproject/abi': 5.7.0 + '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.7.2)(hardhat@2.20.1) + '@types/chai-as-promised': 7.1.8 + chai: 4.4.1 + chai-as-promised: 7.1.1(chai@4.4.1) + deep-eql: 4.1.3 + ethers: 5.7.2 + hardhat: 2.20.1(ts-node@10.9.2)(typescript@5.4.3) + ordinal: 1.0.3 + dev: true + + /@nomicfoundation/hardhat-ethers@3.0.5(ethers@5.7.2)(hardhat@2.20.1): + resolution: {integrity: sha512-RNFe8OtbZK6Ila9kIlHp0+S80/0Bu/3p41HUpaRIoHLm6X3WekTd83vob3rE54Duufu1edCiBDxspBzi2rxHHw==} + peerDependencies: + ethers: ^6.1.0 + hardhat: ^2.0.0 + dependencies: + debug: 4.3.4(supports-color@8.1.1) + ethers: 5.7.2 + hardhat: 2.20.1(ts-node@10.9.2)(typescript@5.4.3) + lodash.isequal: 4.5.0 + transitivePeerDependencies: - supports-color - - utf-8-validate dev: true - /@nomicfoundation/hardhat-network-helpers@1.0.10(hardhat@2.19.2): + /@nomicfoundation/hardhat-network-helpers@1.0.10(hardhat@2.20.1): resolution: {integrity: sha512-R35/BMBlx7tWN5V6d/8/19QCwEmIdbnA4ZrsuXgvs8i2qFx5i7h6mH5pBS4Pwi4WigLH+upl6faYusrNPuzMrQ==} peerDependencies: hardhat: ^2.9.5 dependencies: ethereumjs-util: 7.1.5 - hardhat: 2.19.2(ts-node@10.9.2)(typescript@5.3.3) + hardhat: 2.20.1(ts-node@10.9.2)(typescript@5.4.3) + dev: true + + /@nomicfoundation/hardhat-verify@2.0.5(hardhat@2.20.1): + resolution: {integrity: sha512-Tg4zu8RkWpyADSFIgF4FlJIUEI4VkxcvELsmbJn2OokbvH2SnUrqKmw0BBfDrtvP0hhmx8wsnrRKP5DV/oTyTA==} + peerDependencies: + hardhat: ^2.0.4 + dependencies: + '@ethersproject/abi': 5.7.0 + '@ethersproject/address': 5.7.0 + cbor: 8.1.0 + chalk: 2.4.2 + debug: 4.3.4(supports-color@8.1.1) + hardhat: 2.20.1(ts-node@10.9.2)(typescript@5.4.3) + lodash.clonedeep: 4.5.0 + semver: 6.3.0 + table: 6.8.1 + undici: 5.19.1 + transitivePeerDependencies: + - supports-color dev: true /@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.0: @@ -1374,58 +1199,14 @@ packages: '@nomicfoundation/solidity-analyzer-win32-x64-msvc': 0.1.0 dev: true - /@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2)(hardhat@2.19.2): + /@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2)(hardhat@2.20.1): resolution: {integrity: sha512-YhzPdzb612X591FOe68q+qXVXGG2ANZRvDo0RRUtimev85rCrAlv/TLMEZw5c+kq9AbzocLTVX/h2jVIFPL9Xg==} peerDependencies: ethers: ^5.0.0 hardhat: ^2.0.0 dependencies: ethers: 5.7.2 - hardhat: 2.19.2(ts-node@10.9.2)(typescript@5.3.3) - dev: true - - /@nomiclabs/hardhat-etherscan@3.1.8(hardhat@2.19.2): - resolution: {integrity: sha512-v5F6IzQhrsjHh6kQz4uNrym49brK9K5bYCq2zQZ729RYRaifI9hHbtmK+KkIVevfhut7huQFEQ77JLRMAzWYjQ==} - deprecated: The @nomiclabs/hardhat-etherscan package is deprecated, please use @nomicfoundation/hardhat-verify instead - peerDependencies: - hardhat: ^2.0.4 - dependencies: - '@ethersproject/abi': 5.7.0 - '@ethersproject/address': 5.7.0 - cbor: 8.1.0 - chalk: 2.4.2 - debug: 4.3.4(supports-color@8.1.1) - fs-extra: 7.0.1 - hardhat: 2.19.2(ts-node@10.9.2)(typescript@5.3.3) - lodash: 4.17.21 - semver: 6.3.0 - table: 6.8.1 - undici: 5.19.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@nomiclabs/hardhat-waffle@2.0.6(@nomiclabs/hardhat-ethers@2.2.3)(@types/sinon-chai@3.2.8)(ethereum-waffle@3.4.4)(ethers@5.7.2)(hardhat@2.19.2): - resolution: {integrity: sha512-+Wz0hwmJGSI17B+BhU/qFRZ1l6/xMW82QGXE/Gi+WTmwgJrQefuBs1lIf7hzQ1hLk6hpkvb/zwcNkpVKRYTQYg==} - peerDependencies: - '@nomiclabs/hardhat-ethers': ^2.0.0 - '@types/sinon-chai': ^3.2.3 - ethereum-waffle: '*' - ethers: ^5.0.0 - hardhat: ^2.0.0 - dependencies: - '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.7.2)(hardhat@2.19.2) - '@types/sinon-chai': 3.2.8 - ethereum-waffle: 3.4.4(typescript@5.3.3) - ethers: 5.7.2 - hardhat: 2.19.2(ts-node@10.9.2)(typescript@5.3.3) - dev: true - - /@openzeppelin/contract-loader@0.6.3: - resolution: {integrity: sha512-cOFIjBjwbGgZhDZsitNgJl0Ye1rd5yu/Yx5LMgeq3u0ZYzldm4uObzHDFq4gjDdoypvyORjjJa3BlFA7eAnVIg==} - dependencies: - find-up: 4.1.0 - fs-extra: 8.1.0 + hardhat: 2.20.1(ts-node@10.9.2)(typescript@5.4.3) dev: true /@openzeppelin/contracts-upgradeable@4.9.3: @@ -1436,111 +1217,19 @@ packages: resolution: {integrity: sha512-He3LieZ1pP2TNt5JbkPA4PNT9WC3gOTOlDcFGJW4Le4QKqwmiNJCRt44APfxMxvq7OugU/cqYuPcSBzOw38DAg==} dev: false - /@openzeppelin/defender-base-client@1.52.0(debug@4.3.4): - resolution: {integrity: sha512-VFNu/pjVpAnFKIfuKT1cn9dRpbcO8FO8EAmVZ2XrrAsKXEWDZ3TNBtACxmj7fAu0ad/TzRkb66o5rMts7Fv7jw==} - dependencies: - amazon-cognito-identity-js: 6.3.7 - async-retry: 1.3.3 - axios: 1.6.2(debug@4.3.4) - lodash: 4.17.21 - node-fetch: 2.6.7 - transitivePeerDependencies: - - debug - - encoding + /@pkgr/core@0.1.1: + resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} dev: true - /@openzeppelin/hardhat-upgrades@1.28.0(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.8)(ethers@5.7.2)(hardhat@2.19.2): - resolution: {integrity: sha512-7sb/Jf+X+uIufOBnmHR0FJVWuxEs2lpxjJnLNN6eCJCP8nD0v+Ot5lTOW2Qb/GFnh+fLvJtEkhkowz4ZQ57+zQ==} - hasBin: true - peerDependencies: - '@nomiclabs/hardhat-ethers': ^2.0.0 - '@nomiclabs/hardhat-etherscan': ^3.1.0 - '@nomiclabs/harhdat-etherscan': '*' - ethers: ^5.0.5 - hardhat: ^2.0.2 - peerDependenciesMeta: - '@nomiclabs/harhdat-etherscan': - optional: true - dependencies: - '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.7.2)(hardhat@2.19.2) - '@nomiclabs/hardhat-etherscan': 3.1.8(hardhat@2.19.2) - '@openzeppelin/defender-base-client': 1.52.0(debug@4.3.4) - '@openzeppelin/platform-deploy-client': 0.8.0(debug@4.3.4) - '@openzeppelin/upgrades-core': 1.31.3 - chalk: 4.1.2 - debug: 4.3.4(supports-color@8.1.1) - ethers: 5.7.2 - hardhat: 2.19.2(ts-node@10.9.2)(typescript@5.3.3) - proper-lockfile: 4.1.2 - transitivePeerDependencies: - - encoding - - supports-color - dev: true - - /@openzeppelin/platform-deploy-client@0.8.0(debug@4.3.4): - resolution: {integrity: sha512-POx3AsnKwKSV/ZLOU/gheksj0Lq7Is1q2F3pKmcFjGZiibf+4kjGxr4eSMrT+2qgKYZQH1ZLQZ+SkbguD8fTvA==} - deprecated: '@openzeppelin/platform-deploy-client is deprecated. Please use @openzeppelin/defender-sdk-deploy-client' - dependencies: - '@ethersproject/abi': 5.7.0 - '@openzeppelin/defender-base-client': 1.52.0(debug@4.3.4) - axios: 0.21.4(debug@4.3.4) - lodash: 4.17.21 - node-fetch: 2.6.7 - transitivePeerDependencies: - - debug - - encoding - dev: true - - /@openzeppelin/test-helpers@0.5.16(bn.js@4.12.0): - resolution: {integrity: sha512-T1EvspSfH1qQO/sgGlskLfYVBbqzJR23SZzYl/6B2JnT4EhThcI85UpvDk0BkLWKaDScQTabGHt4GzHW+3SfZg==} - dependencies: - '@openzeppelin/contract-loader': 0.6.3 - '@truffle/contract': 4.6.2 - ansi-colors: 3.2.4 - chai: 4.3.10 - chai-bn: 0.2.2(bn.js@4.12.0)(chai@4.3.10) - ethjs-abi: 0.2.1 - lodash.flatten: 4.4.0 - semver: 5.7.1 - web3: 1.8.0 - web3-utils: 1.8.0 - transitivePeerDependencies: - - bn.js - - bufferutil - - encoding - - supports-color - - utf-8-validate - dev: true - - /@openzeppelin/upgrades-core@1.31.3: - resolution: {integrity: sha512-i7q0IuItKS4uO0clJwm4CARmt98aA9dLfKh38HFRbX+aFLGXwF0sOvB2iwr6f87ShH7d3DNuLrVgnnXUrYb7CA==} - hasBin: true - dependencies: - cbor: 9.0.1 - chalk: 4.1.2 - compare-versions: 6.1.0 - debug: 4.3.4(supports-color@8.1.1) - ethereumjs-util: 7.1.5 - minimist: 1.2.8 - proper-lockfile: 4.1.2 - solidity-ast: 0.4.55 - transitivePeerDependencies: - - supports-color - dev: true - - /@pkgr/core@0.1.1: - resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - dev: true - - /@pnpm/config.env-replace@1.1.0: - resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} - engines: {node: '>=12.22.0'} - dev: true - - /@pnpm/network.ca-file@1.0.2: - resolution: {integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==} - engines: {node: '>=12.22.0'} + /@pnpm/config.env-replace@1.1.0: + resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} + engines: {node: '>=12.22.0'} + dev: true + + /@pnpm/network.ca-file@1.0.2: + resolution: {integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==} + engines: {node: '>=12.22.0'} dependencies: graceful-fs: 4.2.10 dev: true @@ -1562,47 +1251,6 @@ packages: prettier: 3.2.5 dev: true - /@resolver-engine/core@0.3.3: - resolution: {integrity: sha512-eB8nEbKDJJBi5p5SrvrvILn4a0h42bKtbCTri3ZxCGt6UvoQyp7HnGOfki944bUjBSHKK3RvgfViHn+kqdXtnQ==} - dependencies: - debug: 3.2.7 - is-url: 1.2.4 - request: 2.88.2 - transitivePeerDependencies: - - supports-color - dev: true - - /@resolver-engine/fs@0.3.3: - resolution: {integrity: sha512-wQ9RhPUcny02Wm0IuJwYMyAG8fXVeKdmhm8xizNByD4ryZlx6PP6kRen+t/haF43cMfmaV7T3Cx6ChOdHEhFUQ==} - dependencies: - '@resolver-engine/core': 0.3.3 - debug: 3.2.7 - transitivePeerDependencies: - - supports-color - dev: true - - /@resolver-engine/imports-fs@0.3.3: - resolution: {integrity: sha512-7Pjg/ZAZtxpeyCFlZR5zqYkz+Wdo84ugB5LApwriT8XFeQoLwGUj4tZFFvvCuxaNCcqZzCYbonJgmGObYBzyCA==} - dependencies: - '@resolver-engine/fs': 0.3.3 - '@resolver-engine/imports': 0.3.3 - debug: 3.2.7 - transitivePeerDependencies: - - supports-color - dev: true - - /@resolver-engine/imports@0.3.3: - resolution: {integrity: sha512-anHpS4wN4sRMwsAbMXhMfOD/y4a4Oo0Cw/5+rue7hSwGWsDOQaAU1ClK1OxjUC35/peazxEl8JaSRRS+Xb8t3Q==} - dependencies: - '@resolver-engine/core': 0.3.3 - debug: 3.2.7 - hosted-git-info: 2.8.9 - path-browserify: 1.0.1 - url: 0.11.0 - transitivePeerDependencies: - - supports-color - dev: true - /@scroll-tech/contracts@0.1.0: resolution: {integrity: sha512-aBbDOc3WB/WveZdpJYcrfvMYMz7ZTEiW8M9XMJLba8p9FAR5KGYB/cV+8+EUsq3MKt7C1BfR+WnXoTVdvwIY6w==} dev: false @@ -1696,52 +1344,17 @@ packages: tslib: 1.14.1 dev: true - /@sindresorhus/is@0.14.0: - resolution: {integrity: sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==} - engines: {node: '>=6'} - requiresBuild: true - dev: true - /@sindresorhus/is@4.6.0: resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} engines: {node: '>=10'} dev: true - /@smithy/types@2.7.0: - resolution: {integrity: sha512-1OIFyhK+vOkMbu4aN2HZz/MomREkrAC/HqY5mlJMUJfGrPRwijJDTeiN8Rnj9zUaB8ogXAfIOtZrrgqZ4w7Wnw==} - engines: {node: '>=14.0.0'} - dependencies: - tslib: 2.6.2 - dev: true - - /@solidity-parser/parser@0.14.3: - resolution: {integrity: sha512-29g2SZ29HtsqA58pLCtopI1P/cPy5/UAzlcAXO6T/CNJimG6yA8kx4NaseMyJULiC+TEs02Y9/yeHzClqoA0hw==} - dependencies: - antlr4ts: 0.5.0-alpha.4 - dev: true - - /@solidity-parser/parser@0.16.0: - resolution: {integrity: sha512-ESipEcHyRHg4Np4SqBCfcXwyxxna1DgFVz69bgpLV8vzl/NP1DtcKsJ4dJZXWQhY/Z4J2LeKBiOkOVZn9ct33Q==} - dependencies: - antlr4ts: 0.5.0-alpha.4 - dev: true - - /@solidity-parser/parser@0.16.2: - resolution: {integrity: sha512-PI9NfoA3P8XK2VBkK5oIfRgKDsicwDZfkVq9ZTBCQYGOP1N2owgY2dyLGyU5/J/hQs8KRk55kdmvTLjy3Mu3vg==} - dependencies: - antlr4ts: 0.5.0-alpha.4 - dev: true - /@solidity-parser/parser@0.17.0: resolution: {integrity: sha512-Nko8R0/kUo391jsEHHxrGM07QFdnPGvlmox4rmH0kNiNAashItAilhy4Mv4pK5gQmW5f4sXAF58fwJbmlkGcVw==} dev: true - /@szmarczak/http-timer@1.1.2: - resolution: {integrity: sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==} - engines: {node: '>=6'} - requiresBuild: true - dependencies: - defer-to-connect: 1.1.1 + /@solidity-parser/parser@0.18.0: + resolution: {integrity: sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA==} dev: true /@szmarczak/http-timer@5.0.1: @@ -1759,34 +1372,6 @@ packages: web3-utils: 1.7.4 dev: true - /@truffle/blockchain-utils@0.1.4: - resolution: {integrity: sha512-HegAo5A8UX9vE8dtceBRgCY207gOb9wj54c8mNOOWHcFpkyJz7kZYGo44As6Imh10/0hD2j7vHQ56Jf+uszJ3A==} - dev: true - - /@truffle/codec@0.14.5: - resolution: {integrity: sha512-3FCpTJe6o7LGWUfrSdguMpdpH1PTn3u7bIfbj6Cfdzym2OAVSgxTgdlqC1poepbk0xcOVcUW+EsqNwLMqmBiPA==} - dependencies: - '@truffle/abi-utils': 0.3.2 - '@truffle/compile-common': 0.8.1 - big.js: 6.2.1 - bn.js: 5.2.1 - cbor: 5.2.0 - debug: 4.3.4(supports-color@8.1.1) - lodash: 4.17.21 - semver: 7.3.7 - utf8: 3.0.0 - web3-utils: 1.7.4 - transitivePeerDependencies: - - supports-color - dev: true - - /@truffle/compile-common@0.8.1: - resolution: {integrity: sha512-7mzzG9Cfrn+fDT5Sqi7B6pccvIIV5w/GM8/56YgnjysbDzy5aZ6mv0fe37ZbcznEVQ35NJjBy+lEr/ozOGXwQA==} - dependencies: - '@truffle/error': 0.1.1 - colors: 1.4.0 - dev: true - /@truffle/contract-schema@3.4.10: resolution: {integrity: sha512-BhRNRoRvlj2th6E5RNS0BnS0ZxQe01JJz8I7MjkGqdeXSvrn6qDCAnbmvhNgUv0l5h8w5+gBOQhAJhILf1shdQ==} dependencies: @@ -1796,71 +1381,6 @@ packages: - supports-color dev: true - /@truffle/contract@4.6.2: - resolution: {integrity: sha512-OZZIDmKtHgZS2Q6sCczNe8OfTuMWpRaAo3vwY49LGGs0VXLiwc7nIcCFh+bMg14IRK6vBN4pWE9W9eWSBFy31Q==} - dependencies: - '@ensdomains/ensjs': 2.1.0 - '@truffle/blockchain-utils': 0.1.4 - '@truffle/contract-schema': 3.4.10 - '@truffle/debug-utils': 6.0.35 - '@truffle/error': 0.1.1 - '@truffle/interface-adapter': 0.5.22 - bignumber.js: 7.2.1 - debug: 4.3.4(supports-color@8.1.1) - ethers: 4.0.49 - web3: 1.7.4 - web3-core-helpers: 1.7.4 - web3-core-promievent: 1.7.4 - web3-eth-abi: 1.7.4 - web3-utils: 1.7.4 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - - /@truffle/debug-utils@6.0.35: - resolution: {integrity: sha512-GuLsc+GFEYiUM683GWh4/ol3jkBts5a601detVWu1Xo5/bSL5gxooOjgOTovjA8dimCjkyi/DnK2yHHC+q+g0g==} - dependencies: - '@truffle/codec': 0.14.5 - '@trufflesuite/chromafi': 3.0.0 - bn.js: 5.2.1 - chalk: 2.4.2 - debug: 4.3.4(supports-color@8.1.1) - highlightjs-solidity: 2.0.5 - transitivePeerDependencies: - - supports-color - dev: true - - /@truffle/error@0.1.1: - resolution: {integrity: sha512-sE7c9IHIGdbK4YayH4BC8i8qMjoAOeg6nUXUDZZp8wlU21/EMpaG+CLx+KqcIPyR+GSWIW3Dm0PXkr2nlggFDA==} - dev: true - - /@truffle/interface-adapter@0.5.22: - resolution: {integrity: sha512-Bgl5Afb1mPVNedI8CJzZQzVIdrZWSXISTBrXPZmppD4Q+6V1RUzlLxiaGGB4gYHOA+U0pBzD8MCcSycPAD9RsA==} - dependencies: - bn.js: 5.2.1 - ethers: 4.0.49 - web3: 1.7.4 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - - /@trufflesuite/chromafi@3.0.0: - resolution: {integrity: sha512-oqWcOqn8nT1bwlPPfidfzS55vqcIDdpfzo3HbU9EnUmcSTX+I8z0UyUFI3tZQjByVJulbzxHxUGS3ZJPwK/GPQ==} - dependencies: - camelcase: 4.1.0 - chalk: 2.4.2 - cheerio: 1.0.0-rc.12 - detect-indent: 5.0.0 - highlight.js: 10.7.3 - lodash.merge: 4.6.2 - strip-ansi: 4.0.0 - strip-indent: 2.0.0 - dev: true - /@tsconfig/node10@1.0.9: resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} dev: true @@ -1877,17 +1397,7 @@ packages: resolution: {integrity: sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==} dev: true - /@typechain/ethers-v5@2.0.0(ethers@5.7.2)(typechain@3.0.0): - resolution: {integrity: sha512-0xdCkyGOzdqh4h5JSf+zoWx85IusEjDcPIwNEHP8mrWSnCae4rvrqB+/gtpdNfX7zjlFlZiMeePn2r63EI3Lrw==} - peerDependencies: - ethers: ^5.0.0 - typechain: ^3.0.0 - dependencies: - ethers: 5.7.2 - typechain: 3.0.0(typescript@5.3.3) - dev: true - - /@typechain/ethers-v5@7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.3.2)(typescript@5.3.3): + /@typechain/ethers-v5@7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.3.2)(typescript@5.4.3): resolution: {integrity: sha512-jfcmlTvaaJjng63QsT49MT6R1HFhtO/TBMWbyzPFSzMmVIqb2tL6prnKBs4ZJrSvmgIXWy+ttSjpaxCTq8D/Tw==} peerDependencies: '@ethersproject/abi': ^5.0.0 @@ -1902,12 +1412,12 @@ packages: '@ethersproject/providers': 5.7.2 ethers: 5.7.2 lodash: 4.17.21 - ts-essentials: 7.0.3(typescript@5.3.3) - typechain: 8.3.2(typescript@5.3.3) - typescript: 5.3.3 + ts-essentials: 7.0.3(typescript@5.4.3) + typechain: 8.3.2(typescript@5.4.3) + typescript: 5.4.3 dev: true - /@typechain/hardhat@7.0.0(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@typechain/ethers-v5@7.2.0)(ethers@5.7.2)(hardhat@2.19.2)(typechain@8.3.2): + /@typechain/hardhat@7.0.0(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@typechain/ethers-v5@7.2.0)(ethers@5.7.2)(hardhat@2.20.1)(typechain@8.3.2): resolution: {integrity: sha512-XB79i5ewg9Met7gMVGfgVkmypicbnI25T5clJBEooMoW2161p4zvKFpoS2O+lBppQyMrPIZkdvl2M3LMDayVcA==} peerDependencies: '@ethersproject/abi': ^5.4.7 @@ -1919,23 +1429,23 @@ packages: dependencies: '@ethersproject/abi': 5.7.0 '@ethersproject/providers': 5.7.2 - '@typechain/ethers-v5': 7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.3.2)(typescript@5.3.3) + '@typechain/ethers-v5': 7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.3.2)(typescript@5.4.3) ethers: 5.7.2 fs-extra: 9.1.0 - hardhat: 2.19.2(ts-node@10.9.2)(typescript@5.3.3) - typechain: 8.3.2(typescript@5.3.3) + hardhat: 2.20.1(ts-node@10.9.2)(typescript@5.4.3) + typechain: 8.3.2(typescript@5.4.3) dev: true /@types/bn.js@4.11.6: resolution: {integrity: sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==} dependencies: - '@types/node': 16.18.80 + '@types/node': 16.18.91 dev: true /@types/bn.js@5.1.1: resolution: {integrity: sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==} dependencies: - '@types/node': 16.18.80 + '@types/node': 16.18.91 dev: true /@types/cacheable-request@6.0.2: @@ -1943,24 +1453,24 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.1 '@types/keyv': 3.1.4 - '@types/node': 16.18.80 + '@types/node': 16.18.91 '@types/responselike': 1.0.0 dev: true /@types/cbor@5.0.1: resolution: {integrity: sha512-zVqJy2KzusZPLOgyGJDnOIbu3DxIGGqxYbEwtEEe4Z+la8jwIhOyb+GMrlHafs5tvKruwf8f8qOYP6zTvse/pw==} dependencies: - '@types/node': 16.18.80 + '@types/node': 16.18.91 dev: true - /@types/chai@4.3.11: - resolution: {integrity: sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==} + /@types/chai-as-promised@7.1.8: + resolution: {integrity: sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw==} + dependencies: + '@types/chai': 4.3.14 dev: true - /@types/concat-stream@1.6.1: - resolution: {integrity: sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==} - dependencies: - '@types/node': 16.18.80 + /@types/chai@4.3.14: + resolution: {integrity: sha512-Wj71sXE4Q4AkGdG9Tvq1u/fquNz9EdG4LIJMwVVII7ashjD/8cf8fyIfJAjRr6YcsXnSE8cOGQPq1gqeR8z+3w==} dev: true /@types/debug@4.1.12: @@ -1973,24 +1483,6 @@ packages: resolution: {integrity: sha512-jT0O3hAILDKeKbdWJ9FZLD0Xdfhz7hMvfyFlRWpirjiEVr8G+GZ4kVIzPIqM6x6Rpp93TNPgOAed4XmvcuV6Qg==} dev: true - /@types/events@3.0.0: - resolution: {integrity: sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==} - dev: true - - /@types/form-data@0.0.33: - resolution: {integrity: sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==} - dependencies: - '@types/node': 16.18.80 - dev: true - - /@types/glob@7.1.1: - resolution: {integrity: sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==} - dependencies: - '@types/events': 3.0.0 - '@types/minimatch': 3.0.3 - '@types/node': 16.18.80 - dev: true - /@types/http-cache-semantics@4.0.1: resolution: {integrity: sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==} dev: true @@ -2008,27 +1500,17 @@ packages: /@types/keyv@3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 16.18.80 + '@types/node': 16.18.91 dev: true /@types/lru-cache@5.1.1: resolution: {integrity: sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==} dev: true - /@types/minimatch@3.0.3: - resolution: {integrity: sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==} - dev: true - /@types/minimist@1.2.5: resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} dev: false - /@types/mkdirp@0.5.2: - resolution: {integrity: sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg==} - dependencies: - '@types/node': 16.18.80 - dev: true - /@types/mocha@10.0.6: resolution: {integrity: sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==} dev: true @@ -2037,26 +1519,12 @@ packages: resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} dev: true - /@types/node-fetch@2.6.2: - resolution: {integrity: sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==} - dependencies: - '@types/node': 16.18.80 - form-data: 3.0.1 - dev: true - - /@types/node@10.17.60: - resolution: {integrity: sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==} - dev: true - /@types/node@12.19.16: resolution: {integrity: sha512-7xHmXm/QJ7cbK2laF+YYD7gb5MggHIIQwqyjin3bpEGiSuvScMQ5JZZXPvRipi1MwckTQbJZROMns/JxdnIL1Q==} + dev: false - /@types/node@16.18.80: - resolution: {integrity: sha512-vFxJ1Iyl7A0+xB0uW1r1v504yItKZLdqg/VZELUZ4H02U0bXAgBisSQ8Erf0DMruNFz9ggoiEv6T8Ll9bTg8Jw==} - dev: true - - /@types/node@8.10.66: - resolution: {integrity: sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==} + /@types/node@16.18.91: + resolution: {integrity: sha512-h8Q4klc8xzc9kJKr7UYNtJde5TU2qEePVyH3WyzJaUC+3ptyc5kPQbWOIUcn8ZsG5+KSkq+P0py0kC0VqxgAXw==} dev: true /@types/normalize-package-data@2.4.4: @@ -2066,63 +1534,36 @@ packages: /@types/pbkdf2@3.1.0: resolution: {integrity: sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==} dependencies: - '@types/node': 16.18.80 + '@types/node': 16.18.91 dev: true /@types/prettier@2.7.1: resolution: {integrity: sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==} dev: true - /@types/qs@6.9.7: - resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==} - dev: true - /@types/readable-stream@2.3.15: resolution: {integrity: sha512-oM5JSKQCcICF1wvGgmecmHldZ48OZamtMxcGGVICOJA8o8cahXC1zEVAif8iwoc5j8etxFaRFnf095+CDsuoFQ==} dependencies: - '@types/node': 16.18.80 + '@types/node': 16.18.91 safe-buffer: 5.1.2 dev: true - /@types/resolve@0.0.8: - resolution: {integrity: sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==} - dependencies: - '@types/node': 16.18.80 - dev: true - /@types/responselike@1.0.0: resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} dependencies: - '@types/node': 16.18.80 + '@types/node': 16.18.91 dev: true /@types/secp256k1@4.0.3: resolution: {integrity: sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==} dependencies: - '@types/node': 16.18.80 + '@types/node': 16.18.91 dev: true /@types/semver@7.5.0: resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==} - /@types/sinon-chai@3.2.8: - resolution: {integrity: sha512-d4ImIQbT/rKMG8+AXpmcan5T2/PNeSjrYhvkwet6z0p8kzYtfgA32xzOBlbU0yqJfq+/0Ml805iFoODO0LP5/g==} - dependencies: - '@types/chai': 4.3.11 - '@types/sinon': 10.0.13 - dev: true - - /@types/sinon@10.0.13: - resolution: {integrity: sha512-UVjDqJblVNQYvVNUsj0PuYYw0ELRmgt1Nt5Vk0pT5f16ROGfcKJY8o1HVuMOJOpD727RrGB9EGvoaTQE5tgxZQ==} - dependencies: - '@types/sinonjs__fake-timers': 8.1.2 - dev: true - - /@types/sinonjs__fake-timers@8.1.2: - resolution: {integrity: sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==} - dev: true - - /@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.56.0)(typescript@5.3.3): + /@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.4.3): resolution: {integrity: sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -2134,24 +1575,24 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.9.1 - '@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.4.3) '@typescript-eslint/scope-manager': 6.21.0 - '@typescript-eslint/type-utils': 6.21.0(eslint@8.56.0)(typescript@5.3.3) - '@typescript-eslint/utils': 6.21.0(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/type-utils': 6.21.0(eslint@8.57.0)(typescript@5.4.3) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.4.3) '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 8.56.0 + eslint: 8.57.0 graphemer: 1.4.0 ignore: 5.2.4 natural-compare: 1.4.0 - semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@5.3.3) - typescript: 5.3.3 + semver: 7.6.0 + ts-api-utils: 1.0.3(typescript@5.4.3) + typescript: 5.4.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3): + /@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.3): resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -2163,11 +1604,11 @@ packages: dependencies: '@typescript-eslint/scope-manager': 6.21.0 '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.3.3) + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.3) '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 8.56.0 - typescript: 5.3.3 + eslint: 8.57.0 + typescript: 5.4.3 transitivePeerDependencies: - supports-color dev: true @@ -2180,7 +1621,7 @@ packages: '@typescript-eslint/visitor-keys': 6.21.0 dev: true - /@typescript-eslint/type-utils@6.21.0(eslint@8.56.0)(typescript@5.3.3): + /@typescript-eslint/type-utils@6.21.0(eslint@8.57.0)(typescript@5.4.3): resolution: {integrity: sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -2190,12 +1631,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.3.3) - '@typescript-eslint/utils': 6.21.0(eslint@8.56.0)(typescript@5.3.3) + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.3) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.4.3) debug: 4.3.4(supports-color@8.1.1) - eslint: 8.56.0 - ts-api-utils: 1.0.3(typescript@5.3.3) - typescript: 5.3.3 + eslint: 8.57.0 + ts-api-utils: 1.0.3(typescript@5.4.3) + typescript: 5.4.3 transitivePeerDependencies: - supports-color dev: true @@ -2205,7 +1646,7 @@ packages: engines: {node: ^16.0.0 || >=18.0.0} dev: true - /@typescript-eslint/typescript-estree@6.21.0(typescript@5.3.3): + /@typescript-eslint/typescript-estree@6.21.0(typescript@5.4.3): resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -2220,27 +1661,27 @@ packages: globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 - semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@5.3.3) - typescript: 5.3.3 + semver: 7.6.0 + ts-api-utils: 1.0.3(typescript@5.4.3) + typescript: 5.4.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@6.21.0(eslint@8.56.0)(typescript@5.3.3): + /@typescript-eslint/utils@6.21.0(eslint@8.57.0)(typescript@5.4.3): resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.56.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@types/json-schema': 7.0.13 '@types/semver': 7.5.0 '@typescript-eslint/scope-manager': 6.21.0 '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.3.3) - eslint: 8.56.0 - semver: 7.5.4 + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.3) + eslint: 8.57.0 + semver: 7.6.0 transitivePeerDependencies: - supports-color - typescript @@ -2258,18 +1699,6 @@ packages: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} dev: true - /@yarnpkg/lockfile@1.1.0: - resolution: {integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==} - dev: true - - /abbrev@1.0.9: - resolution: {integrity: sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==} - dev: true - - /abbrev@1.1.1: - resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} - dev: true - /abi-to-sol@0.6.6: resolution: {integrity: sha512-PRn81rSpv6NXFPYQSw7ujruqIP6UkwZ/XoFldtiqCX8+2kHVc73xVaUVvdbro06vvBVZiwnxhEIGdI4BRMwGHw==} hasBin: true @@ -2279,7 +1708,7 @@ packages: ajv: 6.12.6 better-ajv-errors: 0.8.2(ajv@6.12.6) neodoc: 2.0.2 - semver: 7.5.4 + semver: 7.6.0 source-map-support: 0.5.21 optionalDependencies: prettier: 2.8.8 @@ -2288,58 +1717,6 @@ packages: - supports-color dev: true - /abortcontroller-polyfill@1.7.3: - resolution: {integrity: sha512-zetDJxd89y3X99Kvo4qFx8GKlt6GsvN3UcRZHwU6iFA/0KiOmhkTVhe8oRoTBiTVPZu09x3vCra47+w8Yz1+2Q==} - dev: true - - /abstract-level@1.0.3: - resolution: {integrity: sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA==} - engines: {node: '>=12'} - dependencies: - buffer: 6.0.3 - catering: 2.1.1 - is-buffer: 2.0.5 - level-supports: 4.0.1 - level-transcoder: 1.0.1 - module-error: 1.0.2 - queue-microtask: 1.2.3 - dev: true - - /abstract-leveldown@2.6.3: - resolution: {integrity: sha512-2++wDf/DYqkPR3o5tbfdhF96EfMApo1GpPfzOsR/ZYXdkSmELlvOOEAl9iKkRsktMPHdGjO4rtkBpf2I7TiTeA==} - dependencies: - xtend: 4.0.2 - dev: true - - /abstract-leveldown@2.7.2: - resolution: {integrity: sha512-+OVvxH2rHVEhWLdbudP6p0+dNMXu8JA1CbhP19T8paTYAcX7oJ4OVjT+ZUVpv7mITxXHqDMej+GdqXBmXkw09w==} - dependencies: - xtend: 4.0.2 - dev: true - - /abstract-leveldown@3.0.0: - resolution: {integrity: sha512-KUWx9UWGQD12zsmLNj64/pndaz4iJh/Pj7nopgkfDG6RlCcbMZvT6+9l7dchK4idog2Is8VdC/PvNbFuFmalIQ==} - engines: {node: '>=4'} - dependencies: - xtend: 4.0.2 - dev: true - - /abstract-leveldown@5.0.0: - resolution: {integrity: sha512-5mU5P1gXtsMIXg65/rsYGsi93+MlogXZ9FA8JnwKurHQg64bfXwGYVdVdijNTVNOlAsuIiOwHdvFFD5JqCJQ7A==} - engines: {node: '>=6'} - dependencies: - xtend: 4.0.2 - dev: true - - /accepts@1.3.7: - resolution: {integrity: sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==} - engines: {node: '>= 0.6'} - requiresBuild: true - dependencies: - mime-types: 2.1.27 - negotiator: 0.6.2 - dev: true - /acorn-jsx@5.3.2(acorn@8.10.0): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -2359,11 +1736,6 @@ packages: hasBin: true dev: true - /address@1.1.2: - resolution: {integrity: sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==} - engines: {node: '>= 0.12.0'} - dev: true - /adm-zip@0.4.16: resolution: {integrity: sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==} engines: {node: '>=0.3.0'} @@ -2372,12 +1744,6 @@ packages: /aes-js@3.0.0: resolution: {integrity: sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==} - /aes-js@3.1.2: - resolution: {integrity: sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==} - requiresBuild: true - dev: true - optional: true - /agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} @@ -2413,33 +1779,10 @@ packages: uri-js: 4.4.1 dev: true - /amazon-cognito-identity-js@6.3.7: - resolution: {integrity: sha512-tSjnM7KyAeOZ7UMah+oOZ6cW4Gf64FFcc7BE2l7MTcp7ekAPrXaCbpcW2xEpH1EiDS4cPcAouHzmCuc2tr72vQ==} + /ansi-align@3.0.1: + resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} dependencies: - '@aws-crypto/sha256-js': 1.2.2 - buffer: 4.9.2 - fast-base64-decode: 1.0.0 - isomorphic-unfetch: 3.1.0 - js-cookie: 2.2.1 - transitivePeerDependencies: - - encoding - dev: true - - /amdefine@1.0.1: - resolution: {integrity: sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==} - engines: {node: '>=0.4.2'} - requiresBuild: true - dev: true - optional: true - - /ansi-colors@3.2.3: - resolution: {integrity: sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==} - engines: {node: '>=6'} - dev: true - - /ansi-colors@3.2.4: - resolution: {integrity: sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==} - engines: {node: '>=6'} + string-width: 4.2.3 dev: true /ansi-colors@4.1.1: @@ -2463,25 +1806,10 @@ packages: engines: {node: '>=0.10.0'} dev: true - /ansi-regex@3.0.1: - resolution: {integrity: sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==} - engines: {node: '>=4'} - dev: true - - /ansi-regex@4.1.1: - resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} - engines: {node: '>=6'} - dev: true - /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - /ansi-styles@2.2.1: - resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==} - engines: {node: '>=0.10.0'} - dev: true - /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} @@ -2494,15 +1822,11 @@ packages: dependencies: color-convert: 2.0.1 - /antlr4@4.13.0: - resolution: {integrity: sha512-zooUbt+UscjnWyOrsuY/tVFL4rwrAGwOivpQmvmUDE22hy/lUA467Rc1rcixyRwcRUIXFYBwv7+dClDSHdmmew==} + /antlr4@4.13.1-patch-1: + resolution: {integrity: sha512-OjFLWWLzDMV9rdFhpvroCWR4ooktNg9/nvVYSA5z28wuVpU36QUNuioR1XLnQtcjVlf8npjyz593PxnU/f/Cow==} engines: {node: '>=16'} dev: true - /antlr4ts@0.5.0-alpha.4: - resolution: {integrity: sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==} - dev: true - /anymatch@3.1.2: resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==} engines: {node: '>= 8'} @@ -2519,48 +1843,20 @@ packages: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} dependencies: sprintf-js: 1.0.3 + dev: false /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} dev: true - /arr-diff@4.0.0: - resolution: {integrity: sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==} - engines: {node: '>=0.10.0'} - dev: true - - /arr-flatten@1.1.0: - resolution: {integrity: sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==} - engines: {node: '>=0.10.0'} + /array-back@3.1.0: + resolution: {integrity: sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==} + engines: {node: '>=6'} dev: true - /arr-union@3.1.0: - resolution: {integrity: sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==} - engines: {node: '>=0.10.0'} - dev: true - - /array-back@1.0.4: - resolution: {integrity: sha512-1WxbZvrmyhkNoeYcizokbmh5oiOCIfyvGtcqbK3Ls1v1fKcquzxnQSceOx6tzq7jmai2kFLWIpGND2cLhH6TPw==} - engines: {node: '>=0.12.0'} - dependencies: - typical: 2.6.1 - dev: true - - /array-back@2.0.0: - resolution: {integrity: sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==} - engines: {node: '>=4'} - dependencies: - typical: 2.6.1 - dev: true - - /array-back@3.1.0: - resolution: {integrity: sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==} - engines: {node: '>=6'} - dev: true - - /array-back@4.0.2: - resolution: {integrity: sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==} - engines: {node: '>=8'} + /array-back@4.0.2: + resolution: {integrity: sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==} + engines: {node: '>=8'} dev: true /array-buffer-byte-length@1.0.0: @@ -2568,37 +1864,12 @@ packages: dependencies: call-bind: 1.0.5 is-array-buffer: 3.0.2 - - /array-flatten@1.1.1: - resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - requiresBuild: true - dev: true + dev: false /array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} - /array-uniq@1.0.3: - resolution: {integrity: sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==} - engines: {node: '>=0.10.0'} - dev: true - - /array-unique@0.3.2: - resolution: {integrity: sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==} - engines: {node: '>=0.10.0'} - dev: true - - /array.prototype.findlast@1.2.3: - resolution: {integrity: sha512-kcBubumjciBg4JKp5KTKtI7ec7tRefPk88yjkWJwaVKYd9QfTaxcsOxoMNKd7iBr447zCfDV0z1kOF47umv42g==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.1 - es-abstract: 1.22.3 - es-shim-unscopables: 1.0.2 - get-intrinsic: 1.2.2 - dev: true - /array.prototype.flat@1.3.2: resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} engines: {node: '>= 0.4'} @@ -2609,17 +1880,6 @@ packages: es-shim-unscopables: 1.0.2 dev: false - /array.prototype.reduce@1.0.4: - resolution: {integrity: sha512-WnM+AjG/DvLRLo4DDl+r+SvCzYtD2Jd9oeBYMcEaI7t3fFrHY9M53/wdLcTvmZNQ70IU6Htj0emFkZ5TS+lrdw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 - es-array-method-boxes-properly: 1.0.0 - is-string: 1.0.7 - dev: true - /arraybuffer.prototype.slice@1.0.2: resolution: {integrity: sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==} engines: {node: '>= 0.4'} @@ -2631,44 +1891,16 @@ packages: get-intrinsic: 1.2.2 is-array-buffer: 3.0.2 is-shared-array-buffer: 1.0.2 + dev: false /arrify@1.0.1: resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} engines: {node: '>=0.10.0'} dev: false - /asap@2.0.6: - resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} - dev: true - - /asn1.js@4.10.1: - resolution: {integrity: sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==} - requiresBuild: true - dependencies: - bn.js: 4.12.0 - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - dev: true - - /asn1@0.2.4: - resolution: {integrity: sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==} - dependencies: - safer-buffer: 2.1.2 - dev: true - - /assert-plus@1.0.0: - resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} - engines: {node: '>=0.8'} - dev: true - /assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} - /assign-symbols@1.0.0: - resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==} - engines: {node: '>=0.10.0'} - dev: true - /ast-parents@0.0.1: resolution: {integrity: sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA==} dev: true @@ -2678,9974 +1910,3856 @@ packages: engines: {node: '>=8'} dev: true - /async-eventemitter@0.2.4: - resolution: {integrity: sha512-pd20BwL7Yt1zwDFy+8MX8F1+WCT8aQeKj0kQnTrH9WaeRETlRamVhD0JtRPmrV4GfOJ2F9CvdQkZeZhnh2TuHw==} - dependencies: - async: 2.6.3 - dev: true - - /async-limiter@1.0.1: - resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==} - dev: true - - /async-retry@1.3.3: - resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} - dependencies: - retry: 0.13.1 - dev: true - - /async@1.5.2: - resolution: {integrity: sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==} - dev: true - - /async@2.6.2: - resolution: {integrity: sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==} - dependencies: - lodash: 4.17.21 - dev: true - - /async@2.6.3: - resolution: {integrity: sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==} - dependencies: - lodash: 4.17.21 - dev: true - - /asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - dev: true - /at-least-node@1.0.0: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} dev: true - /atob@2.1.2: - resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==} - engines: {node: '>= 4.5.0'} - hasBin: true - dev: true - /available-typed-arrays@1.0.5: resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} engines: {node: '>= 0.4'} + dev: false - /aws-sign2@0.7.0: - resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} - dev: true - - /aws4@1.11.0: - resolution: {integrity: sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==} + /balanced-match@1.0.0: + resolution: {integrity: sha512-9Y0g0Q8rmSt+H33DfKv7FOc3v+iRI+o1lbzt8jGcIosYW37IIW/2XVYq5NPdmaD5NQ59Nk26Kl/vZbwW9Fr8vg==} dev: true - /axios@0.21.4(debug@4.3.4): - resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} + /base-x@3.0.9: + resolution: {integrity: sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==} dependencies: - follow-redirects: 1.15.2(debug@4.3.4) - transitivePeerDependencies: - - debug + safe-buffer: 5.2.1 dev: true - /axios@1.6.2(debug@4.3.4): - resolution: {integrity: sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==} - dependencies: - follow-redirects: 1.15.2(debug@4.3.4) - form-data: 4.0.0 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - dev: true + /bech32@1.1.4: + resolution: {integrity: sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==} - /babel-code-frame@6.26.0: - resolution: {integrity: sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==} + /better-ajv-errors@0.8.2(ajv@6.12.6): + resolution: {integrity: sha512-FnODTBJSQSHmJXDLPiC7ca0dC4S1HSTPv1+Hg2sm/C71i3Dj0l1jcUEaq/3OQ6MmnUveshTsUvUj65pDSr3Qow==} + peerDependencies: + ajv: 4.11.8 - 8 dependencies: - chalk: 1.1.3 - esutils: 2.0.3 - js-tokens: 3.0.2 - dev: true - - /babel-core@6.26.3: - resolution: {integrity: sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==} - dependencies: - babel-code-frame: 6.26.0 - babel-generator: 6.26.1 - babel-helpers: 6.24.1 - babel-messages: 6.23.0 - babel-register: 6.26.0 - babel-runtime: 6.26.0 - babel-template: 6.26.0 - babel-traverse: 6.26.0 - babel-types: 6.26.0 - babylon: 6.18.0 - convert-source-map: 1.8.0 - debug: 2.6.9 - json5: 0.5.1 - lodash: 4.17.21 - minimatch: 3.1.2 - path-is-absolute: 1.0.1 - private: 0.1.8 - slash: 1.0.0 - source-map: 0.5.7 - transitivePeerDependencies: - - supports-color + '@babel/code-frame': 7.18.6 + '@babel/runtime': 7.24.0 + ajv: 6.12.6 + chalk: 2.4.2 + core-js: 3.30.1 + json-to-ast: 2.1.0 + jsonpointer: 5.0.1 + leven: 3.1.0 dev: true - /babel-generator@6.26.1: - resolution: {integrity: sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==} + /better-path-resolve@1.0.0: + resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} + engines: {node: '>=4'} dependencies: - babel-messages: 6.23.0 - babel-runtime: 6.26.0 - babel-types: 6.26.0 - detect-indent: 4.0.0 - jsesc: 1.3.0 - lodash: 4.17.21 - source-map: 0.5.7 - trim-right: 1.0.1 - dev: true + is-windows: 1.0.2 + dev: false - /babel-helper-builder-binary-assignment-operator-visitor@6.24.1: - resolution: {integrity: sha512-gCtfYORSG1fUMX4kKraymq607FWgMWg+j42IFPc18kFQEsmtaibP4UrqsXt8FlEJle25HUd4tsoDR7H2wDhe9Q==} - dependencies: - babel-helper-explode-assignable-expression: 6.24.1 - babel-runtime: 6.26.0 - babel-types: 6.26.0 - transitivePeerDependencies: - - supports-color + /bigint-crypto-utils@3.3.0: + resolution: {integrity: sha512-jOTSb+drvEDxEq6OuUybOAv/xxoh3cuYRUIPyu8sSHQNKM303UQ2R1DAo45o1AkcIXw6fzbaFI1+xGGdaXs2lg==} + engines: {node: '>=14.0.0'} dev: true - /babel-helper-call-delegate@6.24.1: - resolution: {integrity: sha512-RL8n2NiEj+kKztlrVJM9JT1cXzzAdvWFh76xh/H1I4nKwunzE4INBXn8ieCZ+wh4zWszZk7NBS1s/8HR5jDkzQ==} - dependencies: - babel-helper-hoist-variables: 6.24.1 - babel-runtime: 6.26.0 - babel-traverse: 6.26.0 - babel-types: 6.26.0 - transitivePeerDependencies: - - supports-color + /bignumber.js@9.1.0: + resolution: {integrity: sha512-4LwHK4nfDOraBCtst+wOWIHbu1vhvAPJK8g8nROd4iuc3PSEjWif/qwbkh8jwCJz6yDBvtU4KPynETgrfh7y3A==} dev: true - /babel-helper-define-map@6.26.0: - resolution: {integrity: sha512-bHkmjcC9lM1kmZcVpA5t2om2nzT/xiZpo6TJq7UlZ3wqKfzia4veeXbIhKvJXAMzhhEBd3cR1IElL5AenWEUpA==} - dependencies: - babel-helper-function-name: 6.24.1 - babel-runtime: 6.26.0 - babel-types: 6.26.0 - lodash: 4.17.21 - transitivePeerDependencies: - - supports-color + /binary-extensions@2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} dev: true - /babel-helper-explode-assignable-expression@6.24.1: - resolution: {integrity: sha512-qe5csbhbvq6ccry9G7tkXbzNtcDiH4r51rrPUbwwoTzZ18AqxWYRZT6AOmxrpxKnQBW0pYlBI/8vh73Z//78nQ==} - dependencies: - babel-runtime: 6.26.0 - babel-traverse: 6.26.0 - babel-types: 6.26.0 - transitivePeerDependencies: - - supports-color + /blakejs@1.2.1: + resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} dev: true - /babel-helper-function-name@6.24.1: - resolution: {integrity: sha512-Oo6+e2iX+o9eVvJ9Y5eKL5iryeRdsIkwRYheCuhYdVHsdEQysbc2z2QkqCLIYnNxkT5Ss3ggrHdXiDI7Dhrn4Q==} - dependencies: - babel-helper-get-function-arity: 6.24.1 - babel-runtime: 6.26.0 - babel-template: 6.26.0 - babel-traverse: 6.26.0 - babel-types: 6.26.0 - transitivePeerDependencies: - - supports-color + /bn.js@4.11.6: + resolution: {integrity: sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==} dev: true - /babel-helper-get-function-arity@6.24.1: - resolution: {integrity: sha512-WfgKFX6swFB1jS2vo+DwivRN4NB8XUdM3ij0Y1gnC21y1tdBoe6xjVnd7NSI6alv+gZXCtJqvrTeMW3fR/c0ng==} - dependencies: - babel-runtime: 6.26.0 - babel-types: 6.26.0 - dev: true + /bn.js@4.12.0: + resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} - /babel-helper-hoist-variables@6.24.1: - resolution: {integrity: sha512-zAYl3tqerLItvG5cKYw7f1SpvIxS9zi7ohyGHaI9cgDUjAT6YcY9jIEH5CstetP5wHIVSceXwNS7Z5BpJg+rOw==} + /bn.js@5.2.1: + resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} + + /boxen@5.1.2: + resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==} + engines: {node: '>=10'} dependencies: - babel-runtime: 6.26.0 - babel-types: 6.26.0 + ansi-align: 3.0.1 + camelcase: 6.3.0 + chalk: 4.1.2 + cli-boxes: 2.2.1 + string-width: 4.2.3 + type-fest: 0.20.2 + widest-line: 3.1.0 + wrap-ansi: 7.0.0 dev: true - /babel-helper-optimise-call-expression@6.24.1: - resolution: {integrity: sha512-Op9IhEaxhbRT8MDXx2iNuMgciu2V8lDvYCNQbDGjdBNCjaMvyLf4wl4A3b8IgndCyQF8TwfgsQ8T3VD8aX1/pA==} + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: - babel-runtime: 6.26.0 - babel-types: 6.26.0 + balanced-match: 1.0.0 + concat-map: 0.0.1 dev: true - /babel-helper-regex@6.26.0: - resolution: {integrity: sha512-VlPiWmqmGJp0x0oK27Out1D+71nVVCTSdlbhIVoaBAj2lUgrNjBCRR9+llO4lTSb2O4r7PJg+RobRkhBrf6ofg==} + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} dependencies: - babel-runtime: 6.26.0 - babel-types: 6.26.0 - lodash: 4.17.21 + balanced-match: 1.0.0 dev: true - /babel-helper-remap-async-to-generator@6.24.1: - resolution: {integrity: sha512-RYqaPD0mQyQIFRu7Ho5wE2yvA/5jxqCIj/Lv4BXNq23mHYu/vxikOy2JueLiBxQknwapwrJeNCesvY0ZcfnlHg==} + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} dependencies: - babel-helper-function-name: 6.24.1 - babel-runtime: 6.26.0 - babel-template: 6.26.0 - babel-traverse: 6.26.0 - babel-types: 6.26.0 - transitivePeerDependencies: - - supports-color - dev: true + fill-range: 7.0.1 - /babel-helper-replace-supers@6.24.1: - resolution: {integrity: sha512-sLI+u7sXJh6+ToqDr57Bv973kCepItDhMou0xCP2YPVmR1jkHSCY+p1no8xErbV1Siz5QE8qKT1WIwybSWlqjw==} + /breakword@1.0.6: + resolution: {integrity: sha512-yjxDAYyK/pBvws9H4xKYpLDpYKEH6CzrBPAuXq3x18I+c/2MkVtT3qAr7Oloi6Dss9qNhPVueAAVU1CSeNDIXw==} dependencies: - babel-helper-optimise-call-expression: 6.24.1 - babel-messages: 6.23.0 - babel-runtime: 6.26.0 - babel-template: 6.26.0 - babel-traverse: 6.26.0 - babel-types: 6.26.0 - transitivePeerDependencies: - - supports-color + wcwidth: 1.0.1 + dev: false + + /brorand@1.1.0: + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + + /browser-stdout@1.3.1: + resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} dev: true - /babel-helpers@6.24.1: - resolution: {integrity: sha512-n7pFrqQm44TCYvrCDb0MqabAF+JUBq+ijBvNMUxpkLjJaAu32faIexewMumrH5KLLJ1HDyT0PTEqRyAe/GwwuQ==} + /browserify-aes@1.2.0: + resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} dependencies: - babel-runtime: 6.26.0 - babel-template: 6.26.0 - transitivePeerDependencies: - - supports-color + buffer-xor: 1.0.3 + cipher-base: 1.0.4 + create-hash: 1.2.0 + evp_bytestokey: 1.0.3 + inherits: 2.0.4 + safe-buffer: 5.2.1 dev: true - /babel-messages@6.23.0: - resolution: {integrity: sha512-Bl3ZiA+LjqaMtNYopA9TYE9HP1tQ+E5dLxE0XrAzcIJeK2UqF0/EaqXwBn9esd4UmTfEab+P+UYQ1GnioFIb/w==} + /bs58@4.0.1: + resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} dependencies: - babel-runtime: 6.26.0 + base-x: 3.0.9 dev: true - /babel-plugin-check-es2015-constants@6.22.0: - resolution: {integrity: sha512-B1M5KBP29248dViEo1owyY32lk1ZSH2DaNNrXLGt8lyjjHm7pBqAdQ7VKUPR6EEDO323+OvT3MQXbCin8ooWdA==} + /bs58check@2.1.2: + resolution: {integrity: sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==} dependencies: - babel-runtime: 6.26.0 + bs58: 4.0.1 + create-hash: 1.2.0 + safe-buffer: 5.2.1 dev: true - /babel-plugin-syntax-async-functions@6.13.0: - resolution: {integrity: sha512-4Zp4unmHgw30A1eWI5EpACji2qMocisdXhAftfhXoSV9j0Tvj6nRFE3tOmRY912E0FMRm/L5xWE7MGVT2FoLnw==} + /buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} dev: true - /babel-plugin-syntax-exponentiation-operator@6.13.0: - resolution: {integrity: sha512-Z/flU+T9ta0aIEKl1tGEmN/pZiI1uXmCiGFRegKacQfEJzp7iNsKloZmyJlQr+75FCJtiFfGIK03SiCvCt9cPQ==} + /buffer-xor@1.0.3: + resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} dev: true - /babel-plugin-syntax-trailing-function-commas@6.22.0: - resolution: {integrity: sha512-Gx9CH3Q/3GKbhs07Bszw5fPTlU+ygrOGfAhEt7W2JICwufpC4SuO0mG0+4NykPBSYPMJhqvVlDBU17qB1D+hMQ==} - dev: true + /bufio@1.0.7: + resolution: {integrity: sha512-bd1dDQhiC+bEbEfg56IdBv7faWa6OipMs/AFFFvtFnB3wAYjlwQpQRZ0pm6ZkgtfL0pILRXhKxOiQj6UzoMR7A==} + engines: {node: '>=8.0.0'} + dev: false - /babel-plugin-transform-async-to-generator@6.24.1: - resolution: {integrity: sha512-7BgYJujNCg0Ti3x0c/DL3tStvnKS6ktIYOmo9wginv/dfZOrbSZ+qG4IRRHMBOzZ5Awb1skTiAsQXg/+IWkZYw==} + /busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} dependencies: - babel-helper-remap-async-to-generator: 6.24.1 - babel-plugin-syntax-async-functions: 6.13.0 - babel-runtime: 6.26.0 - transitivePeerDependencies: - - supports-color + streamsearch: 1.1.0 dev: true - /babel-plugin-transform-es2015-arrow-functions@6.22.0: - resolution: {integrity: sha512-PCqwwzODXW7JMrzu+yZIaYbPQSKjDTAsNNlK2l5Gg9g4rz2VzLnZsStvp/3c46GfXpwkyufb3NCyG9+50FF1Vg==} - dependencies: - babel-runtime: 6.26.0 + /bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} dev: true - /babel-plugin-transform-es2015-block-scoped-functions@6.22.0: - resolution: {integrity: sha512-2+ujAT2UMBzYFm7tidUsYh+ZoIutxJ3pN9IYrF1/H6dCKtECfhmB8UkHVpyxDwkj0CYbQG35ykoz925TUnBc3A==} - dependencies: - babel-runtime: 6.26.0 + /cacheable-lookup@6.1.0: + resolution: {integrity: sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww==} + engines: {node: '>=10.6.0'} dev: true - /babel-plugin-transform-es2015-block-scoping@6.26.0: - resolution: {integrity: sha512-YiN6sFAQ5lML8JjCmr7uerS5Yc/EMbgg9G8ZNmk2E3nYX4ckHR01wrkeeMijEf5WHNK5TW0Sl0Uu3pv3EdOJWw==} + /cacheable-request@7.0.2: + resolution: {integrity: sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==} + engines: {node: '>=8'} dependencies: - babel-runtime: 6.26.0 - babel-template: 6.26.0 - babel-traverse: 6.26.0 - babel-types: 6.26.0 - lodash: 4.17.21 - transitivePeerDependencies: - - supports-color + clone-response: 1.0.2 + get-stream: 5.1.0 + http-cache-semantics: 4.0.3 + keyv: 4.5.0 + lowercase-keys: 2.0.0 + normalize-url: 6.1.0 + responselike: 2.0.1 dev: true - /babel-plugin-transform-es2015-classes@6.24.1: - resolution: {integrity: sha512-5Dy7ZbRinGrNtmWpquZKZ3EGY8sDgIVB4CU8Om8q8tnMLrD/m94cKglVcHps0BCTdZ0TJeeAWOq2TK9MIY6cag==} + /call-bind@1.0.2: + resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} dependencies: - babel-helper-define-map: 6.26.0 - babel-helper-function-name: 6.24.1 - babel-helper-optimise-call-expression: 6.24.1 - babel-helper-replace-supers: 6.24.1 - babel-messages: 6.23.0 - babel-runtime: 6.26.0 - babel-template: 6.26.0 - babel-traverse: 6.26.0 - babel-types: 6.26.0 - transitivePeerDependencies: - - supports-color - dev: true - - /babel-plugin-transform-es2015-computed-properties@6.24.1: - resolution: {integrity: sha512-C/uAv4ktFP/Hmh01gMTvYvICrKze0XVX9f2PdIXuriCSvUmV9j+u+BB9f5fJK3+878yMK6dkdcq+Ymr9mrcLzw==} - dependencies: - babel-runtime: 6.26.0 - babel-template: 6.26.0 - transitivePeerDependencies: - - supports-color - dev: true + function-bind: 1.1.1 + get-intrinsic: 1.1.3 + dev: false - /babel-plugin-transform-es2015-destructuring@6.23.0: - resolution: {integrity: sha512-aNv/GDAW0j/f4Uy1OEPZn1mqD+Nfy9viFGBfQ5bZyT35YqOiqx7/tXdyfZkJ1sC21NyEsBdfDY6PYmLHF4r5iA==} + /call-bind@1.0.5: + resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} dependencies: - babel-runtime: 6.26.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.2 + set-function-length: 1.1.1 + dev: false + + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} dev: true - /babel-plugin-transform-es2015-duplicate-keys@6.24.1: - resolution: {integrity: sha512-ossocTuPOssfxO2h+Z3/Ea1Vo1wWx31Uqy9vIiJusOP4TbF7tPs9U0sJ9pX9OJPf4lXRGj5+6Gkl/HHKiAP5ug==} + /camel-case@3.0.0: + resolution: {integrity: sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==} dependencies: - babel-runtime: 6.26.0 - babel-types: 6.26.0 + no-case: 2.3.2 + upper-case: 1.1.3 dev: true - /babel-plugin-transform-es2015-for-of@6.23.0: - resolution: {integrity: sha512-DLuRwoygCoXx+YfxHLkVx5/NpeSbVwfoTeBykpJK7JhYWlL/O8hgAK/reforUnZDlxasOrVPPJVI/guE3dCwkw==} + /camelcase-keys@6.2.2: + resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==} + engines: {node: '>=8'} dependencies: - babel-runtime: 6.26.0 + camelcase: 5.3.1 + map-obj: 4.3.0 + quick-lru: 4.0.1 + dev: false + + /camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + dev: false + + /camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} dev: true - /babel-plugin-transform-es2015-function-name@6.24.1: - resolution: {integrity: sha512-iFp5KIcorf11iBqu/y/a7DK3MN5di3pNCzto61FqCNnUX4qeBwcV1SLqe10oXNnCaxBUImX3SckX2/o1nsrTcg==} + /cbor@5.2.0: + resolution: {integrity: sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==} + engines: {node: '>=6.0.0'} dependencies: - babel-helper-function-name: 6.24.1 - babel-runtime: 6.26.0 - babel-types: 6.26.0 - transitivePeerDependencies: - - supports-color + bignumber.js: 9.1.0 + nofilter: 1.0.4 dev: true - /babel-plugin-transform-es2015-literals@6.22.0: - resolution: {integrity: sha512-tjFl0cwMPpDYyoqYA9li1/7mGFit39XiNX5DKC/uCNjBctMxyL1/PT/l4rSlbvBG1pOKI88STRdUsWXB3/Q9hQ==} + /cbor@8.1.0: + resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} + engines: {node: '>=12.19'} dependencies: - babel-runtime: 6.26.0 + nofilter: 3.1.0 dev: true - /babel-plugin-transform-es2015-modules-amd@6.24.1: - resolution: {integrity: sha512-LnIIdGWIKdw7zwckqx+eGjcS8/cl8D74A3BpJbGjKTFFNJSMrjN4bIh22HY1AlkUbeLG6X6OZj56BDvWD+OeFA==} + /chai-as-promised@7.1.1(chai@4.4.1): + resolution: {integrity: sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==} + peerDependencies: + chai: '>= 2.1.2 < 5' dependencies: - babel-plugin-transform-es2015-modules-commonjs: 6.26.2 - babel-runtime: 6.26.0 - babel-template: 6.26.0 - transitivePeerDependencies: - - supports-color + chai: 4.4.1 + check-error: 1.0.3 dev: true - /babel-plugin-transform-es2015-modules-commonjs@6.26.2: - resolution: {integrity: sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==} + /chai@4.4.1: + resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} + engines: {node: '>=4'} dependencies: - babel-plugin-transform-strict-mode: 6.24.1 - babel-runtime: 6.26.0 - babel-template: 6.26.0 - babel-types: 6.26.0 - transitivePeerDependencies: - - supports-color - dev: true + assertion-error: 1.1.0 + check-error: 1.0.3 + deep-eql: 4.1.3 + get-func-name: 2.0.2 + loupe: 2.3.7 + pathval: 1.1.1 + type-detect: 4.0.8 - /babel-plugin-transform-es2015-modules-systemjs@6.24.1: - resolution: {integrity: sha512-ONFIPsq8y4bls5PPsAWYXH/21Hqv64TBxdje0FvU3MhIV6QM2j5YS7KvAzg/nTIVLot2D2fmFQrFWCbgHlFEjg==} + /chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} dependencies: - babel-helper-hoist-variables: 6.24.1 - babel-runtime: 6.26.0 - babel-template: 6.26.0 - transitivePeerDependencies: - - supports-color - dev: true + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 - /babel-plugin-transform-es2015-modules-umd@6.24.1: - resolution: {integrity: sha512-LpVbiT9CLsuAIp3IG0tfbVo81QIhn6pE8xBJ7XSeCtFlMltuar5VuBV6y6Q45tpui9QWcy5i0vLQfCfrnF7Kiw==} + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} dependencies: - babel-plugin-transform-es2015-modules-amd: 6.24.1 - babel-runtime: 6.26.0 - babel-template: 6.26.0 - transitivePeerDependencies: - - supports-color - dev: true + ansi-styles: 4.3.0 + supports-color: 7.2.0 - /babel-plugin-transform-es2015-object-super@6.24.1: - resolution: {integrity: sha512-8G5hpZMecb53vpD3mjs64NhI1au24TAmokQ4B+TBFBjN9cVoGoOvotdrMMRmHvVZUEvqGUPWL514woru1ChZMA==} + /change-case@3.0.2: + resolution: {integrity: sha512-Mww+SLF6MZ0U6kdg11algyKd5BARbyM4TbFBepwowYSR5ClfQGCGtxNXgykpN0uF/bstWeaGDT4JWaDh8zWAHA==} dependencies: - babel-helper-replace-supers: 6.24.1 - babel-runtime: 6.26.0 - transitivePeerDependencies: - - supports-color + camel-case: 3.0.0 + constant-case: 2.0.0 + dot-case: 2.1.1 + header-case: 1.0.1 + is-lower-case: 1.1.3 + is-upper-case: 1.1.2 + lower-case: 1.1.4 + lower-case-first: 1.0.2 + no-case: 2.3.2 + param-case: 2.1.1 + pascal-case: 2.0.1 + path-case: 2.1.1 + sentence-case: 2.1.1 + snake-case: 2.1.0 + swap-case: 1.1.2 + title-case: 2.1.1 + upper-case: 1.1.3 + upper-case-first: 1.1.2 dev: true - /babel-plugin-transform-es2015-parameters@6.24.1: - resolution: {integrity: sha512-8HxlW+BB5HqniD+nLkQ4xSAVq3bR/pcYW9IigY+2y0dI+Y7INFeTbfAQr+63T3E4UDsZGjyb+l9txUnABWxlOQ==} + /chardet@0.7.0: + resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} + dev: false + + /check-error@1.0.3: + resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} dependencies: - babel-helper-call-delegate: 6.24.1 - babel-helper-get-function-arity: 6.24.1 - babel-runtime: 6.26.0 - babel-template: 6.26.0 - babel-traverse: 6.26.0 - babel-types: 6.26.0 - transitivePeerDependencies: - - supports-color - dev: true + get-func-name: 2.0.2 - /babel-plugin-transform-es2015-shorthand-properties@6.24.1: - resolution: {integrity: sha512-mDdocSfUVm1/7Jw/FIRNw9vPrBQNePy6wZJlR8HAUBLybNp1w/6lr6zZ2pjMShee65t/ybR5pT8ulkLzD1xwiw==} + /chokidar@3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} dependencies: - babel-runtime: 6.26.0 - babel-types: 6.26.0 + anymatch: 3.1.2 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.2 dev: true - /babel-plugin-transform-es2015-spread@6.22.0: - resolution: {integrity: sha512-3Ghhi26r4l3d0Js933E5+IhHwk0A1yiutj9gwvzmFbVV0sPMYk2lekhOufHBswX7NCoSeF4Xrl3sCIuSIa+zOg==} - dependencies: - babel-runtime: 6.26.0 + /ci-info@2.0.0: + resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} dev: true - /babel-plugin-transform-es2015-sticky-regex@6.24.1: - resolution: {integrity: sha512-CYP359ADryTo3pCsH0oxRo/0yn6UsEZLqYohHmvLQdfS9xkf+MbCzE3/Kolw9OYIY4ZMilH25z/5CbQbwDD+lQ==} + /ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + dev: false + + /cipher-base@1.0.4: + resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} dependencies: - babel-helper-regex: 6.26.0 - babel-runtime: 6.26.0 - babel-types: 6.26.0 + inherits: 2.0.4 + safe-buffer: 5.2.1 dev: true - /babel-plugin-transform-es2015-template-literals@6.22.0: - resolution: {integrity: sha512-x8b9W0ngnKzDMHimVtTfn5ryimars1ByTqsfBDwAqLibmuuQY6pgBQi5z1ErIsUOWBdw1bW9FSz5RZUojM4apg==} - dependencies: - babel-runtime: 6.26.0 + /clean-stack@2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} dev: true - /babel-plugin-transform-es2015-typeof-symbol@6.23.0: - resolution: {integrity: sha512-fz6J2Sf4gYN6gWgRZaoFXmq93X+Li/8vf+fb0sGDVtdeWvxC9y5/bTD7bvfWMEq6zetGEHpWjtzRGSugt5kNqw==} - dependencies: - babel-runtime: 6.26.0 + /cli-boxes@2.2.1: + resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==} + engines: {node: '>=6'} dev: true - /babel-plugin-transform-es2015-unicode-regex@6.24.1: - resolution: {integrity: sha512-v61Dbbihf5XxnYjtBN04B/JBvsScY37R1cZT5r9permN1cp+b70DY3Ib3fIkgn1DI9U3tGgBJZVD8p/mE/4JbQ==} + /cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} dependencies: - babel-helper-regex: 6.26.0 - babel-runtime: 6.26.0 - regexpu-core: 2.0.0 - dev: true + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + dev: false - /babel-plugin-transform-exponentiation-operator@6.24.1: - resolution: {integrity: sha512-LzXDmbMkklvNhprr20//RStKVcT8Cu+SQtX18eMHLhjHf2yFzwtQ0S2f0jQ+89rokoNdmwoSqYzAhq86FxlLSQ==} + /cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} dependencies: - babel-helper-builder-binary-assignment-operator-visitor: 6.24.1 - babel-plugin-syntax-exponentiation-operator: 6.13.0 - babel-runtime: 6.26.0 - transitivePeerDependencies: - - supports-color + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 dev: true - /babel-plugin-transform-regenerator@6.26.0: - resolution: {integrity: sha512-LS+dBkUGlNR15/5WHKe/8Neawx663qttS6AGqoOUhICc9d1KciBvtrQSuc0PI+CxQ2Q/S1aKuJ+u64GtLdcEZg==} - dependencies: - regenerator-transform: 0.10.1 - dev: true - - /babel-plugin-transform-strict-mode@6.24.1: - resolution: {integrity: sha512-j3KtSpjyLSJxNoCDrhwiJad8kw0gJ9REGj8/CqL0HeRyLnvUNYV9zcqluL6QJSXh3nfsLEmSLvwRfGzrgR96Pw==} - dependencies: - babel-runtime: 6.26.0 - babel-types: 6.26.0 - dev: true - - /babel-preset-env@1.7.0: - resolution: {integrity: sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg==} - dependencies: - babel-plugin-check-es2015-constants: 6.22.0 - babel-plugin-syntax-trailing-function-commas: 6.22.0 - babel-plugin-transform-async-to-generator: 6.24.1 - babel-plugin-transform-es2015-arrow-functions: 6.22.0 - babel-plugin-transform-es2015-block-scoped-functions: 6.22.0 - babel-plugin-transform-es2015-block-scoping: 6.26.0 - babel-plugin-transform-es2015-classes: 6.24.1 - babel-plugin-transform-es2015-computed-properties: 6.24.1 - babel-plugin-transform-es2015-destructuring: 6.23.0 - babel-plugin-transform-es2015-duplicate-keys: 6.24.1 - babel-plugin-transform-es2015-for-of: 6.23.0 - babel-plugin-transform-es2015-function-name: 6.24.1 - babel-plugin-transform-es2015-literals: 6.22.0 - babel-plugin-transform-es2015-modules-amd: 6.24.1 - babel-plugin-transform-es2015-modules-commonjs: 6.26.2 - babel-plugin-transform-es2015-modules-systemjs: 6.24.1 - babel-plugin-transform-es2015-modules-umd: 6.24.1 - babel-plugin-transform-es2015-object-super: 6.24.1 - babel-plugin-transform-es2015-parameters: 6.24.1 - babel-plugin-transform-es2015-shorthand-properties: 6.24.1 - babel-plugin-transform-es2015-spread: 6.22.0 - babel-plugin-transform-es2015-sticky-regex: 6.24.1 - babel-plugin-transform-es2015-template-literals: 6.22.0 - babel-plugin-transform-es2015-typeof-symbol: 6.23.0 - babel-plugin-transform-es2015-unicode-regex: 6.24.1 - babel-plugin-transform-exponentiation-operator: 6.24.1 - babel-plugin-transform-regenerator: 6.26.0 - browserslist: 3.2.8 - invariant: 2.2.4 - semver: 5.7.1 - transitivePeerDependencies: - - supports-color - dev: true + /cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: false - /babel-register@6.26.0: - resolution: {integrity: sha512-veliHlHX06wjaeY8xNITbveXSiI+ASFnOqvne/LaIJIqOWi2Ogmj91KOugEz/hoh/fwMhXNBJPCv8Xaz5CyM4A==} + /clone-response@1.0.2: + resolution: {integrity: sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==} dependencies: - babel-core: 6.26.3 - babel-runtime: 6.26.0 - core-js: 2.6.12 - home-or-tmp: 2.0.0 - lodash: 4.17.21 - mkdirp: 0.5.6 - source-map-support: 0.4.18 - transitivePeerDependencies: - - supports-color + mimic-response: 1.0.1 dev: true - /babel-runtime@6.26.0: - resolution: {integrity: sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==} - dependencies: - core-js: 2.6.12 - regenerator-runtime: 0.11.1 + /clone@1.0.4: + resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} + engines: {node: '>=0.8'} + dev: false + + /code-error-fragment@0.0.230: + resolution: {integrity: sha512-cadkfKp6932H8UkhzE/gcUqhRMNf8jHzkAN7+5Myabswaghu4xABTgPHDCjW+dBAJxj/SpkTYokpzDqY4pCzQw==} + engines: {node: '>= 4'} dev: true - /babel-template@6.26.0: - resolution: {integrity: sha512-PCOcLFW7/eazGUKIoqH97sO9A2UYMahsn/yRQ7uOk37iutwjq7ODtcTNF+iFDSHNfkctqsLRjLP7URnOx0T1fg==} + /color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: - babel-runtime: 6.26.0 - babel-traverse: 6.26.0 - babel-types: 6.26.0 - babylon: 6.18.0 - lodash: 4.17.21 - transitivePeerDependencies: - - supports-color - dev: true + color-name: 1.1.3 - /babel-traverse@6.26.0: - resolution: {integrity: sha512-iSxeXx7apsjCHe9c7n8VtRXGzI2Bk1rBSOJgCCjfyXb6v1aCqE1KSEpq/8SXuVN8Ka/Rh1WDTF0MDzkvTA4MIA==} + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} dependencies: - babel-code-frame: 6.26.0 - babel-messages: 6.23.0 - babel-runtime: 6.26.0 - babel-types: 6.26.0 - babylon: 6.18.0 - debug: 2.6.9 - globals: 9.18.0 - invariant: 2.2.4 - lodash: 4.17.21 - transitivePeerDependencies: - - supports-color + color-name: 1.1.4 + + /color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + /command-exists@1.2.9: + resolution: {integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==} dev: true - /babel-types@6.26.0: - resolution: {integrity: sha512-zhe3V/26rCWsEZK8kZN+HaQj5yQ1CilTObixFzKW1UWjqG7618Twz6YEsCnjfg5gBcJh02DrpCkS9h98ZqDY+g==} + /command-line-args@5.2.1: + resolution: {integrity: sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==} + engines: {node: '>=4.0.0'} dependencies: - babel-runtime: 6.26.0 - esutils: 2.0.3 - lodash: 4.17.21 - to-fast-properties: 1.0.3 + array-back: 3.1.0 + find-replace: 3.0.0 + lodash.camelcase: 4.3.0 + typical: 4.0.0 dev: true - /babelify@7.3.0: - resolution: {integrity: sha512-vID8Fz6pPN5pJMdlUnNFSfrlcx5MUule4k9aKs/zbZPyXxMTcRrB0M4Tarw22L8afr8eYSWxDPYCob3TdrqtlA==} + /command-line-usage@6.1.3: + resolution: {integrity: sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==} + engines: {node: '>=8.0.0'} dependencies: - babel-core: 6.26.3 - object-assign: 4.1.1 - transitivePeerDependencies: - - supports-color + array-back: 4.0.2 + chalk: 2.4.2 + table-layout: 1.0.2 + typical: 5.2.0 dev: true - /babylon@6.18.0: - resolution: {integrity: sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==} - hasBin: true + /commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} dev: true - /backoff@2.5.0: - resolution: {integrity: sha512-wC5ihrnUXmR2douXmXLCe5O3zg3GKIyvRi/hi58a/XyRxVI+3/yM0PYueQOZXPXQ9pxBislYkw+sF9b7C/RuMA==} - engines: {node: '>= 0.6'} - dependencies: - precond: 0.2.3 + /commander@3.0.2: + resolution: {integrity: sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==} dev: true - /balanced-match@1.0.0: - resolution: {integrity: sha512-9Y0g0Q8rmSt+H33DfKv7FOc3v+iRI+o1lbzt8jGcIosYW37IIW/2XVYq5NPdmaD5NQ59Nk26Kl/vZbwW9Fr8vg==} + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} dev: true - /base-x@3.0.9: - resolution: {integrity: sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==} + /config-chain@1.1.13: + resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} dependencies: - safe-buffer: 5.2.1 - dev: true - - /base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + ini: 1.3.8 + proto-list: 1.2.4 dev: true - /base@0.11.2: - resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==} - engines: {node: '>=0.10.0'} + /constant-case@2.0.0: + resolution: {integrity: sha512-eS0N9WwmjTqrOmR3o83F5vW8Z+9R1HnVz3xmzT2PMFug9ly+Au/fxRWlEBSb6LcZwspSsEn9Xs1uw9YgzAg1EQ==} dependencies: - cache-base: 1.0.1 - class-utils: 0.3.6 - component-emitter: 1.3.0 - define-property: 1.0.0 - isobject: 3.0.1 - mixin-deep: 1.3.2 - pascalcase: 0.1.1 + snake-case: 2.1.0 + upper-case: 1.1.3 dev: true - /bcrypt-pbkdf@1.0.2: - resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} - dependencies: - tweetnacl: 0.14.5 + /cookie@0.4.2: + resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} + engines: {node: '>= 0.6'} dev: true - /bech32@1.1.4: - resolution: {integrity: sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==} + /core-js@3.30.1: + resolution: {integrity: sha512-ZNS5nbiSwDTq4hFosEDqm65izl2CWmLz0hARJMyNQBgkUZMIF51cQiMvIQKA6hvuaeWxQDP3hEedM1JZIgTldQ==} + requiresBuild: true + dev: true - /better-ajv-errors@0.8.2(ajv@6.12.6): - resolution: {integrity: sha512-FnODTBJSQSHmJXDLPiC7ca0dC4S1HSTPv1+Hg2sm/C71i3Dj0l1jcUEaq/3OQ6MmnUveshTsUvUj65pDSr3Qow==} - peerDependencies: - ajv: 4.11.8 - 8 + /cosmiconfig@8.2.0: + resolution: {integrity: sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==} + engines: {node: '>=14'} dependencies: - '@babel/code-frame': 7.18.6 - '@babel/runtime': 7.19.0 - ajv: 6.12.6 - chalk: 2.4.2 - core-js: 3.30.1 - json-to-ast: 2.1.0 - jsonpointer: 5.0.1 - leven: 3.1.0 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + path-type: 4.0.0 dev: true - /better-path-resolve@1.0.0: - resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} - engines: {node: '>=4'} + /create-hash@1.2.0: + resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} dependencies: - is-windows: 1.0.2 - dev: false + cipher-base: 1.0.4 + inherits: 2.0.4 + md5.js: 1.3.5 + ripemd160: 2.0.2 + sha.js: 2.4.11 + dev: true - /big-integer@1.6.36: - resolution: {integrity: sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg==} - engines: {node: '>=0.6'} + /create-hmac@1.1.7: + resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} + dependencies: + cipher-base: 1.0.4 + create-hash: 1.2.0 + inherits: 2.0.4 + ripemd160: 2.0.2 + safe-buffer: 5.2.1 + sha.js: 2.4.11 dev: true - /big.js@6.2.1: - resolution: {integrity: sha512-bCtHMwL9LeDIozFn+oNhhFoq+yQ3BNdnsLSASUxLciOb1vgvpHsIO1dsENiGMgbb4SkP5TrzWzRiLddn8ahVOQ==} + /create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} dev: true - /bigint-crypto-utils@3.1.8: - resolution: {integrity: sha512-+VMV9Laq8pXLBKKKK49nOoq9bfR3j7NNQAtbA617a4nw9bVLo8rsqkKMBgM2AJWlNX9fEIyYaYX+d0laqYV4tw==} - engines: {node: '>=10.4.0'} + /cross-spawn@5.1.0: + resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==} dependencies: - bigint-mod-arith: 3.1.2 - dev: true + lru-cache: 4.1.5 + shebang-command: 1.2.0 + which: 1.3.1 + dev: false - /bigint-mod-arith@3.1.2: - resolution: {integrity: sha512-nx8J8bBeiRR+NlsROFH9jHswW5HO8mgfOSqW0AmjicMMvaONDa8AO+5ViKDUUNytBPWiwfvZP4/Bj4Y3lUfvgQ==} - engines: {node: '>=10.4.0'} + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 dev: true - /bignumber.js@7.2.1: - resolution: {integrity: sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==} - dev: true + /csv-generate@3.4.3: + resolution: {integrity: sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==} + dev: false - /bignumber.js@9.1.0: - resolution: {integrity: sha512-4LwHK4nfDOraBCtst+wOWIHbu1vhvAPJK8g8nROd4iuc3PSEjWif/qwbkh8jwCJz6yDBvtU4KPynETgrfh7y3A==} - dev: true + /csv-parse@4.16.3: + resolution: {integrity: sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==} + dev: false - /binary-extensions@2.2.0: - resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} - engines: {node: '>=8'} - dev: true + /csv-stringify@5.6.5: + resolution: {integrity: sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A==} + dev: false - /bindings@1.5.0: - resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + /csv@5.5.3: + resolution: {integrity: sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g==} + engines: {node: '>= 0.1.90'} dependencies: - file-uri-to-path: 1.0.0 - dev: true + csv-generate: 3.4.3 + csv-parse: 4.16.3 + csv-stringify: 5.6.5 + stream-transform: 2.1.3 + dev: false + + /dataloader@1.4.0: + resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==} + dev: false - /bip39@2.5.0: - resolution: {integrity: sha512-xwIx/8JKoT2+IPJpFEfXoWdYwP7UVAoUxxLNfGCfVowaJE7yg1Y5B1BVPqlUNsBq5/nGwmFkwRJ8xDW4sX8OdA==} + /debug@4.3.4(supports-color@8.1.1): + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true dependencies: - create-hash: 1.2.0 - pbkdf2: 3.1.2 - randombytes: 2.1.0 - safe-buffer: 5.2.1 - unorm: 1.6.0 + ms: 2.1.2 + supports-color: 8.1.1 dev: true - /bip66@1.1.5: - resolution: {integrity: sha512-nemMHz95EmS38a26XbbdxIYj5csHd3RMP3H5bwQknX0WYHF01qhpufP42mLOwVICuH2JmhIhXiWs89MfUGL7Xw==} + /decamelize-keys@1.1.1: + resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} + engines: {node: '>=0.10.0'} dependencies: - safe-buffer: 5.2.1 - dev: true + decamelize: 1.2.0 + map-obj: 1.0.1 + dev: false - /blakejs@1.2.1: - resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} - dev: true + /decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + dev: false - /bluebird@3.7.2: - resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + /decamelize@4.0.0: + resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} + engines: {node: '>=10'} dev: true - /bn.js@4.11.6: - resolution: {integrity: sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==} + /decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + dependencies: + mimic-response: 3.1.0 dev: true - /bn.js@4.12.0: - resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} - - /bn.js@5.2.1: - resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} + /deep-eql@4.1.3: + resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} + engines: {node: '>=6'} + dependencies: + type-detect: 4.0.8 - /body-parser@1.19.0: - resolution: {integrity: sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==} - engines: {node: '>= 0.8'} - requiresBuild: true + /deep-equal-in-any-order@2.0.6: + resolution: {integrity: sha512-RfnWHQzph10YrUjvWwhd15Dne8ciSJcZ3U6OD7owPwiVwsdE5IFSoZGg8rlwJD11ES+9H5y8j3fCofviRHOqLQ==} dependencies: - bytes: 3.1.0 - content-type: 1.0.4 - debug: 2.6.9 - depd: 1.1.2 - http-errors: 1.7.2 - iconv-lite: 0.4.24 - on-finished: 2.3.0 - qs: 6.7.0 - raw-body: 2.4.0 - type-is: 1.6.18 - transitivePeerDependencies: - - supports-color + lodash.mapvalues: 4.6.0 + sort-any: 2.0.0 dev: true - /boolbase@1.0.0: - resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + /deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} dev: true - /brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - dependencies: - balanced-match: 1.0.0 - concat-map: 0.0.1 + /deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true - /brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + /defaults@1.0.4: + resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} dependencies: - balanced-match: 1.0.0 - dev: true + clone: 1.0.4 + dev: false - /braces@2.3.2: - resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==} - engines: {node: '>=0.10.0'} - dependencies: - arr-flatten: 1.1.0 - array-unique: 0.3.2 - extend-shallow: 2.0.1 - fill-range: 4.0.0 - isobject: 3.0.1 - repeat-element: 1.1.4 - snapdragon: 0.8.2 - snapdragon-node: 2.1.1 - split-string: 3.1.0 - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color + /defer-to-connect@2.0.1: + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} dev: true - /braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} + /define-data-property@1.1.1: + resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} + engines: {node: '>= 0.4'} dependencies: - fill-range: 7.0.1 + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.0 + dev: false - /breakword@1.0.6: - resolution: {integrity: sha512-yjxDAYyK/pBvws9H4xKYpLDpYKEH6CzrBPAuXq3x18I+c/2MkVtT3qAr7Oloi6Dss9qNhPVueAAVU1CSeNDIXw==} + /define-properties@1.1.4: + resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==} + engines: {node: '>= 0.4'} dependencies: - wcwidth: 1.0.1 + has-property-descriptors: 1.0.0 + object-keys: 1.1.1 dev: false - /brorand@1.1.0: - resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + /define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + has-property-descriptors: 1.0.0 + object-keys: 1.1.1 + dev: false - /browser-level@1.0.1: - resolution: {integrity: sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ==} + /delete-empty@3.0.0: + resolution: {integrity: sha512-ZUyiwo76W+DYnKsL3Kim6M/UOavPdBJgDYWOmuQhYaZvJH0AXAHbUNyEDtRbBra8wqqr686+63/0azfEk1ebUQ==} + engines: {node: '>=10'} + hasBin: true dependencies: - abstract-level: 1.0.3 - catering: 2.1.1 - module-error: 1.0.2 - run-parallel-limit: 1.1.0 + ansi-colors: 4.1.3 + minimist: 1.2.8 + path-starts-with: 2.0.1 + rimraf: 2.7.1 dev: true - /browser-stdout@1.3.1: - resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} + /depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} dev: true - /browserify-aes@1.2.0: - resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} - dependencies: - buffer-xor: 1.0.3 - cipher-base: 1.0.4 - create-hash: 1.2.0 - evp_bytestokey: 1.0.3 - inherits: 2.0.4 - safe-buffer: 5.2.1 + /detect-indent@6.1.0: + resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} + engines: {node: '>=8'} + dev: false + + /diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} dev: true - /browserify-cipher@1.0.1: - resolution: {integrity: sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==} - requiresBuild: true - dependencies: - browserify-aes: 1.2.0 - browserify-des: 1.0.2 - evp_bytestokey: 1.0.3 + /diff@5.0.0: + resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} + engines: {node: '>=0.3.1'} dev: true - /browserify-des@1.0.2: - resolution: {integrity: sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==} - requiresBuild: true + /dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} dependencies: - cipher-base: 1.0.4 - des.js: 1.0.1 - inherits: 2.0.4 - safe-buffer: 5.2.1 - dev: true + path-type: 4.0.0 - /browserify-rsa@4.0.1: - resolution: {integrity: sha512-+YpEyaLDDvvdzIxQ+cCx73r5YEhS3ANGOkiHdyWqW4t3gdeoNEYjSiQwntbU4Uo2/9yRkpYX3SRFeH+7jc2Duw==} - requiresBuild: true + /doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} dependencies: - bn.js: 4.12.0 - randombytes: 2.1.0 + esutils: 2.0.3 dev: true - /browserify-sha3@0.0.4: - resolution: {integrity: sha512-WmXX4M8lltqzMnBiPbP9KQdITknmxe4Wp3rhGfpYJst5yOeGwKkHpC0t+Ty22laH4Ltg9YO+p14p93wiipqjxA==} + /dot-case@2.1.1: + resolution: {integrity: sha512-HnM6ZlFqcajLsyudHq7LeeLDr2rFAVYtDv/hV5qchQEidSck8j9OPUsXY9KwJv/lHMtYlX4DjRQqwFYa+0r8Ug==} dependencies: - js-sha3: 0.6.1 - safe-buffer: 5.2.1 + no-case: 2.3.2 dev: true - /browserify-sign@4.0.4: - resolution: {integrity: sha512-D2ItxCwNtLcHRrOCuEDZQlIezlFyUV/N5IYz6TY1svu1noyThFuthoEjzT8ChZe3UEctqnwmykcPhet3Eiz58A==} - requiresBuild: true + /dotenv@8.6.0: + resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} + engines: {node: '>=10'} + dev: false + + /elliptic@6.5.4: + resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==} dependencies: bn.js: 4.12.0 - browserify-rsa: 4.0.1 - create-hash: 1.2.0 - create-hmac: 1.1.7 - elliptic: 6.5.4 + brorand: 1.1.0 + hash.js: 1.1.7 + hmac-drbg: 1.0.1 inherits: 2.0.4 - parse-asn1: 5.1.5 - dev: true + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 - /browserslist@3.2.8: - resolution: {integrity: sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==} - hasBin: true - dependencies: - caniuse-lite: 1.0.30001414 - electron-to-chromium: 1.4.270 - dev: true + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - /bs58@4.0.1: - resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} + /end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} dependencies: - base-x: 3.0.9 + once: 1.4.0 dev: true - /bs58check@2.1.2: - resolution: {integrity: sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==} + /enquirer@2.3.6: + resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==} + engines: {node: '>=8.6'} dependencies: - bs58: 4.0.1 - create-hash: 1.2.0 - safe-buffer: 5.2.1 - dev: true - - /buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - dev: true - - /buffer-to-arraybuffer@0.0.5: - resolution: {integrity: sha512-3dthu5CYiVB1DEJp61FtApNnNndTckcqe4pFcLdvHtrpG+kcyekCJKg4MRiDcFW7A6AODnXB9U4dwQiCW5kzJQ==} - requiresBuild: true - dev: true + ansi-colors: 4.1.3 - /buffer-xor@1.0.3: - resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} + /env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} dev: true - /buffer-xor@2.0.2: - resolution: {integrity: sha512-eHslX0bin3GB+Lx2p7lEYRShRewuNZL3fUl4qlVJGGiwoPGftmt8JQgk2Y9Ji5/01TnVDo33E5b5O3vUB1HdqQ==} + /error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: - safe-buffer: 5.2.1 - dev: true + is-arrayish: 0.2.1 - /buffer@4.9.2: - resolution: {integrity: sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==} + /es-abstract@1.22.3: + resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==} + engines: {node: '>= 0.4'} dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - isarray: 1.0.0 - dev: true + array-buffer-byte-length: 1.0.0 + arraybuffer.prototype.slice: 1.0.2 + available-typed-arrays: 1.0.5 + call-bind: 1.0.5 + es-set-tostringtag: 2.0.2 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.2 + get-symbol-description: 1.0.0 + globalthis: 1.0.3 + gopd: 1.0.1 + has-property-descriptors: 1.0.0 + has-proto: 1.0.1 + has-symbols: 1.0.3 + hasown: 2.0.0 + internal-slot: 1.0.6 + 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.13.1 + 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.13 + dev: false - /buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + /es-set-tostringtag@2.0.2: + resolution: {integrity: sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==} + engines: {node: '>= 0.4'} dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - dev: true + get-intrinsic: 1.2.2 + has-tostringtag: 1.0.0 + hasown: 2.0.0 + dev: false - /buffer@6.0.3: - resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + /es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - dev: true + hasown: 2.0.0 + dev: false - /bufferutil@4.0.6: - resolution: {integrity: sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==} - engines: {node: '>=6.14.2'} - requiresBuild: true + /es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} dependencies: - node-gyp-build: 4.5.0 - dev: true - - /bufio@1.0.7: - resolution: {integrity: sha512-bd1dDQhiC+bEbEfg56IdBv7faWa6OipMs/AFFFvtFnB3wAYjlwQpQRZ0pm6ZkgtfL0pILRXhKxOiQj6UzoMR7A==} - engines: {node: '>=8.0.0'} + is-callable: 1.2.7 + is-date-object: 1.0.2 + is-symbol: 1.0.3 dev: false - /busboy@1.6.0: - resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} - engines: {node: '>=10.16.0'} - dependencies: - streamsearch: 1.1.0 - dev: true + /escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} - /bytes@3.1.0: - resolution: {integrity: sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==} - engines: {node: '>= 0.8'} - requiresBuild: true - dev: true + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} - /bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} + /escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} dev: true - /bytewise-core@1.2.3: - resolution: {integrity: sha512-nZD//kc78OOxeYtRlVk8/zXqTB4gf/nlguL1ggWA8FuchMyOxcyHR4QPQZMUmA7czC+YnaBrPUCubqAWe50DaA==} + /eslint-config-prettier@9.1.0(eslint@8.57.0): + resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' dependencies: - typewise-core: 1.2.0 + eslint: 8.57.0 dev: true - /bytewise@1.1.0: - resolution: {integrity: sha512-rHuuseJ9iQ0na6UDhnrRVDh8YnWVlU6xM3VH6q/+yHDeUH2zIhUzP+2/h3LIrhLDBtTqzWpE3p3tP/boefskKQ==} + /eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.2.5): + resolution: {integrity: sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '*' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true dependencies: - bytewise-core: 1.2.3 - typewise: 1.0.3 + eslint: 8.57.0 + eslint-config-prettier: 9.1.0(eslint@8.57.0) + prettier: 3.2.5 + prettier-linter-helpers: 1.0.0 + synckit: 0.8.8 dev: true - /cache-base@1.0.1: - resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==} - engines: {node: '>=0.10.0'} + /eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - collection-visit: 1.0.0 - component-emitter: 1.3.0 - get-value: 2.0.6 - has-value: 1.0.0 - isobject: 3.0.1 - set-value: 2.0.1 - to-object-path: 0.3.0 - union-value: 1.0.1 - unset-value: 1.0.0 + esrecurse: 4.3.0 + estraverse: 5.3.0 dev: true - /cacheable-lookup@6.1.0: - resolution: {integrity: sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww==} - engines: {node: '>=10.6.0'} + /eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /cacheable-request@6.1.0: - resolution: {integrity: sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==} - engines: {node: '>=8'} - requiresBuild: true + /eslint@8.57.0: + resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true dependencies: - clone-response: 1.0.2 - get-stream: 5.1.0 - http-cache-semantics: 4.0.3 - keyv: 3.1.0 - lowercase-keys: 2.0.0 - normalize-url: 4.5.1 - responselike: 1.0.2 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/regexpp': 4.9.1 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.0 + '@humanwhocodes/config-array': 0.11.14 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4(supports-color@8.1.1) + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.20.0 + graphemer: 1.4.0 + ignore: 5.2.4 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color dev: true - /cacheable-request@7.0.2: - resolution: {integrity: sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==} - engines: {node: '>=8'} + /espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - clone-response: 1.0.2 - get-stream: 5.1.0 - http-cache-semantics: 4.0.3 - keyv: 4.5.0 - lowercase-keys: 2.0.0 - normalize-url: 6.1.0 - responselike: 2.0.1 + acorn: 8.10.0 + acorn-jsx: 5.3.2(acorn@8.10.0) + eslint-visitor-keys: 3.4.3 dev: true - /cachedown@1.0.0: - resolution: {integrity: sha512-t+yVk82vQWCJF3PsWHMld+jhhjkkWjcAzz8NbFx1iULOXWl8Tm/FdM4smZNVw3MRr0X+lVTx9PKzvEn4Ng19RQ==} + /esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + dev: false + + /esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + engines: {node: '>=0.10'} dependencies: - abstract-leveldown: 2.7.2 - lru-cache: 3.2.0 + estraverse: 5.3.0 dev: true - /call-bind@1.0.2: - resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} - dependencies: - function-bind: 1.1.1 - get-intrinsic: 1.1.3 - - /call-bind@1.0.5: - resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} - dependencies: - function-bind: 1.1.2 - get-intrinsic: 1.2.2 - set-function-length: 1.1.1 - - /callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - dev: true - - /camel-case@3.0.0: - resolution: {integrity: sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==} - dependencies: - no-case: 2.3.2 - upper-case: 1.1.3 - dev: true - - /camelcase-keys@6.2.2: - resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==} - engines: {node: '>=8'} - dependencies: - camelcase: 5.3.1 - map-obj: 4.3.0 - quick-lru: 4.0.1 - dev: false - - /camelcase@3.0.0: - resolution: {integrity: sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==} - engines: {node: '>=0.10.0'} - dev: true - - /camelcase@4.1.0: - resolution: {integrity: sha512-FxAv7HpHrXbh3aPo4o2qxHay2lkLY3x5Mw3KeE4KQE8ysVfziWeRZDwcjauvwBSGEC/nXUPzZy8zeh4HokqOnw==} - engines: {node: '>=4'} - dev: true - - /camelcase@5.3.1: - resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} - engines: {node: '>=6'} - - /camelcase@6.3.0: - resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} - engines: {node: '>=10'} - dev: true - - /caniuse-lite@1.0.30001414: - resolution: {integrity: sha512-t55jfSaWjCdocnFdKQoO+d2ct9C59UZg4dY3OnUlSZ447r8pUtIKdp0hpAzrGFultmTC+Us+KpKi4GZl/LXlFg==} - dev: true - - /case@1.6.3: - resolution: {integrity: sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ==} - engines: {node: '>= 0.8.0'} - dev: true - - /caseless@0.12.0: - resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} - dev: true - - /catering@2.1.1: - resolution: {integrity: sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==} - engines: {node: '>=6'} - dev: true - - /cbor@5.2.0: - resolution: {integrity: sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==} - engines: {node: '>=6.0.0'} - dependencies: - bignumber.js: 9.1.0 - nofilter: 1.0.4 - dev: true - - /cbor@8.1.0: - resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} - engines: {node: '>=12.19'} - dependencies: - nofilter: 3.1.0 - dev: true - - /cbor@9.0.1: - resolution: {integrity: sha512-/TQOWyamDxvVIv+DY9cOLNuABkoyz8K/F3QE56539pGVYohx0+MEA1f4lChFTX79dBTBS7R1PF6ovH7G+VtBfQ==} - engines: {node: '>=16'} - dependencies: - nofilter: 3.1.0 - dev: true - - /chai-bn@0.2.2(bn.js@4.12.0)(chai@4.3.10): - resolution: {integrity: sha512-MzjelH0p8vWn65QKmEq/DLBG1Hle4WeyqT79ANhXZhn/UxRWO0OogkAxi5oGGtfzwU9bZR8mvbvYdoqNVWQwFg==} - peerDependencies: - bn.js: ^4.11.0 - chai: ^4.0.0 - dependencies: - bn.js: 4.12.0 - chai: 4.3.10 - dev: true - - /chai@4.3.10: - resolution: {integrity: sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==} - engines: {node: '>=4'} - dependencies: - assertion-error: 1.1.0 - check-error: 1.0.3 - deep-eql: 4.1.3 - get-func-name: 2.0.2 - loupe: 2.3.7 - pathval: 1.1.1 - type-detect: 4.0.8 - - /chalk@1.1.3: - resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==} - engines: {node: '>=0.10.0'} - dependencies: - ansi-styles: 2.2.1 - escape-string-regexp: 1.0.5 - has-ansi: 2.0.0 - strip-ansi: 3.0.1 - supports-color: 2.0.0 - dev: true - - /chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - - /chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - /change-case@3.0.2: - resolution: {integrity: sha512-Mww+SLF6MZ0U6kdg11algyKd5BARbyM4TbFBepwowYSR5ClfQGCGtxNXgykpN0uF/bstWeaGDT4JWaDh8zWAHA==} - dependencies: - camel-case: 3.0.0 - constant-case: 2.0.0 - dot-case: 2.1.1 - header-case: 1.0.1 - is-lower-case: 1.1.3 - is-upper-case: 1.1.2 - lower-case: 1.1.4 - lower-case-first: 1.0.2 - no-case: 2.3.2 - param-case: 2.1.1 - pascal-case: 2.0.1 - path-case: 2.1.1 - sentence-case: 2.1.1 - snake-case: 2.1.0 - swap-case: 1.1.2 - title-case: 2.1.1 - upper-case: 1.1.3 - upper-case-first: 1.1.2 - dev: true - - /chardet@0.7.0: - resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} - dev: false - - /charenc@0.0.2: - resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} - dev: true - - /check-error@1.0.3: - resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} - dependencies: - get-func-name: 2.0.2 - - /checkpoint-store@1.1.0: - resolution: {integrity: sha512-J/NdY2WvIx654cc6LWSq/IYFFCUf75fFTgwzFnmbqyORH4MwgiQCgswLLKBGzmsyTI5V7i5bp/So6sMbDWhedg==} - dependencies: - functional-red-black-tree: 1.0.1 - dev: true - - /cheerio-select@2.1.0: - resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} - dependencies: - boolbase: 1.0.0 - css-select: 5.1.0 - css-what: 6.1.0 - domelementtype: 2.3.0 - domhandler: 5.0.3 - domutils: 3.0.1 - dev: true - - /cheerio@1.0.0-rc.12: - resolution: {integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==} - engines: {node: '>= 6'} - dependencies: - cheerio-select: 2.1.0 - dom-serializer: 2.0.0 - domhandler: 5.0.3 - domutils: 3.0.1 - htmlparser2: 8.0.1 - parse5: 7.1.1 - parse5-htmlparser2-tree-adapter: 7.0.0 - dev: true - - /chokidar@3.3.0: - resolution: {integrity: sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==} - engines: {node: '>= 8.10.0'} - dependencies: - anymatch: 3.1.2 - braces: 3.0.2 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.2.0 - optionalDependencies: - fsevents: 2.1.3 - dev: true - - /chokidar@3.5.3: - resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} - engines: {node: '>= 8.10.0'} - dependencies: - anymatch: 3.1.2 - braces: 3.0.2 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.2 - dev: true - - /chownr@1.1.4: - resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} - requiresBuild: true - dev: true - - /ci-info@2.0.0: - resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} - dev: true - - /ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} - dev: false - - /cids@0.7.5: - resolution: {integrity: sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA==} - engines: {node: '>=4.0.0', npm: '>=3.0.0'} - deprecated: This module has been superseded by the multiformats module - requiresBuild: true - dependencies: - buffer: 5.7.1 - class-is: 1.1.0 - multibase: 0.6.1 - multicodec: 1.0.4 - multihashes: 0.4.21 - dev: true - - /cipher-base@1.0.4: - resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - dev: true - - /class-is@1.1.0: - resolution: {integrity: sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==} - requiresBuild: true - dev: true - - /class-utils@0.3.6: - resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==} - engines: {node: '>=0.10.0'} - dependencies: - arr-union: 3.1.0 - define-property: 0.2.5 - isobject: 3.0.1 - static-extend: 0.1.2 - dev: true - - /classic-level@1.2.0: - resolution: {integrity: sha512-qw5B31ANxSluWz9xBzklRWTUAJ1SXIdaVKTVS7HcTGKOAmExx65Wo5BUICW+YGORe2FOUaDghoI9ZDxj82QcFg==} - engines: {node: '>=12'} - requiresBuild: true - dependencies: - abstract-level: 1.0.3 - catering: 2.1.1 - module-error: 1.0.2 - napi-macros: 2.0.0 - node-gyp-build: 4.5.0 - dev: true - - /clean-stack@2.2.0: - resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} - engines: {node: '>=6'} - dev: true - - /cli-table3@0.5.1: - resolution: {integrity: sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==} - engines: {node: '>=6'} - dependencies: - object-assign: 4.1.1 - string-width: 2.1.1 - optionalDependencies: - colors: 1.4.0 - dev: true - - /cli-table3@0.6.3: - resolution: {integrity: sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==} - engines: {node: 10.* || >= 12.*} - dependencies: - string-width: 4.2.3 - optionalDependencies: - '@colors/colors': 1.5.0 - dev: true - - /cliui@3.2.0: - resolution: {integrity: sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==} - dependencies: - string-width: 1.0.2 - strip-ansi: 3.0.1 - wrap-ansi: 2.1.0 - dev: true - - /cliui@5.0.0: - resolution: {integrity: sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==} - dependencies: - string-width: 3.1.0 - strip-ansi: 5.2.0 - wrap-ansi: 5.1.0 - dev: true - - /cliui@6.0.0: - resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 6.2.0 - dev: false - - /cliui@7.0.4: - resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - dev: true - - /cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - dev: false - - /clone-response@1.0.2: - resolution: {integrity: sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==} - dependencies: - mimic-response: 1.0.1 - dev: true - - /clone@1.0.4: - resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} - engines: {node: '>=0.8'} - dev: false - - /clone@2.1.2: - resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} - engines: {node: '>=0.8'} - dev: true - - /code-error-fragment@0.0.230: - resolution: {integrity: sha512-cadkfKp6932H8UkhzE/gcUqhRMNf8jHzkAN7+5Myabswaghu4xABTgPHDCjW+dBAJxj/SpkTYokpzDqY4pCzQw==} - engines: {node: '>= 4'} - dev: true - - /code-point-at@1.1.0: - resolution: {integrity: sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==} - engines: {node: '>=0.10.0'} - dev: true - - /collection-visit@1.0.0: - resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==} - engines: {node: '>=0.10.0'} - dependencies: - map-visit: 1.0.0 - object-visit: 1.0.1 - dev: true - - /color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - dependencies: - color-name: 1.1.3 - - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - dependencies: - color-name: 1.1.4 - - /color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - /colors@1.4.0: - resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} - engines: {node: '>=0.1.90'} - dev: true - - /combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - dependencies: - delayed-stream: 1.0.0 - dev: true - - /command-exists@1.2.9: - resolution: {integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==} - dev: true - - /command-line-args@4.0.7: - resolution: {integrity: sha512-aUdPvQRAyBvQd2n7jXcsMDz68ckBJELXNzBybCHOibUWEg0mWTnaYCSRU8h9R+aNRSvDihJtssSRCiDRpLaezA==} - hasBin: true - dependencies: - array-back: 2.0.0 - find-replace: 1.0.3 - typical: 2.6.1 - dev: true - - /command-line-args@5.2.1: - resolution: {integrity: sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==} - engines: {node: '>=4.0.0'} - dependencies: - array-back: 3.1.0 - find-replace: 3.0.0 - lodash.camelcase: 4.3.0 - typical: 4.0.0 - dev: true - - /command-line-usage@6.1.3: - resolution: {integrity: sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==} - engines: {node: '>=8.0.0'} - dependencies: - array-back: 4.0.2 - chalk: 2.4.2 - table-layout: 1.0.2 - typical: 5.2.0 - dev: true - - /commander@10.0.1: - resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} - engines: {node: '>=14'} - dev: true - - /commander@3.0.2: - resolution: {integrity: sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==} - dev: true - - /compare-versions@6.1.0: - resolution: {integrity: sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==} - dev: true - - /component-emitter@1.3.0: - resolution: {integrity: sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==} - dev: true - - /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - dev: true - - /concat-stream@1.6.2: - resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} - engines: {'0': node >= 0.8} - dependencies: - buffer-from: 1.1.2 - inherits: 2.0.4 - readable-stream: 2.3.7 - typedarray: 0.0.6 - dev: true - - /config-chain@1.1.13: - resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} - dependencies: - ini: 1.3.8 - proto-list: 1.2.4 - dev: true - - /constant-case@2.0.0: - resolution: {integrity: sha512-eS0N9WwmjTqrOmR3o83F5vW8Z+9R1HnVz3xmzT2PMFug9ly+Au/fxRWlEBSb6LcZwspSsEn9Xs1uw9YgzAg1EQ==} - dependencies: - snake-case: 2.1.0 - upper-case: 1.1.3 - dev: true - - /content-disposition@0.5.3: - resolution: {integrity: sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==} - engines: {node: '>= 0.6'} - requiresBuild: true - dependencies: - safe-buffer: 5.1.2 - dev: true - - /content-hash@2.5.2: - resolution: {integrity: sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw==} - dependencies: - cids: 0.7.5 - multicodec: 0.5.7 - multihashes: 0.4.21 - dev: true - - /content-type@1.0.4: - resolution: {integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==} - engines: {node: '>= 0.6'} - requiresBuild: true - dev: true - - /convert-source-map@1.8.0: - resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==} - dependencies: - safe-buffer: 5.1.2 - dev: true - - /cookie-signature@1.0.6: - resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} - requiresBuild: true - dev: true - - /cookie@0.4.0: - resolution: {integrity: sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==} - engines: {node: '>= 0.6'} - requiresBuild: true - dev: true - - /cookie@0.4.2: - resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} - engines: {node: '>= 0.6'} - dev: true - - /cookiejar@2.1.2: - resolution: {integrity: sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==} - requiresBuild: true - dev: true - - /copy-descriptor@0.1.1: - resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==} - engines: {node: '>=0.10.0'} - dev: true - - /core-js-pure@3.25.3: - resolution: {integrity: sha512-T/7qvgv70MEvRkZ8p6BasLZmOVYKzOaWNBEHAU8FmveCJkl4nko2quqPQOmy6AJIp5MBanhz9no3A94NoRb0XA==} - requiresBuild: true - dev: true - - /core-js@2.6.12: - resolution: {integrity: sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==} - deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js. - requiresBuild: true - dev: true - - /core-js@3.30.1: - resolution: {integrity: sha512-ZNS5nbiSwDTq4hFosEDqm65izl2CWmLz0hARJMyNQBgkUZMIF51cQiMvIQKA6hvuaeWxQDP3hEedM1JZIgTldQ==} - requiresBuild: true - dev: true - - /core-util-is@1.0.2: - resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} - dev: true - - /core-util-is@1.0.3: - resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - dev: true - - /cors@2.8.5: - resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} - engines: {node: '>= 0.10'} - requiresBuild: true - dependencies: - object-assign: 4.1.1 - vary: 1.1.2 - dev: true - - /cosmiconfig@8.2.0: - resolution: {integrity: sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==} - engines: {node: '>=14'} - dependencies: - import-fresh: 3.3.0 - js-yaml: 4.1.0 - parse-json: 5.2.0 - path-type: 4.0.0 - dev: true - - /crc-32@1.2.2: - resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} - engines: {node: '>=0.8'} - hasBin: true - dev: true - - /create-ecdh@4.0.3: - resolution: {integrity: sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==} - requiresBuild: true - dependencies: - bn.js: 4.12.0 - elliptic: 6.5.4 - dev: true - - /create-hash@1.2.0: - resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} - dependencies: - cipher-base: 1.0.4 - inherits: 2.0.4 - md5.js: 1.3.5 - ripemd160: 2.0.2 - sha.js: 2.4.11 - dev: true - - /create-hmac@1.1.7: - resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} - dependencies: - cipher-base: 1.0.4 - create-hash: 1.2.0 - inherits: 2.0.4 - ripemd160: 2.0.2 - safe-buffer: 5.2.1 - sha.js: 2.4.11 - dev: true - - /create-require@1.1.1: - resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - dev: true - - /cross-fetch@2.2.6: - resolution: {integrity: sha512-9JZz+vXCmfKUZ68zAptS7k4Nu8e2qcibe7WVZYps7sAgk5R8GYTc+T1WR0v1rlP9HxgARmOX1UTIJZFytajpNA==} - dependencies: - node-fetch: 2.6.7 - whatwg-fetch: 2.0.4 - transitivePeerDependencies: - - encoding - dev: true - - /cross-fetch@3.1.5: - resolution: {integrity: sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==} - dependencies: - node-fetch: 2.6.7 - transitivePeerDependencies: - - encoding - dev: true - - /cross-spawn@5.1.0: - resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==} - dependencies: - lru-cache: 4.1.5 - shebang-command: 1.2.0 - which: 1.3.1 - dev: false - - /cross-spawn@6.0.5: - resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==} - engines: {node: '>=4.8'} - dependencies: - nice-try: 1.0.5 - path-key: 2.0.1 - semver: 5.7.1 - shebang-command: 1.2.0 - which: 1.3.1 - dev: true - - /cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: '>= 8'} - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - dev: true - - /crypt@0.0.2: - resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} - dev: true - - /crypto-addr-codec@0.1.7: - resolution: {integrity: sha512-X4hzfBzNhy4mAc3UpiXEC/L0jo5E8wAa9unsnA8nNXYzXjCcGk83hfC5avJWCSGT8V91xMnAS9AKMHmjw5+XCg==} - dependencies: - base-x: 3.0.9 - big-integer: 1.6.36 - blakejs: 1.2.1 - bs58: 4.0.1 - ripemd160-min: 0.0.6 - safe-buffer: 5.2.1 - sha3: 2.1.4 - dev: true - - /crypto-browserify@3.12.0: - resolution: {integrity: sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==} - dependencies: - browserify-cipher: 1.0.1 - browserify-sign: 4.0.4 - create-ecdh: 4.0.3 - create-hash: 1.2.0 - create-hmac: 1.1.7 - diffie-hellman: 5.0.3 - inherits: 2.0.4 - pbkdf2: 3.1.2 - public-encrypt: 4.0.3 - randombytes: 2.1.0 - randomfill: 1.0.4 - dev: true - - /css-select@5.1.0: - resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} - dependencies: - boolbase: 1.0.0 - css-what: 6.1.0 - domhandler: 5.0.3 - domutils: 3.0.1 - nth-check: 2.1.1 - dev: true - - /css-what@6.1.0: - resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} - engines: {node: '>= 6'} - dev: true - - /csv-generate@3.4.3: - resolution: {integrity: sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==} - dev: false - - /csv-parse@4.16.3: - resolution: {integrity: sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==} - dev: false - - /csv-stringify@5.6.5: - resolution: {integrity: sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A==} - dev: false - - /csv@5.5.3: - resolution: {integrity: sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g==} - engines: {node: '>= 0.1.90'} - dependencies: - csv-generate: 3.4.3 - csv-parse: 4.16.3 - csv-stringify: 5.6.5 - stream-transform: 2.1.3 - dev: false - - /d@1.0.1: - resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==} - dependencies: - es5-ext: 0.10.62 - type: 1.2.0 - dev: true - - /dashdash@1.14.1: - resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} - engines: {node: '>=0.10'} - dependencies: - assert-plus: 1.0.0 - dev: true - - /dataloader@1.4.0: - resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==} - dev: false - - /death@1.1.0: - resolution: {integrity: sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w==} - dev: true - - /debug@2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.0.0 - dev: true - - /debug@3.2.6(supports-color@6.0.0): - resolution: {integrity: sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==} - deprecated: Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797) - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.3 - supports-color: 6.0.0 - dev: true - - /debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.3 - dev: true - - /debug@4.3.4(supports-color@8.1.1): - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.2 - supports-color: 8.1.1 - dev: true - - /decamelize-keys@1.1.1: - resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} - engines: {node: '>=0.10.0'} - dependencies: - decamelize: 1.2.0 - map-obj: 1.0.1 - dev: false - - /decamelize@1.2.0: - resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} - engines: {node: '>=0.10.0'} - - /decamelize@4.0.0: - resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} - engines: {node: '>=10'} - dev: true - - /decode-uri-component@0.2.0: - resolution: {integrity: sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==} - engines: {node: '>=0.10'} - dev: true - - /decompress-response@3.3.0: - resolution: {integrity: sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==} - engines: {node: '>=4'} - requiresBuild: true - dependencies: - mimic-response: 1.0.1 - dev: true - - /decompress-response@6.0.0: - resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} - engines: {node: '>=10'} - dependencies: - mimic-response: 3.1.0 - dev: true - - /deep-eql@4.1.3: - resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} - engines: {node: '>=6'} - dependencies: - type-detect: 4.0.8 - - /deep-equal-in-any-order@2.0.6: - resolution: {integrity: sha512-RfnWHQzph10YrUjvWwhd15Dne8ciSJcZ3U6OD7owPwiVwsdE5IFSoZGg8rlwJD11ES+9H5y8j3fCofviRHOqLQ==} - dependencies: - lodash.mapvalues: 4.6.0 - sort-any: 2.0.0 - dev: true - - /deep-equal@1.1.1: - resolution: {integrity: sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==} - dependencies: - is-arguments: 1.0.4 - is-date-object: 1.0.2 - is-regex: 1.1.4 - object-is: 1.1.5 - object-keys: 1.1.1 - regexp.prototype.flags: 1.5.1 - dev: true - - /deep-extend@0.6.0: - resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} - engines: {node: '>=4.0.0'} - dev: true - - /deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - dev: true - - /defaults@1.0.4: - resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} - dependencies: - clone: 1.0.4 - dev: false - - /defer-to-connect@1.1.1: - resolution: {integrity: sha512-J7thop4u3mRTkYRQ+Vpfwy2G5Ehoy82I14+14W4YMDLKdWloI9gSzRbV30s/NckQGVJtPkWNcW4oMAUigTdqiQ==} - requiresBuild: true - dev: true - - /defer-to-connect@2.0.1: - resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} - engines: {node: '>=10'} - dev: true - - /deferred-leveldown@1.2.2: - resolution: {integrity: sha512-uukrWD2bguRtXilKt6cAWKyoXrTSMo5m7crUdLfWQmu8kIm88w3QZoUL+6nhpfKVmhHANER6Re3sKoNoZ3IKMA==} - dependencies: - abstract-leveldown: 2.6.3 - dev: true - - /deferred-leveldown@4.0.2: - resolution: {integrity: sha512-5fMC8ek8alH16QiV0lTCis610D1Zt1+LA4MS4d63JgS32lrCjTFDUFz2ao09/j2I4Bqb5jL4FZYwu7Jz0XO1ww==} - engines: {node: '>=6'} - dependencies: - abstract-leveldown: 5.0.0 - inherits: 2.0.4 - dev: true - - /define-data-property@1.1.1: - resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} - engines: {node: '>= 0.4'} - dependencies: - get-intrinsic: 1.2.2 - gopd: 1.0.1 - has-property-descriptors: 1.0.0 - - /define-properties@1.1.4: - resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==} - engines: {node: '>= 0.4'} - dependencies: - has-property-descriptors: 1.0.0 - object-keys: 1.1.1 - - /define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} - dependencies: - define-data-property: 1.1.1 - has-property-descriptors: 1.0.0 - object-keys: 1.1.1 - - /define-property@0.2.5: - resolution: {integrity: sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==} - engines: {node: '>=0.10.0'} - dependencies: - is-descriptor: 0.1.6 - dev: true - - /define-property@1.0.0: - resolution: {integrity: sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==} - engines: {node: '>=0.10.0'} - dependencies: - is-descriptor: 1.0.2 - dev: true - - /define-property@2.0.2: - resolution: {integrity: sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==} - engines: {node: '>=0.10.0'} - dependencies: - is-descriptor: 1.0.2 - isobject: 3.0.1 - dev: true - - /defined@1.0.0: - resolution: {integrity: sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==} - dev: true - - /delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - dev: true - - /delete-empty@3.0.0: - resolution: {integrity: sha512-ZUyiwo76W+DYnKsL3Kim6M/UOavPdBJgDYWOmuQhYaZvJH0AXAHbUNyEDtRbBra8wqqr686+63/0azfEk1ebUQ==} - engines: {node: '>=10'} - hasBin: true - dependencies: - ansi-colors: 4.1.3 - minimist: 1.2.8 - path-starts-with: 2.0.1 - rimraf: 2.7.1 - dev: true - - /depd@1.1.2: - resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} - engines: {node: '>= 0.6'} - requiresBuild: true - dev: true - - /depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - dev: true - - /des.js@1.0.1: - resolution: {integrity: sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==} - requiresBuild: true - dependencies: - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - dev: true - - /destroy@1.0.4: - resolution: {integrity: sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==} - requiresBuild: true - dev: true - - /detect-indent@4.0.0: - resolution: {integrity: sha512-BDKtmHlOzwI7iRuEkhzsnPoi5ypEhWAJB5RvHWe1kMr06js3uK5B3734i3ui5Yd+wOJV1cpE4JnivPD283GU/A==} - engines: {node: '>=0.10.0'} - dependencies: - repeating: 2.0.1 - dev: true - - /detect-indent@5.0.0: - resolution: {integrity: sha512-rlpvsxUtM0PQvy9iZe640/IWwWYyBsTApREbA1pHOpmOUIl9MkP/U4z7vTtg4Oaojvqhxt7sdufnT0EzGaR31g==} - engines: {node: '>=4'} - dev: true - - /detect-indent@6.1.0: - resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} - engines: {node: '>=8'} - dev: false - - /detect-port@1.3.0: - resolution: {integrity: sha512-E+B1gzkl2gqxt1IhUzwjrxBKRqx1UzC3WLONHinn8S3T6lwV/agVCyitiFOsGJ/eYuEUBvD71MZHy3Pv1G9doQ==} - engines: {node: '>= 4.2.1'} - hasBin: true - dependencies: - address: 1.1.2 - debug: 2.6.9 - transitivePeerDependencies: - - supports-color - dev: true - - /diff@3.5.0: - resolution: {integrity: sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==} - engines: {node: '>=0.3.1'} - dev: true - - /diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} - engines: {node: '>=0.3.1'} - dev: true - - /diff@5.0.0: - resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} - engines: {node: '>=0.3.1'} - dev: true - - /diffie-hellman@5.0.3: - resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} - requiresBuild: true - dependencies: - bn.js: 4.12.0 - miller-rabin: 4.0.1 - randombytes: 2.1.0 - dev: true - - /difflib@0.2.4: - resolution: {integrity: sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==} - dependencies: - heap: 0.2.6 - dev: true - - /dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - dependencies: - path-type: 4.0.0 - - /doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - dependencies: - esutils: 2.0.3 - dev: true - - /dom-serializer@2.0.0: - resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - entities: 4.4.0 - dev: true - - /dom-walk@0.1.1: - resolution: {integrity: sha512-8CGZnLAdYN/o0SHjlP3nLvliHpi2f/prVU63/Hc4DTDpBgsNVAJekegjFtxfZ7NTUEDzHUByjX1gT3eYakIKqg==} - dev: true - - /domelementtype@2.3.0: - resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} - dev: true - - /domhandler@5.0.3: - resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} - engines: {node: '>= 4'} - dependencies: - domelementtype: 2.3.0 - dev: true - - /domutils@3.0.1: - resolution: {integrity: sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==} - dependencies: - dom-serializer: 2.0.0 - domelementtype: 2.3.0 - domhandler: 5.0.3 - dev: true - - /dot-case@2.1.1: - resolution: {integrity: sha512-HnM6ZlFqcajLsyudHq7LeeLDr2rFAVYtDv/hV5qchQEidSck8j9OPUsXY9KwJv/lHMtYlX4DjRQqwFYa+0r8Ug==} - dependencies: - no-case: 2.3.2 - dev: true - - /dotenv@8.6.0: - resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} - engines: {node: '>=10'} - dev: false - - /dotignore@0.1.2: - resolution: {integrity: sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw==} - hasBin: true - dependencies: - minimatch: 3.1.2 - dev: true - - /drbg.js@1.0.1: - resolution: {integrity: sha512-F4wZ06PvqxYLFEZKkFxTDcns9oFNk34hvmJSEwdzsxVQ8YI5YaxtACgQatkYgv2VI2CFkUd2Y+xosPQnHv809g==} - engines: {node: '>=0.10'} - dependencies: - browserify-aes: 1.2.0 - create-hash: 1.2.0 - create-hmac: 1.1.7 - dev: true - - /duplexer3@0.1.4: - resolution: {integrity: sha512-CEj8FwwNA4cVH2uFCoHUrmojhYh1vmCdOaneKJXwkeY1i9jnlslVo9dx+hQ5Hl9GnH/Bwy/IjxAyOePyPKYnzA==} - requiresBuild: true - dev: true - - /ecc-jsbn@0.1.2: - resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} - dependencies: - jsbn: 0.1.1 - safer-buffer: 2.1.2 - dev: true - - /ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - requiresBuild: true - dev: true - - /electron-to-chromium@1.4.270: - resolution: {integrity: sha512-KNhIzgLiJmDDC444dj9vEOpZEgsV96ult9Iff98Vanumn+ShJHd5se8aX6KeVxdc0YQeqdrezBZv89rleDbvSg==} - dev: true - - /elliptic@6.5.4: - resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==} - dependencies: - bn.js: 4.12.0 - brorand: 1.1.0 - hash.js: 1.1.7 - hmac-drbg: 1.0.1 - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 - - /emoji-regex@7.0.3: - resolution: {integrity: sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==} - dev: true - - /emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - /encodeurl@1.0.2: - resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} - engines: {node: '>= 0.8'} - requiresBuild: true - dev: true - - /encoding-down@5.0.4: - resolution: {integrity: sha512-8CIZLDcSKxgzT+zX8ZVfgNbu8Md2wq/iqa1Y7zyVR18QBEAc0Nmzuvj/N5ykSKpfGzjM8qxbaFntLPwnVoUhZw==} - engines: {node: '>=6'} - dependencies: - abstract-leveldown: 5.0.0 - inherits: 2.0.4 - level-codec: 9.0.2 - level-errors: 2.0.1 - xtend: 4.0.2 - dev: true - - /encoding@0.1.13: - resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} - dependencies: - iconv-lite: 0.6.3 - dev: true - - /end-of-stream@1.4.4: - resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} - dependencies: - once: 1.4.0 - dev: true - - /enquirer@2.3.6: - resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==} - engines: {node: '>=8.6'} - dependencies: - ansi-colors: 4.1.3 - - /entities@4.4.0: - resolution: {integrity: sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==} - engines: {node: '>=0.12'} - dev: true - - /env-paths@2.2.1: - resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} - engines: {node: '>=6'} - dev: true - - /errno@0.1.8: - resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} - hasBin: true - dependencies: - prr: 1.0.1 - dev: true - - /error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - dependencies: - is-arrayish: 0.2.1 - - /es-abstract@1.22.3: - resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==} - engines: {node: '>= 0.4'} - dependencies: - array-buffer-byte-length: 1.0.0 - arraybuffer.prototype.slice: 1.0.2 - available-typed-arrays: 1.0.5 - call-bind: 1.0.5 - es-set-tostringtag: 2.0.2 - es-to-primitive: 1.2.1 - function.prototype.name: 1.1.6 - get-intrinsic: 1.2.2 - get-symbol-description: 1.0.0 - globalthis: 1.0.3 - gopd: 1.0.1 - has-property-descriptors: 1.0.0 - has-proto: 1.0.1 - has-symbols: 1.0.3 - hasown: 2.0.0 - internal-slot: 1.0.6 - 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.13.1 - 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.13 - - /es-array-method-boxes-properly@1.0.0: - resolution: {integrity: sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==} - dev: true - - /es-set-tostringtag@2.0.2: - resolution: {integrity: sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==} - engines: {node: '>= 0.4'} - dependencies: - get-intrinsic: 1.2.2 - has-tostringtag: 1.0.0 - hasown: 2.0.0 - - /es-shim-unscopables@1.0.2: - resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} - dependencies: - hasown: 2.0.0 - - /es-to-primitive@1.2.1: - resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} - engines: {node: '>= 0.4'} - dependencies: - is-callable: 1.2.7 - is-date-object: 1.0.2 - is-symbol: 1.0.3 - - /es5-ext@0.10.62: - resolution: {integrity: sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==} - engines: {node: '>=0.10'} - requiresBuild: true - dependencies: - es6-iterator: 2.0.3 - es6-symbol: 3.1.3 - next-tick: 1.1.0 - dev: true - - /es6-iterator@2.0.3: - resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} - dependencies: - d: 1.0.1 - es5-ext: 0.10.62 - es6-symbol: 3.1.3 - dev: true - - /es6-promise@4.2.8: - resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} - dev: true - - /es6-symbol@3.1.3: - resolution: {integrity: sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==} - dependencies: - d: 1.0.1 - ext: 1.4.0 - dev: true - - /escalade@3.1.1: - resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} - engines: {node: '>=6'} - - /escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - requiresBuild: true - dev: true - - /escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - - /escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - dev: true - - /escodegen@1.8.1: - resolution: {integrity: sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==} - engines: {node: '>=0.12.0'} - hasBin: true - dependencies: - esprima: 2.7.3 - estraverse: 1.9.3 - esutils: 2.0.3 - optionator: 0.8.3 - optionalDependencies: - source-map: 0.2.0 - dev: true - - /eslint-config-prettier@9.1.0(eslint@8.56.0): - resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} - hasBin: true - peerDependencies: - eslint: '>=7.0.0' - dependencies: - eslint: 8.56.0 - dev: true - - /eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0)(eslint@8.56.0)(prettier@3.2.5): - resolution: {integrity: sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - '@types/eslint': '>=8.0.0' - eslint: '>=8.0.0' - eslint-config-prettier: '*' - prettier: '>=3.0.0' - peerDependenciesMeta: - '@types/eslint': - optional: true - eslint-config-prettier: - optional: true - dependencies: - eslint: 8.56.0 - eslint-config-prettier: 9.1.0(eslint@8.56.0) - prettier: 3.2.5 - prettier-linter-helpers: 1.0.0 - synckit: 0.8.8 - dev: true - - /eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - dev: true - - /eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - - /eslint@8.56.0: - resolution: {integrity: sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - hasBin: true - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.56.0) - '@eslint-community/regexpp': 4.9.1 - '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.56.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.6 - chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4(supports-color@8.1.1) - doctrine: 3.0.0 - escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 - esquery: 1.5.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 - find-up: 5.0.0 - glob-parent: 6.0.2 - globals: 13.20.0 - graphemer: 1.4.0 - ignore: 5.2.4 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-yaml: 4.1.0 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.3 - strip-ansi: 6.0.1 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color - dev: true - - /espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - acorn: 8.10.0 - acorn-jsx: 5.3.2(acorn@8.10.0) - eslint-visitor-keys: 3.4.3 - dev: true - - /esprima@2.7.3: - resolution: {integrity: sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==} - engines: {node: '>=0.10.0'} - hasBin: true - dev: true - - /esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - - /esquery@1.5.0: - resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} - engines: {node: '>=0.10'} - dependencies: - estraverse: 5.3.0 - dev: true - - /esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - dependencies: - estraverse: 5.3.0 - dev: true - - /estraverse@1.9.3: - resolution: {integrity: sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==} - engines: {node: '>=0.10.0'} - dev: true - - /estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - dev: true - - /esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - dev: true - - /etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} - requiresBuild: true - dev: true - - /eth-block-tracker@3.0.1: - resolution: {integrity: sha512-WUVxWLuhMmsfenfZvFO5sbl1qFY2IqUlw/FPVmjjdElpqLsZtSG+wPe9Dz7W/sB6e80HgFKknOmKk2eNlznHug==} - dependencies: - eth-query: 2.1.2 - ethereumjs-tx: 1.3.7 - ethereumjs-util: 5.2.1 - ethjs-util: 0.1.6 - json-rpc-engine: 3.8.0 - pify: 2.3.0 - tape: 4.16.1 - transitivePeerDependencies: - - supports-color - dev: true - - /eth-ens-namehash@2.0.8: - resolution: {integrity: sha512-VWEI1+KJfz4Km//dadyvBBoBeSQ0MHTXPvr8UIXiLW6IanxvAV+DmlZAijZwAyggqGUfwQBeHf7tc9wzc1piSw==} - dependencies: - idna-uts46-hx: 2.3.1 - js-sha3: 0.5.7 - dev: true - - /eth-gas-reporter@0.2.25: - resolution: {integrity: sha512-1fRgyE4xUB8SoqLgN3eDfpDfwEfRxh2Sz1b7wzFbyQA+9TekMmvSjjoRu9SKcSVyK+vLkLIsVbJDsTWjw195OQ==} - peerDependencies: - '@codechecks/client': ^0.1.0 - peerDependenciesMeta: - '@codechecks/client': - optional: true - dependencies: - '@ethersproject/abi': 5.7.0 - '@solidity-parser/parser': 0.14.3 - cli-table3: 0.5.1 - colors: 1.4.0 - ethereum-cryptography: 1.1.2 - ethers: 4.0.49 - fs-readdir-recursive: 1.1.0 - lodash: 4.17.21 - markdown-table: 1.1.3 - mocha: 7.2.0 - req-cwd: 2.0.0 - request: 2.88.2 - request-promise-native: 1.0.9(request@2.88.2) - sha1: 1.1.1 - sync-request: 6.1.0 - dev: true - - /eth-json-rpc-infura@3.2.1: - resolution: {integrity: sha512-W7zR4DZvyTn23Bxc0EWsq4XGDdD63+XPUCEhV2zQvQGavDVC4ZpFDK4k99qN7bd7/fjj37+rxmuBOBeIqCA5Mw==} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - dependencies: - cross-fetch: 2.2.6 - eth-json-rpc-middleware: 1.6.0 - json-rpc-engine: 3.8.0 - json-rpc-error: 2.0.0 - transitivePeerDependencies: - - encoding - - supports-color - dev: true - - /eth-json-rpc-middleware@1.6.0: - resolution: {integrity: sha512-tDVCTlrUvdqHKqivYMjtFZsdD7TtpNLBCfKAcOpaVs7orBMS/A8HWro6dIzNtTZIR05FAbJ3bioFOnZpuCew9Q==} - dependencies: - async: 2.6.3 - eth-query: 2.1.2 - eth-tx-summary: 3.2.4 - ethereumjs-block: 1.7.1 - ethereumjs-tx: 1.3.7 - ethereumjs-util: 5.2.1 - ethereumjs-vm: 2.6.0 - fetch-ponyfill: 4.1.0 - json-rpc-engine: 3.8.0 - json-rpc-error: 2.0.0 - json-stable-stringify: 1.0.1 - promise-to-callback: 1.0.0 - tape: 4.16.1 - transitivePeerDependencies: - - supports-color - dev: true - - /eth-lib@0.1.29: - resolution: {integrity: sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ==} - requiresBuild: true - dependencies: - bn.js: 4.12.0 - elliptic: 6.5.4 - nano-json-stream-parser: 0.1.2 - servify: 0.1.12 - ws: 3.3.3 - xhr-request-promise: 0.1.2 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - - /eth-lib@0.2.8: - resolution: {integrity: sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==} - dependencies: - bn.js: 4.12.0 - elliptic: 6.5.4 - xhr-request-promise: 0.1.2 - dev: true - - /eth-query@2.1.2: - resolution: {integrity: sha512-srES0ZcvwkR/wd5OQBRA1bIJMww1skfGS0s8wlwK3/oNP4+wnds60krvu5R1QbpRQjMmpG5OMIWro5s7gvDPsA==} - dependencies: - json-rpc-random-id: 1.0.1 - xtend: 4.0.2 - dev: true - - /eth-sig-util@1.4.2: - resolution: {integrity: sha512-iNZ576iTOGcfllftB73cPB5AN+XUQAT/T8xzsILsghXC1o8gJUqe3RHlcDqagu+biFpYQ61KQrZZJza8eRSYqw==} - deprecated: Deprecated in favor of '@metamask/eth-sig-util' - dependencies: - ethereumjs-abi: github.com/ethereumjs/ethereumjs-abi/ee3994657fa7a427238e6ba92a84d0b529bbcde0 - ethereumjs-util: 5.2.1 - dev: true - - /eth-sig-util@3.0.0: - resolution: {integrity: sha512-4eFkMOhpGbTxBQ3AMzVf0haUX2uTur7DpWiHzWyTURa28BVJJtOkcb9Ok5TV0YvEPG61DODPW7ZUATbJTslioQ==} - deprecated: Deprecated in favor of '@metamask/eth-sig-util' - dependencies: - buffer: 5.7.1 - elliptic: 6.5.4 - ethereumjs-abi: 0.6.5 - ethereumjs-util: 5.2.1 - tweetnacl: 1.0.3 - tweetnacl-util: 0.15.1 - dev: true - - /eth-tx-summary@3.2.4: - resolution: {integrity: sha512-NtlDnaVZah146Rm8HMRUNMgIwG/ED4jiqk0TME9zFheMl1jOp6jL1m0NKGjJwehXQ6ZKCPr16MTr+qspKpEXNg==} - dependencies: - async: 2.6.3 - clone: 2.1.2 - concat-stream: 1.6.2 - end-of-stream: 1.4.4 - eth-query: 2.1.2 - ethereumjs-block: 1.7.1 - ethereumjs-tx: 1.3.7 - ethereumjs-util: 5.2.1 - ethereumjs-vm: 2.6.0 - through2: 2.0.5 - dev: true - - /ethashjs@0.0.8: - resolution: {integrity: sha512-/MSbf/r2/Ld8o0l15AymjOTlPqpN8Cr4ByUEA9GtR4x0yAh3TdtDzEg29zMjXCNPI7u6E5fOQdj/Cf9Tc7oVNw==} - deprecated: 'New package name format for new versions: @ethereumjs/ethash. Please update.' - dependencies: - async: 2.6.3 - buffer-xor: 2.0.2 - ethereumjs-util: 7.1.5 - miller-rabin: 4.0.1 - dev: true - - /ethereum-bloom-filters@1.0.10: - resolution: {integrity: sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==} - dependencies: - js-sha3: 0.8.0 - dev: true - - /ethereum-common@0.0.18: - resolution: {integrity: sha512-EoltVQTRNg2Uy4o84qpa2aXymXDJhxm7eos/ACOg0DG4baAbMjhbdAEsx9GeE8sC3XCxnYvrrzZDH8D8MtA2iQ==} - dev: true - - /ethereum-common@0.2.0: - resolution: {integrity: sha512-XOnAR/3rntJgbCdGhqdaLIxDLWKLmsZOGhHdBKadEr6gEnJLH52k93Ou+TUdFaPN3hJc3isBZBal3U/XZ15abA==} - dev: true - - /ethereum-cryptography@0.1.3: - resolution: {integrity: sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==} - dependencies: - '@types/pbkdf2': 3.1.0 - '@types/secp256k1': 4.0.3 - blakejs: 1.2.1 - browserify-aes: 1.2.0 - bs58check: 2.1.2 - create-hash: 1.2.0 - create-hmac: 1.1.7 - hash.js: 1.1.7 - keccak: 3.0.2 - pbkdf2: 3.1.2 - randombytes: 2.1.0 - safe-buffer: 5.2.1 - scrypt-js: 3.0.1 - secp256k1: 4.0.3 - setimmediate: 1.0.5 - dev: true - - /ethereum-cryptography@1.1.2: - resolution: {integrity: sha512-XDSJlg4BD+hq9N2FjvotwUET9Tfxpxc3kWGE2AqUG5vcbeunnbImVk3cj6e/xT3phdW21mE8R5IugU4fspQDcQ==} - dependencies: - '@noble/hashes': 1.1.2 - '@noble/secp256k1': 1.6.3 - '@scure/bip32': 1.1.0 - '@scure/bip39': 1.1.0 - dev: true - - /ethereum-waffle@3.4.4(typescript@5.3.3): - resolution: {integrity: sha512-PA9+jCjw4WC3Oc5ocSMBj5sXvueWQeAbvCA+hUlb6oFgwwKyq5ka3bWQ7QZcjzIX+TdFkxP4IbFmoY2D8Dkj9Q==} - engines: {node: '>=10.0'} - hasBin: true - dependencies: - '@ethereum-waffle/chai': 3.4.4 - '@ethereum-waffle/compiler': 3.4.4(typescript@5.3.3) - '@ethereum-waffle/mock-contract': 3.4.4 - '@ethereum-waffle/provider': 3.4.4 - ethers: 5.7.2 - transitivePeerDependencies: - - bufferutil - - encoding - - supports-color - - typescript - - utf-8-validate - dev: true - - /ethereumjs-abi@0.6.5: - resolution: {integrity: sha512-rCjJZ/AE96c/AAZc6O3kaog4FhOsAViaysBxqJNy2+LHP0ttH0zkZ7nXdVHOAyt6lFwLO0nlCwWszysG/ao1+g==} - dependencies: - bn.js: 4.12.0 - ethereumjs-util: 4.5.0 - dev: true - - /ethereumjs-abi@0.6.8: - resolution: {integrity: sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==} - dependencies: - bn.js: 4.12.0 - ethereumjs-util: 6.2.1 - dev: true - - /ethereumjs-account@2.0.5: - resolution: {integrity: sha512-bgDojnXGjhMwo6eXQC0bY6UK2liSFUSMwwylOmQvZbSl/D7NXQ3+vrGO46ZeOgjGfxXmgIeVNDIiHw7fNZM4VA==} - dependencies: - ethereumjs-util: 5.2.1 - rlp: 2.2.7 - safe-buffer: 5.2.1 - dev: true - - /ethereumjs-account@3.0.0: - resolution: {integrity: sha512-WP6BdscjiiPkQfF9PVfMcwx/rDvfZTjFKY0Uwc09zSQr9JfIVH87dYIJu0gNhBhpmovV4yq295fdllS925fnBA==} - deprecated: Please use Util.Account class found on package ethereumjs-util@^7.0.6 https://github.com/ethereumjs/ethereumjs-util/releases/tag/v7.0.6 - dependencies: - ethereumjs-util: 6.2.1 - rlp: 2.2.7 - safe-buffer: 5.2.1 - dev: true - - /ethereumjs-block@1.7.1: - resolution: {integrity: sha512-B+sSdtqm78fmKkBq78/QLKJbu/4Ts4P2KFISdgcuZUPDm9x+N7qgBPIIFUGbaakQh8bzuquiRVbdmvPKqbILRg==} - deprecated: 'New package name format for new versions: @ethereumjs/block. Please update.' - dependencies: - async: 2.6.3 - ethereum-common: 0.2.0 - ethereumjs-tx: 1.3.7 - ethereumjs-util: 5.2.1 - merkle-patricia-tree: 2.3.2 - dev: true - - /ethereumjs-block@2.2.2: - resolution: {integrity: sha512-2p49ifhek3h2zeg/+da6XpdFR3GlqY3BIEiqxGF8j9aSRIgkb7M1Ky+yULBKJOu8PAZxfhsYA+HxUk2aCQp3vg==} - deprecated: 'New package name format for new versions: @ethereumjs/block. Please update.' - dependencies: - async: 2.6.3 - ethereumjs-common: 1.5.0 - ethereumjs-tx: 2.1.2 - ethereumjs-util: 5.2.1 - merkle-patricia-tree: 2.3.2 - dev: true - - /ethereumjs-blockchain@4.0.4: - resolution: {integrity: sha512-zCxaRMUOzzjvX78DTGiKjA+4h2/sF0OYL1QuPux0DHpyq8XiNoF5GYHtb++GUxVlMsMfZV7AVyzbtgcRdIcEPQ==} - deprecated: 'New package name format for new versions: @ethereumjs/blockchain. Please update.' - dependencies: - async: 2.6.3 - ethashjs: 0.0.8 - ethereumjs-block: 2.2.2 - ethereumjs-common: 1.5.0 - ethereumjs-util: 6.2.1 - flow-stoplight: 1.0.0 - level-mem: 3.0.1 - lru-cache: 5.1.1 - rlp: 2.2.7 - semaphore: 1.1.0 - dev: true - - /ethereumjs-common@1.5.0: - resolution: {integrity: sha512-SZOjgK1356hIY7MRj3/ma5qtfr/4B5BL+G4rP/XSMYr2z1H5el4RX5GReYCKmQmYI/nSBmRnwrZ17IfHuG0viQ==} - deprecated: 'New package name format for new versions: @ethereumjs/common. Please update.' - dev: true - - /ethereumjs-tx@1.3.7: - resolution: {integrity: sha512-wvLMxzt1RPhAQ9Yi3/HKZTn0FZYpnsmQdbKYfUUpi4j1SEIcbkd9tndVjcPrufY3V7j2IebOpC00Zp2P/Ay2kA==} - deprecated: 'New package name format for new versions: @ethereumjs/tx. Please update.' - dependencies: - ethereum-common: 0.0.18 - ethereumjs-util: 5.2.1 - dev: true - - /ethereumjs-tx@2.1.2: - resolution: {integrity: sha512-zZEK1onCeiORb0wyCXUvg94Ve5It/K6GD1K+26KfFKodiBiS6d9lfCXlUKGBBdQ+bv7Day+JK0tj1K+BeNFRAw==} - deprecated: 'New package name format for new versions: @ethereumjs/tx. Please update.' - dependencies: - ethereumjs-common: 1.5.0 - ethereumjs-util: 6.2.1 - dev: true - - /ethereumjs-util@4.5.0: - resolution: {integrity: sha512-gT1zBY8aQKkexYu7XNeBZBnJsRLo+sWD1XWRLJOaDSz49/9kCOs6ERP52Bw/TA4uaVFKpM+O8ebWy44Ib5B6xw==} - dependencies: - bn.js: 4.12.0 - create-hash: 1.2.0 - keccakjs: 0.2.3 - rlp: 2.2.7 - secp256k1: 3.7.1 - dev: true - - /ethereumjs-util@5.2.1: - resolution: {integrity: sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==} - dependencies: - bn.js: 4.12.0 - create-hash: 1.2.0 - elliptic: 6.5.4 - ethereum-cryptography: 0.1.3 - ethjs-util: 0.1.6 - rlp: 2.2.7 - safe-buffer: 5.2.1 - dev: true - - /ethereumjs-util@6.2.1: - resolution: {integrity: sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==} - dependencies: - '@types/bn.js': 4.11.6 - bn.js: 4.12.0 - create-hash: 1.2.0 - elliptic: 6.5.4 - ethereum-cryptography: 0.1.3 - ethjs-util: 0.1.6 - rlp: 2.2.7 - dev: true - - /ethereumjs-util@7.1.5: - resolution: {integrity: sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==} - engines: {node: '>=10.0.0'} - dependencies: - '@types/bn.js': 5.1.1 - bn.js: 5.2.1 - create-hash: 1.2.0 - ethereum-cryptography: 0.1.3 - rlp: 2.2.7 - dev: true - - /ethereumjs-vm@2.6.0: - resolution: {integrity: sha512-r/XIUik/ynGbxS3y+mvGnbOKnuLo40V5Mj1J25+HEO63aWYREIqvWeRO/hnROlMBE5WoniQmPmhiaN0ctiHaXw==} - deprecated: 'New package name format for new versions: @ethereumjs/vm. Please update.' - dependencies: - async: 2.6.3 - async-eventemitter: 0.2.4 - ethereumjs-account: 2.0.5 - ethereumjs-block: 2.2.2 - ethereumjs-common: 1.5.0 - ethereumjs-util: 6.2.1 - fake-merkle-patricia-tree: 1.0.1 - functional-red-black-tree: 1.0.1 - merkle-patricia-tree: 2.3.2 - rustbn.js: 0.2.0 - safe-buffer: 5.2.1 - dev: true - - /ethereumjs-vm@4.2.0: - resolution: {integrity: sha512-X6qqZbsY33p5FTuZqCnQ4+lo957iUJMM6Mpa6bL4UW0dxM6WmDSHuI4j/zOp1E2TDKImBGCJA9QPfc08PaNubA==} - deprecated: 'New package name format for new versions: @ethereumjs/vm. Please update.' - dependencies: - async: 2.6.3 - async-eventemitter: 0.2.4 - core-js-pure: 3.25.3 - ethereumjs-account: 3.0.0 - ethereumjs-block: 2.2.2 - ethereumjs-blockchain: 4.0.4 - ethereumjs-common: 1.5.0 - ethereumjs-tx: 2.1.2 - ethereumjs-util: 6.2.1 - fake-merkle-patricia-tree: 1.0.1 - functional-red-black-tree: 1.0.1 - merkle-patricia-tree: 2.3.2 - rustbn.js: 0.2.0 - safe-buffer: 5.2.1 - util.promisify: 1.1.1 - dev: true - - /ethereumjs-wallet@0.6.5: - resolution: {integrity: sha512-MDwjwB9VQVnpp/Dc1XzA6J1a3wgHQ4hSvA1uWNatdpOrtCbPVuQSKSyRnjLvS0a+KKMw2pvQ9Ybqpb3+eW8oNA==} - requiresBuild: true - dependencies: - aes-js: 3.1.2 - bs58check: 2.1.2 - ethereum-cryptography: 0.1.3 - ethereumjs-util: 6.2.1 - randombytes: 2.1.0 - safe-buffer: 5.2.1 - scryptsy: 1.2.1 - utf8: 3.0.0 - uuid: 3.4.0 - dev: true - optional: true - - /ethers@4.0.49: - resolution: {integrity: sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg==} - dependencies: - aes-js: 3.0.0 - bn.js: 4.12.0 - elliptic: 6.5.4 - hash.js: 1.1.3 - js-sha3: 0.5.7 - scrypt-js: 2.0.4 - setimmediate: 1.0.4 - uuid: 2.0.1 - xmlhttprequest: 1.8.0 - dev: true - - /ethers@5.7.2: - resolution: {integrity: sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==} - dependencies: - '@ethersproject/abi': 5.7.0 - '@ethersproject/abstract-provider': 5.7.0 - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/address': 5.7.0 - '@ethersproject/base64': 5.7.0 - '@ethersproject/basex': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/contracts': 5.7.0 - '@ethersproject/hash': 5.7.0 - '@ethersproject/hdnode': 5.7.0 - '@ethersproject/json-wallets': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.0.6 - '@ethersproject/networks': 5.7.1 - '@ethersproject/pbkdf2': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/providers': 5.7.2 - '@ethersproject/random': 5.7.0 - '@ethersproject/rlp': 5.7.0 - '@ethersproject/sha2': 5.7.0 - '@ethersproject/signing-key': 5.7.0 - '@ethersproject/solidity': 5.7.0 - '@ethersproject/strings': 5.7.0 - '@ethersproject/transactions': 5.7.0 - '@ethersproject/units': 5.7.0 - '@ethersproject/wallet': 5.7.0 - '@ethersproject/web': 5.7.1 - '@ethersproject/wordlists': 5.7.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - /ethjs-abi@0.2.1: - resolution: {integrity: sha512-g2AULSDYI6nEJyJaEVEXtTimRY2aPC2fi7ddSy0W+LXvEVL8Fe1y76o43ecbgdUKwZD+xsmEgX1yJr1Ia3r1IA==} - engines: {node: '>=6.5.0', npm: '>=3'} - dependencies: - bn.js: 4.11.6 - js-sha3: 0.5.5 - number-to-bn: 1.7.0 - dev: true - - /ethjs-unit@0.1.6: - resolution: {integrity: sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==} - engines: {node: '>=6.5.0', npm: '>=3'} - dependencies: - bn.js: 4.11.6 - number-to-bn: 1.7.0 - dev: true - - /ethjs-util@0.1.6: - resolution: {integrity: sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==} - engines: {node: '>=6.5.0', npm: '>=3'} - dependencies: - is-hex-prefixed: 1.0.0 - strip-hex-prefix: 1.0.0 - dev: true - - /eventemitter3@4.0.4: - resolution: {integrity: sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==} - dev: true - - /events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} - dev: true - - /evp_bytestokey@1.0.3: - resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} - dependencies: - md5.js: 1.3.5 - safe-buffer: 5.2.1 - dev: true - - /expand-brackets@2.1.4: - resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==} - engines: {node: '>=0.10.0'} - dependencies: - debug: 2.6.9 - define-property: 0.2.5 - extend-shallow: 2.0.1 - posix-character-classes: 0.1.1 - regex-not: 1.0.2 - snapdragon: 0.8.2 - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - dev: true - - /express@4.17.1: - resolution: {integrity: sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==} - engines: {node: '>= 0.10.0'} - requiresBuild: true - dependencies: - accepts: 1.3.7 - array-flatten: 1.1.1 - body-parser: 1.19.0 - content-disposition: 0.5.3 - content-type: 1.0.4 - cookie: 0.4.0 - cookie-signature: 1.0.6 - debug: 2.6.9 - depd: 1.1.2 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 1.1.2 - fresh: 0.5.2 - merge-descriptors: 1.0.1 - methods: 1.1.2 - on-finished: 2.3.0 - parseurl: 1.3.3 - path-to-regexp: 0.1.7 - proxy-addr: 2.0.5 - qs: 6.7.0 - range-parser: 1.2.1 - safe-buffer: 5.1.2 - send: 0.17.1 - serve-static: 1.14.1 - setprototypeof: 1.1.1 - statuses: 1.5.0 - type-is: 1.6.18 - utils-merge: 1.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - dev: true - - /ext@1.4.0: - resolution: {integrity: sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==} - dependencies: - type: 2.0.0 - dev: true - - /extend-shallow@2.0.1: - resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} - engines: {node: '>=0.10.0'} - dependencies: - is-extendable: 0.1.1 - dev: true - - /extend-shallow@3.0.2: - resolution: {integrity: sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==} - engines: {node: '>=0.10.0'} - dependencies: - assign-symbols: 1.0.0 - is-extendable: 1.0.1 - dev: true - - /extend@3.0.2: - resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - dev: true - - /extendable-error@0.1.7: - resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} - dev: false - - /external-editor@3.1.0: - resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} - engines: {node: '>=4'} - dependencies: - chardet: 0.7.0 - iconv-lite: 0.4.24 - tmp: 0.0.33 - dev: false - - /extglob@2.0.4: - resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==} - engines: {node: '>=0.10.0'} - dependencies: - array-unique: 0.3.2 - define-property: 1.0.0 - expand-brackets: 2.1.4 - extend-shallow: 2.0.1 - fragment-cache: 0.2.1 - regex-not: 1.0.2 - snapdragon: 0.8.2 - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - dev: true - - /extsprintf@1.3.0: - resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} - engines: {'0': node >=0.6.0} - dev: true - - /extsprintf@1.4.0: - resolution: {integrity: sha512-6NW8DZ8pWBc5NbGYUiqqccj9dXnuSzilZYqprdKJBZsQodGH9IyUoFOGxIWVDcBzHMb8ET24aqx9p66tZEWZkA==} - engines: {'0': node >=0.6.0} - dev: true - - /fake-merkle-patricia-tree@1.0.1: - resolution: {integrity: sha512-Tgq37lkc9pUIgIKw5uitNUKcgcYL3R6JvXtKQbOf/ZSavXbidsksgp/pAY6p//uhw0I4yoMsvTSovvVIsk/qxA==} - dependencies: - checkpoint-store: 1.1.0 - dev: true - - /fast-base64-decode@1.0.0: - resolution: {integrity: sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==} - dev: true - - /fast-check@3.1.1: - resolution: {integrity: sha512-3vtXinVyuUKCKFKYcwXhGE6NtGWkqF8Yh3rvMZNzmwz8EPrgoc/v4pDdLHyLnCyCI5MZpZZkDEwFyXyEONOxpA==} - engines: {node: '>=8.0.0'} - dependencies: - pure-rand: 5.0.3 - dev: true - - /fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true - - /fast-diff@1.2.0: - resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==} - dev: true - - /fast-glob@3.3.1: - resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} - engines: {node: '>=8.6.0'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.5 - - /fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true - - /fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - dev: true - - /fastq@1.6.0: - resolution: {integrity: sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA==} - dependencies: - reusify: 1.0.4 - - /fetch-ponyfill@4.1.0: - resolution: {integrity: sha512-knK9sGskIg2T7OnYLdZ2hZXn0CtDrAIBxYQLpmEf0BqfdWnwmM1weccUl5+4EdA44tzNSFAuxITPbXtPehUB3g==} - dependencies: - node-fetch: 1.7.3 - dev: true - - /file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} - dependencies: - flat-cache: 3.0.4 - dev: true - - /file-uri-to-path@1.0.0: - resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - dev: true - - /fill-range@4.0.0: - resolution: {integrity: sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==} - engines: {node: '>=0.10.0'} - dependencies: - extend-shallow: 2.0.1 - is-number: 3.0.0 - repeat-string: 1.6.1 - to-regex-range: 2.1.1 - dev: true - - /fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} - engines: {node: '>=8'} - dependencies: - to-regex-range: 5.0.1 - - /finalhandler@1.1.2: - resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} - engines: {node: '>= 0.8'} - requiresBuild: true - dependencies: - debug: 2.6.9 - encodeurl: 1.0.2 - escape-html: 1.0.3 - on-finished: 2.3.0 - parseurl: 1.3.3 - statuses: 1.5.0 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - dev: true - - /find-replace@1.0.3: - resolution: {integrity: sha512-KrUnjzDCD9426YnCP56zGYy/eieTnhtK6Vn++j+JJzmlsWWwEkDnsyVF575spT6HJ6Ow9tlbT3TQTDsa+O4UWA==} - engines: {node: '>=4.0.0'} - dependencies: - array-back: 1.0.4 - test-value: 2.1.0 - dev: true - - /find-replace@3.0.0: - resolution: {integrity: sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==} - engines: {node: '>=4.0.0'} - dependencies: - array-back: 3.1.0 - dev: true - - /find-up@1.1.2: - resolution: {integrity: sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==} - engines: {node: '>=0.10.0'} - dependencies: - path-exists: 2.1.0 - pinkie-promise: 2.0.1 - dev: true - - /find-up@2.1.0: - resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} - engines: {node: '>=4'} - dependencies: - locate-path: 2.0.0 - dev: true - - /find-up@3.0.0: - resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} - engines: {node: '>=6'} - dependencies: - locate-path: 3.0.0 - dev: true - - /find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - - /find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - /find-yarn-workspace-root2@1.2.16: - resolution: {integrity: sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==} - dependencies: - micromatch: 4.0.5 - pkg-dir: 4.2.0 - dev: false - - /find-yarn-workspace-root@1.2.1: - resolution: {integrity: sha512-dVtfb0WuQG+8Ag2uWkbG79hOUzEsRrhBzgfn86g2sJPkzmcpGdghbNTfUKGTxymFrY/tLIodDzLoW9nOJ4FY8Q==} - dependencies: - fs-extra: 4.0.3 - micromatch: 3.1.10 - transitivePeerDependencies: - - supports-color - dev: true - - /find-yarn-workspace-root@2.0.0: - resolution: {integrity: sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==} - dependencies: - micromatch: 4.0.5 - dev: true - - /flat-cache@3.0.4: - resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} - engines: {node: ^10.12.0 || >=12.0.0} - dependencies: - flatted: 3.2.7 - rimraf: 3.0.2 - dev: true - - /flat@4.1.1: - resolution: {integrity: sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==} - hasBin: true - dependencies: - is-buffer: 2.0.5 - dev: true - - /flat@5.0.2: - resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} - hasBin: true - dev: true - - /flatted@3.2.7: - resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} - dev: true - - /flow-stoplight@1.0.0: - resolution: {integrity: sha512-rDjbZUKpN8OYhB0IE/vY/I8UWO/602IIJEU/76Tv4LvYnwHCk0BCsvz4eRr9n+FQcri7L5cyaXOo0+/Kh4HisA==} - dev: true - - /follow-redirects@1.15.2(debug@4.3.4): - resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - dependencies: - debug: 4.3.4(supports-color@8.1.1) - dev: true - - /for-each@0.3.3: - resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} - dependencies: - is-callable: 1.2.7 - - /for-in@1.0.2: - resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==} - engines: {node: '>=0.10.0'} - dev: true - - /foreach@2.0.5: - resolution: {integrity: sha512-ZBbtRiapkZYLsqoPyZOR+uPfto0GRMNQN1GwzZtZt7iZvPPbDDQV0JF5Hx4o/QFQ5c0vyuoZ98T8RSBbopzWtA==} - dev: true - - /forever-agent@0.6.1: - resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} - dev: true - - /form-data-encoder@1.7.1: - resolution: {integrity: sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg==} - dev: true - - /form-data@2.3.3: - resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} - engines: {node: '>= 0.12'} - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.27 - dev: true - - /form-data@3.0.1: - resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} - engines: {node: '>= 6'} - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.27 - dev: true - - /form-data@4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} - engines: {node: '>= 6'} - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.27 - dev: true - - /forwarded@0.1.2: - resolution: {integrity: sha512-Ua9xNhH0b8pwE3yRbFfXJvfdWF0UHNCdeyb2sbi9Ul/M+r3PTdrz7Cv4SCfZRMjmzEM9PhraqfZFbGTIg3OMyA==} - engines: {node: '>= 0.6'} - requiresBuild: true - dev: true - - /fp-ts@1.19.3: - resolution: {integrity: sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==} - dev: true - - /fragment-cache@0.2.1: - resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==} - engines: {node: '>=0.10.0'} - dependencies: - map-cache: 0.2.2 - dev: true - - /fresh@0.5.2: - resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} - engines: {node: '>= 0.6'} - requiresBuild: true - dev: true - - /fs-extra@0.30.0: - resolution: {integrity: sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==} - dependencies: - graceful-fs: 4.2.10 - jsonfile: 2.4.0 - klaw: 1.3.1 - path-is-absolute: 1.0.1 - rimraf: 2.7.1 - dev: true - - /fs-extra@4.0.3: - resolution: {integrity: sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==} - dependencies: - graceful-fs: 4.2.10 - jsonfile: 4.0.0 - universalify: 0.1.2 - dev: true - - /fs-extra@7.0.1: - resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} - engines: {node: '>=6 <7 || >=8'} - dependencies: - graceful-fs: 4.2.10 - jsonfile: 4.0.0 - universalify: 0.1.2 - - /fs-extra@8.1.0: - resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} - engines: {node: '>=6 <7 || >=8'} - dependencies: - graceful-fs: 4.2.10 - jsonfile: 4.0.0 - universalify: 0.1.2 - - /fs-extra@9.1.0: - resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} - engines: {node: '>=10'} - dependencies: - at-least-node: 1.0.0 - graceful-fs: 4.2.10 - jsonfile: 6.1.0 - universalify: 2.0.0 - dev: true - - /fs-minipass@1.2.7: - resolution: {integrity: sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==} - requiresBuild: true - dependencies: - minipass: 2.9.0 - dev: true - - /fs-readdir-recursive@1.1.0: - resolution: {integrity: sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==} - dev: true - - /fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - dev: true - - /fsevents@2.1.3: - resolution: {integrity: sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - deprecated: '"Please update to latest v2.3 or v2.2"' - requiresBuild: true - dev: true - optional: true - - /fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /function-bind@1.1.1: - resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} - - /function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - /function.prototype.name@1.1.6: - resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 - functions-have-names: 1.2.3 - - /functional-red-black-tree@1.0.1: - resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} - dev: true - - /functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - - /ganache-core@2.13.2: - resolution: {integrity: sha512-tIF5cR+ANQz0+3pHWxHjIwHqFXcVo0Mb+kcsNhglNFALcYo49aQpnS9dqHartqPfMFjiHh/qFoD3mYK0d/qGgw==} - engines: {node: '>=8.9.0'} - deprecated: ganache-core is now ganache; visit https://trfl.io/g7 for details - dependencies: - abstract-leveldown: 3.0.0 - async: 2.6.2 - bip39: 2.5.0 - cachedown: 1.0.0 - clone: 2.1.2 - debug: 3.2.6(supports-color@6.0.0) - encoding-down: 5.0.4 - eth-sig-util: 3.0.0 - ethereumjs-abi: 0.6.8 - ethereumjs-account: 3.0.0 - ethereumjs-block: 2.2.2 - ethereumjs-common: 1.5.0 - ethereumjs-tx: 2.1.2 - ethereumjs-util: 6.2.1 - ethereumjs-vm: 4.2.0 - heap: 0.2.6 - level-sublevel: 6.6.4 - levelup: 3.1.1 - lodash: 4.17.20 - lru-cache: 5.1.1 - merkle-patricia-tree: 3.0.0 - patch-package: 6.2.2 - seedrandom: 3.0.1 - source-map-support: 0.5.12 - tmp: 0.1.0 - web3-provider-engine: 14.2.1 - websocket: 1.0.32 - optionalDependencies: - ethereumjs-wallet: 0.6.5 - web3: 1.2.11 - transitivePeerDependencies: - - bufferutil - - encoding - - supports-color - - utf-8-validate - dev: true - bundledDependencies: - - keccak - - /get-caller-file@1.0.3: - resolution: {integrity: sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==} - dev: true - - /get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - - /get-func-name@2.0.2: - resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} - - /get-intrinsic@1.1.3: - resolution: {integrity: sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==} - dependencies: - function-bind: 1.1.1 - has: 1.0.3 - has-symbols: 1.0.3 - - /get-intrinsic@1.2.2: - resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} - dependencies: - function-bind: 1.1.2 - has-proto: 1.0.1 - has-symbols: 1.0.3 - hasown: 2.0.0 - - /get-port@3.2.0: - resolution: {integrity: sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==} - engines: {node: '>=4'} - dev: true - - /get-stream@3.0.0: - resolution: {integrity: sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==} - engines: {node: '>=4'} - requiresBuild: true - dev: true - - /get-stream@4.1.0: - resolution: {integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==} - engines: {node: '>=6'} - requiresBuild: true - dependencies: - pump: 3.0.0 - dev: true - - /get-stream@5.1.0: - resolution: {integrity: sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==} - engines: {node: '>=8'} - dependencies: - pump: 3.0.0 - dev: true - - /get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} - dev: true - - /get-symbol-description@1.0.0: - resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.1.3 - - /get-value@2.0.6: - resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==} - engines: {node: '>=0.10.0'} - dev: true - - /getpass@0.1.7: - resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} - dependencies: - assert-plus: 1.0.0 - dev: true - - /ghost-testrpc@0.0.2: - resolution: {integrity: sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==} - hasBin: true - dependencies: - chalk: 2.4.2 - node-emoji: 1.11.0 - dev: true - - /glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - dependencies: - is-glob: 4.0.3 - - /glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - dependencies: - is-glob: 4.0.3 - dev: true - - /glob@5.0.15: - resolution: {integrity: sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==} - dependencies: - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: true - - /glob@7.1.3: - resolution: {integrity: sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==} - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: true - - /glob@7.1.7: - resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==} - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: true - - /glob@7.2.0: - resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: true - - /glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: true - - /glob@8.1.0: - resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} - engines: {node: '>=12'} - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 5.1.6 - once: 1.4.0 - dev: true - - /global-modules@2.0.0: - resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} - engines: {node: '>=6'} - dependencies: - global-prefix: 3.0.0 - dev: true - - /global-prefix@3.0.0: - resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==} - engines: {node: '>=6'} - dependencies: - ini: 1.3.8 - kind-of: 6.0.3 - which: 1.3.1 - dev: true - - /global@4.3.2: - resolution: {integrity: sha512-/4AybdwIDU4HkCUbJkZdWpe4P6vuw/CUtu+0I1YlLIPe7OlUO7KNJ+q/rO70CW2/NW6Jc6I62++Hzsf5Alu6rQ==} - dependencies: - min-document: 2.19.0 - process: 0.5.2 - dev: true - - /globals@13.20.0: - resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==} - engines: {node: '>=8'} - dependencies: - type-fest: 0.20.2 - dev: true - - /globals@9.18.0: - resolution: {integrity: sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==} - engines: {node: '>=0.10.0'} - dev: true - - /globalthis@1.0.3: - resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} - engines: {node: '>= 0.4'} - dependencies: - define-properties: 1.2.1 - - /globby@10.0.2: - resolution: {integrity: sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==} - engines: {node: '>=8'} - dependencies: - '@types/glob': 7.1.1 - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.1 - glob: 7.2.3 - ignore: 5.2.4 - merge2: 1.4.1 - slash: 3.0.0 - dev: true - - /globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.1 - ignore: 5.2.4 - merge2: 1.4.1 - slash: 3.0.0 - - /gopd@1.0.1: - resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} - dependencies: - get-intrinsic: 1.2.2 - - /got@12.1.0: - resolution: {integrity: sha512-hBv2ty9QN2RdbJJMK3hesmSkFTjVIHyIDDbssCKnSmq62edGgImJWD10Eb1k77TiV1bxloxqcFAVK8+9pkhOig==} - engines: {node: '>=14.16'} - dependencies: - '@sindresorhus/is': 4.6.0 - '@szmarczak/http-timer': 5.0.1 - '@types/cacheable-request': 6.0.2 - '@types/responselike': 1.0.0 - cacheable-lookup: 6.1.0 - cacheable-request: 7.0.2 - decompress-response: 6.0.0 - form-data-encoder: 1.7.1 - get-stream: 6.0.1 - http2-wrapper: 2.1.11 - lowercase-keys: 3.0.0 - p-cancelable: 3.0.0 - responselike: 2.0.1 - dev: true - - /got@7.1.0: - resolution: {integrity: sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==} - engines: {node: '>=4'} - requiresBuild: true - dependencies: - '@types/keyv': 3.1.4 - '@types/responselike': 1.0.0 - decompress-response: 3.3.0 - duplexer3: 0.1.4 - get-stream: 3.0.0 - is-plain-obj: 1.1.0 - is-retry-allowed: 1.2.0 - is-stream: 1.1.0 - isurl: 1.0.0 - lowercase-keys: 1.0.1 - p-cancelable: 0.3.0 - p-timeout: 1.2.1 - safe-buffer: 5.2.1 - timed-out: 4.0.1 - url-parse-lax: 1.0.0 - url-to-options: 1.0.1 - dev: true - - /got@9.6.0: - resolution: {integrity: sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==} - engines: {node: '>=8.6'} - dependencies: - '@sindresorhus/is': 0.14.0 - '@szmarczak/http-timer': 1.1.2 - '@types/keyv': 3.1.4 - '@types/responselike': 1.0.0 - cacheable-request: 6.1.0 - decompress-response: 3.3.0 - duplexer3: 0.1.4 - get-stream: 4.1.0 - lowercase-keys: 1.0.1 - mimic-response: 1.0.1 - p-cancelable: 1.1.0 - to-readable-stream: 1.0.0 - url-parse-lax: 3.0.0 - dev: true - - /graceful-fs@4.2.10: - resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} - - /grapheme-splitter@1.0.4: - resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} - - /graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - dev: true - - /growl@1.10.5: - resolution: {integrity: sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==} - engines: {node: '>=4.x'} - dev: true - - /handlebars@4.7.7: - resolution: {integrity: sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==} - engines: {node: '>=0.4.7'} - hasBin: true - dependencies: - minimist: 1.2.6 - neo-async: 2.6.2 - source-map: 0.6.1 - wordwrap: 1.0.0 - optionalDependencies: - uglify-js: 3.17.3 - dev: true - - /har-schema@2.0.0: - resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==} - engines: {node: '>=4'} - dev: true - - /har-validator@5.1.5: - resolution: {integrity: sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==} - engines: {node: '>=6'} - deprecated: this library is no longer supported - dependencies: - ajv: 6.12.6 - har-schema: 2.0.0 - dev: true - - /hard-rejection@2.1.0: - resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} - engines: {node: '>=6'} - dev: false - - /hardhat-abi-exporter@2.10.1(hardhat@2.19.2): - resolution: {integrity: sha512-X8GRxUTtebMAd2k4fcPyVnCdPa6dYK4lBsrwzKP5yiSq4i+WadWPIumaLfce53TUf/o2TnLpLOduyO1ylE2NHQ==} - engines: {node: '>=14.14.0'} - peerDependencies: - hardhat: ^2.0.0 - dependencies: - '@ethersproject/abi': 5.7.0 - delete-empty: 3.0.0 - hardhat: 2.19.2(ts-node@10.9.2)(typescript@5.3.3) - dev: true - - /hardhat-contract-sizer@2.10.0(hardhat@2.19.2): - resolution: {integrity: sha512-QiinUgBD5MqJZJh1hl1jc9dNnpJg7eE/w4/4GEnrcmZJJTDbVFNe3+/3Ep24XqISSkYxRz36czcPHKHd/a0dwA==} - peerDependencies: - hardhat: ^2.0.0 - dependencies: - chalk: 4.1.2 - cli-table3: 0.6.3 - hardhat: 2.19.2(ts-node@10.9.2)(typescript@5.3.3) - strip-ansi: 6.0.1 - dev: true - - /hardhat-gas-reporter@1.0.9(hardhat@2.19.2): - resolution: {integrity: sha512-INN26G3EW43adGKBNzYWOlI3+rlLnasXTwW79YNnUhXPDa+yHESgt639dJEs37gCjhkbNKcRRJnomXEuMFBXJg==} - peerDependencies: - hardhat: ^2.0.2 - dependencies: - array-uniq: 1.0.3 - eth-gas-reporter: 0.2.25 - hardhat: 2.19.2(ts-node@10.9.2)(typescript@5.3.3) - sha1: 1.1.1 - transitivePeerDependencies: - - '@codechecks/client' - dev: true - - /hardhat-ignore-warnings@0.2.9: - resolution: {integrity: sha512-q1oj6/ixiAx+lgIyGLBajVCSC7qUtAoK7LS9Nr8UVHYo8Iuh5naBiVGo4RDJ6wxbDGYBkeSukUGZrMqzC2DWwA==} - dependencies: - minimatch: 5.1.6 - node-interval-tree: 2.1.2 - solidity-comments: 0.0.2 - dev: true - - /hardhat@2.19.2(ts-node@10.9.2)(typescript@5.3.3): - resolution: {integrity: sha512-CRU3+0Cc8Qh9UpxKd8cLADDPes7ZDtKj4dTK+ERtLBomEzhRPLWklJn4VKOwjre9/k8GNd/e9DYxpfuzcxbXPQ==} - hasBin: true - peerDependencies: - ts-node: '*' - typescript: '*' - peerDependenciesMeta: - ts-node: - optional: true - typescript: - optional: true - dependencies: - '@ethersproject/abi': 5.7.0 - '@metamask/eth-sig-util': 4.0.1 - '@nomicfoundation/ethereumjs-block': 5.0.2 - '@nomicfoundation/ethereumjs-blockchain': 7.0.2 - '@nomicfoundation/ethereumjs-common': 4.0.2 - '@nomicfoundation/ethereumjs-evm': 2.0.2 - '@nomicfoundation/ethereumjs-rlp': 5.0.2 - '@nomicfoundation/ethereumjs-statemanager': 2.0.2 - '@nomicfoundation/ethereumjs-trie': 6.0.2 - '@nomicfoundation/ethereumjs-tx': 5.0.2 - '@nomicfoundation/ethereumjs-util': 9.0.2 - '@nomicfoundation/ethereumjs-vm': 7.0.2 - '@nomicfoundation/solidity-analyzer': 0.1.0 - '@sentry/node': 5.30.0 - '@types/bn.js': 5.1.1 - '@types/lru-cache': 5.1.1 - adm-zip: 0.4.16 - aggregate-error: 3.1.0 - ansi-escapes: 4.3.2 - chalk: 2.4.2 - chokidar: 3.5.3 - ci-info: 2.0.0 - debug: 4.3.4(supports-color@8.1.1) - enquirer: 2.3.6 - env-paths: 2.2.1 - ethereum-cryptography: 1.1.2 - ethereumjs-abi: 0.6.8 - find-up: 2.1.0 - fp-ts: 1.19.3 - fs-extra: 7.0.1 - glob: 7.2.0 - immutable: 4.1.0 - io-ts: 1.10.4 - keccak: 3.0.2 - lodash: 4.17.21 - mnemonist: 0.38.5 - mocha: 10.2.0 - p-map: 4.0.0 - raw-body: 2.5.1 - resolve: 1.17.0 - semver: 6.3.0 - solc: 0.7.3(debug@4.3.4) - source-map-support: 0.5.21 - stacktrace-parser: 0.1.10 - ts-node: 10.9.2(@types/node@16.18.80)(typescript@5.3.3) - tsort: 0.0.1 - typescript: 5.3.3 - undici: 5.19.1 - uuid: 8.3.2 - ws: 7.5.9 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - - /has-ansi@2.0.0: - resolution: {integrity: sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==} - engines: {node: '>=0.10.0'} - dependencies: - ansi-regex: 2.1.1 - dev: true - - /has-bigints@1.0.2: - resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} - - /has-flag@1.0.0: - resolution: {integrity: sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==} - engines: {node: '>=0.10.0'} - dev: true - - /has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} - - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - /has-property-descriptors@1.0.0: - resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} - dependencies: - get-intrinsic: 1.1.3 - - /has-proto@1.0.1: - resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} - engines: {node: '>= 0.4'} - - /has-symbol-support-x@1.4.2: - resolution: {integrity: sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==} - requiresBuild: true - dev: true - - /has-symbols@1.0.3: - resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} - engines: {node: '>= 0.4'} - - /has-to-string-tag-x@1.4.1: - resolution: {integrity: sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==} - requiresBuild: true - dependencies: - has-symbol-support-x: 1.4.2 - dev: true - - /has-tostringtag@1.0.0: - resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} - engines: {node: '>= 0.4'} - dependencies: - has-symbols: 1.0.3 - - /has-value@0.3.1: - resolution: {integrity: sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==} - engines: {node: '>=0.10.0'} - dependencies: - get-value: 2.0.6 - has-values: 0.1.4 - isobject: 2.1.0 - dev: true - - /has-value@1.0.0: - resolution: {integrity: sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==} - engines: {node: '>=0.10.0'} - dependencies: - get-value: 2.0.6 - has-values: 1.0.0 - isobject: 3.0.1 - dev: true - - /has-values@0.1.4: - resolution: {integrity: sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==} - engines: {node: '>=0.10.0'} - dev: true - - /has-values@1.0.0: - resolution: {integrity: sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==} - engines: {node: '>=0.10.0'} - dependencies: - is-number: 3.0.0 - kind-of: 4.0.0 - dev: true - - /has@1.0.3: - resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} - engines: {node: '>= 0.4.0'} - dependencies: - function-bind: 1.1.1 - - /hash-base@3.1.0: - resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} - engines: {node: '>=4'} - dependencies: - inherits: 2.0.4 - readable-stream: 3.6.0 - safe-buffer: 5.2.1 - dev: true - - /hash.js@1.1.3: - resolution: {integrity: sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==} - dependencies: - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - dev: true - - /hash.js@1.1.7: - resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} - dependencies: - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - - /hasown@2.0.0: - resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} - engines: {node: '>= 0.4'} - dependencies: - function-bind: 1.1.2 - - /he@1.2.0: - resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} - hasBin: true - dev: true - - /header-case@1.0.1: - resolution: {integrity: sha512-i0q9mkOeSuhXw6bGgiQCCBgY/jlZuV/7dZXyZ9c6LcBrqwvT8eT719E9uxE5LiZftdl+z81Ugbg/VvXV4OJOeQ==} - dependencies: - no-case: 2.3.2 - upper-case: 1.1.3 - dev: true - - /heap@0.2.6: - resolution: {integrity: sha512-MzzWcnfB1e4EG2vHi3dXHoBupmuXNZzx6pY6HldVS55JKKBoq3xOyzfSaZRkJp37HIhEYC78knabHff3zc4dQQ==} - dev: true - - /highlight.js@10.7.3: - resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} - dev: true - - /highlightjs-solidity@2.0.5: - resolution: {integrity: sha512-ReXxQSGQkODMUgHcWzVSnfDCDrL2HshOYgw3OlIYmfHeRzUPkfJTUIp95pK4CmbiNG2eMTOmNLpfCz9Zq7Cwmg==} - dev: true - - /hmac-drbg@1.0.1: - resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} - dependencies: - hash.js: 1.1.7 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 - - /home-or-tmp@2.0.0: - resolution: {integrity: sha512-ycURW7oUxE2sNiPVw1HVEFsW+ecOpJ5zaj7eC0RlwhibhRBod20muUN8qu/gzx956YrLolVvs1MTXwKgC2rVEg==} - engines: {node: '>=0.10.0'} - dependencies: - os-homedir: 1.0.2 - os-tmpdir: 1.0.2 - dev: true - - /hosted-git-info@2.8.9: - resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} - - /htmlparser2@8.0.1: - resolution: {integrity: sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==} - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - domutils: 3.0.1 - entities: 4.4.0 - dev: true - - /http-basic@8.1.3: - resolution: {integrity: sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==} - engines: {node: '>=6.0.0'} - dependencies: - caseless: 0.12.0 - concat-stream: 1.6.2 - http-response-object: 3.0.2 - parse-cache-control: 1.0.1 - dev: true - - /http-cache-semantics@4.0.3: - resolution: {integrity: sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew==} - dev: true - - /http-errors@1.7.2: - resolution: {integrity: sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==} - engines: {node: '>= 0.6'} - requiresBuild: true - dependencies: - depd: 1.1.2 - inherits: 2.0.3 - setprototypeof: 1.1.1 - statuses: 1.5.0 - toidentifier: 1.0.0 - dev: true - - /http-errors@1.7.3: - resolution: {integrity: sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==} - engines: {node: '>= 0.6'} - requiresBuild: true - dependencies: - depd: 1.1.2 - inherits: 2.0.4 - setprototypeof: 1.1.1 - statuses: 1.5.0 - toidentifier: 1.0.0 - dev: true - - /http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.1 - toidentifier: 1.0.1 - dev: true - - /http-https@1.0.0: - resolution: {integrity: sha512-o0PWwVCSp3O0wS6FvNr6xfBCHgt0m1tvPLFOCc2iFDKTRAXhB7m8klDf7ErowFH8POa6dVdGatKU5I1YYwzUyg==} - dev: true - - /http-response-object@3.0.2: - resolution: {integrity: sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==} - dependencies: - '@types/node': 10.17.60 - dev: true - - /http-signature@1.2.0: - resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==} - engines: {node: '>=0.8', npm: '>=1.3.7'} - dependencies: - assert-plus: 1.0.0 - jsprim: 1.4.1 - sshpk: 1.16.1 - dev: true - - /http2-wrapper@2.1.11: - resolution: {integrity: sha512-aNAk5JzLturWEUiuhAN73Jcbq96R7rTitAoXV54FYMatvihnpD2+6PUgU4ce3D/m5VDbw+F5CsyKSF176ptitQ==} - engines: {node: '>=10.19.0'} - dependencies: - quick-lru: 5.1.1 - resolve-alpn: 1.2.1 - dev: true - - /https-proxy-agent@5.0.1: - resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} - engines: {node: '>= 6'} - dependencies: - agent-base: 6.0.2 - debug: 4.3.4(supports-color@8.1.1) - transitivePeerDependencies: - - supports-color - dev: true - - /human-id@1.0.2: - resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} - dev: false - - /iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} - dependencies: - safer-buffer: 2.1.2 - - /iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - dependencies: - safer-buffer: 2.1.2 - dev: true - - /idna-uts46-hx@2.3.1: - resolution: {integrity: sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA==} - engines: {node: '>=4.0.0'} - dependencies: - punycode: 2.1.0 - dev: true - - /ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - dev: true - - /ignore@5.2.4: - resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} - engines: {node: '>= 4'} - - /immediate@3.2.3: - resolution: {integrity: sha512-RrGCXRm/fRVqMIhqXrGEX9rRADavPiDFSoMb/k64i9XMk8uH4r/Omi5Ctierj6XzNecwDbO4WuFbDD1zmpl3Tg==} - dev: true - - /immediate@3.3.0: - resolution: {integrity: sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==} - dev: true - - /immutable@4.1.0: - resolution: {integrity: sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==} - dev: true - - /import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - dev: true - - /imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - dev: true - - /indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} - - /inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - dev: true - - /inherits@2.0.3: - resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} - requiresBuild: true - dev: true - - /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - /ini@1.3.8: - resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - dev: true - - /internal-slot@1.0.6: - resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==} - engines: {node: '>= 0.4'} - dependencies: - get-intrinsic: 1.2.2 - hasown: 2.0.0 - side-channel: 1.0.4 - - /interpret@1.2.0: - resolution: {integrity: sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==} - engines: {node: '>= 0.10'} - dev: true - - /invariant@2.2.4: - resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} - dependencies: - loose-envify: 1.4.0 - dev: true - - /invert-kv@1.0.0: - resolution: {integrity: sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==} - engines: {node: '>=0.10.0'} - dev: true - - /io-ts@1.10.4: - resolution: {integrity: sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==} - dependencies: - fp-ts: 1.19.3 - dev: true - - /ipaddr.js@1.9.0: - resolution: {integrity: sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==} - engines: {node: '>= 0.10'} - requiresBuild: true - dev: true - - /is-accessor-descriptor@0.1.6: - resolution: {integrity: sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==} - engines: {node: '>=0.10.0'} - dependencies: - kind-of: 3.2.2 - dev: true - - /is-accessor-descriptor@1.0.0: - resolution: {integrity: sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==} - engines: {node: '>=0.10.0'} - dependencies: - kind-of: 6.0.3 - dev: true - - /is-arguments@1.0.4: - resolution: {integrity: sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==} - engines: {node: '>= 0.4'} - dev: true - - /is-array-buffer@3.0.2: - resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} - dependencies: - call-bind: 1.0.5 - get-intrinsic: 1.2.2 - is-typed-array: 1.1.12 - - /is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - - /is-bigint@1.0.4: - resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} - dependencies: - has-bigints: 1.0.2 - - /is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - dependencies: - binary-extensions: 2.2.0 - dev: true - - /is-boolean-object@1.1.2: - resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - has-tostringtag: 1.0.0 - - /is-buffer@1.1.6: - resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} - dev: true - - /is-buffer@2.0.5: - resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} - engines: {node: '>=4'} - dev: true - - /is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} - - /is-ci@2.0.0: - resolution: {integrity: sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==} - hasBin: true - dependencies: - ci-info: 2.0.0 - dev: true - - /is-ci@3.0.1: - resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} - hasBin: true - dependencies: - ci-info: 3.9.0 - dev: false - - /is-core-module@2.10.0: - resolution: {integrity: sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==} - dependencies: - has: 1.0.3 - - /is-data-descriptor@0.1.4: - resolution: {integrity: sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==} - engines: {node: '>=0.10.0'} - dependencies: - kind-of: 3.2.2 - dev: true - - /is-data-descriptor@1.0.0: - resolution: {integrity: sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==} - engines: {node: '>=0.10.0'} - dependencies: - kind-of: 6.0.3 - dev: true - - /is-date-object@1.0.2: - resolution: {integrity: sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==} - engines: {node: '>= 0.4'} - - /is-descriptor@0.1.6: - resolution: {integrity: sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==} - engines: {node: '>=0.10.0'} - dependencies: - is-accessor-descriptor: 0.1.6 - is-data-descriptor: 0.1.4 - kind-of: 5.1.0 - dev: true - - /is-descriptor@1.0.2: - resolution: {integrity: sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==} - engines: {node: '>=0.10.0'} - dependencies: - is-accessor-descriptor: 1.0.0 - is-data-descriptor: 1.0.0 - kind-of: 6.0.3 - dev: true - - /is-docker@2.2.1: - resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} - engines: {node: '>=8'} - hasBin: true - dev: true - - /is-extendable@0.1.1: - resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} - engines: {node: '>=0.10.0'} - dev: true - - /is-extendable@1.0.1: - resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==} - engines: {node: '>=0.10.0'} - dependencies: - is-plain-object: 2.0.4 - dev: true - - /is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - /is-finite@1.1.0: - resolution: {integrity: sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==} - engines: {node: '>=0.10.0'} - dev: true - - /is-fn@1.0.0: - resolution: {integrity: sha512-XoFPJQmsAShb3jEQRfzf2rqXavq7fIqF/jOekp308JlThqrODnMpweVSGilKTCXELfLhltGP2AGgbQGVP8F1dg==} - engines: {node: '>=0.10.0'} - dev: true - - /is-fullwidth-code-point@1.0.0: - resolution: {integrity: sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==} - engines: {node: '>=0.10.0'} - dependencies: - number-is-nan: 1.0.1 - dev: true - - /is-fullwidth-code-point@2.0.0: - resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} - engines: {node: '>=4'} - dev: true - - /is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - /is-function@1.0.1: - resolution: {integrity: sha512-coTeFCk0VaNTNO/FwMMaI30KOPOIkLp1q5M7dIVDn4Zop70KyGFZqXSgKClBisjrD3S2cVIuD7MD793/lyLGZQ==} - dev: true - - /is-generator-function@1.0.8: - resolution: {integrity: sha512-2Omr/twNtufVZFr1GhxjOMFPAj2sjc/dKaIqBhvo4qciXfJmITGH6ZGd8eZYNHza8t1y0e01AuqRhJwfWp26WQ==} - engines: {node: '>= 0.4'} - dev: true - - /is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - dependencies: - is-extglob: 2.1.1 - - /is-hex-prefixed@1.0.0: - resolution: {integrity: sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==} - engines: {node: '>=6.5.0', npm: '>=3'} - dev: true - - /is-lower-case@1.1.3: - resolution: {integrity: sha512-+5A1e/WJpLLXZEDlgz4G//WYSHyQBD32qa4Jd3Lw06qQlv3fJHnp3YIHjTQSGzHMgzmVKz2ZP3rBxTHkPw/lxA==} - dependencies: - lower-case: 1.1.4 - dev: true - - /is-negative-zero@2.0.2: - resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} - engines: {node: '>= 0.4'} - - /is-number-object@1.0.7: - resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} - engines: {node: '>= 0.4'} - dependencies: - has-tostringtag: 1.0.0 - - /is-number@3.0.0: - resolution: {integrity: sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==} - engines: {node: '>=0.10.0'} - dependencies: - kind-of: 3.2.2 - dev: true - - /is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - /is-object@1.0.1: - resolution: {integrity: sha512-+XzmTRB/JXoIdK20Ge8K8PRsP5UlthLaVhIRxzIwQ73jRgER8iRw98DilvERx/tSjOHLy9JM4sKUfLRMB5ui0Q==} - requiresBuild: true - dev: true - - /is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - dev: true - - /is-plain-obj@1.1.0: - resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} - engines: {node: '>=0.10.0'} - - /is-plain-obj@2.1.0: - resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} - engines: {node: '>=8'} - dev: true - - /is-plain-object@2.0.4: - resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} - engines: {node: '>=0.10.0'} - dependencies: - isobject: 3.0.1 - dev: true - - /is-regex@1.1.4: - resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - has-tostringtag: 1.0.0 - - /is-retry-allowed@1.2.0: - resolution: {integrity: sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==} - engines: {node: '>=0.10.0'} - requiresBuild: true - dev: true - - /is-shared-array-buffer@1.0.2: - resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} - dependencies: - call-bind: 1.0.2 - - /is-stream@1.1.0: - resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==} - engines: {node: '>=0.10.0'} - dev: true - - /is-string@1.0.7: - resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} - engines: {node: '>= 0.4'} - dependencies: - has-tostringtag: 1.0.0 - - /is-subdir@1.2.0: - resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} - engines: {node: '>=4'} - dependencies: - better-path-resolve: 1.0.0 - dev: false - - /is-symbol@1.0.3: - resolution: {integrity: sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==} - engines: {node: '>= 0.4'} - dependencies: - has-symbols: 1.0.3 - - /is-typed-array@1.1.12: - resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} - engines: {node: '>= 0.4'} - dependencies: - which-typed-array: 1.1.13 - - /is-typed-array@1.1.5: - resolution: {integrity: sha512-S+GRDgJlR3PyEbsX/Fobd9cqpZBuvUS+8asRqYDMLCb2qMzt1oz5m5oxQCxOgUDxiWsOVNi4yaF+/uvdlHlYug==} - engines: {node: '>= 0.4'} - dependencies: - available-typed-arrays: 1.0.5 - call-bind: 1.0.5 - es-abstract: 1.22.3 - foreach: 2.0.5 - has-symbols: 1.0.3 - dev: true - - /is-typedarray@1.0.0: - resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} - dev: true - - /is-unicode-supported@0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} - engines: {node: '>=10'} - dev: true - - /is-upper-case@1.1.2: - resolution: {integrity: sha512-GQYSJMgfeAmVwh9ixyk888l7OIhNAGKtY6QA+IrWlu9MDTCaXmeozOZ2S9Knj7bQwBO/H6J2kb+pbyTUiMNbsw==} - dependencies: - upper-case: 1.1.3 - dev: true - - /is-url@1.2.4: - resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==} - dev: true - - /is-utf8@0.2.1: - resolution: {integrity: sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==} - dev: true - - /is-weakref@1.0.2: - resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} - dependencies: - call-bind: 1.0.2 - - /is-windows@1.0.2: - resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} - engines: {node: '>=0.10.0'} - - /is-wsl@2.2.0: - resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} - engines: {node: '>=8'} - dependencies: - is-docker: 2.2.1 - dev: true - - /isarray@0.0.1: - resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} - dev: true - - /isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - dev: true - - /isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - /isobject@2.1.0: - resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==} - engines: {node: '>=0.10.0'} - dependencies: - isarray: 1.0.0 - dev: true - - /isobject@3.0.1: - resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} - engines: {node: '>=0.10.0'} - dev: true - - /isomorphic-unfetch@3.1.0: - resolution: {integrity: sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==} - dependencies: - node-fetch: 2.6.7 - unfetch: 4.2.0 - transitivePeerDependencies: - - encoding - dev: true - - /isstream@0.1.2: - resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} - dev: true - - /istanbul@0.4.5: - resolution: {integrity: sha512-nMtdn4hvK0HjUlzr1DrKSUY8ychprt8dzHOgY2KXsIhHu5PuQQEOTM27gV9Xblyon7aUH/TSFIjRHEODF/FRPg==} - deprecated: |- - This module is no longer maintained, try this instead: - npm i nyc - Visit https://istanbul.js.org/integrations for other alternatives. - hasBin: true - dependencies: - abbrev: 1.0.9 - async: 1.5.2 - escodegen: 1.8.1 - esprima: 2.7.3 - glob: 5.0.15 - handlebars: 4.7.7 - js-yaml: 3.14.1 - mkdirp: 0.5.6 - nopt: 3.0.6 - once: 1.4.0 - resolve: 1.1.7 - supports-color: 3.2.3 - which: 1.3.1 - wordwrap: 1.0.0 - dev: true - - /isurl@1.0.0: - resolution: {integrity: sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==} - engines: {node: '>= 4'} - requiresBuild: true - dependencies: - has-to-string-tag-x: 1.4.1 - is-object: 1.0.1 - dev: true - - /js-cookie@2.2.1: - resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==} - dev: true - - /js-sdsl@4.4.2: - resolution: {integrity: sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w==} - dev: true - - /js-sha3@0.5.5: - resolution: {integrity: sha512-yLLwn44IVeunwjpDVTDZmQeVbB0h+dZpY2eO68B/Zik8hu6dH+rKeLxwua79GGIvW6xr8NBAcrtiUbYrTjEFTA==} - dev: true - - /js-sha3@0.5.7: - resolution: {integrity: sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==} - dev: true - - /js-sha3@0.6.1: - resolution: {integrity: sha512-2OHj7sAZ9gnJS4lQsgIsTslmqVrNQdDC99bvwYGQKU1w6k/gwsTLeGBfWt8yHCuTOGqk7DXzuVlK8J+dDXnG7A==} - dev: true - - /js-sha3@0.8.0: - resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} - - /js-tokens@3.0.2: - resolution: {integrity: sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==} - dev: true - - /js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - /js-yaml@3.13.1: - resolution: {integrity: sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==} - hasBin: true - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - dev: true - - /js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} - hasBin: true - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - - /js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true - dependencies: - argparse: 2.0.1 - dev: true - - /jsbn@0.1.1: - resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} - dev: true - - /jsesc@0.5.0: - resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} - hasBin: true - dev: true - - /jsesc@1.3.0: - resolution: {integrity: sha512-Mke0DA0QjUWuJlhsE0ZPPhYiJkRap642SmI/4ztCFaUs6V2AiH1sfecc+57NgaryfAA2VR3v6O+CSjC1jZJKOA==} - hasBin: true - dev: true - - /json-buffer@3.0.0: - resolution: {integrity: sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==} - requiresBuild: true - dev: true - - /json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - dev: true - - /json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - - /json-rpc-engine@3.8.0: - resolution: {integrity: sha512-6QNcvm2gFuuK4TKU1uwfH0Qd/cOSb9c1lls0gbnIhciktIUQJwz6NQNAW4B1KiGPenv7IKu97V222Yo1bNhGuA==} - dependencies: - async: 2.6.3 - babel-preset-env: 1.7.0 - babelify: 7.3.0 - json-rpc-error: 2.0.0 - promise-to-callback: 1.0.0 - safe-event-emitter: 1.0.1 - transitivePeerDependencies: - - supports-color - dev: true - - /json-rpc-error@2.0.0: - resolution: {integrity: sha512-EwUeWP+KgAZ/xqFpaP6YDAXMtCJi+o/QQpCQFIYyxr01AdADi2y413eM8hSqJcoQym9WMePAJWoaODEJufC4Ug==} - dependencies: - inherits: 2.0.4 - dev: true - - /json-rpc-random-id@1.0.1: - resolution: {integrity: sha512-RJ9YYNCkhVDBuP4zN5BBtYAzEl03yq/jIIsyif0JY9qyJuQQZNeDK7anAPKKlyEtLSj2s8h6hNh2F8zO5q7ScA==} - dev: true - - /json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - dev: true - - /json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - dev: true - - /json-schema@0.2.3: - resolution: {integrity: sha512-a3xHnILGMtk+hDOqNwHzF6e2fNbiMrXZvxKQiEv2MlgQP+pjIOzqAmKYD2mDpXYE/44M7g+n9p2bKkYWDUcXCQ==} - dev: true - - /json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - dev: true - - /json-stable-stringify@1.0.1: - resolution: {integrity: sha512-i/J297TW6xyj7sDFa7AmBPkQvLIxWr2kKPWI26tXydnZrzVAocNqn5DMNT1Mzk0vit1V5UkRM7C1KdVNp7Lmcg==} - dependencies: - jsonify: 0.0.0 - dev: true - - /json-stringify-safe@5.0.1: - resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} - dev: true - - /json-to-ast@2.1.0: - resolution: {integrity: sha512-W9Lq347r8tA1DfMvAGn9QNcgYm4Wm7Yc+k8e6vezpMnRT+NHbtlxgNBXRVjXe9YM6eTn6+p/MKOlV/aABJcSnQ==} - engines: {node: '>= 4'} - dependencies: - code-error-fragment: 0.0.230 - grapheme-splitter: 1.0.4 - dev: true - - /json5@0.5.1: - resolution: {integrity: sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw==} - hasBin: true - dev: true - - /jsonfile@2.4.0: - resolution: {integrity: sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==} - optionalDependencies: - graceful-fs: 4.2.10 - dev: true - - /jsonfile@4.0.0: - resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} - optionalDependencies: - graceful-fs: 4.2.10 - - /jsonfile@6.1.0: - resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} - dependencies: - universalify: 2.0.0 - optionalDependencies: - graceful-fs: 4.2.10 - dev: true - - /jsonify@0.0.0: - resolution: {integrity: sha512-trvBk1ki43VZptdBI5rIlG4YOzyeH/WefQt5rj1grasPn4iiZWKet8nkgc4GlsAylaztn0qZfUYOiTsASJFdNA==} - dev: true - - /jsonpointer@5.0.1: - resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} - engines: {node: '>=0.10.0'} - dev: true - - /jsonschema@1.4.0: - resolution: {integrity: sha512-/YgW6pRMr6M7C+4o8kS+B/2myEpHCrxO4PEWnqJNBFMjn7EWXqlQ4tGwL6xTHeRplwuZmcAncdvfOad1nT2yMw==} - dev: true - - /jsprim@1.4.1: - resolution: {integrity: sha512-4Dj8Rf+fQ+/Pn7C5qeEX02op1WfOss3PKTE9Nsop3Dx+6UPxlm1dr/og7o2cRa5hNN07CACr4NFzRLtj/rjWog==} - engines: {'0': node >=0.6.0} - dependencies: - assert-plus: 1.0.0 - extsprintf: 1.3.0 - json-schema: 0.2.3 - verror: 1.10.0 - dev: true - - /keccak@3.0.2: - resolution: {integrity: sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ==} - engines: {node: '>=10.0.0'} - requiresBuild: true - dependencies: - node-addon-api: 2.0.2 - node-gyp-build: 4.5.0 - readable-stream: 3.6.0 - dev: true - - /keccakjs@0.2.3: - resolution: {integrity: sha512-BjLkNDcfaZ6l8HBG9tH0tpmDv3sS2mA7FNQxFHpCdzP3Gb2MVruXBSuoM66SnVxKJpAr5dKGdkHD+bDokt8fTg==} - dependencies: - browserify-sha3: 0.0.4 - sha3: 1.2.6 - dev: true - - /keyv@3.1.0: - resolution: {integrity: sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==} - requiresBuild: true - dependencies: - json-buffer: 3.0.0 - dev: true - - /keyv@4.5.0: - resolution: {integrity: sha512-2YvuMsA+jnFGtBareKqgANOEKe1mk3HKiXu2fRmAfyxG0MJAywNhi5ttWA3PMjl4NmpyjZNbFifR2vNjW1znfA==} - dependencies: - json-buffer: 3.0.1 - dev: true - - /kind-of@3.2.2: - resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==} - engines: {node: '>=0.10.0'} - dependencies: - is-buffer: 1.1.6 - dev: true - - /kind-of@4.0.0: - resolution: {integrity: sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==} - engines: {node: '>=0.10.0'} - dependencies: - is-buffer: 1.1.6 - dev: true - - /kind-of@5.1.0: - resolution: {integrity: sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==} - engines: {node: '>=0.10.0'} - dev: true - - /kind-of@6.0.3: - resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} - engines: {node: '>=0.10.0'} - - /klaw-sync@6.0.0: - resolution: {integrity: sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==} - dependencies: - graceful-fs: 4.2.10 - dev: true - - /klaw@1.3.1: - resolution: {integrity: sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==} - optionalDependencies: - graceful-fs: 4.2.10 - dev: true - - /kleur@4.1.5: - resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} - engines: {node: '>=6'} - dev: false - - /latest-version@7.0.0: - resolution: {integrity: sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==} - engines: {node: '>=14.16'} - dependencies: - package-json: 8.1.1 - dev: true - - /lcid@1.0.0: - resolution: {integrity: sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==} - engines: {node: '>=0.10.0'} - dependencies: - invert-kv: 1.0.0 - dev: true - - /level-codec@7.0.1: - resolution: {integrity: sha512-Ua/R9B9r3RasXdRmOtd+t9TCOEIIlts+TN/7XTT2unhDaL6sJn83S3rUyljbr6lVtw49N3/yA0HHjpV6Kzb2aQ==} - dev: true - - /level-codec@9.0.2: - resolution: {integrity: sha512-UyIwNb1lJBChJnGfjmO0OR+ezh2iVu1Kas3nvBS/BzGnx79dv6g7unpKIDNPMhfdTEGoc7mC8uAu51XEtX+FHQ==} - engines: {node: '>=6'} - dependencies: - buffer: 5.7.1 - dev: true - - /level-errors@1.0.5: - resolution: {integrity: sha512-/cLUpQduF6bNrWuAC4pwtUKA5t669pCsCi2XbmojG2tFeOr9j6ShtdDCtFFQO1DRt+EVZhx9gPzP9G2bUaG4ig==} - dependencies: - errno: 0.1.8 - dev: true - - /level-errors@2.0.1: - resolution: {integrity: sha512-UVprBJXite4gPS+3VznfgDSU8PTRuVX0NXwoWW50KLxd2yw4Y1t2JUR5In1itQnudZqRMT9DlAM3Q//9NCjCFw==} - engines: {node: '>=6'} - dependencies: - errno: 0.1.8 - dev: true - - /level-iterator-stream@1.3.1: - resolution: {integrity: sha512-1qua0RHNtr4nrZBgYlpV0qHHeHpcRRWTxEZJ8xsemoHAXNL5tbooh4tPEEqIqsbWCAJBmUmkwYK/sW5OrFjWWw==} - dependencies: - inherits: 2.0.4 - level-errors: 1.0.5 - readable-stream: 1.0.34 - xtend: 4.0.2 - dev: true - - /level-iterator-stream@2.0.3: - resolution: {integrity: sha512-I6Heg70nfF+e5Y3/qfthJFexhRw/Gi3bIymCoXAlijZdAcLaPuWSJs3KXyTYf23ID6g0o2QF62Yh+grOXY3Rig==} - engines: {node: '>=4'} - dependencies: - inherits: 2.0.4 - readable-stream: 2.3.7 - xtend: 4.0.2 - dev: true - - /level-iterator-stream@3.0.1: - resolution: {integrity: sha512-nEIQvxEED9yRThxvOrq8Aqziy4EGzrxSZK+QzEFAVuJvQ8glfyZ96GB6BoI4sBbLfjMXm2w4vu3Tkcm9obcY0g==} - engines: {node: '>=6'} - dependencies: - inherits: 2.0.4 - readable-stream: 2.3.7 - xtend: 4.0.2 - dev: true - - /level-mem@3.0.1: - resolution: {integrity: sha512-LbtfK9+3Ug1UmvvhR2DqLqXiPW1OJ5jEh0a3m9ZgAipiwpSxGj/qaVVy54RG5vAQN1nCuXqjvprCuKSCxcJHBg==} - engines: {node: '>=6'} - dependencies: - level-packager: 4.0.1 - memdown: 3.0.0 - dev: true - - /level-packager@4.0.1: - resolution: {integrity: sha512-svCRKfYLn9/4CoFfi+d8krOtrp6RoX8+xm0Na5cgXMqSyRru0AnDYdLl+YI8u1FyS6gGZ94ILLZDE5dh2but3Q==} - engines: {node: '>=6'} - dependencies: - encoding-down: 5.0.4 - levelup: 3.1.1 - dev: true - - /level-post@1.0.7: - resolution: {integrity: sha512-PWYqG4Q00asOrLhX7BejSajByB4EmG2GaKHfj3h5UmmZ2duciXLPGYWIjBzLECFWUGOZWlm5B20h/n3Gs3HKew==} - dependencies: - ltgt: 2.2.1 - dev: true - - /level-sublevel@6.6.4: - resolution: {integrity: sha512-pcCrTUOiO48+Kp6F1+UAzF/OtWqLcQVTVF39HLdZ3RO8XBoXt+XVPKZO1vVr1aUoxHZA9OtD2e1v7G+3S5KFDA==} - dependencies: - bytewise: 1.1.0 - level-codec: 9.0.2 - level-errors: 2.0.1 - level-iterator-stream: 2.0.3 - ltgt: 2.1.3 - pull-defer: 0.2.3 - pull-level: 2.0.4 - pull-stream: 3.6.14 - typewiselite: 1.0.0 - xtend: 4.0.2 - dev: true - - /level-supports@4.0.1: - resolution: {integrity: sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA==} - engines: {node: '>=12'} - dev: true - - /level-transcoder@1.0.1: - resolution: {integrity: sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w==} - engines: {node: '>=12'} - dependencies: - buffer: 6.0.3 - module-error: 1.0.2 - dev: true - - /level-ws@0.0.0: - resolution: {integrity: sha512-XUTaO/+Db51Uiyp/t7fCMGVFOTdtLS/NIACxE/GHsij15mKzxksZifKVjlXDF41JMUP/oM1Oc4YNGdKnc3dVLw==} - dependencies: - readable-stream: 1.0.34 - xtend: 2.1.2 - dev: true - - /level-ws@1.0.0: - resolution: {integrity: sha512-RXEfCmkd6WWFlArh3X8ONvQPm8jNpfA0s/36M4QzLqrLEIt1iJE9WBHLZ5vZJK6haMjJPJGJCQWfjMNnRcq/9Q==} - engines: {node: '>=6'} - dependencies: - inherits: 2.0.4 - readable-stream: 2.3.7 - xtend: 4.0.2 - dev: true - - /level@8.0.0: - resolution: {integrity: sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ==} - engines: {node: '>=12'} - dependencies: - browser-level: 1.0.1 - classic-level: 1.2.0 - dev: true - - /levelup@1.3.9: - resolution: {integrity: sha512-VVGHfKIlmw8w1XqpGOAGwq6sZm2WwWLmlDcULkKWQXEA5EopA8OBNJ2Ck2v6bdk8HeEZSbCSEgzXadyQFm76sQ==} - dependencies: - deferred-leveldown: 1.2.2 - level-codec: 7.0.1 - level-errors: 1.0.5 - level-iterator-stream: 1.3.1 - prr: 1.0.1 - semver: 5.4.1 - xtend: 4.0.2 - dev: true - - /levelup@3.1.1: - resolution: {integrity: sha512-9N10xRkUU4dShSRRFTBdNaBxofz+PGaIZO962ckboJZiNmLuhVT6FZ6ZKAsICKfUBO76ySaYU6fJWX/jnj3Lcg==} - engines: {node: '>=6'} - dependencies: - deferred-leveldown: 4.0.2 - level-errors: 2.0.1 - level-iterator-stream: 3.0.1 - xtend: 4.0.2 - dev: true - - /leven@3.1.0: - resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} - engines: {node: '>=6'} - dev: true - - /levn@0.3.0: - resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==} - engines: {node: '>= 0.8.0'} - dependencies: - prelude-ls: 1.1.2 - type-check: 0.3.2 - dev: true - - /levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - dev: true - - /lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - - /load-json-file@1.1.0: - resolution: {integrity: sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==} - engines: {node: '>=0.10.0'} - dependencies: - graceful-fs: 4.2.10 - parse-json: 2.2.0 - pify: 2.3.0 - pinkie-promise: 2.0.1 - strip-bom: 2.0.0 - dev: true - - /load-yaml-file@0.2.0: - resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==} - engines: {node: '>=6'} - dependencies: - graceful-fs: 4.2.10 - js-yaml: 3.14.1 - pify: 4.0.1 - strip-bom: 3.0.0 - dev: false - - /locate-path@2.0.0: - resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} - engines: {node: '>=4'} - dependencies: - p-locate: 2.0.0 - path-exists: 3.0.0 - dev: true - - /locate-path@3.0.0: - resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} - engines: {node: '>=6'} - dependencies: - p-locate: 3.0.0 - path-exists: 3.0.0 - dev: true - - /locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} - dependencies: - p-locate: 4.1.0 - - /locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - dependencies: - p-locate: 5.0.0 - - /lodash.assign@4.2.0: - resolution: {integrity: sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw==} - dev: true - - /lodash.camelcase@4.3.0: - resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} - dev: true - - /lodash.flatten@4.4.0: - resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} - dev: true - - /lodash.mapvalues@4.6.0: - resolution: {integrity: sha512-JPFqXFeZQ7BfS00H58kClY7SPVeHertPE0lNuCyZ26/XlN8TvakYD7b9bGyNmXbT/D3BbtPAAmq90gPWqLkxlQ==} - dev: true - - /lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - dev: true - - /lodash.startcase@4.4.0: - resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} - dev: false - - /lodash.truncate@4.4.2: - resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} - dev: true - - /lodash@4.17.20: - resolution: {integrity: sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==} - dev: true - - /lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - dev: true - - /log-symbols@3.0.0: - resolution: {integrity: sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==} - engines: {node: '>=8'} - dependencies: - chalk: 2.4.2 - dev: true - - /log-symbols@4.1.0: - resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} - engines: {node: '>=10'} - dependencies: - chalk: 4.1.2 - is-unicode-supported: 0.1.0 - dev: true - - /looper@2.0.0: - resolution: {integrity: sha512-6DzMHJcjbQX/UPHc1rRCBfKlLwDkvuGZ715cIR36wSdYqWXFT35uLXq5P/2orl3tz+t+VOVPxw4yPinQlUDGDQ==} - dev: true - - /looper@3.0.0: - resolution: {integrity: sha512-LJ9wplN/uSn72oJRsXTx+snxPet5c8XiZmOKCm906NVYu+ag6SB6vUcnJcWxgnl2NfbIyeobAn7Bwv6xRj2XJg==} - dev: true - - /loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true - dependencies: - js-tokens: 4.0.0 - dev: true - - /loupe@2.3.7: - resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} - dependencies: - get-func-name: 2.0.2 - - /lower-case-first@1.0.2: - resolution: {integrity: sha512-UuxaYakO7XeONbKrZf5FEgkantPf5DUqDayzP5VXZrtRPdH86s4kN47I8B3TW10S4QKiE3ziHNf3kRN//okHjA==} - dependencies: - lower-case: 1.1.4 - dev: true - - /lower-case@1.1.4: - resolution: {integrity: sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==} - dev: true - - /lowercase-keys@1.0.1: - resolution: {integrity: sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==} - engines: {node: '>=0.10.0'} - requiresBuild: true - dev: true - - /lowercase-keys@2.0.0: - resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} - engines: {node: '>=8'} - dev: true - - /lowercase-keys@3.0.0: - resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dev: true - - /lru-cache@3.2.0: - resolution: {integrity: sha512-91gyOKTc2k66UG6kHiH4h3S2eltcPwE1STVfMYC/NG+nZwf8IIuiamfmpGZjpbbxzSyEJaLC0tNSmhjlQUTJow==} - dependencies: - pseudomap: 1.0.2 - dev: true - - /lru-cache@4.1.5: - resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} - dependencies: - pseudomap: 1.0.2 - yallist: 2.1.2 - dev: false - - /lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - dependencies: - yallist: 3.1.1 - dev: true - - /lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - dependencies: - yallist: 4.0.0 - - /lru_map@0.3.3: - resolution: {integrity: sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==} - dev: true - - /ltgt@2.1.3: - resolution: {integrity: sha512-5VjHC5GsENtIi5rbJd+feEpDKhfr7j0odoUR2Uh978g+2p93nd5o34cTjQWohXsPsCZeqoDnIqEf88mPCe0Pfw==} - dev: true - - /ltgt@2.2.1: - resolution: {integrity: sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA==} - dev: true - - /make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - dev: true - - /map-cache@0.2.2: - resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==} - engines: {node: '>=0.10.0'} - dev: true - - /map-obj@1.0.1: - resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} - engines: {node: '>=0.10.0'} - dev: false - - /map-obj@4.3.0: - resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} - engines: {node: '>=8'} - dev: false - - /map-visit@1.0.0: - resolution: {integrity: sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==} - engines: {node: '>=0.10.0'} - dependencies: - object-visit: 1.0.1 - dev: true - - /markdown-table@1.1.3: - resolution: {integrity: sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==} - dev: true - - /mcl-wasm@0.7.9: - resolution: {integrity: sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ==} - engines: {node: '>=8.9.0'} - dev: true - - /md5.js@1.3.5: - resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} - dependencies: - hash-base: 3.1.0 - inherits: 2.0.4 - safe-buffer: 5.2.1 - dev: true - - /media-typer@0.3.0: - resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} - engines: {node: '>= 0.6'} - requiresBuild: true - dev: true - - /memdown@1.4.1: - resolution: {integrity: sha512-iVrGHZB8i4OQfM155xx8akvG9FIj+ht14DX5CQkCTG4EHzZ3d3sgckIf/Lm9ivZalEsFuEVnWv2B2WZvbrro2w==} - dependencies: - abstract-leveldown: 2.7.2 - functional-red-black-tree: 1.0.1 - immediate: 3.3.0 - inherits: 2.0.4 - ltgt: 2.2.1 - safe-buffer: 5.1.2 - dev: true - - /memdown@3.0.0: - resolution: {integrity: sha512-tbV02LfZMWLcHcq4tw++NuqMO+FZX8tNJEiD2aNRm48ZZusVg5N8NART+dmBkepJVye986oixErf7jfXboMGMA==} - engines: {node: '>=6'} - dependencies: - abstract-leveldown: 5.0.0 - functional-red-black-tree: 1.0.1 - immediate: 3.2.3 - inherits: 2.0.4 - ltgt: 2.2.1 - safe-buffer: 5.1.2 - dev: true - - /memory-level@1.0.0: - resolution: {integrity: sha512-UXzwewuWeHBz5krr7EvehKcmLFNoXxGcvuYhC41tRnkrTbJohtS7kVn9akmgirtRygg+f7Yjsfi8Uu5SGSQ4Og==} - engines: {node: '>=12'} - dependencies: - abstract-level: 1.0.3 - functional-red-black-tree: 1.0.1 - module-error: 1.0.2 - dev: true - - /memorystream@0.3.1: - resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} - engines: {node: '>= 0.10.0'} - dev: true - - /meow@6.1.1: - resolution: {integrity: sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg==} - engines: {node: '>=8'} - dependencies: - '@types/minimist': 1.2.5 - camelcase-keys: 6.2.2 - decamelize-keys: 1.1.1 - hard-rejection: 2.1.0 - minimist-options: 4.1.0 - normalize-package-data: 2.5.0 - read-pkg-up: 7.0.1 - redent: 3.0.0 - trim-newlines: 3.0.1 - type-fest: 0.13.1 - yargs-parser: 18.1.3 - dev: false - - /merge-descriptors@1.0.1: - resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} - requiresBuild: true - dev: true - - /merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - - /merkle-patricia-tree@2.3.2: - resolution: {integrity: sha512-81PW5m8oz/pz3GvsAwbauj7Y00rqm81Tzad77tHBwU7pIAtN+TJnMSOJhxBKflSVYhptMMb9RskhqHqrSm1V+g==} - dependencies: - async: 1.5.2 - ethereumjs-util: 5.2.1 - level-ws: 0.0.0 - levelup: 1.3.9 - memdown: 1.4.1 - readable-stream: 2.3.7 - rlp: 2.2.7 - semaphore: 1.1.0 - dev: true - - /merkle-patricia-tree@3.0.0: - resolution: {integrity: sha512-soRaMuNf/ILmw3KWbybaCjhx86EYeBbD8ph0edQCTed0JN/rxDt1EBN52Ajre3VyGo+91f8+/rfPIRQnnGMqmQ==} - dependencies: - async: 2.6.3 - ethereumjs-util: 5.2.1 - level-mem: 3.0.1 - level-ws: 1.0.0 - readable-stream: 3.6.0 - rlp: 2.2.7 - semaphore: 1.1.0 - dev: true - - /methods@1.1.2: - resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} - engines: {node: '>= 0.6'} - requiresBuild: true - dev: true - - /micromatch@3.1.10: - resolution: {integrity: sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==} - engines: {node: '>=0.10.0'} - dependencies: - arr-diff: 4.0.0 - array-unique: 0.3.2 - braces: 2.3.2 - define-property: 2.0.2 - extend-shallow: 3.0.2 - extglob: 2.0.4 - fragment-cache: 0.2.1 - kind-of: 6.0.3 - nanomatch: 1.2.13 - object.pick: 1.3.0 - regex-not: 1.0.2 - snapdragon: 0.8.2 - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - dev: true - - /micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} - dependencies: - braces: 3.0.2 - picomatch: 2.3.1 - - /miller-rabin@4.0.1: - resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==} - hasBin: true - dependencies: - bn.js: 4.12.0 - brorand: 1.1.0 - dev: true - - /mime-db@1.44.0: - resolution: {integrity: sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==} - engines: {node: '>= 0.6'} - dev: true - - /mime-types@2.1.27: - resolution: {integrity: sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==} - engines: {node: '>= 0.6'} - dependencies: - mime-db: 1.44.0 - dev: true - - /mime@1.6.0: - resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} - engines: {node: '>=4'} - hasBin: true - requiresBuild: true - dev: true - - /mimic-response@1.0.1: - resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} - engines: {node: '>=4'} - dev: true - - /mimic-response@3.1.0: - resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} - engines: {node: '>=10'} - dev: true - - /min-document@2.19.0: - resolution: {integrity: sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==} - dependencies: - dom-walk: 0.1.1 - dev: true - - /min-indent@1.0.1: - resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} - engines: {node: '>=4'} - dev: false - - /minimalistic-assert@1.0.1: - resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} - - /minimalistic-crypto-utils@1.0.1: - resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} - - /minimatch@3.0.4: - resolution: {integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==} - dependencies: - brace-expansion: 1.1.11 - dev: true - - /minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - dependencies: - brace-expansion: 1.1.11 - dev: true - - /minimatch@5.0.1: - resolution: {integrity: sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==} - engines: {node: '>=10'} - dependencies: - brace-expansion: 2.0.1 - dev: true - - /minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} - dependencies: - brace-expansion: 2.0.1 - dev: true - - /minimatch@9.0.3: - resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} - engines: {node: '>=16 || 14 >=14.17'} - dependencies: - brace-expansion: 2.0.1 - dev: true - - /minimist-options@4.1.0: - resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} - engines: {node: '>= 6'} - dependencies: - arrify: 1.0.1 - is-plain-obj: 1.1.0 - kind-of: 6.0.3 - dev: false - - /minimist@1.2.6: - resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} - dev: true - - /minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: true - - /minipass@2.9.0: - resolution: {integrity: sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==} - requiresBuild: true - dependencies: - safe-buffer: 5.2.1 - yallist: 3.1.1 - dev: true - - /minizlib@1.3.3: - resolution: {integrity: sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==} - requiresBuild: true - dependencies: - minipass: 2.9.0 - dev: true - - /mixin-deep@1.3.2: - resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==} - engines: {node: '>=0.10.0'} - dependencies: - for-in: 1.0.2 - is-extendable: 1.0.1 - dev: true - - /mixme@0.5.10: - resolution: {integrity: sha512-5H76ANWinB1H3twpJ6JY8uvAtpmFvHNArpilJAjXRKXSDDLPIMoZArw5SH0q9z+lLs8IrMw7Q2VWpWimFKFT1Q==} - engines: {node: '>= 8.0.0'} - dev: false - - /mkdirp-promise@5.0.1: - resolution: {integrity: sha512-Hepn5kb1lJPtVW84RFT40YG1OddBNTOVUZR2bzQUHc+Z03en8/3uX0+060JDhcEzyO08HmipsN9DcnFMxhIL9w==} - engines: {node: '>=4'} - deprecated: This package is broken and no longer maintained. 'mkdirp' itself supports promises now, please switch to that. - requiresBuild: true - dependencies: - mkdirp: 1.0.4 - dev: true - - /mkdirp@0.5.5: - resolution: {integrity: sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==} - hasBin: true - dependencies: - minimist: 1.2.8 - dev: true - - /mkdirp@0.5.6: - resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} - hasBin: true - dependencies: - minimist: 1.2.6 - dev: true - - /mkdirp@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true - dev: true - - /mnemonist@0.38.5: - resolution: {integrity: sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==} - dependencies: - obliterator: 2.0.4 - dev: true - - /mocha@10.2.0: - resolution: {integrity: sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==} - engines: {node: '>= 14.0.0'} - hasBin: true - dependencies: - ansi-colors: 4.1.1 - browser-stdout: 1.3.1 - chokidar: 3.5.3 - debug: 4.3.4(supports-color@8.1.1) - diff: 5.0.0 - escape-string-regexp: 4.0.0 - find-up: 5.0.0 - glob: 7.2.0 - he: 1.2.0 - js-yaml: 4.1.0 - log-symbols: 4.1.0 - minimatch: 5.0.1 - ms: 2.1.3 - nanoid: 3.3.3 - serialize-javascript: 6.0.0 - strip-json-comments: 3.1.1 - supports-color: 8.1.1 - workerpool: 6.2.1 - yargs: 16.2.0 - yargs-parser: 20.2.4 - yargs-unparser: 2.0.0 - dev: true - - /mocha@7.2.0: - resolution: {integrity: sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==} - engines: {node: '>= 8.10.0'} - hasBin: true - dependencies: - ansi-colors: 3.2.3 - browser-stdout: 1.3.1 - chokidar: 3.3.0 - debug: 3.2.6(supports-color@6.0.0) - 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 - dev: true - - /mock-fs@4.12.0: - resolution: {integrity: sha512-/P/HtrlvBxY4o/PzXY9cCNBrdylDNxg7gnrv2sMNxj+UJ2m8jSpl0/A6fuJeNAWr99ZvGWH8XCbE0vmnM5KupQ==} - requiresBuild: true - dev: true - - /module-error@1.0.2: - resolution: {integrity: sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==} - engines: {node: '>=10'} - dev: true - - /moment@2.29.4: - resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==} - dev: true - - /ms@2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - dev: true - - /ms@2.1.1: - resolution: {integrity: sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==} - dev: true - - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: true - - /ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: true - - /multibase@0.6.1: - resolution: {integrity: sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw==} - deprecated: This module has been superseded by the multiformats module - requiresBuild: true - dependencies: - base-x: 3.0.9 - buffer: 5.7.1 - dev: true - - /multibase@0.7.0: - resolution: {integrity: sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==} - deprecated: This module has been superseded by the multiformats module - requiresBuild: true - dependencies: - base-x: 3.0.9 - buffer: 5.7.1 - dev: true - - /multicodec@0.5.7: - resolution: {integrity: sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA==} - deprecated: This module has been superseded by the multiformats module - requiresBuild: true - dependencies: - varint: 5.0.2 - dev: true - - /multicodec@1.0.4: - resolution: {integrity: sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg==} - deprecated: This module has been superseded by the multiformats module - requiresBuild: true - dependencies: - buffer: 5.7.1 - varint: 5.0.2 - dev: true - - /multihashes@0.4.21: - resolution: {integrity: sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw==} - requiresBuild: true - dependencies: - buffer: 5.7.1 - multibase: 0.7.0 - varint: 5.0.2 - dev: true - - /nan@2.13.2: - resolution: {integrity: sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==} - dev: true - - /nan@2.16.0: - resolution: {integrity: sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==} - dev: true - - /nano-base32@1.0.1: - resolution: {integrity: sha512-sxEtoTqAPdjWVGv71Q17koMFGsOMSiHsIFEvzOM7cNp8BXB4AnEwmDabm5dorusJf/v1z7QxaZYxUorU9RKaAw==} - dev: true - - /nano-json-stream-parser@0.1.2: - resolution: {integrity: sha512-9MqxMH/BSJC7dnLsEMPyfN5Dvoo49IsPFYMcHw3Bcfc2kN0lpHRBSzlMSVx4HGyJ7s9B31CyBTVehWJoQ8Ctew==} - requiresBuild: true - dev: true - - /nanoid@3.3.3: - resolution: {integrity: sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - dev: true - - /nanomatch@1.2.13: - resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==} - engines: {node: '>=0.10.0'} - dependencies: - arr-diff: 4.0.0 - array-unique: 0.3.2 - define-property: 2.0.2 - extend-shallow: 3.0.2 - fragment-cache: 0.2.1 - is-windows: 1.0.2 - kind-of: 6.0.3 - object.pick: 1.3.0 - regex-not: 1.0.2 - snapdragon: 0.8.2 - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - dev: true - - /napi-macros@2.0.0: - resolution: {integrity: sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==} - dev: true - - /natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - dev: true - - /negotiator@0.6.2: - resolution: {integrity: sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==} - engines: {node: '>= 0.6'} - requiresBuild: true - dev: true - - /neo-async@2.6.2: - resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - dev: true - - /neodoc@2.0.2: - resolution: {integrity: sha512-NAppJ0YecKWdhSXFYCHbo6RutiX8vOt/Jo3l46mUg6pQlpJNaqc5cGxdrW2jITQm5JIYySbFVPDl3RrREXNyPw==} - dependencies: - ansi-regex: 2.1.1 - dev: true - - /next-tick@1.1.0: - resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} - dev: true - - /nice-try@1.0.5: - resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} - dev: true - - /no-case@2.3.2: - resolution: {integrity: sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==} - dependencies: - lower-case: 1.1.4 - dev: true - - /node-addon-api@2.0.2: - resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==} - dev: true - - /node-emoji@1.11.0: - resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} - dependencies: - lodash: 4.17.21 - dev: true - - /node-environment-flags@1.0.6: - resolution: {integrity: sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==} - dependencies: - object.getownpropertydescriptors: 2.1.4 - semver: 5.7.1 - dev: true - - /node-fetch@1.7.3: - resolution: {integrity: sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==} - dependencies: - encoding: 0.1.13 - is-stream: 1.1.0 - dev: true - - /node-fetch@2.6.7: - resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - dependencies: - whatwg-url: 5.0.0 - - /node-gyp-build@4.5.0: - resolution: {integrity: sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==} - hasBin: true - dev: true - - /node-interval-tree@2.1.2: - resolution: {integrity: sha512-bJ9zMDuNGzVQg1xv0bCPzyEDxHgbrx7/xGj6CDokvizZZmastPsOh0JJLuY8wA5q2SfX1TLNMk7XNV8WxbGxzA==} - engines: {node: '>= 14.0.0'} - dependencies: - shallowequal: 1.1.0 - dev: true - - /nofilter@1.0.4: - resolution: {integrity: sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==} - engines: {node: '>=8'} - dev: true - - /nofilter@3.1.0: - resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} - engines: {node: '>=12.19'} - dev: true - - /nopt@3.0.6: - resolution: {integrity: sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==} - hasBin: true - dependencies: - abbrev: 1.1.1 - dev: true - - /normalize-package-data@2.5.0: - resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} - dependencies: - hosted-git-info: 2.8.9 - resolve: 1.22.1 - semver: 5.7.1 - validate-npm-package-license: 3.0.4 - - /normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - dev: true - - /normalize-url@4.5.1: - resolution: {integrity: sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==} - engines: {node: '>=8'} - requiresBuild: true - dev: true - - /normalize-url@6.1.0: - resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} - engines: {node: '>=10'} - dev: true - - /nth-check@2.1.1: - resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - dependencies: - boolbase: 1.0.0 - dev: true - - /number-is-nan@1.0.1: - resolution: {integrity: sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==} - engines: {node: '>=0.10.0'} - dev: true - - /number-to-bn@1.7.0: - resolution: {integrity: sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==} - engines: {node: '>=6.5.0', npm: '>=3'} - dependencies: - bn.js: 4.11.6 - strip-hex-prefix: 1.0.0 - dev: true - - /oauth-sign@0.9.0: - resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==} - dev: true - - /object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - dev: true - - /object-copy@0.1.0: - resolution: {integrity: sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==} - engines: {node: '>=0.10.0'} - dependencies: - copy-descriptor: 0.1.1 - define-property: 0.2.5 - kind-of: 3.2.2 - dev: true - - /object-inspect@1.12.2: - resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} - - /object-inspect@1.13.1: - resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} - - /object-is@1.1.5: - resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - dev: true - - /object-keys@0.4.0: - resolution: {integrity: sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw==} - dev: true - - /object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} - - /object-visit@1.0.1: - resolution: {integrity: sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==} - engines: {node: '>=0.10.0'} - dependencies: - isobject: 3.0.1 - dev: true - - /object.assign@4.1.0: - resolution: {integrity: sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==} - engines: {node: '>= 0.4'} - dependencies: - define-properties: 1.2.1 - function-bind: 1.1.1 - has-symbols: 1.0.3 - object-keys: 1.1.1 - dev: true - - /object.assign@4.1.4: - resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - has-symbols: 1.0.3 - object-keys: 1.1.1 - - /object.getownpropertydescriptors@2.1.4: - resolution: {integrity: sha512-sccv3L/pMModT6dJAYF3fzGMVcb38ysQ0tEE6ixv2yXJDtEIPph268OlAdJj5/qZMZDq2g/jqvwppt36uS/uQQ==} - engines: {node: '>= 0.8'} - dependencies: - array.prototype.reduce: 1.0.4 - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 - dev: true - - /object.pick@1.3.0: - resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==} - engines: {node: '>=0.10.0'} - dependencies: - isobject: 3.0.1 - dev: true - - /obliterator@2.0.4: - resolution: {integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==} - dev: true - - /oboe@2.1.4: - resolution: {integrity: sha512-ymBJ4xSC6GBXLT9Y7lirj+xbqBLa+jADGJldGEYG7u8sZbS9GyG+u1Xk9c5cbriKwSpCg41qUhPjvU5xOpvIyQ==} - requiresBuild: true - dependencies: - http-https: 1.0.0 - dev: true - optional: true - - /oboe@2.1.5: - resolution: {integrity: sha512-zRFWiF+FoicxEs3jNI/WYUrVEgA7DeET/InK0XQuudGHRg8iIob3cNPrJTKaz4004uaA9Pbe+Dwa8iluhjLZWA==} - dependencies: - http-https: 1.0.0 - dev: true - - /on-finished@2.3.0: - resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} - engines: {node: '>= 0.8'} - requiresBuild: true - dependencies: - ee-first: 1.1.1 - dev: true - - /once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - dependencies: - wrappy: 1.0.2 - dev: true - - /open@7.4.2: - resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} - engines: {node: '>=8'} - dependencies: - is-docker: 2.2.1 - is-wsl: 2.2.0 - dev: true - - /optionator@0.8.3: - resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} - engines: {node: '>= 0.8.0'} - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.3.0 - prelude-ls: 1.1.2 - type-check: 0.3.2 - word-wrap: 1.2.3 - dev: true - - /optionator@0.9.3: - resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} - engines: {node: '>= 0.8.0'} - dependencies: - '@aashutoshrathi/word-wrap': 1.2.6 - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - dev: true - - /os-homedir@1.0.2: - resolution: {integrity: sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==} - engines: {node: '>=0.10.0'} - dev: true - - /os-locale@1.4.0: - resolution: {integrity: sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==} - engines: {node: '>=0.10.0'} - dependencies: - lcid: 1.0.0 - dev: true - - /os-tmpdir@1.0.2: - resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} - engines: {node: '>=0.10.0'} - - /outdent@0.5.0: - resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} - dev: false - - /p-cancelable@0.3.0: - resolution: {integrity: sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==} - engines: {node: '>=4'} - requiresBuild: true - dev: true - - /p-cancelable@1.1.0: - resolution: {integrity: sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==} - engines: {node: '>=6'} - requiresBuild: true - dev: true - - /p-cancelable@3.0.0: - resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==} - engines: {node: '>=12.20'} - dev: true - - /p-filter@2.1.0: - resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} - engines: {node: '>=8'} - dependencies: - p-map: 2.1.0 - dev: false - - /p-finally@1.0.0: - resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} - engines: {node: '>=4'} - requiresBuild: true - dev: true - - /p-limit@1.3.0: - resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} - engines: {node: '>=4'} - dependencies: - p-try: 1.0.0 - dev: true - - /p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} - dependencies: - p-try: 2.2.0 - - /p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - dependencies: - yocto-queue: 0.1.0 - - /p-locate@2.0.0: - resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} - engines: {node: '>=4'} - dependencies: - p-limit: 1.3.0 - dev: true - - /p-locate@3.0.0: - resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} - engines: {node: '>=6'} - dependencies: - p-limit: 2.3.0 - dev: true - - /p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} - dependencies: - p-limit: 2.3.0 - - /p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - dependencies: - p-limit: 3.1.0 - - /p-map@2.1.0: - resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} - engines: {node: '>=6'} - dev: false - - /p-map@4.0.0: - resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} - engines: {node: '>=10'} - dependencies: - aggregate-error: 3.1.0 - dev: true - - /p-timeout@1.2.1: - resolution: {integrity: sha512-gb0ryzr+K2qFqFv6qi3khoeqMZF/+ajxQipEF6NteZVnvz9tzdsfAVj3lYtn1gAXvH5lfLwfxEII799gt/mRIA==} - engines: {node: '>=4'} - requiresBuild: true - dependencies: - p-finally: 1.0.0 - dev: true - - /p-try@1.0.0: - resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==} - engines: {node: '>=4'} - dev: true - - /p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - - /package-json@8.1.1: - resolution: {integrity: sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==} - engines: {node: '>=14.16'} - dependencies: - got: 12.1.0 - registry-auth-token: 5.0.2 - registry-url: 6.0.1 - semver: 7.5.4 - dev: true - - /param-case@2.1.1: - resolution: {integrity: sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==} - dependencies: - no-case: 2.3.2 - dev: true - - /parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - dependencies: - callsites: 3.1.0 - dev: true - - /parse-asn1@5.1.5: - resolution: {integrity: sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==} - requiresBuild: true - dependencies: - asn1.js: 4.10.1 - browserify-aes: 1.2.0 - create-hash: 1.2.0 - evp_bytestokey: 1.0.3 - pbkdf2: 3.1.2 - safe-buffer: 5.2.1 - dev: true - - /parse-cache-control@1.0.1: - resolution: {integrity: sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==} - dev: true - - /parse-headers@2.0.3: - resolution: {integrity: sha512-QhhZ+DCCit2Coi2vmAKbq5RGTRcQUOE2+REgv8vdyu7MnYx2eZztegqtTx99TZ86GTIwqiy3+4nQTWZ2tgmdCA==} - dev: true - - /parse-json@2.2.0: - resolution: {integrity: sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==} - engines: {node: '>=0.10.0'} - dependencies: - error-ex: 1.3.2 - dev: true - - /parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} - dependencies: - '@babel/code-frame': 7.18.6 - error-ex: 1.3.2 - json-parse-even-better-errors: 2.3.1 - lines-and-columns: 1.2.4 - - /parse5-htmlparser2-tree-adapter@7.0.0: - resolution: {integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==} - dependencies: - domhandler: 5.0.3 - parse5: 7.1.1 - dev: true - - /parse5@7.1.1: - resolution: {integrity: sha512-kwpuwzB+px5WUg9pyK0IcK/shltJN5/OVhQagxhCQNtT9Y9QRZqNY2e1cmbu/paRh5LMnz/oVTVLBpjFmMZhSg==} - dependencies: - entities: 4.4.0 - dev: true - - /parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - requiresBuild: true - dev: true - - /pascal-case@2.0.1: - resolution: {integrity: sha512-qjS4s8rBOJa2Xm0jmxXiyh1+OFf6ekCWOvUaRgAQSktzlTbMotS0nmG9gyYAybCWBcuP4fsBeRCKNwGBnMe2OQ==} - dependencies: - camel-case: 3.0.0 - upper-case-first: 1.1.2 - dev: true - - /pascalcase@0.1.1: - resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==} - engines: {node: '>=0.10.0'} - dev: true - - /patch-package@6.2.2: - resolution: {integrity: sha512-YqScVYkVcClUY0v8fF0kWOjDYopzIM8e3bj/RU1DPeEF14+dCGm6UeOYm4jvCyxqIEQ5/eJzmbWfDWnUleFNMg==} - engines: {npm: '>5'} - hasBin: true - dependencies: - '@yarnpkg/lockfile': 1.1.0 - chalk: 2.4.2 - cross-spawn: 6.0.5 - find-yarn-workspace-root: 1.2.1 - fs-extra: 7.0.1 - is-ci: 2.0.0 - klaw-sync: 6.0.0 - minimist: 1.2.8 - rimraf: 2.7.1 - semver: 5.7.1 - slash: 2.0.0 - tmp: 0.0.33 - transitivePeerDependencies: - - supports-color - dev: true - - /patch-package@6.4.7: - resolution: {integrity: sha512-S0vh/ZEafZ17hbhgqdnpunKDfzHQibQizx9g8yEf5dcVk3KOflOfdufRXQX8CSEkyOQwuM/bNz1GwKvFj54kaQ==} - engines: {npm: '>5'} - hasBin: true - dependencies: - '@yarnpkg/lockfile': 1.1.0 - chalk: 2.4.2 - cross-spawn: 6.0.5 - find-yarn-workspace-root: 2.0.0 - fs-extra: 7.0.1 - is-ci: 2.0.0 - klaw-sync: 6.0.0 - minimist: 1.2.8 - open: 7.4.2 - rimraf: 2.7.1 - semver: 5.7.1 - slash: 2.0.0 - tmp: 0.0.33 - dev: true - - /path-browserify@1.0.1: - resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} - dev: true - - /path-case@2.1.1: - resolution: {integrity: sha512-Ou0N05MioItesaLr9q8TtHVWmJ6fxWdqKB2RohFmNWVyJ+2zeKIeDNWAN6B/Pe7wpzWChhZX6nONYmOnMeJQ/Q==} - dependencies: - no-case: 2.3.2 - dev: true - - /path-exists@2.1.0: - resolution: {integrity: sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==} - engines: {node: '>=0.10.0'} + /esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} dependencies: - pinkie-promise: 2.0.1 + estraverse: 5.3.0 dev: true - /path-exists@3.0.0: - resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} - engines: {node: '>=4'} + /estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} dev: true - /path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - /path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} dev: true - /path-key@2.0.1: - resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==} - engines: {node: '>=4'} - dev: true - - /path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - dev: true - - /path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - - /path-starts-with@2.0.1: - resolution: {integrity: sha512-wZ3AeiRBRlNwkdUxvBANh0+esnt38DLffHDujZyRHkqkaKHTglnY2EP5UX3b8rdeiSutgO4y9NEJwXezNP5vHg==} - engines: {node: '>=8'} - dev: true - - /path-to-regexp@0.1.7: - resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} - requiresBuild: true - dev: true - - /path-type@1.1.0: - resolution: {integrity: sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==} - engines: {node: '>=0.10.0'} + /ethereum-bloom-filters@1.0.10: + resolution: {integrity: sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==} dependencies: - graceful-fs: 4.2.10 - pify: 2.3.0 - pinkie-promise: 2.0.1 + js-sha3: 0.8.0 dev: true - /path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - - /pathval@1.1.1: - resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} - - /pbkdf2@3.1.2: - resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} - engines: {node: '>=0.12'} + /ethereum-cryptography@0.1.3: + resolution: {integrity: sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==} dependencies: + '@types/pbkdf2': 3.1.0 + '@types/secp256k1': 4.0.3 + blakejs: 1.2.1 + browserify-aes: 1.2.0 + bs58check: 2.1.2 create-hash: 1.2.0 create-hmac: 1.1.7 - ripemd160: 2.0.2 + hash.js: 1.1.7 + keccak: 3.0.2 + pbkdf2: 3.1.2 + randombytes: 2.1.0 safe-buffer: 5.2.1 - sha.js: 2.4.11 - dev: true - - /performance-now@2.1.0: - resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} - dev: true - - /picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - - /pify@2.3.0: - resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} - engines: {node: '>=0.10.0'} - dev: true - - /pify@4.0.1: - resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} - engines: {node: '>=6'} - - /pinkie-promise@2.0.1: - resolution: {integrity: sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==} - engines: {node: '>=0.10.0'} - dependencies: - pinkie: 2.0.4 - dev: true - - /pinkie@2.0.4: - resolution: {integrity: sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==} - engines: {node: '>=0.10.0'} - dev: true - - /pkg-dir@4.2.0: - resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} - engines: {node: '>=8'} - dependencies: - find-up: 4.1.0 - dev: false - - /pluralize@8.0.0: - resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} - engines: {node: '>=4'} - dev: true - - /posix-character-classes@0.1.1: - resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==} - engines: {node: '>=0.10.0'} - dev: true - - /postinstall-postinstall@2.1.0: - resolution: {integrity: sha512-7hQX6ZlZXIoRiWNrbMQaLzUUfH+sSx39u8EJ9HYuDc1kLo9IXKWjM5RSquZN1ad5GnH8CGFM78fsAAQi3OKEEQ==} - requiresBuild: true - dev: true - - /precond@0.2.3: - resolution: {integrity: sha512-QCYG84SgGyGzqJ/vlMsxeXd/pgL/I94ixdNFyh1PusWmTCyVfPJjZ1K1jvHtsbfnXQs2TSkEP2fR7QiMZAnKFQ==} - engines: {node: '>= 0.6'} - dev: true - - /preferred-pm@3.1.3: - resolution: {integrity: sha512-MkXsENfftWSRpzCzImcp4FRsCc3y1opwB73CfCNWyzMqArju2CrlMHlqB7VexKiPEOjGMbttv1r9fSCn5S610w==} - engines: {node: '>=10'} - dependencies: - find-up: 5.0.0 - find-yarn-workspace-root2: 1.2.16 - path-exists: 4.0.0 - which-pm: 2.0.0 - dev: false - - /prelude-ls@1.1.2: - resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} - engines: {node: '>= 0.8.0'} - dev: true - - /prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - dev: true - - /prepend-http@1.0.4: - resolution: {integrity: sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg==} - engines: {node: '>=0.10.0'} - requiresBuild: true - dev: true - - /prepend-http@2.0.0: - resolution: {integrity: sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==} - engines: {node: '>=4'} - requiresBuild: true - dev: true - - /prettier-linter-helpers@1.0.0: - resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} - engines: {node: '>=6.0.0'} - dependencies: - fast-diff: 1.2.0 - dev: true - - /prettier-plugin-solidity@1.3.1(prettier@2.8.8): - resolution: {integrity: sha512-MN4OP5I2gHAzHZG1wcuJl0FsLS3c4Cc5494bbg+6oQWBPuEamjwDvmGfFMZ6NFzsh3Efd9UUxeT7ImgjNH4ozA==} - engines: {node: '>=16'} - peerDependencies: - prettier: '>=2.3.0' - dependencies: - '@solidity-parser/parser': 0.17.0 - prettier: 2.8.8 - semver: 7.5.4 - solidity-comments-extractor: 0.0.8 - dev: true - optional: true - - /prettier-plugin-solidity@1.3.1(prettier@3.2.5): - resolution: {integrity: sha512-MN4OP5I2gHAzHZG1wcuJl0FsLS3c4Cc5494bbg+6oQWBPuEamjwDvmGfFMZ6NFzsh3Efd9UUxeT7ImgjNH4ozA==} - engines: {node: '>=16'} - peerDependencies: - prettier: '>=2.3.0' - dependencies: - '@solidity-parser/parser': 0.17.0 - prettier: 3.2.5 - semver: 7.5.4 - solidity-comments-extractor: 0.0.8 - dev: true - - /prettier@2.8.8: - resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} - engines: {node: '>=10.13.0'} - hasBin: true - - /prettier@3.2.5: - resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} - engines: {node: '>=14'} - hasBin: true - dev: true - - /private@0.1.8: - resolution: {integrity: sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==} - engines: {node: '>= 0.6'} - dev: true - - /process-nextick-args@2.0.1: - resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + scrypt-js: 3.0.1 + secp256k1: 4.0.3 + setimmediate: 1.0.5 dev: true - /process@0.5.2: - resolution: {integrity: sha512-oNpcutj+nYX2FjdEW7PGltWhXulAnFlM0My/k48L90hARCOJtvBbQXc/6itV2jDvU5xAAtonP+r6wmQgCcbAUA==} - engines: {node: '>= 0.6.0'} + /ethereum-cryptography@1.1.2: + resolution: {integrity: sha512-XDSJlg4BD+hq9N2FjvotwUET9Tfxpxc3kWGE2AqUG5vcbeunnbImVk3cj6e/xT3phdW21mE8R5IugU4fspQDcQ==} + dependencies: + '@noble/hashes': 1.1.2 + '@noble/secp256k1': 1.6.3 + '@scure/bip32': 1.1.0 + '@scure/bip39': 1.1.0 dev: true - /promise-to-callback@1.0.0: - resolution: {integrity: sha512-uhMIZmKM5ZteDMfLgJnoSq9GCwsNKrYau73Awf1jIy6/eUcuuZ3P+CD9zUv0kJsIUbU+x6uLNIhXhLHDs1pNPA==} - engines: {node: '>=0.10.0'} + /ethereumjs-abi@0.6.8: + resolution: {integrity: sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==} dependencies: - is-fn: 1.0.0 - set-immediate-shim: 1.0.1 + bn.js: 4.12.0 + ethereumjs-util: 6.2.1 dev: true - /promise@8.3.0: - resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==} + /ethereumjs-util@6.2.1: + resolution: {integrity: sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==} dependencies: - asap: 2.0.6 + '@types/bn.js': 4.11.6 + bn.js: 4.12.0 + create-hash: 1.2.0 + elliptic: 6.5.4 + ethereum-cryptography: 0.1.3 + ethjs-util: 0.1.6 + rlp: 2.2.7 dev: true - /proper-lockfile@4.1.2: - resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} + /ethereumjs-util@7.1.5: + resolution: {integrity: sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==} + engines: {node: '>=10.0.0'} dependencies: - graceful-fs: 4.2.10 - retry: 0.12.0 - signal-exit: 3.0.7 + '@types/bn.js': 5.1.1 + bn.js: 5.2.1 + create-hash: 1.2.0 + ethereum-cryptography: 0.1.3 + rlp: 2.2.7 dev: true - /proto-list@1.2.4: - resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} - dev: true + /ethers@5.7.2: + resolution: {integrity: sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==} + dependencies: + '@ethersproject/abi': 5.7.0 + '@ethersproject/abstract-provider': 5.7.0 + '@ethersproject/abstract-signer': 5.7.0 + '@ethersproject/address': 5.7.0 + '@ethersproject/base64': 5.7.0 + '@ethersproject/basex': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/constants': 5.7.0 + '@ethersproject/contracts': 5.7.0 + '@ethersproject/hash': 5.7.0 + '@ethersproject/hdnode': 5.7.0 + '@ethersproject/json-wallets': 5.7.0 + '@ethersproject/keccak256': 5.7.0 + '@ethersproject/logger': 5.0.6 + '@ethersproject/networks': 5.7.1 + '@ethersproject/pbkdf2': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/providers': 5.7.2 + '@ethersproject/random': 5.7.0 + '@ethersproject/rlp': 5.7.0 + '@ethersproject/sha2': 5.7.0 + '@ethersproject/signing-key': 5.7.0 + '@ethersproject/solidity': 5.7.0 + '@ethersproject/strings': 5.7.0 + '@ethersproject/transactions': 5.7.0 + '@ethersproject/units': 5.7.0 + '@ethersproject/wallet': 5.7.0 + '@ethersproject/web': 5.7.1 + '@ethersproject/wordlists': 5.7.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate - /proxy-addr@2.0.5: - resolution: {integrity: sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==} - engines: {node: '>= 0.10'} - requiresBuild: true + /ethjs-unit@0.1.6: + resolution: {integrity: sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==} + engines: {node: '>=6.5.0', npm: '>=3'} dependencies: - forwarded: 0.1.2 - ipaddr.js: 1.9.0 + bn.js: 4.11.6 + number-to-bn: 1.7.0 dev: true - /proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + /ethjs-util@0.1.6: + resolution: {integrity: sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==} + engines: {node: '>=6.5.0', npm: '>=3'} + dependencies: + is-hex-prefixed: 1.0.0 + strip-hex-prefix: 1.0.0 dev: true - /prr@1.0.1: - resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} + /evp_bytestokey@1.0.3: + resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} + dependencies: + md5.js: 1.3.5 + safe-buffer: 5.2.1 dev: true - /pseudomap@1.0.2: - resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} + /extendable-error@0.1.7: + resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} + dev: false - /psl@1.9.0: - resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} - dev: true + /external-editor@3.1.0: + resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} + engines: {node: '>=4'} + dependencies: + chardet: 0.7.0 + iconv-lite: 0.4.24 + tmp: 0.0.33 + dev: false - /public-encrypt@4.0.3: - resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==} - requiresBuild: true + /fast-check@3.1.1: + resolution: {integrity: sha512-3vtXinVyuUKCKFKYcwXhGE6NtGWkqF8Yh3rvMZNzmwz8EPrgoc/v4pDdLHyLnCyCI5MZpZZkDEwFyXyEONOxpA==} + engines: {node: '>=8.0.0'} dependencies: - bn.js: 4.12.0 - browserify-rsa: 4.0.1 - create-hash: 1.2.0 - parse-asn1: 5.1.5 - randombytes: 2.1.0 - safe-buffer: 5.2.1 + pure-rand: 5.0.3 dev: true - /pull-cat@1.1.11: - resolution: {integrity: sha512-i3w+xZ3DCtTVz8S62hBOuNLRHqVDsHMNZmgrZsjPnsxXUgbWtXEee84lo1XswE7W2a3WHyqsNuDJTjVLAQR8xg==} + /fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: true - /pull-defer@0.2.3: - resolution: {integrity: sha512-/An3KE7mVjZCqNhZsr22k1Tx8MACnUnHZZNPSJ0S62td8JtYr/AiRG42Vz7Syu31SoTLUzVIe61jtT/pNdjVYA==} + /fast-diff@1.2.0: + resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==} dev: true - /pull-level@2.0.4: - resolution: {integrity: sha512-fW6pljDeUThpq5KXwKbRG3X7Ogk3vc75d5OQU/TvXXui65ykm+Bn+fiktg+MOx2jJ85cd+sheufPL+rw9QSVZg==} + /fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} dependencies: - level-post: 1.0.7 - pull-cat: 1.1.11 - pull-live: 1.0.1 - pull-pushable: 2.2.0 - pull-stream: 3.6.14 - pull-window: 2.1.4 - stream-to-pull-stream: 1.7.3 - dev: true + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 - /pull-live@1.0.1: - resolution: {integrity: sha512-tkNz1QT5gId8aPhV5+dmwoIiA1nmfDOzJDlOOUpU5DNusj6neNd3EePybJ5+sITr2FwyCs/FVpx74YMCfc8YeA==} - dependencies: - pull-cat: 1.1.11 - pull-stream: 3.6.14 + /fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} dev: true - /pull-pushable@2.2.0: - resolution: {integrity: sha512-M7dp95enQ2kaHvfCt2+DJfyzgCSpWVR2h2kWYnVsW6ZpxQBx5wOu0QWOvQPVoPnBLUZYitYP2y7HyHkLQNeGXg==} + /fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} dev: true - /pull-stream@3.6.14: - resolution: {integrity: sha512-KIqdvpqHHaTUA2mCYcLG1ibEbu/LCKoJZsBWyv9lSYtPkJPBq8m3Hxa103xHi6D2thj5YXa0TqK3L3GUkwgnew==} - dev: true + /fastq@1.6.0: + resolution: {integrity: sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA==} + dependencies: + reusify: 1.0.4 - /pull-window@2.1.4: - resolution: {integrity: sha512-cbDzN76BMlcGG46OImrgpkMf/VkCnupj8JhsrpBw3aWBM9ye345aYnqitmZCgauBkc0HbbRRn9hCnsa3k2FNUg==} + /file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} dependencies: - looper: 2.0.0 + flat-cache: 3.0.4 dev: true - /pump@3.0.0: - resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + /fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} dependencies: - end-of-stream: 1.4.4 - once: 1.4.0 - dev: true + to-regex-range: 5.0.1 - /punycode@1.3.2: - resolution: {integrity: sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==} + /find-replace@3.0.0: + resolution: {integrity: sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==} + engines: {node: '>=4.0.0'} + dependencies: + array-back: 3.1.0 dev: true - /punycode@2.1.0: - resolution: {integrity: sha512-Yxz2kRwT90aPiWEMHVYnEf4+rhwF1tBmmZ4KepCP+Wkium9JxtWnUm1nqGwpiAHr/tnTSeHqr3wb++jgSkXjhA==} - engines: {node: '>=6'} + /find-up@2.1.0: + resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} + engines: {node: '>=4'} + dependencies: + locate-path: 2.0.0 dev: true - /punycode@2.1.1: - resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} - engines: {node: '>=6'} - dev: true + /find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + dev: false - /pure-rand@5.0.3: - resolution: {integrity: sha512-9N8x1h8dptBQpHyC7aZMS+iNOAm97WMGY0AFrguU1cpfW3I5jINkWe5BIY5md0ofy+1TCIELsVcm/GJXZSaPbw==} - dev: true + /find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 - /qs@6.11.0: - resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} - engines: {node: '>=0.6'} + /find-yarn-workspace-root2@1.2.16: + resolution: {integrity: sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==} dependencies: - side-channel: 1.0.4 + micromatch: 4.0.5 + pkg-dir: 4.2.0 + dev: false + + /flat-cache@3.0.4: + resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flatted: 3.2.7 + rimraf: 3.0.2 dev: true - /qs@6.5.3: - resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==} - engines: {node: '>=0.6'} + /flat@5.0.2: + resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} + hasBin: true dev: true - /qs@6.7.0: - resolution: {integrity: sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==} - engines: {node: '>=0.6'} - requiresBuild: true + /flatted@3.2.7: + resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} dev: true - /query-string@5.1.1: - resolution: {integrity: sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==} - engines: {node: '>=0.10.0'} - requiresBuild: true + /follow-redirects@1.15.2(debug@4.3.4): + resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true dependencies: - decode-uri-component: 0.2.0 - object-assign: 4.1.1 - strict-uri-encode: 1.1.0 + debug: 4.3.4(supports-color@8.1.1) dev: true - /querystring@0.2.0: - resolution: {integrity: sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==} - engines: {node: '>=0.4.x'} - deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. - dev: true + /for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + dependencies: + is-callable: 1.2.7 + dev: false - /queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + /form-data-encoder@1.7.1: + resolution: {integrity: sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg==} dev: true - /quick-lru@4.0.1: - resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} - engines: {node: '>=8'} - dev: false - - /quick-lru@5.1.1: - resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} - engines: {node: '>=10'} + /fp-ts@1.19.3: + resolution: {integrity: sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==} dev: true - /randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + /fs-extra@0.30.0: + resolution: {integrity: sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==} dependencies: - safe-buffer: 5.2.1 + graceful-fs: 4.2.10 + jsonfile: 2.4.0 + klaw: 1.3.1 + path-is-absolute: 1.0.1 + rimraf: 2.7.1 dev: true - /randomfill@1.0.4: - resolution: {integrity: sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==} - requiresBuild: true + /fs-extra@7.0.1: + resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} + engines: {node: '>=6 <7 || >=8'} + dependencies: + graceful-fs: 4.2.10 + jsonfile: 4.0.0 + universalify: 0.1.2 + + /fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + dependencies: + graceful-fs: 4.2.10 + jsonfile: 4.0.0 + universalify: 0.1.2 + dev: false + + /fs-extra@9.1.0: + resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} + engines: {node: '>=10'} dependencies: - randombytes: 2.1.0 - safe-buffer: 5.2.1 + at-least-node: 1.0.0 + graceful-fs: 4.2.10 + jsonfile: 6.1.0 + universalify: 2.0.0 dev: true - /range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - requiresBuild: true + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} dev: true - /raw-body@2.4.0: - resolution: {integrity: sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==} - engines: {node: '>= 0.8'} + /fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] requiresBuild: true - dependencies: - bytes: 3.1.0 - http-errors: 1.7.2 - iconv-lite: 0.4.24 - unpipe: 1.0.0 dev: true + optional: true - /raw-body@2.5.1: - resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==} - engines: {node: '>= 0.8'} - dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - dev: true + /function-bind@1.1.1: + resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + dev: false - /rc@1.2.8: - resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} - hasBin: true - dependencies: - deep-extend: 0.6.0 - ini: 1.3.8 - minimist: 1.2.8 - strip-json-comments: 2.0.1 - dev: true + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: false - /read-pkg-up@1.0.1: - resolution: {integrity: sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==} - engines: {node: '>=0.10.0'} + /function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} dependencies: - find-up: 1.1.2 - read-pkg: 1.1.0 - dev: true + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + functions-have-names: 1.2.3 + dev: false - /read-pkg-up@7.0.1: - resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} - engines: {node: '>=8'} - dependencies: - find-up: 4.1.0 - read-pkg: 5.2.0 - type-fest: 0.8.1 + /functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} dev: false - /read-pkg@1.1.0: - resolution: {integrity: sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==} - engines: {node: '>=0.10.0'} - dependencies: - load-json-file: 1.1.0 - normalize-package-data: 2.5.0 - path-type: 1.1.0 - dev: true + /get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} - /read-pkg@5.2.0: - resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} - engines: {node: '>=8'} + /get-func-name@2.0.2: + resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} + + /get-intrinsic@1.1.3: + resolution: {integrity: sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==} dependencies: - '@types/normalize-package-data': 2.4.4 - normalize-package-data: 2.5.0 - parse-json: 5.2.0 - type-fest: 0.6.0 + function-bind: 1.1.1 + has: 1.0.3 + has-symbols: 1.0.3 dev: false - /read-yaml-file@1.1.0: - resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} - engines: {node: '>=6'} + /get-intrinsic@1.2.2: + resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} dependencies: - graceful-fs: 4.2.10 - js-yaml: 3.14.1 - pify: 4.0.1 - strip-bom: 3.0.0 + function-bind: 1.1.2 + has-proto: 1.0.1 + has-symbols: 1.0.3 + hasown: 2.0.0 dev: false - /readable-stream@1.0.34: - resolution: {integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==} + /get-stream@5.1.0: + resolution: {integrity: sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==} + engines: {node: '>=8'} dependencies: - core-util-is: 1.0.3 - inherits: 2.0.4 - isarray: 0.0.1 - string_decoder: 0.10.31 + pump: 3.0.0 dev: true - /readable-stream@2.3.7: - resolution: {integrity: sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==} - dependencies: - core-util-is: 1.0.3 - inherits: 2.0.4 - isarray: 1.0.0 - process-nextick-args: 2.0.1 - safe-buffer: 5.1.2 - string_decoder: 1.1.1 - util-deprecate: 1.0.2 + /get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} dev: true - /readable-stream@3.6.0: - resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==} - engines: {node: '>= 6'} + /get-symbol-description@1.0.0: + resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} + engines: {node: '>= 0.4'} dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - dev: true + call-bind: 1.0.2 + get-intrinsic: 1.1.3 + dev: false - /readdirp@3.2.0: - resolution: {integrity: sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==} - engines: {node: '>= 8'} + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} dependencies: - picomatch: 2.3.1 - dev: true + is-glob: 4.0.3 - /readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} + /glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} dependencies: - picomatch: 2.3.1 + is-glob: 4.0.3 dev: true - /rechoir@0.6.2: - resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} - engines: {node: '>= 0.10'} + /glob@7.1.7: + resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==} dependencies: - resolve: 1.22.1 + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 dev: true - /recursive-readdir@2.2.2: - resolution: {integrity: sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==} - engines: {node: '>=0.10.0'} + /glob@7.2.0: + resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} dependencies: - minimatch: 3.0.4 + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 dev: true - /redent@3.0.0: - resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} - engines: {node: '>=8'} + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} dependencies: - indent-string: 4.0.0 - strip-indent: 3.0.0 - dev: false - - /reduce-flatten@2.0.0: - resolution: {integrity: sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==} - engines: {node: '>=6'} - dev: true - - /regenerate@1.4.2: - resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} - dev: true - - /regenerator-runtime@0.11.1: - resolution: {integrity: sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==} - dev: true - - /regenerator-runtime@0.13.9: - resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==} + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 dev: true - /regenerator-runtime@0.14.1: - resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - dev: false - - /regenerator-transform@0.10.1: - resolution: {integrity: sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==} + /glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} dependencies: - babel-runtime: 6.26.0 - babel-types: 6.26.0 - private: 0.1.8 + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.6 + once: 1.4.0 dev: true - /regex-not@1.0.2: - resolution: {integrity: sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==} - engines: {node: '>=0.10.0'} + /globals@13.20.0: + resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==} + engines: {node: '>=8'} dependencies: - extend-shallow: 3.0.2 - safe-regex: 1.1.0 + type-fest: 0.20.2 dev: true - /regexp.prototype.flags@1.5.1: - resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==} + /globalthis@1.0.3: + resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 define-properties: 1.2.1 - set-function-name: 2.0.1 - - /regexpu-core@2.0.0: - resolution: {integrity: sha512-tJ9+S4oKjxY8IZ9jmjnp/mtytu1u3iyIQAfmI51IKWH6bFf7XR1ybtaO6j7INhZKXOTYADk7V5qxaqLkmNxiZQ==} - dependencies: - regenerate: 1.4.2 - regjsgen: 0.2.0 - regjsparser: 0.1.5 - dev: true + dev: false - /registry-auth-token@5.0.2: - resolution: {integrity: sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==} - engines: {node: '>=14'} + /globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} dependencies: - '@pnpm/npm-conf': 2.2.2 - dev: true + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.1 + ignore: 5.2.4 + merge2: 1.4.1 + slash: 3.0.0 - /registry-url@6.0.1: - resolution: {integrity: sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==} - engines: {node: '>=12'} + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: - rc: 1.2.8 - dev: true - - /regjsgen@0.2.0: - resolution: {integrity: sha512-x+Y3yA24uF68m5GA+tBjbGYo64xXVJpbToBaWCoSNSc1hdk6dfctaRWrNFTVJZIIhL5GxW8zwjoixbnifnK59g==} - dev: true + get-intrinsic: 1.2.2 + dev: false - /regjsparser@0.1.5: - resolution: {integrity: sha512-jlQ9gYLfk2p3V5Ag5fYhA7fv7OHzd1KUH0PRP46xc3TgwjwgROIW572AfYg/X9kaNq/LJnu6oJcFRXlIrGoTRw==} - hasBin: true + /got@12.1.0: + resolution: {integrity: sha512-hBv2ty9QN2RdbJJMK3hesmSkFTjVIHyIDDbssCKnSmq62edGgImJWD10Eb1k77TiV1bxloxqcFAVK8+9pkhOig==} + engines: {node: '>=14.16'} dependencies: - jsesc: 0.5.0 - dev: true - - /repeat-element@1.1.4: - resolution: {integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==} - engines: {node: '>=0.10.0'} + '@sindresorhus/is': 4.6.0 + '@szmarczak/http-timer': 5.0.1 + '@types/cacheable-request': 6.0.2 + '@types/responselike': 1.0.0 + cacheable-lookup: 6.1.0 + cacheable-request: 7.0.2 + decompress-response: 6.0.0 + form-data-encoder: 1.7.1 + get-stream: 6.0.1 + http2-wrapper: 2.1.11 + lowercase-keys: 3.0.0 + p-cancelable: 3.0.0 + responselike: 2.0.1 dev: true - /repeat-string@1.6.1: - resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} - engines: {node: '>=0.10'} - dev: true + /graceful-fs@4.2.10: + resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} - /repeating@2.0.1: - resolution: {integrity: sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A==} - engines: {node: '>=0.10.0'} - dependencies: - is-finite: 1.1.0 + /grapheme-splitter@1.0.4: + resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} + + /graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} dev: true - /req-cwd@2.0.0: - resolution: {integrity: sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ==} - engines: {node: '>=4'} + /hard-rejection@2.1.0: + resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} + engines: {node: '>=6'} + dev: false + + /hardhat-abi-exporter@2.10.1(hardhat@2.20.1): + resolution: {integrity: sha512-X8GRxUTtebMAd2k4fcPyVnCdPa6dYK4lBsrwzKP5yiSq4i+WadWPIumaLfce53TUf/o2TnLpLOduyO1ylE2NHQ==} + engines: {node: '>=14.14.0'} + peerDependencies: + hardhat: ^2.0.0 dependencies: - req-from: 2.0.0 + '@ethersproject/abi': 5.7.0 + delete-empty: 3.0.0 + hardhat: 2.20.1(ts-node@10.9.2)(typescript@5.4.3) dev: true - /req-from@2.0.0: - resolution: {integrity: sha512-LzTfEVDVQHBRfjOUMgNBA+V6DWsSnoeKzf42J7l0xa/B4jyPOuuF5MlNSmomLNGemWTnV2TIdjSSLnEn95fOQA==} - engines: {node: '>=4'} + /hardhat-ignore-warnings@0.2.11: + resolution: {integrity: sha512-+nHnRbP6COFZaXE7HAY7TZNE3au5vHe5dkcnyq0XaP07ikT2fJ3NhFY0vn7Deh4Qbz0Z/9Xpnj2ki6Ktgk61pg==} dependencies: - resolve-from: 3.0.0 + minimatch: 5.1.6 + node-interval-tree: 2.1.2 + solidity-comments: 0.0.2 dev: true - /request-promise-core@1.1.4(request@2.88.2): - resolution: {integrity: sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==} - engines: {node: '>=0.10.0'} + /hardhat@2.20.1(ts-node@10.9.2)(typescript@5.4.3): + resolution: {integrity: sha512-q75xDQiQtCZcTMBwjTovrXEU5ECr49baxr4/OBkIu/ULTPzlB20yk1dRWNmD2IFbAeAeXggaWvQAdpiScaHtPw==} + hasBin: true peerDependencies: - request: ^2.34 + ts-node: '*' + typescript: '*' + peerDependenciesMeta: + ts-node: + optional: true + typescript: + optional: true dependencies: + '@ethersproject/abi': 5.7.0 + '@metamask/eth-sig-util': 4.0.1 + '@nomicfoundation/ethereumjs-block': 5.0.4 + '@nomicfoundation/ethereumjs-blockchain': 7.0.4 + '@nomicfoundation/ethereumjs-common': 4.0.4 + '@nomicfoundation/ethereumjs-evm': 2.0.4(@nomicfoundation/ethereumjs-verkle@0.0.2) + '@nomicfoundation/ethereumjs-rlp': 5.0.4 + '@nomicfoundation/ethereumjs-statemanager': 2.0.4(@nomicfoundation/ethereumjs-verkle@0.0.2) + '@nomicfoundation/ethereumjs-trie': 6.0.4 + '@nomicfoundation/ethereumjs-tx': 5.0.4 + '@nomicfoundation/ethereumjs-util': 9.0.4 + '@nomicfoundation/ethereumjs-verkle': 0.0.2 + '@nomicfoundation/ethereumjs-vm': 7.0.4(@nomicfoundation/ethereumjs-verkle@0.0.2) + '@nomicfoundation/solidity-analyzer': 0.1.0 + '@sentry/node': 5.30.0 + '@types/bn.js': 5.1.1 + '@types/lru-cache': 5.1.1 + adm-zip: 0.4.16 + aggregate-error: 3.1.0 + ansi-escapes: 4.3.2 + boxen: 5.1.2 + chalk: 2.4.2 + chokidar: 3.5.3 + ci-info: 2.0.0 + debug: 4.3.4(supports-color@8.1.1) + enquirer: 2.3.6 + env-paths: 2.2.1 + ethereum-cryptography: 1.1.2 + ethereumjs-abi: 0.6.8 + find-up: 2.1.0 + fp-ts: 1.19.3 + fs-extra: 7.0.1 + glob: 7.2.0 + immutable: 4.1.0 + io-ts: 1.10.4 + keccak: 3.0.2 lodash: 4.17.21 - request: 2.88.2 + mnemonist: 0.38.5 + mocha: 10.2.0 + p-map: 4.0.0 + raw-body: 2.5.1 + resolve: 1.17.0 + semver: 6.3.0 + solc: 0.7.3(debug@4.3.4) + source-map-support: 0.5.21 + stacktrace-parser: 0.1.10 + ts-node: 10.9.2(@types/node@16.18.91)(typescript@5.4.3) + tsort: 0.0.1 + typescript: 5.4.3 + undici: 5.19.1 + uuid: 8.3.2 + ws: 7.5.9 + transitivePeerDependencies: + - bufferutil + - c-kzg + - supports-color + - utf-8-validate dev: true - /request-promise-native@1.0.9(request@2.88.2): - resolution: {integrity: sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==} - engines: {node: '>=0.12.0'} - deprecated: request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142 - peerDependencies: - request: ^2.34 - dependencies: - request: 2.88.2 - request-promise-core: 1.1.4(request@2.88.2) - stealthy-require: 1.1.1 - tough-cookie: 2.5.0 - dev: true + /has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + dev: false - /request@2.88.2: - resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==} - engines: {node: '>= 6'} - deprecated: request has been deprecated, see https://github.com/request/request/issues/3142 - dependencies: - aws-sign2: 0.7.0 - aws4: 1.11.0 - caseless: 0.12.0 - combined-stream: 1.0.8 - extend: 3.0.2 - forever-agent: 0.6.1 - form-data: 2.3.3 - har-validator: 5.1.5 - http-signature: 1.2.0 - is-typedarray: 1.0.0 - isstream: 0.1.2 - json-stringify-safe: 5.0.1 - mime-types: 2.1.27 - oauth-sign: 0.9.0 - performance-now: 2.1.0 - qs: 6.5.3 - safe-buffer: 5.2.1 - tough-cookie: 2.5.0 - tunnel-agent: 0.6.0 - uuid: 3.4.0 - dev: true + /has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} - /require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} - /require-from-string@1.2.1: - resolution: {integrity: sha512-H7AkJWMobeskkttHyhTVtS0fxpFLjxhbfMa6Bk3wimP7sdPRGL3EyCg3sAQenFfAe+xQ+oAc85Nmtvq0ROM83Q==} - engines: {node: '>=0.10.0'} - dev: true + /has-property-descriptors@1.0.0: + resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} + dependencies: + get-intrinsic: 1.1.3 + dev: false - /require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - dev: true + /has-proto@1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} + dev: false - /require-main-filename@1.0.1: - resolution: {integrity: sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==} - dev: true + /has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + dev: false - /require-main-filename@2.0.0: - resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + /has-tostringtag@1.0.0: + resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: false - /resolve-alpn@1.2.1: - resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} - dev: true + /has@1.0.3: + resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + engines: {node: '>= 0.4.0'} + dependencies: + function-bind: 1.1.1 + dev: false - /resolve-from@3.0.0: - resolution: {integrity: sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==} + /hash-base@3.1.0: + resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} engines: {node: '>=4'} + dependencies: + inherits: 2.0.4 + readable-stream: 3.6.0 + safe-buffer: 5.2.1 dev: true - /resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - dev: true + /hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 - /resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} + /hasown@2.0.0: + resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 dev: false - /resolve-url@0.2.1: - resolution: {integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==} - deprecated: https://github.com/lydell/resolve-url#deprecated - dev: true - - /resolve@1.1.7: - resolution: {integrity: sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==} + /he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true dev: true - /resolve@1.17.0: - resolution: {integrity: sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==} + /header-case@1.0.1: + resolution: {integrity: sha512-i0q9mkOeSuhXw6bGgiQCCBgY/jlZuV/7dZXyZ9c6LcBrqwvT8eT719E9uxE5LiZftdl+z81Ugbg/VvXV4OJOeQ==} dependencies: - path-parse: 1.0.7 + no-case: 2.3.2 + upper-case: 1.1.3 dev: true - /resolve@1.22.1: - resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} - hasBin: true + /hmac-drbg@1.0.1: + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} dependencies: - is-core-module: 2.10.0 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 + hash.js: 1.1.7 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 - /responselike@1.0.2: - resolution: {integrity: sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==} - requiresBuild: true - dependencies: - lowercase-keys: 1.0.1 + /hosted-git-info@2.8.9: + resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + dev: false + + /http-cache-semantics@4.0.3: + resolution: {integrity: sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew==} dev: true - /responselike@2.0.1: - resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} + /http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} dependencies: - lowercase-keys: 2.0.0 + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 dev: true - /resumer@0.0.0: - resolution: {integrity: sha512-Fn9X8rX8yYF4m81rZCK/5VmrmsSbqS/i3rDLl6ZZHAXgC2nTAx3dhwG8q8odP/RmdLa2YrybDJaAMg+X1ajY3w==} + /http2-wrapper@2.1.11: + resolution: {integrity: sha512-aNAk5JzLturWEUiuhAN73Jcbq96R7rTitAoXV54FYMatvihnpD2+6PUgU4ce3D/m5VDbw+F5CsyKSF176ptitQ==} + engines: {node: '>=10.19.0'} dependencies: - through: 2.3.8 + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 dev: true - /ret@0.1.15: - resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==} - engines: {node: '>=0.12'} + /https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + dependencies: + agent-base: 6.0.2 + debug: 4.3.4(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color dev: true - /retry@0.12.0: - resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} - engines: {node: '>= 4'} - dev: true + /human-id@1.0.2: + resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} + dev: false - /retry@0.13.1: - resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} - engines: {node: '>= 4'} - dev: true + /iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 - /reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + /ignore@5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + engines: {node: '>= 4'} - /rimraf@2.7.1: - resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} - hasBin: true - dependencies: - glob: 7.2.3 + /immutable@4.1.0: + resolution: {integrity: sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==} dev: true - /rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - hasBin: true + /import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} dependencies: - glob: 7.2.3 - dev: true - - /ripemd160-min@0.0.6: - resolution: {integrity: sha512-+GcJgQivhs6S9qvLogusiTcS9kQUfgR75whKuy5jIhuiOfQuJ8fjqxV6EGD5duH1Y/FawFUMtMhyeq3Fbnib8A==} - engines: {node: '>=8'} + parent-module: 1.0.1 + resolve-from: 4.0.0 dev: true - /ripemd160@2.0.2: - resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} - dependencies: - hash-base: 3.1.0 - inherits: 2.0.4 + /imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} dev: true - /rlp@2.2.7: - resolution: {integrity: sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==} - hasBin: true - dependencies: - bn.js: 5.2.1 - dev: true + /indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} - /run-parallel-limit@1.1.0: - resolution: {integrity: sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==} + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} dependencies: - queue-microtask: 1.2.3 + once: 1.4.0 + wrappy: 1.0.2 dev: true - /run-parallel@1.1.9: - resolution: {integrity: sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==} + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - /rustbn.js@0.2.0: - resolution: {integrity: sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==} + /ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} dev: true - /safe-array-concat@1.0.1: - resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==} - engines: {node: '>=0.4'} + /internal-slot@1.0.6: + resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 get-intrinsic: 1.2.2 - has-symbols: 1.0.3 - isarray: 2.0.5 - - /safe-buffer@5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - dev: true + hasown: 2.0.0 + side-channel: 1.0.4 + dev: false - /safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + /io-ts@1.10.4: + resolution: {integrity: sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==} + dependencies: + fp-ts: 1.19.3 dev: true - /safe-event-emitter@1.0.1: - resolution: {integrity: sha512-e1wFe99A91XYYxoQbcq2ZJUWurxEyP8vfz7A7vuUe1s95q8r5ebraVaA1BukYJcpM6V16ugWoD9vngi8Ccu5fg==} - deprecated: Renamed to @metamask/safe-event-emitter + /is-array-buffer@3.0.2: + resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} dependencies: - events: 3.3.0 - dev: true + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + is-typed-array: 1.1.12 + dev: false - /safe-regex-test@1.0.0: - resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} + /is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + /is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.1.3 - is-regex: 1.1.4 + has-bigints: 1.0.2 + dev: false - /safe-regex@1.1.0: - resolution: {integrity: sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==} + /is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} dependencies: - ret: 0.1.15 + binary-extensions: 2.2.0 dev: true - /safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + /is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + has-tostringtag: 1.0.0 + dev: false + + /is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + dev: false - /sc-istanbul@0.4.6: - resolution: {integrity: sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g==} + /is-ci@3.0.1: + resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} hasBin: true dependencies: - abbrev: 1.0.9 - async: 1.5.2 - escodegen: 1.8.1 - esprima: 2.7.3 - glob: 5.0.15 - handlebars: 4.7.7 - js-yaml: 3.14.1 - mkdirp: 0.5.6 - nopt: 3.0.6 - once: 1.4.0 - resolve: 1.1.7 - supports-color: 3.2.3 - which: 1.3.1 - wordwrap: 1.0.0 - dev: true + ci-info: 3.9.0 + dev: false - /scrypt-js@2.0.4: - resolution: {integrity: sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==} - dev: true + /is-core-module@2.10.0: + resolution: {integrity: sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==} + dependencies: + has: 1.0.3 + dev: false - /scrypt-js@3.0.1: - resolution: {integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==} + /is-date-object@1.0.2: + resolution: {integrity: sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==} + engines: {node: '>= 0.4'} + dev: false - /scryptsy@1.2.1: - resolution: {integrity: sha512-aldIRgMozSJ/Gl6K6qmJZysRP82lz83Wb42vl4PWN8SaLFHIaOzLPc9nUUW2jQN88CuGm5q5HefJ9jZ3nWSmTw==} - requiresBuild: true - dependencies: - pbkdf2: 3.1.2 - dev: true - optional: true + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} - /secp256k1@3.7.1: - resolution: {integrity: sha512-1cf8sbnRreXrQFdH6qsg2H71Xw91fCCS9Yp021GnUNJzWJS/py96fS4lHbnTnouLp08Xj6jBoBB6V78Tdbdu5g==} - engines: {node: '>=4.0.0'} - requiresBuild: true + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} dependencies: - bindings: 1.5.0 - bip66: 1.1.5 - bn.js: 4.12.0 - create-hash: 1.2.0 - drbg.js: 1.0.1 - elliptic: 6.5.4 - nan: 2.16.0 - safe-buffer: 5.2.1 + is-extglob: 2.1.1 + + /is-hex-prefixed@1.0.0: + resolution: {integrity: sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==} + engines: {node: '>=6.5.0', npm: '>=3'} dev: true - /secp256k1@4.0.3: - resolution: {integrity: sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==} - engines: {node: '>=10.0.0'} - requiresBuild: true + /is-lower-case@1.1.3: + resolution: {integrity: sha512-+5A1e/WJpLLXZEDlgz4G//WYSHyQBD32qa4Jd3Lw06qQlv3fJHnp3YIHjTQSGzHMgzmVKz2ZP3rBxTHkPw/lxA==} dependencies: - elliptic: 6.5.4 - node-addon-api: 2.0.2 - node-gyp-build: 4.5.0 + lower-case: 1.1.4 dev: true - /seedrandom@3.0.1: - resolution: {integrity: sha512-1/02Y/rUeU1CJBAGLebiC5Lbo5FnB22gQbIFFYTLkwvp1xdABZJH1sn4ZT1MzXmPpzv+Rf/Lu2NcsLJiK4rcDg==} - dev: true + /is-negative-zero@2.0.2: + resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} + engines: {node: '>= 0.4'} + dev: false - /semaphore@1.1.0: - resolution: {integrity: sha512-O4OZEaNtkMd/K0i6js9SL+gqy0ZCBMgUvlSqHKi4IBdjhe7wB8pwztUk1BbZ1fmrvpwFrPbHzqd2w5pTcJH6LA==} - engines: {node: '>=0.8.0'} - dev: true + /is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: false - /semver@5.4.1: - resolution: {integrity: sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==} - hasBin: true + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + /is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} dev: true - /semver@5.7.1: - resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} - hasBin: true + /is-plain-obj@1.1.0: + resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} + engines: {node: '>=0.10.0'} + dev: false - /semver@6.3.0: - resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} - hasBin: true + /is-plain-obj@2.1.0: + resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} + engines: {node: '>=8'} dev: true - /semver@7.3.7: - resolution: {integrity: sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==} - engines: {node: '>=10'} - hasBin: true + /is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} dependencies: - lru-cache: 6.0.0 - dev: true + call-bind: 1.0.2 + has-tostringtag: 1.0.0 + dev: false - /semver@7.5.4: - resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} - engines: {node: '>=10'} - hasBin: true + /is-shared-array-buffer@1.0.2: + resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} dependencies: - lru-cache: 6.0.0 + call-bind: 1.0.2 + dev: false - /send@0.17.1: - resolution: {integrity: sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==} - engines: {node: '>= 0.8.0'} - requiresBuild: true + /is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} dependencies: - debug: 2.6.9 - depd: 1.1.2 - destroy: 1.0.4 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 1.7.3 - mime: 1.6.0 - ms: 2.1.1 - on-finished: 2.3.0 - range-parser: 1.2.1 - statuses: 1.5.0 - transitivePeerDependencies: - - supports-color - dev: true + has-tostringtag: 1.0.0 + dev: false - /sentence-case@2.1.1: - resolution: {integrity: sha512-ENl7cYHaK/Ktwk5OTD+aDbQ3uC8IByu/6Bkg+HDv8Mm+XnBnppVNalcfJTNsp1ibstKh030/JKQQWglDvtKwEQ==} + /is-subdir@1.2.0: + resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} + engines: {node: '>=4'} dependencies: - no-case: 2.3.2 - upper-case-first: 1.1.2 - dev: true + better-path-resolve: 1.0.0 + dev: false - /serialize-javascript@6.0.0: - resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} + /is-symbol@1.0.3: + resolution: {integrity: sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==} + engines: {node: '>= 0.4'} dependencies: - randombytes: 2.1.0 - dev: true + has-symbols: 1.0.3 + dev: false - /serve-static@1.14.1: - resolution: {integrity: sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==} - engines: {node: '>= 0.8.0'} - requiresBuild: true + /is-typed-array@1.1.12: + resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} + engines: {node: '>= 0.4'} dependencies: - encodeurl: 1.0.2 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.17.1 - transitivePeerDependencies: - - supports-color - dev: true + which-typed-array: 1.1.13 + dev: false - /servify@0.1.12: - resolution: {integrity: sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw==} - engines: {node: '>=6'} - requiresBuild: true - dependencies: - body-parser: 1.19.0 - cors: 2.8.5 - express: 4.17.1 - request: 2.88.2 - xhr: 2.5.0 - transitivePeerDependencies: - - supports-color + /is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} dev: true - /set-blocking@2.0.0: - resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - - /set-function-length@1.1.1: - resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==} - engines: {node: '>= 0.4'} + /is-upper-case@1.1.2: + resolution: {integrity: sha512-GQYSJMgfeAmVwh9ixyk888l7OIhNAGKtY6QA+IrWlu9MDTCaXmeozOZ2S9Knj7bQwBO/H6J2kb+pbyTUiMNbsw==} dependencies: - define-data-property: 1.1.1 - get-intrinsic: 1.2.2 - gopd: 1.0.1 - has-property-descriptors: 1.0.0 + upper-case: 1.1.3 + dev: true - /set-function-name@2.0.1: - resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} - engines: {node: '>= 0.4'} + /is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: - define-data-property: 1.1.1 - functions-have-names: 1.2.3 - has-property-descriptors: 1.0.0 + call-bind: 1.0.2 + dev: false - /set-immediate-shim@1.0.1: - resolution: {integrity: sha512-Li5AOqrZWCVA2n5kryzEmqai6bKSIvpz5oUJHPVj6+dsbD3X1ixtsY5tEnsaNpH3pFAHmG8eIHUrtEtohrg+UQ==} + /is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} - dev: true + dev: false - /set-value@2.0.1: - resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==} - engines: {node: '>=0.10.0'} - dependencies: - extend-shallow: 2.0.1 - is-extendable: 0.1.1 - is-plain-object: 2.0.4 - split-string: 3.1.0 - dev: true + /isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + dev: false - /setimmediate@1.0.4: - resolution: {integrity: sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog==} - dev: true + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - /setimmediate@1.0.5: - resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + /js-sdsl@4.4.2: + resolution: {integrity: sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w==} dev: true - /setprototypeof@1.1.1: - resolution: {integrity: sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==} - requiresBuild: true - dev: true + /js-sha3@0.8.0: + resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} - /setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - dev: true + /js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - /sha.js@2.4.11: - resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} + /js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} hasBin: true dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - dev: true + argparse: 1.0.10 + esprima: 4.0.1 + dev: false - /sha1@1.1.1: - resolution: {integrity: sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==} + /js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true dependencies: - charenc: 0.0.2 - crypt: 0.0.2 + argparse: 2.0.1 dev: true - /sha3@1.2.6: - resolution: {integrity: sha512-KgLGmJGrmNB4JWVsAV11Yk6KbvsAiygWJc7t5IebWva/0NukNrjJqhtKhzy3Eiv2AKuGvhZZt7dt1mDo7HkoiQ==} - requiresBuild: true - dependencies: - nan: 2.13.2 + /json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} dev: true - /sha3@2.1.4: - resolution: {integrity: sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg==} - dependencies: - buffer: 6.0.3 - dev: true + /json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - /shallowequal@1.1.0: - resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} + /json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} dev: true - /shebang-command@1.2.0: - resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} - engines: {node: '>=0.10.0'} - dependencies: - shebang-regex: 1.0.0 - - /shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - dependencies: - shebang-regex: 3.0.0 + /json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} dev: true - /shebang-regex@1.0.0: - resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} - engines: {node: '>=0.10.0'} - - /shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} + /json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} dev: true - /shelljs@0.8.3: - resolution: {integrity: sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==} - engines: {node: '>=4'} - hasBin: true + /json-to-ast@2.1.0: + resolution: {integrity: sha512-W9Lq347r8tA1DfMvAGn9QNcgYm4Wm7Yc+k8e6vezpMnRT+NHbtlxgNBXRVjXe9YM6eTn6+p/MKOlV/aABJcSnQ==} + engines: {node: '>= 4'} dependencies: - glob: 7.2.3 - interpret: 1.2.0 - rechoir: 0.6.2 + code-error-fragment: 0.0.230 + grapheme-splitter: 1.0.4 dev: true - /side-channel@1.0.4: - resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.1.3 - object-inspect: 1.12.2 - - /signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - - /simple-concat@1.0.0: - resolution: {integrity: sha512-pgxq9iGMSS24atefsqEznXW1Te610qB4pwMdrEg6mxczHh7sPtPyiixkP/VaQic8JjZofnIvT7CDeKlHqfbPBg==} - requiresBuild: true + /jsonfile@2.4.0: + resolution: {integrity: sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==} + optionalDependencies: + graceful-fs: 4.2.10 dev: true - /simple-get@2.8.1: - resolution: {integrity: sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==} - requiresBuild: true + /jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + optionalDependencies: + graceful-fs: 4.2.10 + + /jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} dependencies: - decompress-response: 3.3.0 - once: 1.4.0 - simple-concat: 1.0.0 + universalify: 2.0.0 + optionalDependencies: + graceful-fs: 4.2.10 dev: true - /slash@1.0.0: - resolution: {integrity: sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==} + /jsonpointer@5.0.1: + resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} engines: {node: '>=0.10.0'} dev: true - /slash@2.0.0: - resolution: {integrity: sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==} - engines: {node: '>=6'} + /keccak@3.0.2: + resolution: {integrity: sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ==} + engines: {node: '>=10.0.0'} + requiresBuild: true + dependencies: + node-addon-api: 2.0.2 + node-gyp-build: 4.5.0 + readable-stream: 3.6.0 dev: true - /slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - - /slice-ansi@4.0.0: - resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} - engines: {node: '>=10'} + /keyv@4.5.0: + resolution: {integrity: sha512-2YvuMsA+jnFGtBareKqgANOEKe1mk3HKiXu2fRmAfyxG0MJAywNhi5ttWA3PMjl4NmpyjZNbFifR2vNjW1znfA==} dependencies: - ansi-styles: 4.3.0 - astral-regex: 2.0.0 - is-fullwidth-code-point: 3.0.0 + json-buffer: 3.0.1 dev: true - /smartwrap@2.0.2: - resolution: {integrity: sha512-vCsKNQxb7PnCNd2wY1WClWifAc2lwqsG8OaswpJkVJsvMGcnEntdTCDajZCkk93Ay1U3t/9puJmb525Rg5MZBA==} - engines: {node: '>=6'} - hasBin: true - dependencies: - array.prototype.flat: 1.3.2 - breakword: 1.0.6 - grapheme-splitter: 1.0.4 - strip-ansi: 6.0.1 - wcwidth: 1.0.1 - yargs: 15.4.1 + /kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} dev: false - /snake-case@2.1.0: - resolution: {integrity: sha512-FMR5YoPFwOLuh4rRz92dywJjyKYZNLpMn1R5ujVpIYkbA9p01fq8RMg0FkO4M+Yobt4MjHeLTJVm5xFFBHSV2Q==} - dependencies: - no-case: 2.3.2 + /klaw@1.3.1: + resolution: {integrity: sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==} + optionalDependencies: + graceful-fs: 4.2.10 dev: true - /snapdragon-node@2.1.1: - resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==} - engines: {node: '>=0.10.0'} - dependencies: - define-property: 1.0.0 - isobject: 3.0.1 - snapdragon-util: 3.0.1 - dev: true + /kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + dev: false - /snapdragon-util@3.0.1: - resolution: {integrity: sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==} - engines: {node: '>=0.10.0'} + /latest-version@7.0.0: + resolution: {integrity: sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==} + engines: {node: '>=14.16'} dependencies: - kind-of: 3.2.2 + package-json: 8.1.1 dev: true - /snapdragon@0.8.2: - resolution: {integrity: sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==} - engines: {node: '>=0.10.0'} - dependencies: - base: 0.11.2 - debug: 2.6.9 - define-property: 0.2.5 - extend-shallow: 2.0.1 - map-cache: 0.2.2 - source-map: 0.5.7 - source-map-resolve: 0.5.3 - use: 3.1.1 - transitivePeerDependencies: - - supports-color + /leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} dev: true - /solc@0.4.26: - resolution: {integrity: sha512-o+c6FpkiHd+HPjmjEVpQgH7fqZ14tJpXhho+/bQXlXbliLIS/xjXb42Vxh+qQY1WCSTMQ0+a5vR9vi0MfhU6mA==} - hasBin: true + /levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} dependencies: - fs-extra: 0.30.0 - memorystream: 0.3.1 - require-from-string: 1.2.1 - semver: 5.7.1 - yargs: 4.8.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 dev: true - /solc@0.6.12: - resolution: {integrity: sha512-Lm0Ql2G9Qc7yPP2Ba+WNmzw2jwsrd3u4PobHYlSOxaut3TtUbj9+5ZrT6f4DUpNPEoBaFUOEg9Op9C0mk7ge9g==} - engines: {node: '>=8.0.0'} - hasBin: true - dependencies: - command-exists: 1.2.9 - commander: 3.0.2 - fs-extra: 0.30.0 - js-sha3: 0.8.0 - memorystream: 0.3.1 - require-from-string: 2.0.2 - semver: 5.7.1 - tmp: 0.0.33 - dev: true + /lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - /solc@0.7.3(debug@4.3.4): - resolution: {integrity: sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==} - engines: {node: '>=8.0.0'} - hasBin: true + /load-yaml-file@0.2.0: + resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==} + engines: {node: '>=6'} dependencies: - command-exists: 1.2.9 - commander: 3.0.2 - follow-redirects: 1.15.2(debug@4.3.4) - fs-extra: 0.30.0 - js-sha3: 0.8.0 - memorystream: 0.3.1 - require-from-string: 2.0.2 - semver: 5.7.1 - tmp: 0.0.33 - transitivePeerDependencies: - - debug - dev: true + graceful-fs: 4.2.10 + js-yaml: 3.14.1 + pify: 4.0.1 + strip-bom: 3.0.0 + dev: false - /solhint-plugin-prettier@0.1.0(prettier-plugin-solidity@1.3.1)(prettier@3.2.5): - resolution: {integrity: sha512-SDOTSM6tZxZ6hamrzl3GUgzF77FM6jZplgL2plFBclj/OjKP8Z3eIPojKU73gRr0MvOS8ACZILn8a5g0VTz/Gw==} - peerDependencies: - prettier: ^3.0.0 - prettier-plugin-solidity: ^1.0.0 + /locate-path@2.0.0: + resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} + engines: {node: '>=4'} dependencies: - '@prettier/sync': 0.3.0(prettier@3.2.5) - prettier: 3.2.5 - prettier-linter-helpers: 1.0.0 - prettier-plugin-solidity: 1.3.1(prettier@3.2.5) + p-locate: 2.0.0 + path-exists: 3.0.0 dev: true - /solhint@4.1.1: - resolution: {integrity: sha512-7G4iF8H5hKHc0tR+/uyZesSKtfppFIMvPSW+Ku6MSL25oVRuyFeqNhOsXHfkex64wYJyXs4fe+pvhB069I19Tw==} - hasBin: true - dependencies: - '@solidity-parser/parser': 0.16.2 - ajv: 6.12.6 - antlr4: 4.13.0 - ast-parents: 0.0.1 - chalk: 4.1.2 - commander: 10.0.1 - cosmiconfig: 8.2.0 - fast-diff: 1.2.0 - glob: 8.1.0 - ignore: 5.2.4 - js-yaml: 4.1.0 - latest-version: 7.0.0 - lodash: 4.17.21 - pluralize: 8.0.0 - semver: 7.5.4 - strip-ansi: 6.0.1 - table: 6.8.1 - text-table: 0.2.0 - optionalDependencies: - prettier: 2.8.8 - dev: true + /locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + dependencies: + p-locate: 4.1.0 + dev: false - /solidity-ast@0.4.55: - resolution: {integrity: sha512-qeEU/r/K+V5lrAw8iswf2/yfWAnSGs3WKPHI+zAFKFjX0dIBVXEU/swQ8eJQYHf6PJWUZFO2uWV4V1wEOkeQbA==} + /locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} dependencies: - array.prototype.findlast: 1.2.3 + p-locate: 5.0.0 + + /lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} dev: true - /solidity-comments-darwin-arm64@0.0.2: - resolution: {integrity: sha512-HidWkVLSh7v+Vu0CA7oI21GWP/ZY7ro8g8OmIxE8oTqyMwgMbE8F1yc58Sj682Hj199HCZsjmtn1BE4PCbLiGA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - requiresBuild: true + /lodash.clonedeep@4.5.0: + resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} dev: true - optional: true - /solidity-comments-darwin-x64@0.0.2: - resolution: {integrity: sha512-Zjs0Ruz6faBTPT6fBecUt6qh4CdloT8Bwoc0+qxRoTn9UhYscmbPQkUgQEbS0FQPysYqVzzxJB4h1Ofbf4wwtA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - requiresBuild: true + /lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} dev: true - optional: true - /solidity-comments-extractor@0.0.8: - resolution: {integrity: sha512-htM7Vn6LhHreR+EglVMd2s+sZhcXAirB1Zlyrv5zBuTxieCvjfnRpd7iZk75m/u6NOlEyQ94C6TWbBn2cY7w8g==} + /lodash.mapvalues@4.6.0: + resolution: {integrity: sha512-JPFqXFeZQ7BfS00H58kClY7SPVeHertPE0lNuCyZ26/XlN8TvakYD7b9bGyNmXbT/D3BbtPAAmq90gPWqLkxlQ==} dev: true - /solidity-comments-freebsd-x64@0.0.2: - resolution: {integrity: sha512-8Qe4mpjuAxFSwZJVk7B8gAoLCdbtS412bQzBwk63L8dmlHogvE39iT70aAk3RHUddAppT5RMBunlPUCFYJ3ZTw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [freebsd] - requiresBuild: true + /lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true - optional: true - /solidity-comments-linux-arm64-gnu@0.0.2: - resolution: {integrity: sha512-spkb0MZZnmrP+Wtq4UxP+nyPAVRe82idOjqndolcNR0S9Xvu4ebwq+LvF4HiUgjTDmeiqYiFZQ8T9KGdLSIoIg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - requiresBuild: true + /lodash.startcase@4.4.0: + resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + dev: false + + /lodash.truncate@4.4.2: + resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} dev: true - optional: true - /solidity-comments-linux-arm64-musl@0.0.2: - resolution: {integrity: sha512-guCDbHArcjE+JDXYkxx5RZzY1YF6OnAKCo+sTC5fstyW/KGKaQJNPyBNWuwYsQiaEHpvhW1ha537IvlGek8GqA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - requiresBuild: true + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: true - optional: true - /solidity-comments-linux-x64-gnu@0.0.2: - resolution: {integrity: sha512-zIqLehBK/g7tvrFmQljrfZXfkEeLt2v6wbe+uFu6kH/qAHZa7ybt8Vc0wYcmjo2U0PeBm15d79ee3AkwbIjFdQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - requiresBuild: true + /log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 dev: true - optional: true - /solidity-comments-linux-x64-musl@0.0.2: - resolution: {integrity: sha512-R9FeDloVlFGTaVkOlELDVC7+1Tjx5WBPI5L8r0AGOPHK3+jOcRh6sKYpI+VskSPDc3vOO46INkpDgUXrKydlIw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - requiresBuild: true + /loupe@2.3.7: + resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} + dependencies: + get-func-name: 2.0.2 + + /lower-case-first@1.0.2: + resolution: {integrity: sha512-UuxaYakO7XeONbKrZf5FEgkantPf5DUqDayzP5VXZrtRPdH86s4kN47I8B3TW10S4QKiE3ziHNf3kRN//okHjA==} + dependencies: + lower-case: 1.1.4 dev: true - optional: true - /solidity-comments-win32-arm64-msvc@0.0.2: - resolution: {integrity: sha512-QnWJoCQcJj+rnutULOihN9bixOtYWDdF5Rfz9fpHejL1BtNjdLW1om55XNVHGAHPqBxV4aeQQ6OirKnp9zKsug==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - requiresBuild: true + /lower-case@1.1.4: + resolution: {integrity: sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==} dev: true - optional: true - /solidity-comments-win32-ia32-msvc@0.0.2: - resolution: {integrity: sha512-vUg4nADtm/NcOtlIymG23NWJUSuMsvX15nU7ynhGBsdKtt8xhdP3C/zA6vjDk8Jg+FXGQL6IHVQ++g/7rSQi0w==} - engines: {node: '>= 10'} - cpu: [ia32] - os: [win32] - requiresBuild: true + /lowercase-keys@2.0.0: + resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} + engines: {node: '>=8'} dev: true - optional: true - /solidity-comments-win32-x64-msvc@0.0.2: - resolution: {integrity: sha512-36j+KUF4V/y0t3qatHm/LF5sCUCBx2UndxE1kq5bOzh/s+nQgatuyB+Pd5BfuPQHdWu2KaExYe20FlAa6NL7+Q==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - requiresBuild: true + /lowercase-keys@3.0.0: + resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dev: true - optional: true - /solidity-comments@0.0.2: - resolution: {integrity: sha512-G+aK6qtyUfkn1guS8uzqUeua1dURwPlcOjoTYW/TwmXAcE7z/1+oGCfZUdMSe4ZMKklNbVZNiG5ibnF8gkkFfw==} - engines: {node: '>= 12'} - optionalDependencies: - solidity-comments-darwin-arm64: 0.0.2 - solidity-comments-darwin-x64: 0.0.2 - solidity-comments-freebsd-x64: 0.0.2 - solidity-comments-linux-arm64-gnu: 0.0.2 - solidity-comments-linux-arm64-musl: 0.0.2 - solidity-comments-linux-x64-gnu: 0.0.2 - solidity-comments-linux-x64-musl: 0.0.2 - solidity-comments-win32-arm64-msvc: 0.0.2 - solidity-comments-win32-ia32-msvc: 0.0.2 - solidity-comments-win32-x64-msvc: 0.0.2 + /lru-cache@10.2.0: + resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} + engines: {node: 14 || >=16.14} dev: true - /solidity-coverage@0.8.5(hardhat@2.19.2): - resolution: {integrity: sha512-6C6N6OV2O8FQA0FWA95FdzVH+L16HU94iFgg5wAFZ29UpLFkgNI/DRR2HotG1bC0F4gAc/OMs2BJI44Q/DYlKQ==} - hasBin: true - peerDependencies: - hardhat: ^2.11.0 + /lru-cache@4.1.5: + resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} dependencies: - '@ethersproject/abi': 5.7.0 - '@solidity-parser/parser': 0.16.0 - chalk: 2.4.2 - death: 1.1.0 - detect-port: 1.3.0 - difflib: 0.2.4 - fs-extra: 8.1.0 - ghost-testrpc: 0.0.2 - global-modules: 2.0.0 - globby: 10.0.2 - hardhat: 2.19.2(ts-node@10.9.2)(typescript@5.3.3) - jsonschema: 1.4.0 - lodash: 4.17.21 - mocha: 10.2.0 - node-emoji: 1.11.0 - pify: 4.0.1 - recursive-readdir: 2.2.2 - sc-istanbul: 0.4.6 - semver: 7.5.4 - shelljs: 0.8.3 - web3-utils: 1.8.0 - transitivePeerDependencies: - - supports-color - dev: true + pseudomap: 1.0.2 + yallist: 2.1.2 + dev: false - /sort-any@2.0.0: - resolution: {integrity: sha512-T9JoiDewQEmWcnmPn/s9h/PH9t3d/LSWi0RgVmXSuDYeZXTZOZ1/wrK2PHaptuR1VXe3clLLt0pD6sgVOwjNEA==} + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} dependencies: - lodash: 4.17.21 + yallist: 4.0.0 + + /lru_map@0.3.3: + resolution: {integrity: sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==} dev: true - /source-map-resolve@0.5.3: - resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==} - deprecated: See https://github.com/lydell/source-map-resolve#deprecated - dependencies: - atob: 2.1.2 - decode-uri-component: 0.2.0 - resolve-url: 0.2.1 - source-map-url: 0.4.1 - urix: 0.1.0 + /make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} dev: true - /source-map-support@0.4.18: - resolution: {integrity: sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==} + /map-obj@1.0.1: + resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} + engines: {node: '>=0.10.0'} + dev: false + + /map-obj@4.3.0: + resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} + engines: {node: '>=8'} + dev: false + + /md5.js@1.3.5: + resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} dependencies: - source-map: 0.5.7 + hash-base: 3.1.0 + inherits: 2.0.4 + safe-buffer: 5.2.1 dev: true - /source-map-support@0.5.12: - resolution: {integrity: sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==} - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 + /memorystream@0.3.1: + resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} + engines: {node: '>= 0.10.0'} dev: true - /source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + /meow@6.1.1: + resolution: {integrity: sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg==} + engines: {node: '>=8'} dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - dev: true + '@types/minimist': 1.2.5 + camelcase-keys: 6.2.2 + decamelize-keys: 1.1.1 + hard-rejection: 2.1.0 + minimist-options: 4.1.0 + normalize-package-data: 2.5.0 + read-pkg-up: 7.0.1 + redent: 3.0.0 + trim-newlines: 3.0.1 + type-fest: 0.13.1 + yargs-parser: 18.1.3 + dev: false - /source-map-url@0.4.1: - resolution: {integrity: sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==} - deprecated: See https://github.com/lydell/source-map-url#deprecated - dev: true + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} - /source-map@0.2.0: - resolution: {integrity: sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==} - engines: {node: '>=0.8.0'} - requiresBuild: true + /micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} dependencies: - amdefine: 1.0.1 - dev: true - optional: true + braces: 3.0.2 + picomatch: 2.3.1 - /source-map@0.5.7: - resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} - engines: {node: '>=0.10.0'} + /mimic-response@1.0.1: + resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} + engines: {node: '>=4'} + requiresBuild: true dev: true - /source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} + /mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} dev: true - /spawndamnit@2.0.0: - resolution: {integrity: sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==} - dependencies: - cross-spawn: 5.1.0 - signal-exit: 3.0.7 + /min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} dev: false - /spdx-correct@3.1.1: - resolution: {integrity: sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==} - dependencies: - spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.12 - - /spdx-exceptions@2.3.0: - resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} - - /spdx-expression-parse@3.0.1: - resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - dependencies: - spdx-exceptions: 2.3.0 - spdx-license-ids: 3.0.12 + /minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} - /spdx-license-ids@3.0.12: - resolution: {integrity: sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==} + /minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} - /split-string@3.1.0: - resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==} - engines: {node: '>=0.10.0'} + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: - extend-shallow: 3.0.2 + brace-expansion: 1.1.11 dev: true - /sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - - /sshpk@1.16.1: - resolution: {integrity: sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==} - engines: {node: '>=0.10.0'} - hasBin: true + /minimatch@5.0.1: + resolution: {integrity: sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==} + engines: {node: '>=10'} dependencies: - asn1: 0.2.4 - assert-plus: 1.0.0 - bcrypt-pbkdf: 1.0.2 - dashdash: 1.14.1 - ecc-jsbn: 0.1.2 - getpass: 0.1.7 - jsbn: 0.1.1 - safer-buffer: 2.1.2 - tweetnacl: 0.14.5 + brace-expansion: 2.0.1 dev: true - /stacktrace-parser@0.1.10: - resolution: {integrity: sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==} - engines: {node: '>=6'} + /minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} dependencies: - type-fest: 0.7.1 + brace-expansion: 2.0.1 dev: true - /static-extend@0.1.2: - resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==} - engines: {node: '>=0.10.0'} + /minimatch@9.0.3: + resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + engines: {node: '>=16 || 14 >=14.17'} dependencies: - define-property: 0.2.5 - object-copy: 0.1.0 + brace-expansion: 2.0.1 dev: true - /statuses@1.5.0: - resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} - engines: {node: '>= 0.6'} - requiresBuild: true - dev: true + /minimist-options@4.1.0: + resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} + engines: {node: '>= 6'} + dependencies: + arrify: 1.0.1 + is-plain-obj: 1.1.0 + kind-of: 6.0.3 + dev: false - /statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} + /minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} dev: true - /stealthy-require@1.1.1: - resolution: {integrity: sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==} - engines: {node: '>=0.10.0'} + /mixme@0.5.10: + resolution: {integrity: sha512-5H76ANWinB1H3twpJ6JY8uvAtpmFvHNArpilJAjXRKXSDDLPIMoZArw5SH0q9z+lLs8IrMw7Q2VWpWimFKFT1Q==} + engines: {node: '>= 8.0.0'} + dev: false + + /mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true dev: true - /stream-to-pull-stream@1.7.3: - resolution: {integrity: sha512-6sNyqJpr5dIOQdgNy/xcDWwDuzAsAwVzhzrWlAPAQ7Lkjx/rv0wgvxEyKwTq6FmNd5rjTrELt/CLmaSw7crMGg==} + /mnemonist@0.38.5: + resolution: {integrity: sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==} dependencies: - looper: 3.0.0 - pull-stream: 3.6.14 + obliterator: 2.0.4 dev: true - /stream-transform@2.1.3: - resolution: {integrity: sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==} + /mocha@10.2.0: + resolution: {integrity: sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==} + engines: {node: '>= 14.0.0'} + hasBin: true dependencies: - mixme: 0.5.10 - dev: false + ansi-colors: 4.1.1 + browser-stdout: 1.3.1 + chokidar: 3.5.3 + debug: 4.3.4(supports-color@8.1.1) + diff: 5.0.0 + escape-string-regexp: 4.0.0 + find-up: 5.0.0 + glob: 7.2.0 + he: 1.2.0 + js-yaml: 4.1.0 + log-symbols: 4.1.0 + minimatch: 5.0.1 + ms: 2.1.3 + nanoid: 3.3.3 + serialize-javascript: 6.0.0 + strip-json-comments: 3.1.1 + supports-color: 8.1.1 + workerpool: 6.2.1 + yargs: 16.2.0 + yargs-parser: 20.2.4 + yargs-unparser: 2.0.0 + dev: true - /streamsearch@1.1.0: - resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} - engines: {node: '>=10.0.0'} + /moment@2.30.1: + resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} dev: true - /strict-uri-encode@1.1.0: - resolution: {integrity: sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==} - engines: {node: '>=0.10.0'} - requiresBuild: true + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} dev: true - /string-format@2.0.0: - resolution: {integrity: sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==} + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} dev: true - /string-width@1.0.2: - resolution: {integrity: sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==} - engines: {node: '>=0.10.0'} - dependencies: - code-point-at: 1.1.0 - is-fullwidth-code-point: 1.0.0 - strip-ansi: 3.0.1 + /nanoid@3.3.3: + resolution: {integrity: sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true dev: true - /string-width@2.1.1: - resolution: {integrity: sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==} - engines: {node: '>=4'} - dependencies: - is-fullwidth-code-point: 2.0.0 - strip-ansi: 4.0.0 + /natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true - /string-width@3.1.0: - resolution: {integrity: sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==} - engines: {node: '>=6'} + /neodoc@2.0.2: + resolution: {integrity: sha512-NAppJ0YecKWdhSXFYCHbo6RutiX8vOt/Jo3l46mUg6pQlpJNaqc5cGxdrW2jITQm5JIYySbFVPDl3RrREXNyPw==} dependencies: - emoji-regex: 7.0.3 - is-fullwidth-code-point: 2.0.0 - strip-ansi: 5.2.0 + ansi-regex: 2.1.1 dev: true - /string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} + /no-case@2.3.2: + resolution: {integrity: sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==} dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 + lower-case: 1.1.4 + dev: true - /string.prototype.trim@1.2.8: - resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 + /node-addon-api@2.0.2: + resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==} + dev: true - /string.prototype.trimend@1.0.7: - resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} + /node-fetch@2.6.7: + resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 + whatwg-url: 5.0.0 + dev: false - /string.prototype.trimstart@1.0.7: - resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} + /node-gyp-build@4.5.0: + resolution: {integrity: sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==} + hasBin: true + dev: true + + /node-interval-tree@2.1.2: + resolution: {integrity: sha512-bJ9zMDuNGzVQg1xv0bCPzyEDxHgbrx7/xGj6CDokvizZZmastPsOh0JJLuY8wA5q2SfX1TLNMk7XNV8WxbGxzA==} + engines: {node: '>= 14.0.0'} dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 + shallowequal: 1.1.0 + dev: true - /string_decoder@0.10.31: - resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==} + /nofilter@1.0.4: + resolution: {integrity: sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==} + engines: {node: '>=8'} dev: true - /string_decoder@1.1.1: - resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} - dependencies: - safe-buffer: 5.1.2 + /nofilter@3.1.0: + resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} + engines: {node: '>=12.19'} dev: true - /string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + /normalize-package-data@2.5.0: + resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} dependencies: - safe-buffer: 5.2.1 - dev: true + hosted-git-info: 2.8.9 + resolve: 1.22.1 + semver: 5.7.1 + validate-npm-package-license: 3.0.4 + dev: false - /strip-ansi@3.0.1: - resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - dependencies: - ansi-regex: 2.1.1 dev: true - /strip-ansi@4.0.0: - resolution: {integrity: sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==} - engines: {node: '>=4'} - dependencies: - ansi-regex: 3.0.1 + /normalize-url@6.1.0: + resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} + engines: {node: '>=10'} dev: true - /strip-ansi@5.2.0: - resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==} - engines: {node: '>=6'} + /number-to-bn@1.7.0: + resolution: {integrity: sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==} + engines: {node: '>=6.5.0', npm: '>=3'} dependencies: - ansi-regex: 4.1.1 + bn.js: 4.11.6 + strip-hex-prefix: 1.0.0 dev: true - /strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - dependencies: - ansi-regex: 5.0.1 + /object-inspect@1.12.2: + resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} + dev: false - /strip-bom@2.0.0: - resolution: {integrity: sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==} - engines: {node: '>=0.10.0'} - dependencies: - is-utf8: 0.2.1 - dev: true + /object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + dev: false - /strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} + /object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} dev: false - /strip-hex-prefix@1.0.0: - resolution: {integrity: sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==} - engines: {node: '>=6.5.0', npm: '>=3'} + /object.assign@4.1.4: + resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} + engines: {node: '>= 0.4'} dependencies: - is-hex-prefixed: 1.0.0 + call-bind: 1.0.2 + define-properties: 1.1.4 + has-symbols: 1.0.3 + object-keys: 1.1.1 + dev: false + + /obliterator@2.0.4: + resolution: {integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==} dev: true - /strip-indent@2.0.0: - resolution: {integrity: sha512-RsSNPLpq6YUL7QYy44RnPVTn/lcVZtb48Uof3X5JLbF4zD/Gs7ZFDv2HWol+leoQN2mT86LAzSshGfkTlSOpsA==} - engines: {node: '>=4'} + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 dev: true - /strip-indent@3.0.0: - resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} - engines: {node: '>=8'} + /optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} + engines: {node: '>= 0.8.0'} dependencies: - min-indent: 1.0.1 + '@aashutoshrathi/word-wrap': 1.2.6 + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /ordinal@1.0.3: + resolution: {integrity: sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ==} + dev: true + + /os-tmpdir@1.0.2: + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} + engines: {node: '>=0.10.0'} + + /outdent@0.5.0: + resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} dev: false - /strip-json-comments@2.0.1: - resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} - engines: {node: '>=0.10.0'} + /p-cancelable@3.0.0: + resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==} + engines: {node: '>=12.20'} dev: true - /strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + /p-filter@2.1.0: + resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} engines: {node: '>=8'} - dev: true + dependencies: + p-map: 2.1.0 + dev: false - /supports-color@2.0.0: - resolution: {integrity: sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==} - engines: {node: '>=0.8.0'} + /p-limit@1.3.0: + resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} + engines: {node: '>=4'} + dependencies: + p-try: 1.0.0 dev: true - /supports-color@3.2.3: - resolution: {integrity: sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==} - engines: {node: '>=0.8.0'} + /p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} dependencies: - has-flag: 1.0.0 - dev: true + p-try: 2.2.0 + dev: false - /supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} + /p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} dependencies: - has-flag: 3.0.0 + yocto-queue: 0.1.0 - /supports-color@6.0.0: - resolution: {integrity: sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==} - engines: {node: '>=6'} + /p-locate@2.0.0: + resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} + engines: {node: '>=4'} dependencies: - has-flag: 3.0.0 + p-limit: 1.3.0 dev: true - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + /p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} dependencies: - has-flag: 4.0.0 + p-limit: 2.3.0 + dev: false - /supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + /p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} dependencies: - has-flag: 4.0.0 - dev: true + p-limit: 3.1.0 - /supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} + /p-map@2.1.0: + resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} + engines: {node: '>=6'} + dev: false - /swap-case@1.1.2: - resolution: {integrity: sha512-BAmWG6/bx8syfc6qXPprof3Mn5vQgf5dwdUNJhsNqU9WdPt5P+ES/wQ5bxfijy8zwZgZZHslC3iAsxsuQMCzJQ==} + /p-map@4.0.0: + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} dependencies: - lower-case: 1.1.4 - upper-case: 1.1.3 + aggregate-error: 3.1.0 dev: true - /swarm-js@0.1.40: - resolution: {integrity: sha512-yqiOCEoA4/IShXkY3WKwP5PvZhmoOOD8clsKA7EEcRILMkTEYHCQ21HDCAcVpmIxZq4LyZvWeRJ6quIyHk1caA==} - dependencies: - bluebird: 3.7.2 - buffer: 5.7.1 - eth-lib: 0.1.29 - fs-extra: 4.0.3 - got: 7.1.0 - mime-types: 2.1.27 - mkdirp-promise: 5.0.1 - mock-fs: 4.12.0 - setimmediate: 1.0.5 - tar: 4.4.19 - xhr-request: 1.1.0 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate + /p-try@1.0.0: + resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==} + engines: {node: '>=4'} dev: true - /sync-request@6.1.0: - resolution: {integrity: sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==} - engines: {node: '>=8.0.0'} + /p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + dev: false + + /package-json@8.1.1: + resolution: {integrity: sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==} + engines: {node: '>=14.16'} dependencies: - http-response-object: 3.0.2 - sync-rpc: 1.3.6 - then-request: 6.0.2 + got: 12.1.0 + registry-auth-token: 5.0.2 + registry-url: 6.0.1 + semver: 7.6.0 dev: true - /sync-rpc@1.3.6: - resolution: {integrity: sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==} + /param-case@2.1.1: + resolution: {integrity: sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==} dependencies: - get-port: 3.2.0 + no-case: 2.3.2 dev: true - /synckit@0.8.8: - resolution: {integrity: sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==} - engines: {node: ^14.18.0 || >=16.0.0} + /parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} dependencies: - '@pkgr/core': 0.1.1 - tslib: 2.6.2 + callsites: 3.1.0 dev: true - /table-layout@1.0.2: - resolution: {integrity: sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==} - engines: {node: '>=8.0.0'} + /parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} dependencies: - array-back: 4.0.2 - deep-extend: 0.6.0 - typical: 5.2.0 - wordwrapjs: 4.0.1 - dev: true + '@babel/code-frame': 7.18.6 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 - /table@6.8.1: - resolution: {integrity: sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==} - engines: {node: '>=10.0.0'} + /pascal-case@2.0.1: + resolution: {integrity: sha512-qjS4s8rBOJa2Xm0jmxXiyh1+OFf6ekCWOvUaRgAQSktzlTbMotS0nmG9gyYAybCWBcuP4fsBeRCKNwGBnMe2OQ==} dependencies: - ajv: 8.11.0 - lodash.truncate: 4.4.2 - slice-ansi: 4.0.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 + camel-case: 3.0.0 + upper-case-first: 1.1.2 dev: true - /tape@4.16.1: - resolution: {integrity: sha512-U4DWOikL5gBYUrlzx+J0oaRedm2vKLFbtA/+BRAXboGWpXO7bMP8ddxlq3Cse2bvXFQ0jZMOj6kk3546mvCdFg==} - hasBin: true + /path-case@2.1.1: + resolution: {integrity: sha512-Ou0N05MioItesaLr9q8TtHVWmJ6fxWdqKB2RohFmNWVyJ+2zeKIeDNWAN6B/Pe7wpzWChhZX6nONYmOnMeJQ/Q==} dependencies: - call-bind: 1.0.5 - deep-equal: 1.1.1 - defined: 1.0.0 - dotignore: 0.1.2 - for-each: 0.3.3 - glob: 7.2.3 - has: 1.0.3 - inherits: 2.0.4 - is-regex: 1.1.4 - minimist: 1.2.8 - object-inspect: 1.12.2 - resolve: 1.22.1 - resumer: 0.0.0 - string.prototype.trim: 1.2.8 - through: 2.3.8 + no-case: 2.3.2 dev: true - /tar@4.4.19: - resolution: {integrity: sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==} - engines: {node: '>=4.5'} - requiresBuild: true - dependencies: - chownr: 1.1.4 - fs-minipass: 1.2.7 - minipass: 2.9.0 - minizlib: 1.3.3 - mkdirp: 0.5.6 - safe-buffer: 5.2.1 - yallist: 3.1.1 + /path-exists@3.0.0: + resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} + engines: {node: '>=4'} dev: true - /term-size@2.2.1: - resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} + /path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - dev: false - /test-value@2.1.0: - resolution: {integrity: sha512-+1epbAxtKeXttkGFMTX9H42oqzOTufR1ceCF+GYA5aOmvaPq9wd4PUS8329fn2RRLGNeUkgRLnVpycjx8DsO2w==} + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} - dependencies: - array-back: 1.0.4 - typical: 2.6.1 dev: true - /testrpc@0.0.1: - resolution: {integrity: sha512-afH1hO+SQ/VPlmaLUFj2636QMeDvPCeQMc/9RBMW0IfjNe9gFD9Ra3ShqYkB7py0do1ZcCna/9acHyzTJ+GcNA==} - deprecated: testrpc has been renamed to ganache-cli, please use this package from now on. - dev: true - - /text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} dev: true - /then-request@6.0.2: - resolution: {integrity: sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==} - engines: {node: '>=6.0.0'} - dependencies: - '@types/concat-stream': 1.6.1 - '@types/form-data': 0.0.33 - '@types/node': 8.10.66 - '@types/qs': 6.9.7 - caseless: 0.12.0 - concat-stream: 1.6.2 - form-data: 2.3.3 - http-basic: 8.1.3 - http-response-object: 3.0.2 - promise: 8.3.0 - qs: 6.11.0 - dev: true + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - /through2@2.0.5: - resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} - dependencies: - readable-stream: 2.3.7 - xtend: 4.0.2 + /path-starts-with@2.0.1: + resolution: {integrity: sha512-wZ3AeiRBRlNwkdUxvBANh0+esnt38DLffHDujZyRHkqkaKHTglnY2EP5UX3b8rdeiSutgO4y9NEJwXezNP5vHg==} + engines: {node: '>=8'} dev: true - /through@2.3.8: - resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - dev: true + /path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} - /timed-out@4.0.1: - resolution: {integrity: sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==} - engines: {node: '>=0.10.0'} - requiresBuild: true - dev: true + /pathval@1.1.1: + resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} - /title-case@2.1.1: - resolution: {integrity: sha512-EkJoZ2O3zdCz3zJsYCsxyq2OC5hrxR9mfdd5I+w8h/tmFfeOxJ+vvkxsKxdmN0WtS9zLdHEgfgVOiMVgv+Po4Q==} + /pbkdf2@3.1.2: + resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} + engines: {node: '>=0.12'} dependencies: - no-case: 2.3.2 - upper-case: 1.1.3 + create-hash: 1.2.0 + create-hmac: 1.1.7 + ripemd160: 2.0.2 + safe-buffer: 5.2.1 + sha.js: 2.4.11 dev: true - /tmp@0.0.33: - resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} - engines: {node: '>=0.6.0'} - dependencies: - os-tmpdir: 1.0.2 + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} - /tmp@0.1.0: - resolution: {integrity: sha512-J7Z2K08jbGcdA1kkQpJSqLF6T0tdQqpR2pnSUXsIchbPdTI9v3e85cLW0d6WDhwuAleOV71j2xWs8qMPfK7nKw==} + /pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} + dev: false + + /pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} dependencies: - rimraf: 2.7.1 + find-up: 4.1.0 + dev: false + + /pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} dev: true - /to-fast-properties@1.0.3: - resolution: {integrity: sha512-lxrWP8ejsq+7E3nNjwYmUBMAgjMTZoTI+sdBOpvNyijeDLa29LUn9QaoXAHv4+Z578hbmHHJKZknzxVtvo77og==} - engines: {node: '>=0.10.0'} + /preferred-pm@3.1.3: + resolution: {integrity: sha512-MkXsENfftWSRpzCzImcp4FRsCc3y1opwB73CfCNWyzMqArju2CrlMHlqB7VexKiPEOjGMbttv1r9fSCn5S610w==} + engines: {node: '>=10'} + dependencies: + find-up: 5.0.0 + find-yarn-workspace-root2: 1.2.16 + path-exists: 4.0.0 + which-pm: 2.0.0 + dev: false + + /prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} dev: true - /to-object-path@0.3.0: - resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==} - engines: {node: '>=0.10.0'} + /prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} dependencies: - kind-of: 3.2.2 + fast-diff: 1.2.0 dev: true - /to-readable-stream@1.0.0: - resolution: {integrity: sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==} - engines: {node: '>=6'} - requiresBuild: true + /prettier-plugin-solidity@1.3.1(prettier@2.8.8): + resolution: {integrity: sha512-MN4OP5I2gHAzHZG1wcuJl0FsLS3c4Cc5494bbg+6oQWBPuEamjwDvmGfFMZ6NFzsh3Efd9UUxeT7ImgjNH4ozA==} + engines: {node: '>=16'} + peerDependencies: + prettier: '>=2.3.0' + dependencies: + '@solidity-parser/parser': 0.17.0 + prettier: 2.8.8 + semver: 7.6.0 + solidity-comments-extractor: 0.0.8 dev: true + optional: true - /to-regex-range@2.1.1: - resolution: {integrity: sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==} - engines: {node: '>=0.10.0'} + /prettier-plugin-solidity@1.3.1(prettier@3.2.5): + resolution: {integrity: sha512-MN4OP5I2gHAzHZG1wcuJl0FsLS3c4Cc5494bbg+6oQWBPuEamjwDvmGfFMZ6NFzsh3Efd9UUxeT7ImgjNH4ozA==} + engines: {node: '>=16'} + peerDependencies: + prettier: '>=2.3.0' dependencies: - is-number: 3.0.0 - repeat-string: 1.6.1 + '@solidity-parser/parser': 0.17.0 + prettier: 3.2.5 + semver: 7.6.0 + solidity-comments-extractor: 0.0.8 dev: true - /to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - dependencies: - is-number: 7.0.0 + /prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} + engines: {node: '>=10.13.0'} + hasBin: true - /to-regex@3.0.2: - resolution: {integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==} - engines: {node: '>=0.10.0'} - dependencies: - define-property: 2.0.2 - extend-shallow: 3.0.2 - regex-not: 1.0.2 - safe-regex: 1.1.0 + /prettier@3.2.5: + resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} + engines: {node: '>=14'} + hasBin: true dev: true - /toidentifier@1.0.0: - resolution: {integrity: sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==} - engines: {node: '>=0.6'} - requiresBuild: true + /proto-list@1.2.4: + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} dev: true - /toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - dev: true + /pseudomap@1.0.2: + resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} + dev: false - /tough-cookie@2.5.0: - resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==} - engines: {node: '>=0.8'} + /pump@3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + requiresBuild: true dependencies: - psl: 1.9.0 - punycode: 2.1.1 + end-of-stream: 1.4.4 + once: 1.4.0 dev: true - /tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + /punycode@2.1.1: + resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} + engines: {node: '>=6'} + dev: true - /trim-newlines@3.0.1: - resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} + /pure-rand@5.0.3: + resolution: {integrity: sha512-9N8x1h8dptBQpHyC7aZMS+iNOAm97WMGY0AFrguU1cpfW3I5jINkWe5BIY5md0ofy+1TCIELsVcm/GJXZSaPbw==} + dev: true + + /quick-lru@4.0.1: + resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} engines: {node: '>=8'} dev: false - /trim-right@1.0.1: - resolution: {integrity: sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw==} - engines: {node: '>=0.10.0'} + /quick-lru@5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} dev: true - /ts-api-utils@1.0.3(typescript@5.3.3): - resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} - engines: {node: '>=16.13.0'} - peerDependencies: - typescript: '>=4.2.0' + /randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} dependencies: - typescript: 5.3.3 + safe-buffer: 5.2.1 dev: true - /ts-command-line-args@2.5.1: - resolution: {integrity: sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw==} - hasBin: true + /raw-body@2.5.1: + resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==} + engines: {node: '>= 0.8'} dependencies: - chalk: 4.1.2 - command-line-args: 5.2.1 - command-line-usage: 6.1.3 - string-format: 2.0.0 - dev: true - - /ts-essentials@1.0.4: - resolution: {integrity: sha512-q3N1xS4vZpRouhYHDPwO0bDW3EZ6SK9CrrDHxi/D6BPReSjpVgWIOpLS2o0gSBZm+7q/wyKp6RVM1AeeW7uyfQ==} + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 dev: true - /ts-essentials@6.0.7(typescript@5.3.3): - resolution: {integrity: sha512-2E4HIIj4tQJlIHuATRHayv0EfMGK3ris/GRk1E3CFnsZzeNV+hUmelbaTZHLtXaZppM5oLhHRtO04gINC4Jusw==} - peerDependencies: - typescript: '>=3.7.0' + /rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true dependencies: - typescript: 5.3.3 + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 dev: true - /ts-essentials@7.0.3(typescript@5.3.3): - resolution: {integrity: sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==} - peerDependencies: - typescript: '>=3.7.0' + /read-pkg-up@7.0.1: + resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} + engines: {node: '>=8'} dependencies: - typescript: 5.3.3 - dev: true + find-up: 4.1.0 + read-pkg: 5.2.0 + type-fest: 0.8.1 + dev: false - /ts-generator@0.1.1: - resolution: {integrity: sha512-N+ahhZxTLYu1HNTQetwWcx3so8hcYbkKBHTr4b4/YgObFTIKkOSSsaa+nal12w8mfrJAyzJfETXawbNjSfP2gQ==} - hasBin: true + /read-pkg@5.2.0: + resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} + engines: {node: '>=8'} dependencies: - '@types/mkdirp': 0.5.2 - '@types/prettier': 2.7.1 - '@types/resolve': 0.0.8 - chalk: 2.4.2 - glob: 7.2.3 - mkdirp: 0.5.6 - prettier: 2.8.8 - resolve: 1.22.1 - ts-essentials: 1.0.4 - dev: true + '@types/normalize-package-data': 2.4.4 + normalize-package-data: 2.5.0 + parse-json: 5.2.0 + type-fest: 0.6.0 + dev: false - /ts-node@10.9.2(@types/node@16.18.80)(typescript@5.3.3): - resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true + /read-yaml-file@1.1.0: + resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} + engines: {node: '>=6'} dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.9 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.3 - '@types/node': 16.18.80 - acorn: 8.10.0 - acorn-walk: 8.2.0 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.3.3 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - dev: true - - /tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - dev: true + graceful-fs: 4.2.10 + js-yaml: 3.14.1 + pify: 4.0.1 + strip-bom: 3.0.0 + dev: false - /tslib@2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + /readable-stream@3.6.0: + resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 dev: true - /tsort@0.0.1: - resolution: {integrity: sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==} + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 dev: true - /tty-table@4.2.3: - resolution: {integrity: sha512-Fs15mu0vGzCrj8fmJNP7Ynxt5J7praPXqFN0leZeZBXJwkMxv9cb2D454k1ltrtUSJbZ4yH4e0CynsHLxmUfFA==} - engines: {node: '>=8.0.0'} - hasBin: true + /redent@3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} dependencies: - chalk: 4.1.2 - csv: 5.5.3 - kleur: 4.1.5 - smartwrap: 2.0.2 - strip-ansi: 6.0.1 - wcwidth: 1.0.1 - yargs: 17.7.2 + indent-string: 4.0.0 + strip-indent: 3.0.0 dev: false - /tunnel-agent@0.6.0: - resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} - dependencies: - safe-buffer: 5.2.1 - dev: true - - /tweetnacl-util@0.15.1: - resolution: {integrity: sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==} + /reduce-flatten@2.0.0: + resolution: {integrity: sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==} + engines: {node: '>=6'} dev: true - /tweetnacl@0.14.5: - resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} - dev: true + /regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - /tweetnacl@1.0.3: - resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==} - dev: true + /regexp.prototype.flags@1.5.1: + resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + set-function-name: 2.0.1 + dev: false - /type-check@0.3.2: - resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} - engines: {node: '>= 0.8.0'} + /registry-auth-token@5.0.2: + resolution: {integrity: sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==} + engines: {node: '>=14'} dependencies: - prelude-ls: 1.1.2 + '@pnpm/npm-conf': 2.2.2 dev: true - /type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} + /registry-url@6.0.1: + resolution: {integrity: sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==} + engines: {node: '>=12'} dependencies: - prelude-ls: 1.2.1 + rc: 1.2.8 dev: true - /type-detect@4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} - engines: {node: '>=4'} - - /type-fest@0.13.1: - resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} - engines: {node: '>=10'} - dev: false - - /type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - dev: true + /require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} - /type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} + /require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} dev: true - /type-fest@0.6.0: - resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} - engines: {node: '>=8'} + /require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} dev: false - /type-fest@0.7.1: - resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} - engines: {node: '>=8'} + /resolve-alpn@1.2.1: + resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} dev: true - /type-fest@0.8.1: - resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} + /resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: true + + /resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} dev: false - /type-is@1.6.18: - resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} - engines: {node: '>= 0.6'} - requiresBuild: true + /resolve@1.17.0: + resolution: {integrity: sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==} dependencies: - media-typer: 0.3.0 - mime-types: 2.1.27 + path-parse: 1.0.7 dev: true - /type@1.2.0: - resolution: {integrity: sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==} - dev: true + /resolve@1.22.1: + resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} + hasBin: true + dependencies: + is-core-module: 2.10.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: false - /type@2.0.0: - resolution: {integrity: sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==} + /responselike@2.0.1: + resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} + dependencies: + lowercase-keys: 2.0.0 dev: true - /typechain@3.0.0(typescript@5.3.3): - resolution: {integrity: sha512-ft4KVmiN3zH4JUFu2WJBrwfHeDf772Tt2d8bssDTo/YcckKW2D+OwFrHXRC6hJvO3mHjFQTihoMV6fJOi0Hngg==} + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + /rimraf@2.7.1: + resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} hasBin: true dependencies: - command-line-args: 4.0.7 - debug: 4.3.4(supports-color@8.1.1) - fs-extra: 7.0.1 - js-sha3: 0.8.0 - lodash: 4.17.21 - ts-essentials: 6.0.7(typescript@5.3.3) - ts-generator: 0.1.1 - transitivePeerDependencies: - - supports-color - - typescript + glob: 7.2.3 dev: true - /typechain@8.3.2(typescript@5.3.3): - resolution: {integrity: sha512-x/sQYr5w9K7yv3es7jo4KTX05CLxOf7TRWwoHlrjRh8H82G64g+k7VuWPJlgMo6qrjfCulOdfBjiaDtmhFYD/Q==} + /rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} hasBin: true - peerDependencies: - typescript: '>=4.3.0' dependencies: - '@types/prettier': 2.7.1 - debug: 4.3.4(supports-color@8.1.1) - fs-extra: 7.0.1 - glob: 7.1.7 - js-sha3: 0.8.0 - lodash: 4.17.21 - mkdirp: 1.0.4 - prettier: 2.8.8 - ts-command-line-args: 2.5.1 - ts-essentials: 7.0.3(typescript@5.3.3) - typescript: 5.3.3 - transitivePeerDependencies: - - supports-color + glob: 7.2.3 dev: true - /typed-array-buffer@1.0.0: - resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} - engines: {node: '>= 0.4'} + /ripemd160@2.0.2: + resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} dependencies: - call-bind: 1.0.5 - get-intrinsic: 1.2.2 - is-typed-array: 1.1.12 + hash-base: 3.1.0 + inherits: 2.0.4 + dev: true - /typed-array-byte-length@1.0.0: - resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} - engines: {node: '>= 0.4'} + /rlp@2.2.7: + resolution: {integrity: sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==} + hasBin: true dependencies: - call-bind: 1.0.5 - for-each: 0.3.3 - has-proto: 1.0.1 - is-typed-array: 1.1.12 + bn.js: 5.2.1 + dev: true - /typed-array-byte-offset@1.0.0: - resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} - engines: {node: '>= 0.4'} - dependencies: - available-typed-arrays: 1.0.5 - call-bind: 1.0.5 - for-each: 0.3.3 - has-proto: 1.0.1 - is-typed-array: 1.1.12 + /run-parallel@1.1.9: + resolution: {integrity: sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==} - /typed-array-length@1.0.4: - resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} - dependencies: - call-bind: 1.0.5 - for-each: 0.3.3 - is-typed-array: 1.1.12 + /rust-verkle-wasm@0.0.1: + resolution: {integrity: sha512-BN6fiTsxcd2dCECz/cHtGTt9cdLJR925nh7iAuRcj8ymKw7OOaPmCneQZ7JePOJ/ia27TjEL91VdOi88Yf+mcA==} + dev: true - /typedarray-to-buffer@3.1.5: - resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} + /rustbn-wasm@0.2.0: + resolution: {integrity: sha512-FThvYFNTqrEKGqXuseeg0zR7yROh/6U1617mCHF68OVqrN1tNKRN7Tdwy4WayPVsCmmK+eMxtIZX1qL6JxTkMg==} dependencies: - is-typedarray: 1.0.0 + '@scure/base': 1.1.1 dev: true - /typedarray@0.0.6: - resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - dev: true + /safe-array-concat@1.0.1: + resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==} + engines: {node: '>=0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + has-symbols: 1.0.3 + isarray: 2.0.5 + dev: false - /typescript@5.3.3: - resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} - engines: {node: '>=14.17'} - hasBin: true + /safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} dev: true - /typewise-core@1.2.0: - resolution: {integrity: sha512-2SCC/WLzj2SbUwzFOzqMCkz5amXLlxtJqDKTICqg30x+2DZxcfZN2MvQZmGfXWKNWaKK9pBPsvkcwv8bF/gxKg==} + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} dev: true - /typewise@1.0.3: - resolution: {integrity: sha512-aXofE06xGhaQSPzt8hlTY+/YWQhm9P0jYUp1f2XtmW/3Bk0qzXcyFWAtPoo2uTGQj1ZwbDuSyuxicq+aDo8lCQ==} + /safe-regex-test@1.0.0: + resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} dependencies: - typewise-core: 1.2.0 - dev: true + call-bind: 1.0.2 + get-intrinsic: 1.1.3 + is-regex: 1.1.4 + dev: false - /typewiselite@1.0.0: - resolution: {integrity: sha512-J9alhjVHupW3Wfz6qFRGgQw0N3gr8hOkw6zm7FZ6UR1Cse/oD9/JVok7DNE9TT9IbciDHX2Ex9+ksE6cRmtymw==} - dev: true + /safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - /typical@2.6.1: - resolution: {integrity: sha512-ofhi8kjIje6npGozTip9Fr8iecmYfEbS06i0JnIg+rh51KakryWF4+jX8lLKZVhy6N+ID45WYSFCxPOdTWCzNg==} - dev: true + /scrypt-js@3.0.1: + resolution: {integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==} - /typical@4.0.0: - resolution: {integrity: sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==} - engines: {node: '>=8'} + /secp256k1@4.0.3: + resolution: {integrity: sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==} + engines: {node: '>=10.0.0'} + requiresBuild: true + dependencies: + elliptic: 6.5.4 + node-addon-api: 2.0.2 + node-gyp-build: 4.5.0 dev: true - /typical@5.2.0: - resolution: {integrity: sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==} - engines: {node: '>=8'} + /semver@5.7.1: + resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} + hasBin: true + + /semver@6.3.0: + resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} + hasBin: true dev: true - /uglify-js@3.17.3: - resolution: {integrity: sha512-JmMFDME3iufZnBpyKL+uS78LRiC+mK55zWfM5f/pWBJfpOttXAqYfdDGRukYhJuyRinvPVAtUhvy7rlDybNtFg==} - engines: {node: '>=0.8.0'} + /semver@7.6.0: + resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} + engines: {node: '>=10'} hasBin: true - requiresBuild: true + dependencies: + lru-cache: 6.0.0 + + /sentence-case@2.1.1: + resolution: {integrity: sha512-ENl7cYHaK/Ktwk5OTD+aDbQ3uC8IByu/6Bkg+HDv8Mm+XnBnppVNalcfJTNsp1ibstKh030/JKQQWglDvtKwEQ==} + dependencies: + no-case: 2.3.2 + upper-case-first: 1.1.2 dev: true - optional: true - /ultron@1.1.1: - resolution: {integrity: sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==} - requiresBuild: true + /serialize-javascript@6.0.0: + resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} + dependencies: + randombytes: 2.1.0 dev: true - /unbox-primitive@1.0.2: - resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + /set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + dev: false + + /set-function-length@1.1.1: + resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - has-bigints: 1.0.2 - has-symbols: 1.0.3 - which-boxed-primitive: 1.0.2 + define-data-property: 1.1.1 + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.0 + dev: false - /underscore@1.9.1: - resolution: {integrity: sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==} - requiresBuild: true + /set-function-name@2.0.1: + resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.0 + dev: false + + /setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} dev: true - optional: true - /undici@5.19.1: - resolution: {integrity: sha512-YiZ61LPIgY73E7syxCDxxa3LV2yl3sN8spnIuTct60boiiRaE1J8mNWHO8Im2Zi/sFrPusjLlmRPrsyraSqX6A==} - engines: {node: '>=12.18'} + /setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + dev: true + + /sha.js@2.4.11: + resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} + hasBin: true dependencies: - busboy: 1.6.0 + inherits: 2.0.4 + safe-buffer: 5.2.1 dev: true - /unfetch@4.2.0: - resolution: {integrity: sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==} + /shallowequal@1.1.0: + resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} dev: true - /union-value@1.0.1: - resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==} + /shebang-command@1.2.0: + resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} engines: {node: '>=0.10.0'} dependencies: - arr-union: 3.1.0 - get-value: 2.0.6 - is-extendable: 0.1.1 - set-value: 2.0.1 - dev: true - - /universalify@0.1.2: - resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} - engines: {node: '>= 4.0.0'} + shebang-regex: 1.0.0 + dev: false - /universalify@2.0.0: - resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} - engines: {node: '>= 10.0.0'} + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 dev: true - /unorm@1.6.0: - resolution: {integrity: sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==} - engines: {node: '>= 0.4.0'} - dev: true + /shebang-regex@1.0.0: + resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} + engines: {node: '>=0.10.0'} + dev: false - /unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} dev: true - /unset-value@1.0.0: - resolution: {integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==} - engines: {node: '>=0.10.0'} + /side-channel@1.0.4: + resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} dependencies: - has-value: 0.3.1 - isobject: 3.0.1 - dev: true + call-bind: 1.0.5 + get-intrinsic: 1.1.3 + object-inspect: 1.12.2 + dev: false - /upper-case-first@1.1.2: - resolution: {integrity: sha512-wINKYvI3Db8dtjikdAqoBbZoP6Q+PZUyfMR7pmwHzjC2quzSkUq5DmPrTtPEqHaz8AGtmsB4TqwapMTM1QAQOQ==} + /signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + dev: false + + /slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + /slice-ansi@4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} dependencies: - upper-case: 1.1.3 + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 dev: true - /upper-case@1.1.3: - resolution: {integrity: sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==} - dev: true + /smartwrap@2.0.2: + resolution: {integrity: sha512-vCsKNQxb7PnCNd2wY1WClWifAc2lwqsG8OaswpJkVJsvMGcnEntdTCDajZCkk93Ay1U3t/9puJmb525Rg5MZBA==} + engines: {node: '>=6'} + hasBin: true + dependencies: + array.prototype.flat: 1.3.2 + breakword: 1.0.6 + grapheme-splitter: 1.0.4 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + yargs: 15.4.1 + dev: false - /uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + /snake-case@2.1.0: + resolution: {integrity: sha512-FMR5YoPFwOLuh4rRz92dywJjyKYZNLpMn1R5ujVpIYkbA9p01fq8RMg0FkO4M+Yobt4MjHeLTJVm5xFFBHSV2Q==} dependencies: - punycode: 2.1.1 + no-case: 2.3.2 dev: true - /urix@0.1.0: - resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==} - deprecated: Please see https://github.com/lydell/urix#deprecated + /solc@0.7.3(debug@4.3.4): + resolution: {integrity: sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==} + engines: {node: '>=8.0.0'} + hasBin: true + dependencies: + command-exists: 1.2.9 + commander: 3.0.2 + follow-redirects: 1.15.2(debug@4.3.4) + fs-extra: 0.30.0 + js-sha3: 0.8.0 + memorystream: 0.3.1 + require-from-string: 2.0.2 + semver: 5.7.1 + tmp: 0.0.33 + transitivePeerDependencies: + - debug dev: true - /url-parse-lax@1.0.0: - resolution: {integrity: sha512-BVA4lR5PIviy2PMseNd2jbFQ+jwSwQGdJejf5ctd1rEXt0Ypd7yanUK9+lYechVlN5VaTJGsu2U/3MDDu6KgBA==} - engines: {node: '>=0.10.0'} - requiresBuild: true + /solhint-plugin-prettier@0.1.0(prettier-plugin-solidity@1.3.1)(prettier@3.2.5): + resolution: {integrity: sha512-SDOTSM6tZxZ6hamrzl3GUgzF77FM6jZplgL2plFBclj/OjKP8Z3eIPojKU73gRr0MvOS8ACZILn8a5g0VTz/Gw==} + peerDependencies: + prettier: ^3.0.0 + prettier-plugin-solidity: ^1.0.0 dependencies: - prepend-http: 1.0.4 + '@prettier/sync': 0.3.0(prettier@3.2.5) + prettier: 3.2.5 + prettier-linter-helpers: 1.0.0 + prettier-plugin-solidity: 1.3.1(prettier@3.2.5) dev: true - /url-parse-lax@3.0.0: - resolution: {integrity: sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==} - engines: {node: '>=4'} - requiresBuild: true + /solhint@4.5.2: + resolution: {integrity: sha512-o7MNYS5QPgE6l+PTGOTAUtCzo0ZLnffQsv586hntSHBe2JbSDfkoxfhAOcjZjN4OesTgaX4UEEjCjH9y/4BP5w==} + hasBin: true dependencies: - prepend-http: 2.0.0 + '@solidity-parser/parser': 0.18.0 + ajv: 6.12.6 + antlr4: 4.13.1-patch-1 + ast-parents: 0.0.1 + chalk: 4.1.2 + commander: 10.0.1 + cosmiconfig: 8.2.0 + fast-diff: 1.2.0 + glob: 8.1.0 + ignore: 5.2.4 + js-yaml: 4.1.0 + latest-version: 7.0.0 + lodash: 4.17.21 + pluralize: 8.0.0 + semver: 7.6.0 + strip-ansi: 6.0.1 + table: 6.8.1 + text-table: 0.2.0 + optionalDependencies: + prettier: 2.8.8 dev: true - /url-set-query@1.0.0: - resolution: {integrity: sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg==} + /solidity-comments-darwin-arm64@0.0.2: + resolution: {integrity: sha512-HidWkVLSh7v+Vu0CA7oI21GWP/ZY7ro8g8OmIxE8oTqyMwgMbE8F1yc58Sj682Hj199HCZsjmtn1BE4PCbLiGA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] requiresBuild: true dev: true + optional: true - /url-to-options@1.0.1: - resolution: {integrity: sha512-0kQLIzG4fdk/G5NONku64rSH/x32NOA39LVQqlK8Le6lvTF6GGRJpqaQFGgU+CLwySIqBSMdwYM0sYcW9f6P4A==} - engines: {node: '>= 4'} + /solidity-comments-darwin-x64@0.0.2: + resolution: {integrity: sha512-Zjs0Ruz6faBTPT6fBecUt6qh4CdloT8Bwoc0+qxRoTn9UhYscmbPQkUgQEbS0FQPysYqVzzxJB4h1Ofbf4wwtA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] requiresBuild: true dev: true + optional: true - /url@0.11.0: - resolution: {integrity: sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==} - dependencies: - punycode: 1.3.2 - querystring: 0.2.0 - dev: true - - /use@3.1.1: - resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==} - engines: {node: '>=0.10.0'} + /solidity-comments-extractor@0.0.8: + resolution: {integrity: sha512-htM7Vn6LhHreR+EglVMd2s+sZhcXAirB1Zlyrv5zBuTxieCvjfnRpd7iZk75m/u6NOlEyQ94C6TWbBn2cY7w8g==} dev: true - /utf-8-validate@5.0.9: - resolution: {integrity: sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q==} - engines: {node: '>=6.14.2'} + /solidity-comments-freebsd-x64@0.0.2: + resolution: {integrity: sha512-8Qe4mpjuAxFSwZJVk7B8gAoLCdbtS412bQzBwk63L8dmlHogvE39iT70aAk3RHUddAppT5RMBunlPUCFYJ3ZTw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] requiresBuild: true - dependencies: - node-gyp-build: 4.5.0 - dev: true - - /utf8@3.0.0: - resolution: {integrity: sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==} dev: true + optional: true - /util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + /solidity-comments-linux-arm64-gnu@0.0.2: + resolution: {integrity: sha512-spkb0MZZnmrP+Wtq4UxP+nyPAVRe82idOjqndolcNR0S9Xvu4ebwq+LvF4HiUgjTDmeiqYiFZQ8T9KGdLSIoIg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true dev: true + optional: true - /util.promisify@1.1.1: - resolution: {integrity: sha512-/s3UsZUrIfa6xDhr7zZhnE9SLQ5RIXyYfiVnMMyMDzOc8WhWN4Nbh36H842OyurKbCDAesZOJaVyvmSl6fhGQw==} - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - for-each: 0.3.3 - has-symbols: 1.0.3 - object.getownpropertydescriptors: 2.1.4 + /solidity-comments-linux-arm64-musl@0.0.2: + resolution: {integrity: sha512-guCDbHArcjE+JDXYkxx5RZzY1YF6OnAKCo+sTC5fstyW/KGKaQJNPyBNWuwYsQiaEHpvhW1ha537IvlGek8GqA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true dev: true + optional: true - /util@0.12.3: - resolution: {integrity: sha512-I8XkoQwE+fPQEhy9v012V+TSdH2kp9ts29i20TaaDUXsg7x/onePbhFJUExBfv/2ay1ZOp/Vsm3nDlmnFGSAog==} - dependencies: - inherits: 2.0.4 - is-arguments: 1.0.4 - is-generator-function: 1.0.8 - is-typed-array: 1.1.5 - safe-buffer: 5.2.1 - which-typed-array: 1.1.4 + /solidity-comments-linux-x64-gnu@0.0.2: + resolution: {integrity: sha512-zIqLehBK/g7tvrFmQljrfZXfkEeLt2v6wbe+uFu6kH/qAHZa7ybt8Vc0wYcmjo2U0PeBm15d79ee3AkwbIjFdQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true dev: true + optional: true - /utils-merge@1.0.1: - resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} - engines: {node: '>= 0.4.0'} + /solidity-comments-linux-x64-musl@0.0.2: + resolution: {integrity: sha512-R9FeDloVlFGTaVkOlELDVC7+1Tjx5WBPI5L8r0AGOPHK3+jOcRh6sKYpI+VskSPDc3vOO46INkpDgUXrKydlIw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] requiresBuild: true dev: true + optional: true - /uuid@2.0.1: - resolution: {integrity: sha512-nWg9+Oa3qD2CQzHIP4qKUqwNfzKn8P0LtFhotaCTFchsV7ZfDhAybeip/HZVeMIpZi9JgY1E3nUlwaCmZT1sEg==} - deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. + /solidity-comments-win32-arm64-msvc@0.0.2: + resolution: {integrity: sha512-QnWJoCQcJj+rnutULOihN9bixOtYWDdF5Rfz9fpHejL1BtNjdLW1om55XNVHGAHPqBxV4aeQQ6OirKnp9zKsug==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + requiresBuild: true dev: true + optional: true - /uuid@3.3.2: - resolution: {integrity: sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==} - deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. - hasBin: true + /solidity-comments-win32-ia32-msvc@0.0.2: + resolution: {integrity: sha512-vUg4nADtm/NcOtlIymG23NWJUSuMsvX15nU7ynhGBsdKtt8xhdP3C/zA6vjDk8Jg+FXGQL6IHVQ++g/7rSQi0w==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + requiresBuild: true dev: true + optional: true - /uuid@3.4.0: - resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} - deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. - hasBin: true + /solidity-comments-win32-x64-msvc@0.0.2: + resolution: {integrity: sha512-36j+KUF4V/y0t3qatHm/LF5sCUCBx2UndxE1kq5bOzh/s+nQgatuyB+Pd5BfuPQHdWu2KaExYe20FlAa6NL7+Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + requiresBuild: true dev: true + optional: true - /uuid@8.3.2: - resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} - hasBin: true + /solidity-comments@0.0.2: + resolution: {integrity: sha512-G+aK6qtyUfkn1guS8uzqUeua1dURwPlcOjoTYW/TwmXAcE7z/1+oGCfZUdMSe4ZMKklNbVZNiG5ibnF8gkkFfw==} + engines: {node: '>= 12'} + optionalDependencies: + solidity-comments-darwin-arm64: 0.0.2 + solidity-comments-darwin-x64: 0.0.2 + solidity-comments-freebsd-x64: 0.0.2 + solidity-comments-linux-arm64-gnu: 0.0.2 + solidity-comments-linux-arm64-musl: 0.0.2 + solidity-comments-linux-x64-gnu: 0.0.2 + solidity-comments-linux-x64-musl: 0.0.2 + solidity-comments-win32-arm64-msvc: 0.0.2 + solidity-comments-win32-ia32-msvc: 0.0.2 + solidity-comments-win32-x64-msvc: 0.0.2 dev: true - /v8-compile-cache-lib@3.0.1: - resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + /sort-any@2.0.0: + resolution: {integrity: sha512-T9JoiDewQEmWcnmPn/s9h/PH9t3d/LSWi0RgVmXSuDYeZXTZOZ1/wrK2PHaptuR1VXe3clLLt0pD6sgVOwjNEA==} + dependencies: + lodash: 4.17.21 dev: true - /validate-npm-package-license@3.0.4: - resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + /source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} dependencies: - spdx-correct: 3.1.1 - spdx-expression-parse: 3.0.1 - - /varint@5.0.2: - resolution: {integrity: sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==} - requiresBuild: true + buffer-from: 1.1.2 + source-map: 0.6.1 dev: true - /vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - requiresBuild: true + /source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} dev: true - /verror@1.10.0: - resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} - engines: {'0': node >=0.6.0} + /spawndamnit@2.0.0: + resolution: {integrity: sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==} dependencies: - assert-plus: 1.0.0 - core-util-is: 1.0.2 - extsprintf: 1.4.0 - dev: true + cross-spawn: 5.1.0 + signal-exit: 3.0.7 + dev: false - /wcwidth@1.0.1: - resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + /spdx-correct@3.1.1: + resolution: {integrity: sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==} dependencies: - defaults: 1.0.4 + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.12 dev: false - /web3-bzz@1.2.11: - resolution: {integrity: sha512-XGpWUEElGypBjeFyUhTkiPXFbDVD6Nr/S5jznE3t8cWUA0FxRf1n3n/NuIZeb0H9RkN2Ctd/jNma/k8XGa3YKg==} - engines: {node: '>=8.0.0'} - requiresBuild: true - dependencies: - '@types/node': 12.19.16 - got: 9.6.0 - swarm-js: 0.1.40 - underscore: 1.9.1 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - optional: true + /spdx-exceptions@2.3.0: + resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} + dev: false - /web3-bzz@1.7.4: - resolution: {integrity: sha512-w9zRhyEqTK/yi0LGRHjZMcPCfP24LBjYXI/9YxFw9VqsIZ9/G0CRCnUt12lUx0A56LRAMpF7iQ8eA73aBcO29Q==} - engines: {node: '>=8.0.0'} - requiresBuild: true + /spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} dependencies: - '@types/node': 12.19.16 - got: 9.6.0 - swarm-js: 0.1.40 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true + spdx-exceptions: 2.3.0 + spdx-license-ids: 3.0.12 + dev: false - /web3-bzz@1.8.0: - resolution: {integrity: sha512-caDtdKeLi7+2Vb+y+cq2yyhkNjnxkFzVW0j1DtemarBg3dycG1iEl75CVQMLNO6Wkg+HH9tZtRnUyFIe5LIUeQ==} - engines: {node: '>=8.0.0'} - requiresBuild: true - dependencies: - '@types/node': 12.19.16 - got: 12.1.0 - swarm-js: 0.1.40 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true + /spdx-license-ids@3.0.12: + resolution: {integrity: sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==} + dev: false + + /sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + dev: false - /web3-core-helpers@1.2.11: - resolution: {integrity: sha512-PEPoAoZd5ME7UfbnCZBdzIerpe74GEvlwT4AjOmHeCVZoIFk7EqvOZDejJHt+feJA6kMVTdd0xzRNN295UhC1A==} - engines: {node: '>=8.0.0'} - requiresBuild: true + /stacktrace-parser@0.1.10: + resolution: {integrity: sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==} + engines: {node: '>=6'} dependencies: - underscore: 1.9.1 - web3-eth-iban: 1.2.11 - web3-utils: 1.2.11 + type-fest: 0.7.1 dev: true - optional: true - /web3-core-helpers@1.7.4: - resolution: {integrity: sha512-F8PH11qIkE/LpK4/h1fF/lGYgt4B6doeMi8rukeV/s4ivseZHHslv1L6aaijLX/g/j4PsFmR42byynBI/MIzFg==} - engines: {node: '>=8.0.0'} - dependencies: - web3-eth-iban: 1.7.4 - web3-utils: 1.7.4 + /statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} dev: true - /web3-core-helpers@1.8.0: - resolution: {integrity: sha512-nMAVwZB3rEp/khHI2BvFy0e/xCryf501p5NGjswmJtEM+Zrd3Biaw52JrB1qAZZIzCA8cmLKaOgdfamoDOpWdw==} - engines: {node: '>=8.0.0'} + /stream-transform@2.1.3: + resolution: {integrity: sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==} dependencies: - web3-eth-iban: 1.8.0 - web3-utils: 1.8.0 - dev: true + mixme: 0.5.10 + dev: false - /web3-core-method@1.2.11: - resolution: {integrity: sha512-ff0q76Cde94HAxLDZ6DbdmKniYCQVtvuaYh+rtOUMB6kssa5FX0q3vPmixi7NPooFnbKmmZCM6NvXg4IreTPIw==} - engines: {node: '>=8.0.0'} - requiresBuild: true - dependencies: - '@ethersproject/transactions': 5.7.0 - underscore: 1.9.1 - web3-core-helpers: 1.2.11 - web3-core-promievent: 1.2.11 - web3-core-subscriptions: 1.2.11 - web3-utils: 1.2.11 + /streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} dev: true - optional: true - /web3-core-method@1.7.4: - resolution: {integrity: sha512-56K7pq+8lZRkxJyzf5MHQPI9/VL3IJLoy4L/+q8HRdZJ3CkB1DkXYaXGU2PeylG1GosGiSzgIfu1ljqS7CP9xQ==} - engines: {node: '>=8.0.0'} - dependencies: - '@ethersproject/transactions': 5.7.0 - web3-core-helpers: 1.7.4 - web3-core-promievent: 1.7.4 - web3-core-subscriptions: 1.7.4 - web3-utils: 1.7.4 + /string-format@2.0.0: + resolution: {integrity: sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==} dev: true - /web3-core-method@1.8.0: - resolution: {integrity: sha512-c94RAzo3gpXwf2rf8rL8C77jOzNWF4mXUoUfZYYsiY35cJFd46jQDPI00CB5+ZbICTiA5mlVzMj4e7jAsTqiLA==} - engines: {node: '>=8.0.0'} + /string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} dependencies: - '@ethersproject/transactions': 5.7.0 - web3-core-helpers: 1.8.0 - web3-core-promievent: 1.8.0 - web3-core-subscriptions: 1.8.0 - web3-utils: 1.8.0 - dev: true + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 - /web3-core-promievent@1.2.11: - resolution: {integrity: sha512-il4McoDa/Ox9Agh4kyfQ8Ak/9ABYpnF8poBLL33R/EnxLsJOGQG2nZhkJa3I067hocrPSjEdlPt/0bHXsln4qA==} - engines: {node: '>=8.0.0'} - requiresBuild: true + /string.prototype.trim@1.2.8: + resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} + engines: {node: '>= 0.4'} dependencies: - eventemitter3: 4.0.4 - dev: true - optional: true + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: false - /web3-core-promievent@1.7.4: - resolution: {integrity: sha512-o4uxwXKDldN7ER7VUvDfWsqTx9nQSP1aDssi1XYXeYC2xJbVo0n+z6ryKtmcoWoRdRj7uSpVzal3nEmlr480mA==} - engines: {node: '>=8.0.0'} + /string.prototype.trimend@1.0.7: + resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} dependencies: - eventemitter3: 4.0.4 - dev: true + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: false - /web3-core-promievent@1.8.0: - resolution: {integrity: sha512-FGLyjAuOaAQ+ZhV6iuw9tg/9WvIkSZXKHQ4mdTyQ8MxVraOtFivOCbuLLsGgapfHYX+RPxsc1j1YzQjKoupagQ==} - engines: {node: '>=8.0.0'} + /string.prototype.trimstart@1.0.7: + resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} dependencies: - eventemitter3: 4.0.4 - dev: true + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: false - /web3-core-requestmanager@1.2.11: - resolution: {integrity: sha512-oFhBtLfOiIbmfl6T6gYjjj9igOvtyxJ+fjS+byRxiwFJyJ5BQOz4/9/17gWR1Cq74paTlI7vDGxYfuvfE/mKvA==} - engines: {node: '>=8.0.0'} - requiresBuild: true + /string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} dependencies: - underscore: 1.9.1 - web3-core-helpers: 1.2.11 - web3-providers-http: 1.2.11 - web3-providers-ipc: 1.2.11 - web3-providers-ws: 1.2.11 - transitivePeerDependencies: - - supports-color + safe-buffer: 5.2.1 dev: true - optional: true - /web3-core-requestmanager@1.7.4: - resolution: {integrity: sha512-IuXdAm65BQtPL4aI6LZJJOrKAs0SM5IK2Cqo2/lMNvVMT9Kssq6qOk68Uf7EBDH0rPuINi+ReLP+uH+0g3AnPA==} - engines: {node: '>=8.0.0'} + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} dependencies: - util: 0.12.3 - web3-core-helpers: 1.7.4 - web3-providers-http: 1.7.4 - web3-providers-ipc: 1.7.4 - web3-providers-ws: 1.7.4 - transitivePeerDependencies: - - supports-color - dev: true + ansi-regex: 5.0.1 - /web3-core-requestmanager@1.8.0: - resolution: {integrity: sha512-2AoYCs3Owl5foWcf4uKPONyqFygSl9T54L8b581U16nsUirjhoTUGK/PBhMDVcLCmW4QQmcY5A8oPFpkQc1TTg==} - engines: {node: '>=8.0.0'} + /strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + dev: false + + /strip-hex-prefix@1.0.0: + resolution: {integrity: sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==} + engines: {node: '>=6.5.0', npm: '>=3'} dependencies: - util: 0.12.3 - web3-core-helpers: 1.8.0 - web3-providers-http: 1.8.0 - web3-providers-ipc: 1.8.0 - web3-providers-ws: 1.8.0 - transitivePeerDependencies: - - encoding - - supports-color + is-hex-prefixed: 1.0.0 dev: true - /web3-core-subscriptions@1.2.11: - resolution: {integrity: sha512-qEF/OVqkCvQ7MPs1JylIZCZkin0aKK9lDxpAtQ1F8niEDGFqn7DT8E/vzbIa0GsOjL2fZjDhWJsaW+BSoAW1gg==} - engines: {node: '>=8.0.0'} - requiresBuild: true + /strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} dependencies: - eventemitter3: 4.0.4 - underscore: 1.9.1 - web3-core-helpers: 1.2.11 + min-indent: 1.0.1 + dev: false + + /strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} dev: true - optional: true - /web3-core-subscriptions@1.7.4: - resolution: {integrity: sha512-VJvKWaXRyxk2nFWumOR94ut9xvjzMrRtS38c4qj8WBIRSsugrZr5lqUwgndtj0qx4F+50JhnU++QEqUEAtKm3g==} - engines: {node: '>=8.0.0'} - dependencies: - eventemitter3: 4.0.4 - web3-core-helpers: 1.7.4 + /strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} dev: true - /web3-core-subscriptions@1.8.0: - resolution: {integrity: sha512-7lHVRzDdg0+Gcog55lG6Q3D8JV+jN+4Ly6F8cSn9xFUAwOkdbgdWsjknQG7t7CDWy21DQkvdiY2BJF8S68AqOA==} - engines: {node: '>=8.0.0'} + /supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} dependencies: - eventemitter3: 4.0.4 - web3-core-helpers: 1.8.0 - dev: true + has-flag: 3.0.0 - /web3-core@1.2.11: - resolution: {integrity: sha512-CN7MEYOY5ryo5iVleIWRE3a3cZqVaLlIbIzDPsvQRUfzYnvzZQRZBm9Mq+ttDi2STOOzc1MKylspz/o3yq/LjQ==} - engines: {node: '>=8.0.0'} - requiresBuild: true + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} dependencies: - '@types/bn.js': 4.11.6 - '@types/node': 12.19.16 - bignumber.js: 9.1.0 - web3-core-helpers: 1.2.11 - web3-core-method: 1.2.11 - web3-core-requestmanager: 1.2.11 - web3-utils: 1.2.11 - transitivePeerDependencies: - - supports-color - dev: true - optional: true + has-flag: 4.0.0 - /web3-core@1.7.4: - resolution: {integrity: sha512-L0DCPlIh9bgIED37tYbe7bsWrddoXYc897ANGvTJ6MFkSNGiMwDkTLWSgYd9Mf8qu8b4iuPqXZHMwIo4atoh7Q==} - engines: {node: '>=8.0.0'} + /supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} dependencies: - '@types/bn.js': 5.1.1 - '@types/node': 12.19.16 - bignumber.js: 9.1.0 - web3-core-helpers: 1.7.4 - web3-core-method: 1.7.4 - web3-core-requestmanager: 1.7.4 - web3-utils: 1.7.4 - transitivePeerDependencies: - - supports-color + has-flag: 4.0.0 dev: true - /web3-core@1.8.0: - resolution: {integrity: sha512-9sCA+Z02ci6zoY2bAquFiDjujRwmSKHiSGi4B8IstML8okSytnzXk1izHYSynE7ahIkguhjWAuXFvX76F5rAbA==} - engines: {node: '>=8.0.0'} + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: false + + /swap-case@1.1.2: + resolution: {integrity: sha512-BAmWG6/bx8syfc6qXPprof3Mn5vQgf5dwdUNJhsNqU9WdPt5P+ES/wQ5bxfijy8zwZgZZHslC3iAsxsuQMCzJQ==} dependencies: - '@types/bn.js': 5.1.1 - '@types/node': 12.19.16 - bignumber.js: 9.1.0 - web3-core-helpers: 1.8.0 - web3-core-method: 1.8.0 - web3-core-requestmanager: 1.8.0 - web3-utils: 1.8.0 - transitivePeerDependencies: - - encoding - - supports-color + lower-case: 1.1.4 + upper-case: 1.1.3 dev: true - /web3-eth-abi@1.2.11: - resolution: {integrity: sha512-PkRYc0+MjuLSgg03QVWqWlQivJqRwKItKtEpRUaxUAeLE7i/uU39gmzm2keHGcQXo3POXAbOnMqkDvOep89Crg==} - engines: {node: '>=8.0.0'} - requiresBuild: true + /synckit@0.8.8: + resolution: {integrity: sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==} + engines: {node: ^14.18.0 || >=16.0.0} dependencies: - '@ethersproject/abi': 5.0.0-beta.153 - underscore: 1.9.1 - web3-utils: 1.2.11 + '@pkgr/core': 0.1.1 + tslib: 2.6.2 dev: true - optional: true - /web3-eth-abi@1.7.4: - resolution: {integrity: sha512-eMZr8zgTbqyL9MCTCAvb67RbVyN5ZX7DvA0jbLOqRWCiw+KlJKTGnymKO6jPE8n5yjk4w01e165Qb11hTDwHgg==} + /table-layout@1.0.2: + resolution: {integrity: sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==} engines: {node: '>=8.0.0'} dependencies: - '@ethersproject/abi': 5.7.0 - web3-utils: 1.7.4 + array-back: 4.0.2 + deep-extend: 0.6.0 + typical: 5.2.0 + wordwrapjs: 4.0.1 dev: true - /web3-eth-abi@1.8.0: - resolution: {integrity: sha512-xPeMb2hS9YLQK/Q5YZpkcmzoRGM+/R8bogSrYHhNC3hjZSSU0YRH+1ZKK0f9YF4qDZaPMI8tKWIMSCDIpjG6fg==} - engines: {node: '>=8.0.0'} + /table@6.8.1: + resolution: {integrity: sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==} + engines: {node: '>=10.0.0'} dependencies: - '@ethersproject/abi': 5.7.0 - web3-utils: 1.8.0 + ajv: 8.11.0 + lodash.truncate: 4.4.2 + slice-ansi: 4.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 dev: true - /web3-eth-accounts@1.2.11: - resolution: {integrity: sha512-6FwPqEpCfKIh3nSSGeo3uBm2iFSnFJDfwL3oS9pyegRBXNsGRVpgiW63yhNzL0796StsvjHWwQnQHsZNxWAkGw==} - engines: {node: '>=8.0.0'} - requiresBuild: true - dependencies: - crypto-browserify: 3.12.0 - eth-lib: 0.2.8 - ethereumjs-common: 1.5.0 - ethereumjs-tx: 2.1.2 - scrypt-js: 3.0.1 - underscore: 1.9.1 - uuid: 3.3.2 - web3-core: 1.2.11 - web3-core-helpers: 1.2.11 - web3-core-method: 1.2.11 - web3-utils: 1.2.11 - transitivePeerDependencies: - - supports-color + /term-size@2.2.1: + resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} + engines: {node: '>=8'} + dev: false + + /text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true - optional: true - /web3-eth-accounts@1.7.4: - resolution: {integrity: sha512-Y9vYLRKP7VU7Cgq6wG1jFaG2k3/eIuiTKAG8RAuQnb6Cd9k5BRqTm5uPIiSo0AP/u11jDomZ8j7+WEgkU9+Btw==} - engines: {node: '>=8.0.0'} + /title-case@2.1.1: + resolution: {integrity: sha512-EkJoZ2O3zdCz3zJsYCsxyq2OC5hrxR9mfdd5I+w8h/tmFfeOxJ+vvkxsKxdmN0WtS9zLdHEgfgVOiMVgv+Po4Q==} dependencies: - '@ethereumjs/common': 2.6.5 - '@ethereumjs/tx': 3.5.2 - crypto-browserify: 3.12.0 - eth-lib: 0.2.8 - ethereumjs-util: 7.1.5 - scrypt-js: 3.0.1 - uuid: 3.3.2 - web3-core: 1.7.4 - web3-core-helpers: 1.7.4 - web3-core-method: 1.7.4 - web3-utils: 1.7.4 - transitivePeerDependencies: - - supports-color + no-case: 2.3.2 + upper-case: 1.1.3 dev: true - /web3-eth-accounts@1.8.0: - resolution: {integrity: sha512-HQ/MDSv4bexwJLvnqsM6xpGE7c2NVOqyhzOZFyMUKXbIwIq85T3TaLnM9pCN7XqMpDcfxqiZ3q43JqQVkzHdmw==} - engines: {node: '>=8.0.0'} + /tmp@0.0.33: + resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} + engines: {node: '>=0.6.0'} dependencies: - '@ethereumjs/common': 2.6.5 - '@ethereumjs/tx': 3.5.2 - crypto-browserify: 3.12.0 - eth-lib: 0.2.8 - ethereumjs-util: 7.1.5 - scrypt-js: 3.0.1 - uuid: 3.3.2 - web3-core: 1.8.0 - web3-core-helpers: 1.8.0 - web3-core-method: 1.8.0 - web3-utils: 1.8.0 - transitivePeerDependencies: - - encoding - - supports-color - dev: true + os-tmpdir: 1.0.2 - /web3-eth-contract@1.2.11: - resolution: {integrity: sha512-MzYuI/Rq2o6gn7vCGcnQgco63isPNK5lMAan2E51AJLknjSLnOxwNY3gM8BcKoy4Z+v5Dv00a03Xuk78JowFow==} - engines: {node: '>=8.0.0'} - requiresBuild: true + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} dependencies: - '@types/bn.js': 4.11.6 - underscore: 1.9.1 - web3-core: 1.2.11 - web3-core-helpers: 1.2.11 - web3-core-method: 1.2.11 - web3-core-promievent: 1.2.11 - web3-core-subscriptions: 1.2.11 - web3-eth-abi: 1.2.11 - web3-utils: 1.2.11 - transitivePeerDependencies: - - supports-color + is-number: 7.0.0 + + /toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} dev: true - optional: true - /web3-eth-contract@1.7.4: - resolution: {integrity: sha512-ZgSZMDVI1pE9uMQpK0T0HDT2oewHcfTCv0osEqf5qyn5KrcQDg1GT96/+S0dfqZ4HKj4lzS5O0rFyQiLPQ8LzQ==} - engines: {node: '>=8.0.0'} - dependencies: - '@types/bn.js': 5.1.1 - web3-core: 1.7.4 - web3-core-helpers: 1.7.4 - web3-core-method: 1.7.4 - web3-core-promievent: 1.7.4 - web3-core-subscriptions: 1.7.4 - web3-eth-abi: 1.7.4 - web3-utils: 1.7.4 - transitivePeerDependencies: - - supports-color + /tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + dev: false + + /trim-newlines@3.0.1: + resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} + engines: {node: '>=8'} + dev: false + + /ts-api-utils@1.0.3(typescript@5.4.3): + resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} + engines: {node: '>=16.13.0'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: 5.4.3 dev: true - /web3-eth-contract@1.8.0: - resolution: {integrity: sha512-6xeXhW2YoCrz2Ayf2Vm4srWiMOB6LawkvxWJDnUWJ8SMATg4Pgu42C/j8rz/enXbYWt2IKuj0kk8+QszxQbK+Q==} - engines: {node: '>=8.0.0'} + /ts-command-line-args@2.5.1: + resolution: {integrity: sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw==} + hasBin: true dependencies: - '@types/bn.js': 5.1.1 - web3-core: 1.8.0 - web3-core-helpers: 1.8.0 - web3-core-method: 1.8.0 - web3-core-promievent: 1.8.0 - web3-core-subscriptions: 1.8.0 - web3-eth-abi: 1.8.0 - web3-utils: 1.8.0 - transitivePeerDependencies: - - encoding - - supports-color + chalk: 4.1.2 + command-line-args: 5.2.1 + command-line-usage: 6.1.3 + string-format: 2.0.0 dev: true - /web3-eth-ens@1.2.11: - resolution: {integrity: sha512-dbW7dXP6HqT1EAPvnniZVnmw6TmQEKF6/1KgAxbo8iBBYrVTMDGFQUUnZ+C4VETGrwwaqtX4L9d/FrQhZ6SUiA==} - engines: {node: '>=8.0.0'} - requiresBuild: true + /ts-essentials@7.0.3(typescript@5.4.3): + resolution: {integrity: sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==} + peerDependencies: + typescript: '>=3.7.0' dependencies: - content-hash: 2.5.2 - eth-ens-namehash: 2.0.8 - underscore: 1.9.1 - web3-core: 1.2.11 - web3-core-helpers: 1.2.11 - web3-core-promievent: 1.2.11 - web3-eth-abi: 1.2.11 - web3-eth-contract: 1.2.11 - web3-utils: 1.2.11 - transitivePeerDependencies: - - supports-color + typescript: 5.4.3 dev: true - optional: true - /web3-eth-ens@1.7.4: - resolution: {integrity: sha512-Gw5CVU1+bFXP5RVXTCqJOmHn71X2ghNk9VcEH+9PchLr0PrKbHTA3hySpsPco1WJAyK4t8SNQVlNr3+bJ6/WZA==} - engines: {node: '>=8.0.0'} + /ts-node@10.9.2(@types/node@16.18.91)(typescript@5.4.3): + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true dependencies: - content-hash: 2.5.2 - eth-ens-namehash: 2.0.8 - web3-core: 1.7.4 - web3-core-helpers: 1.7.4 - web3-core-promievent: 1.7.4 - web3-eth-abi: 1.7.4 - web3-eth-contract: 1.7.4 - web3-utils: 1.7.4 - transitivePeerDependencies: - - supports-color + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.9 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.3 + '@types/node': 16.18.91 + acorn: 8.10.0 + acorn-walk: 8.2.0 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.4.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 dev: true - /web3-eth-ens@1.8.0: - resolution: {integrity: sha512-/eFbQEwvsMOEiOhw9/iuRXCsPkqAmHHWuFOrThQkozRgcnSTRnvxkkRC/b6koiT5/HaKeUs4yQDg+/ixsIxZxA==} - engines: {node: '>=8.0.0'} - dependencies: - content-hash: 2.5.2 - eth-ens-namehash: 2.0.8 - web3-core: 1.8.0 - web3-core-helpers: 1.8.0 - web3-core-promievent: 1.8.0 - web3-eth-abi: 1.8.0 - web3-eth-contract: 1.8.0 - web3-utils: 1.8.0 - transitivePeerDependencies: - - encoding - - supports-color + /tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} dev: true - /web3-eth-iban@1.2.11: - resolution: {integrity: sha512-ozuVlZ5jwFC2hJY4+fH9pIcuH1xP0HEFhtWsR69u9uDIANHLPQQtWYmdj7xQ3p2YT4bQLq/axKhZi7EZVetmxQ==} - engines: {node: '>=8.0.0'} - requiresBuild: true - dependencies: - bn.js: 4.12.0 - web3-utils: 1.2.11 + /tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} dev: true - optional: true - /web3-eth-iban@1.7.4: - resolution: {integrity: sha512-XyrsgWlZQMv5gRcjXMsNvAoCRvV5wN7YCfFV5+tHUCqN8g9T/o4XUS20vDWD0k4HNiAcWGFqT1nrls02MGZ08w==} - engines: {node: '>=8.0.0'} - dependencies: - bn.js: 5.2.1 - web3-utils: 1.7.4 + /tsort@0.0.1: + resolution: {integrity: sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==} dev: true - /web3-eth-iban@1.8.0: - resolution: {integrity: sha512-4RbvUxcMpo/e5811sE3a6inJ2H4+FFqUVmlRYs0RaXaxiHweahSRBNcpO0UWgmlePTolj0rXqPT2oEr0DuC8kg==} + /tty-table@4.2.3: + resolution: {integrity: sha512-Fs15mu0vGzCrj8fmJNP7Ynxt5J7praPXqFN0leZeZBXJwkMxv9cb2D454k1ltrtUSJbZ4yH4e0CynsHLxmUfFA==} engines: {node: '>=8.0.0'} + hasBin: true dependencies: - bn.js: 5.2.1 - web3-utils: 1.8.0 + chalk: 4.1.2 + csv: 5.5.3 + kleur: 4.1.5 + smartwrap: 2.0.2 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + yargs: 17.7.2 + dev: false + + /tweetnacl-util@0.15.1: + resolution: {integrity: sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==} dev: true - /web3-eth-personal@1.2.11: - resolution: {integrity: sha512-42IzUtKq9iHZ8K9VN0vAI50iSU9tOA1V7XU2BhF/tb7We2iKBVdkley2fg26TxlOcKNEHm7o6HRtiiFsVK4Ifw==} - engines: {node: '>=8.0.0'} - requiresBuild: true - dependencies: - '@types/node': 12.19.16 - web3-core: 1.2.11 - web3-core-helpers: 1.2.11 - web3-core-method: 1.2.11 - web3-net: 1.2.11 - web3-utils: 1.2.11 - transitivePeerDependencies: - - supports-color + /tweetnacl@1.0.3: + resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==} dev: true - optional: true - /web3-eth-personal@1.7.4: - resolution: {integrity: sha512-O10C1Hln5wvLQsDhlhmV58RhXo+GPZ5+W76frSsyIrkJWLtYQTCr5WxHtRC9sMD1idXLqODKKgI2DL+7xeZ0/g==} - engines: {node: '>=8.0.0'} + /type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} dependencies: - '@types/node': 12.19.16 - web3-core: 1.7.4 - web3-core-helpers: 1.7.4 - web3-core-method: 1.7.4 - web3-net: 1.7.4 - web3-utils: 1.7.4 - transitivePeerDependencies: - - supports-color + prelude-ls: 1.2.1 dev: true - /web3-eth-personal@1.8.0: - resolution: {integrity: sha512-L7FT4nR3HmsfZyIAhFpEctKkYGOjRC2h6iFKs9gnFCHZga8yLcYcGaYOBIoYtaKom99MuGBoosayWt/Twh7F5A==} - engines: {node: '>=8.0.0'} - dependencies: - '@types/node': 12.19.16 - web3-core: 1.8.0 - web3-core-helpers: 1.8.0 - web3-core-method: 1.8.0 - web3-net: 1.8.0 - web3-utils: 1.8.0 - transitivePeerDependencies: - - encoding - - supports-color + /type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + + /type-fest@0.13.1: + resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} + engines: {node: '>=10'} + dev: false + + /type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} dev: true - /web3-eth@1.2.11: - resolution: {integrity: sha512-REvxW1wJ58AgHPcXPJOL49d1K/dPmuw4LjPLBPStOVkQjzDTVmJEIsiLwn2YeuNDd4pfakBwT8L3bz1G1/wVsQ==} - engines: {node: '>=8.0.0'} - requiresBuild: true - dependencies: - underscore: 1.9.1 - web3-core: 1.2.11 - web3-core-helpers: 1.2.11 - web3-core-method: 1.2.11 - web3-core-subscriptions: 1.2.11 - web3-eth-abi: 1.2.11 - web3-eth-accounts: 1.2.11 - web3-eth-contract: 1.2.11 - web3-eth-ens: 1.2.11 - web3-eth-iban: 1.2.11 - web3-eth-personal: 1.2.11 - web3-net: 1.2.11 - web3-utils: 1.2.11 - transitivePeerDependencies: - - supports-color + /type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} dev: true - optional: true - /web3-eth@1.7.4: - resolution: {integrity: sha512-JG0tTMv0Ijj039emXNHi07jLb0OiWSA9O24MRSk5vToTQyDNXihdF2oyq85LfHuF690lXZaAXrjhtLNlYqb7Ug==} - engines: {node: '>=8.0.0'} - dependencies: - web3-core: 1.7.4 - web3-core-helpers: 1.7.4 - web3-core-method: 1.7.4 - web3-core-subscriptions: 1.7.4 - web3-eth-abi: 1.7.4 - web3-eth-accounts: 1.7.4 - web3-eth-contract: 1.7.4 - web3-eth-ens: 1.7.4 - web3-eth-iban: 1.7.4 - web3-eth-personal: 1.7.4 - web3-net: 1.7.4 - web3-utils: 1.7.4 - transitivePeerDependencies: - - supports-color + /type-fest@0.6.0: + resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} + engines: {node: '>=8'} + dev: false + + /type-fest@0.7.1: + resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} + engines: {node: '>=8'} dev: true - /web3-eth@1.8.0: - resolution: {integrity: sha512-hist52os3OT4TQFB/GxPSMxTh3995sz6LPvQpPvj7ktSbpg9RNSFaSsPlCT63wUAHA3PZb1FemkAIeQM5t72Lw==} - engines: {node: '>=8.0.0'} + /type-fest@0.8.1: + resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} + engines: {node: '>=8'} + dev: false + + /typechain@8.3.2(typescript@5.4.3): + resolution: {integrity: sha512-x/sQYr5w9K7yv3es7jo4KTX05CLxOf7TRWwoHlrjRh8H82G64g+k7VuWPJlgMo6qrjfCulOdfBjiaDtmhFYD/Q==} + hasBin: true + peerDependencies: + typescript: '>=4.3.0' dependencies: - web3-core: 1.8.0 - web3-core-helpers: 1.8.0 - web3-core-method: 1.8.0 - web3-core-subscriptions: 1.8.0 - web3-eth-abi: 1.8.0 - web3-eth-accounts: 1.8.0 - web3-eth-contract: 1.8.0 - web3-eth-ens: 1.8.0 - web3-eth-iban: 1.8.0 - web3-eth-personal: 1.8.0 - web3-net: 1.8.0 - web3-utils: 1.8.0 + '@types/prettier': 2.7.1 + debug: 4.3.4(supports-color@8.1.1) + fs-extra: 7.0.1 + glob: 7.1.7 + js-sha3: 0.8.0 + lodash: 4.17.21 + mkdirp: 1.0.4 + prettier: 2.8.8 + ts-command-line-args: 2.5.1 + ts-essentials: 7.0.3(typescript@5.4.3) + typescript: 5.4.3 transitivePeerDependencies: - - encoding - supports-color dev: true - /web3-net@1.2.11: - resolution: {integrity: sha512-sjrSDj0pTfZouR5BSTItCuZ5K/oZPVdVciPQ6981PPPIwJJkCMeVjD7I4zO3qDPCnBjBSbWvVnLdwqUBPtHxyg==} - engines: {node: '>=8.0.0'} - requiresBuild: true + /typed-array-buffer@1.0.0: + resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} + engines: {node: '>= 0.4'} dependencies: - web3-core: 1.2.11 - web3-core-method: 1.2.11 - web3-utils: 1.2.11 - transitivePeerDependencies: - - supports-color - dev: true - optional: true + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + is-typed-array: 1.1.12 + dev: false - /web3-net@1.7.4: - resolution: {integrity: sha512-d2Gj+DIARHvwIdmxFQ4PwAAXZVxYCR2lET0cxz4KXbE5Og3DNjJi+MoPkX+WqoUXqimu/EOd4Cd+7gefqVAFDg==} - engines: {node: '>=8.0.0'} + /typed-array-byte-length@1.0.0: + resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} + engines: {node: '>= 0.4'} dependencies: - web3-core: 1.7.4 - web3-core-method: 1.7.4 - web3-utils: 1.7.4 - transitivePeerDependencies: - - supports-color - dev: true + call-bind: 1.0.5 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + dev: false - /web3-net@1.8.0: - resolution: {integrity: sha512-kX6EAacK7QrOe7DOh0t5yHS5q2kxZmTCxPVwSz9io9xBeE4n4UhmzGJ/VfhP2eM3OPKYeypcR3LEO6zZ8xn2vw==} - engines: {node: '>=8.0.0'} + /typed-array-byte-offset@1.0.0: + resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} + engines: {node: '>= 0.4'} dependencies: - web3-core: 1.8.0 - web3-core-method: 1.8.0 - web3-utils: 1.8.0 - transitivePeerDependencies: - - encoding - - supports-color + available-typed-arrays: 1.0.5 + call-bind: 1.0.5 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + dev: false + + /typed-array-length@1.0.4: + resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} + dependencies: + call-bind: 1.0.5 + for-each: 0.3.3 + is-typed-array: 1.1.12 + dev: false + + /typescript@5.4.3: + resolution: {integrity: sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==} + engines: {node: '>=14.17'} + hasBin: true dev: true - /web3-provider-engine@14.2.1: - resolution: {integrity: sha512-iSv31h2qXkr9vrL6UZDm4leZMc32SjWJFGOp/D92JXfcEboCqraZyuExDkpxKw8ziTufXieNM7LSXNHzszYdJw==} - dependencies: - async: 2.6.3 - backoff: 2.5.0 - clone: 2.1.2 - cross-fetch: 2.2.6 - eth-block-tracker: 3.0.1 - eth-json-rpc-infura: 3.2.1 - eth-sig-util: 1.4.2 - ethereumjs-block: 1.7.1 - ethereumjs-tx: 1.3.7 - ethereumjs-util: 5.2.1 - ethereumjs-vm: 2.6.0 - json-rpc-error: 2.0.0 - json-stable-stringify: 1.0.1 - promise-to-callback: 1.0.0 - readable-stream: 2.3.7 - request: 2.88.2 - semaphore: 1.1.0 - ws: 5.2.3 - xhr: 2.5.0 - xtend: 4.0.2 - transitivePeerDependencies: - - bufferutil - - encoding - - supports-color - - utf-8-validate + /typical@4.0.0: + resolution: {integrity: sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==} + engines: {node: '>=8'} dev: true - /web3-providers-http@1.2.11: - resolution: {integrity: sha512-psh4hYGb1+ijWywfwpB2cvvOIMISlR44F/rJtYkRmQ5jMvG4FOCPlQJPiHQZo+2cc3HbktvvSJzIhkWQJdmvrA==} - engines: {node: '>=8.0.0'} - requiresBuild: true - dependencies: - web3-core-helpers: 1.2.11 - xhr2-cookies: 1.1.0 + /typical@5.2.0: + resolution: {integrity: sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==} + engines: {node: '>=8'} dev: true - optional: true - /web3-providers-http@1.7.4: - resolution: {integrity: sha512-AU+/S+49rcogUER99TlhW+UBMk0N2DxvN54CJ2pK7alc2TQ7+cprNPLHJu4KREe8ndV0fT6JtWUfOMyTvl+FRA==} - engines: {node: '>=8.0.0'} + /unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: - web3-core-helpers: 1.7.4 - xhr2-cookies: 1.1.0 - dev: true + call-bind: 1.0.2 + has-bigints: 1.0.2 + has-symbols: 1.0.3 + which-boxed-primitive: 1.0.2 + dev: false - /web3-providers-http@1.8.0: - resolution: {integrity: sha512-/MqxwRzExohBWW97mqlCSW/+NHydGRyoEDUS1bAIF2YjfKFwyRtHgrEzOojzkC9JvB+8LofMvbXk9CcltpZapw==} - engines: {node: '>=8.0.0'} + /undici@5.19.1: + resolution: {integrity: sha512-YiZ61LPIgY73E7syxCDxxa3LV2yl3sN8spnIuTct60boiiRaE1J8mNWHO8Im2Zi/sFrPusjLlmRPrsyraSqX6A==} + engines: {node: '>=12.18'} dependencies: - abortcontroller-polyfill: 1.7.3 - cross-fetch: 3.1.5 - es6-promise: 4.2.8 - web3-core-helpers: 1.8.0 - transitivePeerDependencies: - - encoding + busboy: 1.6.0 dev: true - /web3-providers-ipc@1.2.11: - resolution: {integrity: sha512-yhc7Y/k8hBV/KlELxynWjJDzmgDEDjIjBzXK+e0rHBsYEhdCNdIH5Psa456c+l0qTEU2YzycF8VAjYpWfPnBpQ==} - engines: {node: '>=8.0.0'} - requiresBuild: true - dependencies: - oboe: 2.1.4 - underscore: 1.9.1 - web3-core-helpers: 1.2.11 + /universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + + /universalify@2.0.0: + resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} + engines: {node: '>= 10.0.0'} dev: true - optional: true - /web3-providers-ipc@1.7.4: - resolution: {integrity: sha512-jhArOZ235dZy8fS8090t60nTxbd1ap92ibQw5xIrAQ9m7LcZKNfmLAQUVsD+3dTFvadRMi6z1vCO7zRi84gWHw==} - engines: {node: '>=8.0.0'} - dependencies: - oboe: 2.1.5 - web3-core-helpers: 1.7.4 + /unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} dev: true - /web3-providers-ipc@1.8.0: - resolution: {integrity: sha512-tAXHtVXNUOgehaBU8pzAlB3qhjn/PRpjdzEjzHNFqtRRTwzSEKOJxFeEhaUA4FzHnTlbnrs8ujHWUitcp1elfg==} - engines: {node: '>=8.0.0'} + /upper-case-first@1.1.2: + resolution: {integrity: sha512-wINKYvI3Db8dtjikdAqoBbZoP6Q+PZUyfMR7pmwHzjC2quzSkUq5DmPrTtPEqHaz8AGtmsB4TqwapMTM1QAQOQ==} dependencies: - oboe: 2.1.5 - web3-core-helpers: 1.8.0 + upper-case: 1.1.3 dev: true - /web3-providers-ws@1.2.11: - resolution: {integrity: sha512-ZxnjIY1Er8Ty+cE4migzr43zA/+72AF1myzsLaU5eVgdsfV7Jqx7Dix1hbevNZDKFlSoEyq/3j/jYalh3So1Zg==} - engines: {node: '>=8.0.0'} - requiresBuild: true - dependencies: - eventemitter3: 4.0.4 - underscore: 1.9.1 - web3-core-helpers: 1.2.11 - websocket: 1.0.34 - transitivePeerDependencies: - - supports-color + /upper-case@1.1.3: + resolution: {integrity: sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==} dev: true - optional: true - /web3-providers-ws@1.7.4: - resolution: {integrity: sha512-g72X77nrcHMFU8hRzQJzfgi/072n8dHwRCoTw+WQrGp+XCQ71fsk2qIu3Tp+nlp5BPn8bRudQbPblVm2uT4myQ==} - engines: {node: '>=8.0.0'} + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: - eventemitter3: 4.0.4 - web3-core-helpers: 1.7.4 - websocket: 1.0.34 - transitivePeerDependencies: - - supports-color + punycode: 2.1.1 dev: true - /web3-providers-ws@1.8.0: - resolution: {integrity: sha512-bcZtSifsqyJxwkfQYamfdIRp4nhj9eJd7cxHg1uUkfLJK125WP96wyJL1xbPt7qt0MpfnTFn8/UuIqIB6nFENg==} - engines: {node: '>=8.0.0'} - dependencies: - eventemitter3: 4.0.4 - web3-core-helpers: 1.8.0 - websocket: 1.0.34 - transitivePeerDependencies: - - supports-color + /utf8@3.0.0: + resolution: {integrity: sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==} dev: true - /web3-shh@1.2.11: - resolution: {integrity: sha512-B3OrO3oG1L+bv3E1sTwCx66injW1A8hhwpknDUbV+sw3fehFazA06z9SGXUefuFI1kVs4q2vRi0n4oCcI4dZDg==} - engines: {node: '>=8.0.0'} - requiresBuild: true - dependencies: - web3-core: 1.2.11 - web3-core-method: 1.2.11 - web3-core-subscriptions: 1.2.11 - web3-net: 1.2.11 - transitivePeerDependencies: - - supports-color + /util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} dev: true - optional: true - /web3-shh@1.7.4: - resolution: {integrity: sha512-mlSZxSYcMkuMCxqhTYnZkUdahZ11h+bBv/8TlkXp/IHpEe4/Gg+KAbmfudakq3EzG/04z70XQmPgWcUPrsEJ+A==} - engines: {node: '>=8.0.0'} - requiresBuild: true - dependencies: - web3-core: 1.7.4 - web3-core-method: 1.7.4 - web3-core-subscriptions: 1.7.4 - web3-net: 1.7.4 - transitivePeerDependencies: - - supports-color + /uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true dev: true - /web3-shh@1.8.0: - resolution: {integrity: sha512-DNRgSa9Jf9xYFUGKSMylrf+zt3MPjhI2qF+UWX07o0y3+uf8zalDGiJOWvIS4upAsdPiKKVJ7co+Neof47OMmg==} - engines: {node: '>=8.0.0'} - requiresBuild: true - dependencies: - web3-core: 1.8.0 - web3-core-method: 1.8.0 - web3-core-subscriptions: 1.8.0 - web3-net: 1.8.0 - transitivePeerDependencies: - - encoding - - supports-color + /v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} dev: true - /web3-utils@1.2.11: - resolution: {integrity: sha512-3Tq09izhD+ThqHEaWYX4VOT7dNPdZiO+c/1QMA0s5X2lDFKK/xHJb7cyTRRVzN2LvlHbR7baS1tmQhSua51TcQ==} - engines: {node: '>=8.0.0'} - requiresBuild: true + /validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} dependencies: - bn.js: 4.12.0 - eth-lib: 0.2.8 - ethereum-bloom-filters: 1.0.10 - ethjs-unit: 0.1.6 - number-to-bn: 1.7.0 - randombytes: 2.1.0 - underscore: 1.9.1 - utf8: 3.0.0 - dev: true - optional: true + spdx-correct: 3.1.1 + spdx-expression-parse: 3.0.1 + dev: false - /web3-utils@1.7.4: - resolution: {integrity: sha512-acBdm6Evd0TEZRnChM/MCvGsMwYKmSh7OaUfNf5OKG0CIeGWD/6gqLOWIwmwSnre/2WrA1nKGId5uW2e5EfluA==} - engines: {node: '>=8.0.0'} + /wcwidth@1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} dependencies: - bn.js: 5.2.1 - ethereum-bloom-filters: 1.0.10 - ethereumjs-util: 7.1.5 - ethjs-unit: 0.1.6 - number-to-bn: 1.7.0 - randombytes: 2.1.0 - utf8: 3.0.0 - dev: true + defaults: 1.0.4 + dev: false - /web3-utils@1.8.0: - resolution: {integrity: sha512-7nUIl7UWpLVka2f09CMbKOSEvorvHnaugIabU4mj7zfMvm0tSByLcEu3eyV9qgS11qxxLuOkzBIwCstTflhmpQ==} + /web3-utils@1.7.4: + resolution: {integrity: sha512-acBdm6Evd0TEZRnChM/MCvGsMwYKmSh7OaUfNf5OKG0CIeGWD/6gqLOWIwmwSnre/2WrA1nKGId5uW2e5EfluA==} engines: {node: '>=8.0.0'} dependencies: bn.js: 5.2.1 @@ -12657,102 +5771,16 @@ packages: utf8: 3.0.0 dev: true - /web3@1.2.11: - resolution: {integrity: sha512-mjQ8HeU41G6hgOYm1pmeH0mRAeNKJGnJEUzDMoerkpw7QUQT4exVREgF1MYPvL/z6vAshOXei25LE/t/Bxl8yQ==} - engines: {node: '>=8.0.0'} - requiresBuild: true - dependencies: - web3-bzz: 1.2.11 - web3-core: 1.2.11 - web3-eth: 1.2.11 - web3-eth-personal: 1.2.11 - web3-net: 1.2.11 - web3-shh: 1.2.11 - web3-utils: 1.2.11 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - optional: true - - /web3@1.7.4: - resolution: {integrity: sha512-iFGK5jO32vnXM/ASaJBaI0+gVR6uHozvYdxkdhaeOCD6HIQ4iIXadbO2atVpE9oc/H8l2MovJ4LtPhG7lIBN8A==} - engines: {node: '>=8.0.0'} - requiresBuild: true - dependencies: - web3-bzz: 1.7.4 - web3-core: 1.7.4 - web3-eth: 1.7.4 - web3-eth-personal: 1.7.4 - web3-net: 1.7.4 - web3-shh: 1.7.4 - web3-utils: 1.7.4 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: true - - /web3@1.8.0: - resolution: {integrity: sha512-sldr9stK/SALSJTgI/8qpnDuBJNMGjVR84hJ+AcdQ+MLBGLMGsCDNubCoyO6qgk1/Y9SQ7ignegOI/7BPLoiDA==} - engines: {node: '>=8.0.0'} - requiresBuild: true - dependencies: - web3-bzz: 1.8.0 - web3-core: 1.8.0 - web3-eth: 1.8.0 - web3-eth-personal: 1.8.0 - web3-net: 1.8.0 - web3-shh: 1.8.0 - web3-utils: 1.8.0 - transitivePeerDependencies: - - bufferutil - - encoding - - supports-color - - utf-8-validate - dev: true - /webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - - /websocket@1.0.32: - resolution: {integrity: sha512-i4yhcllSP4wrpoPMU2N0TQ/q0O94LRG/eUQjEAamRltjQ1oT1PFFKOG4i877OlJgCG8rw6LrrowJp+TYCEWF7Q==} - engines: {node: '>=4.0.0'} - dependencies: - bufferutil: 4.0.6 - debug: 2.6.9 - es5-ext: 0.10.62 - typedarray-to-buffer: 3.1.5 - utf-8-validate: 5.0.9 - yaeti: 0.0.6 - transitivePeerDependencies: - - supports-color - dev: true - - /websocket@1.0.34: - resolution: {integrity: sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==} - engines: {node: '>=4.0.0'} - dependencies: - bufferutil: 4.0.6 - debug: 2.6.9 - es5-ext: 0.10.62 - typedarray-to-buffer: 3.1.5 - utf-8-validate: 5.0.9 - yaeti: 0.0.6 - transitivePeerDependencies: - - supports-color - dev: true - - /whatwg-fetch@2.0.4: - resolution: {integrity: sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==} - dev: true + dev: false /whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} dependencies: tr46: 0.0.3 webidl-conversions: 3.0.1 + dev: false /which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} @@ -12762,13 +5790,11 @@ packages: is-number-object: 1.0.7 is-string: 1.0.7 is-symbol: 1.0.3 - - /which-module@1.0.0: - resolution: {integrity: sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==} - dev: true + dev: false /which-module@2.0.0: resolution: {integrity: sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==} + dev: false /which-pm@2.0.0: resolution: {integrity: sha512-Lhs9Pmyph0p5n5Z3mVnN0yWcbQYUAD7rbQUiMsQxOJ3T57k7RFe35SUwWMf7dsbDZks1uOmw4AecB/JMDj3v/w==} @@ -12787,25 +5813,14 @@ packages: for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.0 - - /which-typed-array@1.1.4: - resolution: {integrity: sha512-49E0SpUe90cjpoc7BOJwyPHRqSAd12c10Qm2amdEZrJPCY2NDxaW01zHITrem+rnETY3dwrbH3UUrUwagfCYDA==} - engines: {node: '>= 0.4'} - dependencies: - available-typed-arrays: 1.0.5 - call-bind: 1.0.5 - es-abstract: 1.22.3 - foreach: 2.0.5 - function-bind: 1.1.2 - has-symbols: 1.0.3 - is-typed-array: 1.1.12 - dev: true + dev: false /which@1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} hasBin: true dependencies: isexe: 2.0.0 + dev: false /which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} @@ -12815,25 +5830,11 @@ packages: isexe: 2.0.0 dev: true - /wide-align@1.1.3: - resolution: {integrity: sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==} + /widest-line@3.1.0: + resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==} + engines: {node: '>=8'} dependencies: - string-width: 2.1.1 - dev: true - - /window-size@0.2.0: - resolution: {integrity: sha512-UD7d8HFA2+PZsbKyaOCEy8gMh1oDtHgJh1LfgjQ4zVXmYjAT/kvz3PueITKuqDiIXQe7yzpPnxX3lNc+AhQMyw==} - engines: {node: '>= 0.10.0'} - hasBin: true - dev: true - - /word-wrap@1.2.3: - resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} - engines: {node: '>=0.10.0'} - dev: true - - /wordwrap@1.0.0: - resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + string-width: 4.2.3 dev: true /wordwrapjs@4.0.1: @@ -12848,23 +5849,6 @@ packages: resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==} dev: true - /wrap-ansi@2.1.0: - resolution: {integrity: sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==} - engines: {node: '>=0.10.0'} - dependencies: - string-width: 1.0.2 - strip-ansi: 3.0.1 - dev: true - - /wrap-ansi@5.1.0: - resolution: {integrity: sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==} - engines: {node: '>=6'} - dependencies: - ansi-styles: 3.2.1 - string-width: 3.1.0 - strip-ansi: 5.2.0 - dev: true - /wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} @@ -12886,37 +5870,6 @@ packages: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true - /ws@3.3.3: - resolution: {integrity: sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==} - requiresBuild: true - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dependencies: - async-limiter: 1.0.1 - safe-buffer: 5.1.2 - ultron: 1.1.1 - dev: true - - /ws@5.2.3: - resolution: {integrity: sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA==} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dependencies: - async-limiter: 1.0.1 - dev: true - /ws@7.4.6: resolution: {integrity: sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==} engines: {node: '>=8.3.0'} @@ -12942,92 +5895,21 @@ packages: optional: true dev: true - /xhr-request-promise@0.1.2: - resolution: {integrity: sha512-yAQlCCNLwPgoGxw4k+IdRp1uZ7MZibS4kFw2boSUOesjnmvcxxj73j5a8KavE5Bzas++8P49OpJ4m8qjWGiDsA==} - requiresBuild: true - dependencies: - xhr-request: 1.1.0 - dev: true - - /xhr-request@1.1.0: - resolution: {integrity: sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA==} - requiresBuild: true - dependencies: - buffer-to-arraybuffer: 0.0.5 - object-assign: 4.1.1 - query-string: 5.1.1 - simple-get: 2.8.1 - timed-out: 4.0.1 - url-set-query: 1.0.0 - xhr: 2.5.0 - dev: true - - /xhr2-cookies@1.1.0: - resolution: {integrity: sha512-hjXUA6q+jl/bd8ADHcVfFsSPIf+tyLIjuO9TwJC9WI6JP2zKcS7C+p56I9kCLLsaCiNT035iYvEUUzdEFj/8+g==} - dependencies: - cookiejar: 2.1.2 - dev: true - - /xhr@2.5.0: - resolution: {integrity: sha512-4nlO/14t3BNUZRXIXfXe+3N6w3s1KoxcJUUURctd64BLRe67E4gRwp4PjywtDY72fXpZ1y6Ch0VZQRY/gMPzzQ==} - dependencies: - global: 4.3.2 - is-function: 1.0.1 - parse-headers: 2.0.3 - xtend: 4.0.2 - dev: true - - /xmlhttprequest@1.8.0: - resolution: {integrity: sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==} - engines: {node: '>=0.4.0'} - dev: true - - /xtend@2.1.2: - resolution: {integrity: sha512-vMNKzr2rHP9Dp/e1NQFnLQlwlhp9L/LfvnsVdHxN1f+uggyVI3i08uD14GPvCToPkdsRfyPqIyYGmIk58V98ZQ==} - engines: {node: '>=0.4'} - dependencies: - object-keys: 0.4.0 - dev: true - - /xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - dev: true - - /y18n@3.2.2: - resolution: {integrity: sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==} - dev: true - /y18n@4.0.3: resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + dev: false /y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - /yaeti@0.0.6: - resolution: {integrity: sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==} - engines: {node: '>=0.10.32'} - dev: true - /yallist@2.1.2: resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} dev: false - /yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - dev: true - /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - /yargs-parser@13.1.2: - resolution: {integrity: sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==} - dependencies: - camelcase: 5.3.1 - decamelize: 1.2.0 - dev: true - /yargs-parser@18.1.3: resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} engines: {node: '>=6'} @@ -13036,13 +5918,6 @@ packages: decamelize: 1.2.0 dev: false - /yargs-parser@2.4.1: - resolution: {integrity: sha512-9pIKIJhnI5tonzG6OnCFlz/yln8xHYcGl+pn3xR0Vzff0vzN1PbNRaelgfgRUwZ3s4i3jvxT9WhmUGL4whnasA==} - dependencies: - camelcase: 3.0.0 - lodash.assign: 4.2.0 - dev: true - /yargs-parser@20.2.4: resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} engines: {node: '>=10'} @@ -13053,15 +5928,6 @@ packages: engines: {node: '>=12'} dev: false - /yargs-unparser@1.6.0: - resolution: {integrity: sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==} - engines: {node: '>=6'} - dependencies: - flat: 4.1.1 - lodash: 4.17.21 - yargs: 13.3.2 - dev: true - /yargs-unparser@2.0.0: resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} engines: {node: '>=10'} @@ -13072,21 +5938,6 @@ packages: is-plain-obj: 2.1.0 dev: true - /yargs@13.3.2: - resolution: {integrity: sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==} - dependencies: - cliui: 5.0.0 - find-up: 3.0.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - require-main-filename: 2.0.0 - set-blocking: 2.0.0 - string-width: 3.1.0 - which-module: 2.0.0 - y18n: 4.0.3 - yargs-parser: 13.1.2 - dev: true - /yargs@15.4.1: resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} engines: {node: '>=8'} @@ -13130,25 +5981,6 @@ packages: yargs-parser: 21.1.1 dev: false - /yargs@4.8.1: - resolution: {integrity: sha512-LqodLrnIDM3IFT+Hf/5sxBnEGECrfdC1uIbgZeJmESCSo4HoCAaKEus8MylXHAkdacGc0ye+Qa+dpkuom8uVYA==} - dependencies: - cliui: 3.2.0 - decamelize: 1.2.0 - get-caller-file: 1.0.3 - lodash.assign: 4.2.0 - os-locale: 1.4.0 - read-pkg-up: 1.0.1 - require-directory: 2.1.1 - require-main-filename: 1.0.1 - set-blocking: 2.0.0 - string-width: 1.0.2 - which-module: 1.0.0 - window-size: 0.2.0 - y18n: 3.2.2 - yargs-parser: 2.4.1 - dev: true - /yn@3.1.1: resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} engines: {node: '>=6'} @@ -13158,15 +5990,6 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - github.com/ethereumjs/ethereumjs-abi/ee3994657fa7a427238e6ba92a84d0b529bbcde0: - resolution: {tarball: https://codeload.github.com/ethereumjs/ethereumjs-abi/tar.gz/ee3994657fa7a427238e6ba92a84d0b529bbcde0} - name: ethereumjs-abi - version: 0.6.8 - dependencies: - bn.js: 4.12.0 - ethereumjs-util: 6.2.1 - dev: true - github.com/smartcontractkit/chainlink-solhint-rules/1b4c0c2663fcd983589d4f33a2e73908624ed43c: resolution: {tarball: https://codeload.github.com/smartcontractkit/chainlink-solhint-rules/tar.gz/1b4c0c2663fcd983589d4f33a2e73908624ed43c} name: '@chainlink/solhint-plugin-chainlink-solidity' diff --git a/contracts/scripts/generate-automation-master-interface-v2_3.ts b/contracts/scripts/generate-automation-master-interface-v2_3.ts index c1c4718aa0b..cb566d744bb 100644 --- a/contracts/scripts/generate-automation-master-interface-v2_3.ts +++ b/contracts/scripts/generate-automation-master-interface-v2_3.ts @@ -5,6 +5,7 @@ import { AutomationRegistry2_3__factory as Registry } from '../typechain/factories/AutomationRegistry2_3__factory' import { AutomationRegistryLogicA2_3__factory as RegistryLogicA } from '../typechain/factories/AutomationRegistryLogicA2_3__factory' import { AutomationRegistryLogicB2_3__factory as RegistryLogicB } from '../typechain/factories/AutomationRegistryLogicB2_3__factory' +import { AutomationRegistryLogicC2_3__factory as RegistryLogicC } from '../typechain/factories/AutomationRegistryLogicC2_3__factory' import { utils } from 'ethers' import fs from 'fs' import { exec } from 'child_process' @@ -15,7 +16,12 @@ const tmpDest = `${dest}/tmp.txt` const combinedABI = [] const abiSet = new Set() -const abis = [Registry.abi, RegistryLogicA.abi, RegistryLogicB.abi] +const abis = [ + Registry.abi, + RegistryLogicA.abi, + RegistryLogicB.abi, + RegistryLogicC.abi, +] for (const abi of abis) { for (const entry of abi) { diff --git a/contracts/scripts/native_solc_compile_all b/contracts/scripts/native_solc_compile_all index f4cec6ce1ee..542337a191a 100755 --- a/contracts/scripts/native_solc_compile_all +++ b/contracts/scripts/native_solc_compile_all @@ -12,7 +12,7 @@ python3 -m pip install --require-hashes -r $SCRIPTPATH/requirements.txt # 6 and 7 are legacy contracts, for each other product we have a native_solc_compile_all_$product script # These scripts can be run individually, or all together with this script. # To add new CL products, simply write a native_solc_compile_all_$product script and add it to the list below. -for product in 6 7 automation events_mock feeds functions keystone llo-feeds logpoller operatorforwarder shared transmission vrf +for product in automation events_mock feeds functions keystone llo-feeds logpoller operatorforwarder shared transmission vrf do $SCRIPTPATH/native_solc_compile_all_$product done diff --git a/contracts/scripts/native_solc_compile_all_6 b/contracts/scripts/native_solc_compile_all_6 deleted file mode 100755 index f7bd60d6781..00000000000 --- a/contracts/scripts/native_solc_compile_all_6 +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env bash - -set -e - -echo " ┌──────────────────────────────────────────────┐" -echo " │ Compiling legacy Solidity 0.6 contracts... │" -echo " └──────────────────────────────────────────────┘" - -SOLC_VERSION="0.6.6" -OPTIMIZE_RUNS=1000000 - - -SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" -ROOT="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; cd ../../ && pwd -P )" -python3 -m pip install --require-hashes -r "$SCRIPTPATH"/requirements.txt - -solc-select install $SOLC_VERSION -solc-select use $SOLC_VERSION -export SOLC_VERSION=$SOLC_VERSION - - -compileContract () { - local contract - contract=$(basename "$1" ".sol") - - solc --overwrite --optimize --optimize-runs $OPTIMIZE_RUNS --metadata-hash none \ - -o "$ROOT"/contracts/solc/v0.6/"$contract" \ - --abi --bin --allow-paths "$ROOT"/contracts/src/v0.6 \ - "$ROOT"/contracts/src/v0.6/"$1" -} - -compileContract Flags.sol -compileContract Oracle.sol -compileContract FluxAggregator.sol -compileContract VRF.sol -compileContract VRFCoordinator.sol -compileContract tests/VRFRequestIDBaseTestHelper.sol -compileContract tests/VRFTestHelper.sol -compileContract Chainlink.sol -compileContract VRFRequestIDBase.sol -compileContract tests/VRFConsumer.sol -compileContract ChainlinkClient.sol -compileContract VRFConsumerBase.sol -compileContract BlockhashStore.sol -compileContract tests/TestAPIConsumer.sol -compileContract tests/MockETHLINKAggregator.sol -compileContract tests/MockGASAggregator.sol \ No newline at end of file diff --git a/contracts/scripts/native_solc_compile_all_7 b/contracts/scripts/native_solc_compile_all_7 deleted file mode 100755 index fd64d9ffce7..00000000000 --- a/contracts/scripts/native_solc_compile_all_7 +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bash - -set -e - -echo " ┌──────────────────────────────────────────────┐" -echo " │ Compiling legacy Solidity 0.7 contracts... │" -echo " └──────────────────────────────────────────────┘" - -SOLC_VERSION="0.7.6" -OPTIMIZE_RUNS=1000000 - - -SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" -ROOT="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; cd ../../ && pwd -P )" -python3 -m pip install --require-hashes -r "$SCRIPTPATH"/requirements.txt - -solc-select install $SOLC_VERSION -solc-select use $SOLC_VERSION -export SOLC_VERSION=$SOLC_VERSION - - -compileContract () { - local contract - contract=$(basename "$1" ".sol") - - solc --overwrite --optimize --optimize-runs $OPTIMIZE_RUNS --metadata-hash none \ - -o "$ROOT"/contracts/solc/v0.7/"$contract" \ - --abi --bin --allow-paths "$ROOT"/contracts/src/v0.7 \ - "$ROOT"/contracts/src/v0.7/"$1" -} - -compileContract tests/MultiWordConsumer.sol -compileContract Operator.sol -compileContract AuthorizedForwarder.sol -compileContract AuthorizedReceiver.sol -compileContract OperatorFactory.sol -compileContract tests/Consumer.sol -compileContract tests/VRFCoordinatorMock.sol - -# Keeper/Automation -compileContract KeeperRegistry1_1.sol -compileContract KeeperRegistry1_1Mock.sol -compileContract UpkeepRegistrationRequests.sol -compileContract tests/UpkeepPerformCounterRestrictive.sol -compileContract tests/UpkeepCounter.sol \ No newline at end of file diff --git a/contracts/scripts/native_solc_compile_all_transmission b/contracts/scripts/native_solc_compile_all_transmission index 281fa7aea73..9650a2b27d3 100755 --- a/contracts/scripts/native_solc_compile_all_transmission +++ b/contracts/scripts/native_solc_compile_all_transmission @@ -6,7 +6,7 @@ echo " ┌─────────────────────── echo " │ Compiling Transmission contracts... │" echo " └──────────────────────────────────────────────┘" -SOLC_VERSION="0.8.15" +SOLC_VERSION="0.8.19" OPTIMIZE_RUNS=1000000 SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" diff --git a/contracts/scripts/native_solc_compile_all_vrf b/contracts/scripts/native_solc_compile_all_vrf index 3b6b96d2f50..1bbaa0a75be 100755 --- a/contracts/scripts/native_solc_compile_all_vrf +++ b/contracts/scripts/native_solc_compile_all_vrf @@ -54,7 +54,6 @@ compileContract vrf/testhelpers/VRFV2RevertingExample.sol compileContract vrf/testhelpers/VRFV2ProxyAdmin.sol compileContract vrf/testhelpers/VRFV2TransparentUpgradeableProxy.sol compileContract vrf/testhelpers/VRFConsumerV2UpgradeableExample.sol -compileContract vrf/BatchBlockhashStore.sol compileContract vrf/BatchVRFCoordinatorV2.sol compileContract vrf/testhelpers/VRFCoordinatorV2TestHelper.sol compileContractAltOpts vrf/VRFCoordinatorV2.sol 10000 @@ -63,28 +62,6 @@ compileContract vrf/VRFOwner.sol compileContract vrf/dev/VRFSubscriptionBalanceMonitor.sol compileContract vrf/KeepersVRFConsumer.sol -# VRF V2Plus -compileContract vrf/dev/interfaces/IVRFCoordinatorV2PlusInternal.sol -compileContract vrf/dev/testhelpers/VRFV2PlusConsumerExample.sol -compileContractAltOpts vrf/dev/VRFCoordinatorV2_5.sol 50 -compileContract vrf/dev/BatchVRFCoordinatorV2Plus.sol -compileContract vrf/dev/VRFV2PlusWrapper.sol -compileContract vrf/dev/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol -compileContract vrf/dev/testhelpers/VRFMaliciousConsumerV2Plus.sol -compileContract vrf/dev/testhelpers/VRFV2PlusExternalSubOwnerExample.sol -compileContract vrf/dev/testhelpers/VRFV2PlusSingleConsumerExample.sol -compileContract vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol -compileContract vrf/dev/testhelpers/VRFV2PlusRevertingExample.sol -compileContract vrf/dev/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol -compileContract vrf/dev/testhelpers/VRFV2PlusMaliciousMigrator.sol -compileContract vrf/dev/libraries/VRFV2PlusClient.sol -compileContract vrf/dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol -compileContract vrf/dev/BlockhashStore.sol -compileContract vrf/dev/TrustedBlockhashStore.sol -compileContract vrf/dev/testhelpers/VRFV2PlusLoadTestWithMetrics.sol -compileContractAltOpts vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol 5 -compileContract vrf/dev/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol - # VRF V2 Wrapper compileContract vrf/VRFV2Wrapper.sol compileContract vrf/interfaces/VRFV2WrapperInterface.sol @@ -108,3 +85,33 @@ compileContract vrf/testhelpers/VRFMockETHLINKAggregator.sol compileContract vrf/interfaces/IAuthorizedReceiver.sol compileContract vrf/interfaces/VRFCoordinatorV2Interface.sol compileContract vrf/interfaces/VRFV2WrapperInterface.sol + +SOLC_VERSION="0.8.19" + +solc-select install $SOLC_VERSION +solc-select use $SOLC_VERSION +export SOLC_VERSION=$SOLC_VERSION + +# v0.8.19 +# VRF V2 Plus +compileContract vrf/dev/interfaces/IVRFCoordinatorV2PlusInternal.sol +compileContract vrf/dev/testhelpers/VRFV2PlusConsumerExample.sol +compileContractAltOpts vrf/dev/VRFCoordinatorV2_5.sol 500 +compileContract vrf/dev/BatchVRFCoordinatorV2Plus.sol +compileContract vrf/dev/VRFV2PlusWrapper.sol +compileContract vrf/dev/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol +compileContract vrf/dev/testhelpers/VRFMaliciousConsumerV2Plus.sol +compileContract vrf/dev/testhelpers/VRFV2PlusExternalSubOwnerExample.sol +compileContract vrf/dev/testhelpers/VRFV2PlusSingleConsumerExample.sol +compileContract vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol +compileContract vrf/dev/testhelpers/VRFV2PlusRevertingExample.sol +compileContract vrf/dev/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol +compileContract vrf/dev/testhelpers/VRFV2PlusMaliciousMigrator.sol +compileContract vrf/dev/libraries/VRFV2PlusClient.sol +compileContract vrf/dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol +compileContract vrf/dev/TrustedBlockhashStore.sol +compileContract vrf/dev/testhelpers/VRFV2PlusLoadTestWithMetrics.sol +compileContractAltOpts vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol 5 +compileContract vrf/dev/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol +compileContract vrf/BatchBlockhashStore.sol +compileContract vrf/dev/BlockhashStore.sol \ No newline at end of file diff --git a/contracts/scripts/native_solc_compile_all_vrfv2plus b/contracts/scripts/native_solc_compile_all_vrfv2plus index fb7d783cc03..2c7e8693792 100755 --- a/contracts/scripts/native_solc_compile_all_vrfv2plus +++ b/contracts/scripts/native_solc_compile_all_vrfv2plus @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +\#!/usr/bin/env bash set -e @@ -6,7 +6,7 @@ echo " ┌─────────────────────── echo " │ Compiling VRF contracts... │" echo " └──────────────────────────────────────────────┘" -SOLC_VERSION="0.8.6" +SOLC_VERSION="0.8.19" OPTIMIZE_RUNS=1000000 SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" @@ -37,17 +37,10 @@ compileContractAltOpts () { "$ROOT"/contracts/src/v0.8/"$1" } -# VRF -compileContract vrf/VRFRequestIDBase.sol -compileContract vrf/VRFConsumerBase.sol -compileContract vrf/testhelpers/VRFConsumer.sol -compileContract vrf/testhelpers/VRFRequestIDBaseTestHelper.sol -compileContract vrf/mocks/VRFCoordinatorMock.sol - # VRF V2Plus compileContract vrf/dev/interfaces/IVRFCoordinatorV2PlusInternal.sol compileContract vrf/dev/testhelpers/VRFV2PlusConsumerExample.sol -compileContractAltOpts vrf/dev/VRFCoordinatorV2_5.sol 50 +compileContractAltOpts vrf/dev/VRFCoordinatorV2_5.sol 500 compileContract vrf/dev/BatchVRFCoordinatorV2Plus.sol compileContract vrf/dev/VRFV2PlusWrapper.sol compileContract vrf/dev/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol @@ -60,10 +53,11 @@ compileContract vrf/dev/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol compileContract vrf/dev/testhelpers/VRFV2PlusMaliciousMigrator.sol compileContract vrf/dev/libraries/VRFV2PlusClient.sol compileContract vrf/dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol -compileContract vrf/dev/BlockhashStore.sol compileContract vrf/dev/TrustedBlockhashStore.sol compileContract vrf/dev/testhelpers/VRFV2PlusLoadTestWithMetrics.sol compileContractAltOpts vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol 5 compileContract vrf/dev/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol compileContract vrf/testhelpers/VRFMockETHLINKAggregator.sol compileContract vrf/dev/testhelpers/VRFV2PlusLoadTestWithMetrics.sol +compileContract vrf/BatchBlockhashStore.sol +compileContract vrf/dev/BlockhashStore.sol \ No newline at end of file diff --git a/contracts/scripts/prepublish_generate_abi_folder b/contracts/scripts/prepublish_generate_abi_folder index 36e58faf79e..f81b39fd5fa 100755 --- a/contracts/scripts/prepublish_generate_abi_folder +++ b/contracts/scripts/prepublish_generate_abi_folder @@ -9,7 +9,7 @@ SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; cd .. && pwd -P )" TARGET="abi" # For each version directory in src, copy the json files to the correct location -versions=( v0.4 v0.5 v0.6 v0.7 v0.8 ) +versions=( v0.8 ) for version in "${versions[@]}" do rm -rf $SCRIPTPATH/$TARGET/$version diff --git a/contracts/src/v0.4/Aggregator.sol b/contracts/src/v0.4/Aggregator.sol deleted file mode 100644 index 69a166478c3..00000000000 --- a/contracts/src/v0.4/Aggregator.sol +++ /dev/null @@ -1,426 +0,0 @@ -pragma solidity 0.4.24; - -import "./ChainlinkClient.sol"; -import "./interfaces/AggregatorInterface.sol"; -import "./vendor/SignedSafeMath.sol"; -import "./vendor/Ownable.sol"; -import "./vendor/SafeMathChainlink.sol"; - -/** - * @title An example Chainlink contract with aggregation - * @notice Requesters can use this contract as a framework for creating - * requests to multiple Chainlink nodes and running aggregation - * as the contract receives answers. - */ -contract Aggregator is AggregatorInterface, ChainlinkClient, Ownable { - using SafeMathChainlink for uint256; - using SignedSafeMath for int256; - - struct Answer { - uint128 minimumResponses; - uint128 maxResponses; - int256[] responses; - } - - event ResponseReceived(int256 indexed response, uint256 indexed answerId, address indexed sender); - - int256 private currentAnswerValue; - uint256 private updatedTimestampValue; - uint256 private latestCompletedAnswer; - uint128 public paymentAmount; - uint128 public minimumResponses; - bytes32[] public jobIds; - address[] public oracles; - - uint256 private answerCounter = 1; - mapping(address => bool) public authorizedRequesters; - mapping(bytes32 => uint256) private requestAnswers; - mapping(uint256 => Answer) private answers; - mapping(uint256 => int256) private currentAnswers; - mapping(uint256 => uint256) private updatedTimestamps; - - uint256 constant private MAX_ORACLE_COUNT = 28; - - /** - * @notice Deploy with the address of the LINK token and arrays of matching - * length containing the addresses of the oracles and their corresponding - * Job IDs. - * @dev Sets the LinkToken address for the network, addresses of the oracles, - * and jobIds in storage. - * @param _link The address of the LINK token - * @param _paymentAmount the amount of LINK to be sent to each oracle for each request - * @param _minimumResponses the minimum number of responses - * before an answer will be calculated - * @param _oracles An array of oracle addresses - * @param _jobIds An array of Job IDs - */ - constructor( - address _link, - uint128 _paymentAmount, - uint128 _minimumResponses, - address[] _oracles, - bytes32[] _jobIds - ) public Ownable() { - setChainlinkToken(_link); - updateRequestDetails(_paymentAmount, _minimumResponses, _oracles, _jobIds); - } - - /** - * @notice Creates a Chainlink request for each oracle in the oracles array. - * @dev This example does not include request parameters. Reference any documentation - * associated with the Job IDs used to determine the required parameters per-request. - */ - function requestRateUpdate() - external - ensureAuthorizedRequester() - { - Chainlink.Request memory request; - bytes32 requestId; - uint256 oraclePayment = paymentAmount; - - for (uint i = 0; i < oracles.length; i++) { - request = buildChainlinkRequest(jobIds[i], this, this.chainlinkCallback.selector); - requestId = sendChainlinkRequestTo(oracles[i], request, oraclePayment); - requestAnswers[requestId] = answerCounter; - } - answers[answerCounter].minimumResponses = minimumResponses; - answers[answerCounter].maxResponses = uint128(oracles.length); - - emit NewRound(answerCounter, msg.sender, block.timestamp); - - answerCounter = answerCounter.add(1); - } - - /** - * @notice Receives the answer from the Chainlink node. - * @dev This function can only be called by the oracle that received the request. - * @param _clRequestId The Chainlink request ID associated with the answer - * @param _response The answer provided by the Chainlink node - */ - function chainlinkCallback(bytes32 _clRequestId, int256 _response) - external - { - validateChainlinkCallback(_clRequestId); - - uint256 answerId = requestAnswers[_clRequestId]; - delete requestAnswers[_clRequestId]; - - answers[answerId].responses.push(_response); - emit ResponseReceived(_response, answerId, msg.sender); - updateLatestAnswer(answerId); - deleteAnswer(answerId); - } - - /** - * @notice Updates the arrays of oracles and jobIds with new values, - * overwriting the old values. - * @dev Arrays are validated to be equal length. - * @param _paymentAmount the amount of LINK to be sent to each oracle for each request - * @param _minimumResponses the minimum number of responses - * before an answer will be calculated - * @param _oracles An array of oracle addresses - * @param _jobIds An array of Job IDs - */ - function updateRequestDetails( - uint128 _paymentAmount, - uint128 _minimumResponses, - address[] _oracles, - bytes32[] _jobIds - ) - public - onlyOwner() - validateAnswerRequirements(_minimumResponses, _oracles, _jobIds) - { - paymentAmount = _paymentAmount; - minimumResponses = _minimumResponses; - jobIds = _jobIds; - oracles = _oracles; - } - - /** - * @notice Allows the owner of the contract to withdraw any LINK balance - * available on the contract. - * @dev The contract will need to have a LINK balance in order to create requests. - * @param _recipient The address to receive the LINK tokens - * @param _amount The amount of LINK to send from the contract - */ - function transferLINK(address _recipient, uint256 _amount) - public - onlyOwner() - { - LinkTokenInterface linkToken = LinkTokenInterface(chainlinkTokenAddress()); - require(linkToken.transfer(_recipient, _amount), "LINK transfer failed"); - } - - /** - * @notice Called by the owner to permission other addresses to generate new - * requests to oracles. - * @param _requester the address whose permissions are being set - * @param _allowed boolean that determines whether the requester is - * permissioned or not - */ - function setAuthorization(address _requester, bool _allowed) - external - onlyOwner() - { - authorizedRequesters[_requester] = _allowed; - } - - /** - * @notice Cancels an outstanding Chainlink request. - * The oracle contract requires the request ID and additional metadata to - * validate the cancellation. Only old answers can be cancelled. - * @param _requestId is the identifier for the chainlink request being cancelled - * @param _payment is the amount of LINK paid to the oracle for the request - * @param _expiration is the time when the request expires - */ - function cancelRequest( - bytes32 _requestId, - uint256 _payment, - uint256 _expiration - ) - external - ensureAuthorizedRequester() - { - uint256 answerId = requestAnswers[_requestId]; - require(answerId < latestCompletedAnswer, "Cannot modify an in-progress answer"); - - delete requestAnswers[_requestId]; - answers[answerId].responses.push(0); - deleteAnswer(answerId); - - cancelChainlinkRequest( - _requestId, - _payment, - this.chainlinkCallback.selector, - _expiration - ); - } - - /** - * @notice Called by the owner to kill the contract. This transfers all LINK - * balance and ETH balance (if there is any) to the owner. - */ - function destroy() - external - onlyOwner() - { - LinkTokenInterface linkToken = LinkTokenInterface(chainlinkTokenAddress()); - transferLINK(owner, linkToken.balanceOf(address(this))); - selfdestruct(owner); - } - - /** - * @dev Performs aggregation of the answers received from the Chainlink nodes. - * Assumes that at least half the oracles are honest and so can't control the - * middle of the ordered responses. - * @param _answerId The answer ID associated with the group of requests - */ - function updateLatestAnswer(uint256 _answerId) - private - ensureMinResponsesReceived(_answerId) - ensureOnlyLatestAnswer(_answerId) - { - uint256 responseLength = answers[_answerId].responses.length; - uint256 middleIndex = responseLength.div(2); - int256 currentAnswerTemp; - if (responseLength % 2 == 0) { - int256 median1 = quickselect(answers[_answerId].responses, middleIndex); - int256 median2 = quickselect(answers[_answerId].responses, middleIndex.add(1)); // quickselect is 1 indexed - currentAnswerTemp = median1.add(median2) / 2; // signed integers are not supported by SafeMath - } else { - currentAnswerTemp = quickselect(answers[_answerId].responses, middleIndex.add(1)); // quickselect is 1 indexed - } - currentAnswerValue = currentAnswerTemp; - latestCompletedAnswer = _answerId; - updatedTimestampValue = now; - updatedTimestamps[_answerId] = now; - currentAnswers[_answerId] = currentAnswerTemp; - emit AnswerUpdated(currentAnswerTemp, _answerId, now); - } - - /** - * @notice get the most recently reported answer - */ - function latestAnswer() - external - view - returns (int256) - { - return currentAnswers[latestCompletedAnswer]; - } - - /** - * @notice get the last updated at block timestamp - */ - function latestTimestamp() - external - view - returns (uint256) - { - return updatedTimestamps[latestCompletedAnswer]; - } - - /** - * @notice get past rounds answers - * @param _roundId the answer number to retrieve the answer for - */ - function getAnswer(uint256 _roundId) - external - view - returns (int256) - { - return currentAnswers[_roundId]; - } - - /** - * @notice get block timestamp when an answer was last updated - * @param _roundId the answer number to retrieve the updated timestamp for - */ - function getTimestamp(uint256 _roundId) - external - view - returns (uint256) - { - return updatedTimestamps[_roundId]; - } - - /** - * @notice get the latest completed round where the answer was updated - */ - function latestRound() - external - view - returns (uint256) - { - return latestCompletedAnswer; - } - - /** - * @dev Returns the kth value of the ordered array - * See: http://www.cs.yale.edu/homes/aspnes/pinewiki/QuickSelect.html - * @param _a The list of elements to pull from - * @param _k The index, 1 based, of the elements you want to pull from when ordered - */ - function quickselect(int256[] memory _a, uint256 _k) - private - pure - returns (int256) - { - int256[] memory a = _a; - uint256 k = _k; - uint256 aLen = a.length; - int256[] memory a1 = new int256[](aLen); - int256[] memory a2 = new int256[](aLen); - uint256 a1Len; - uint256 a2Len; - int256 pivot; - uint256 i; - - while (true) { - pivot = a[aLen.div(2)]; - a1Len = 0; - a2Len = 0; - for (i = 0; i < aLen; i++) { - if (a[i] < pivot) { - a1[a1Len] = a[i]; - a1Len++; - } else if (a[i] > pivot) { - a2[a2Len] = a[i]; - a2Len++; - } - } - if (k <= a1Len) { - aLen = a1Len; - (a, a1) = swap(a, a1); - } else if (k > (aLen.sub(a2Len))) { - k = k.sub(aLen.sub(a2Len)); - aLen = a2Len; - (a, a2) = swap(a, a2); - } else { - return pivot; - } - } - } - - /** - * @dev Swaps the pointers to two uint256 arrays in memory - * @param _a The pointer to the first in memory array - * @param _b The pointer to the second in memory array - */ - function swap(int256[] memory _a, int256[] memory _b) - private - pure - returns(int256[] memory, int256[] memory) - { - return (_b, _a); - } - - /** - * @dev Cleans up the answer record if all responses have been received. - * @param _answerId The identifier of the answer to be deleted - */ - function deleteAnswer(uint256 _answerId) - private - ensureAllResponsesReceived(_answerId) - { - delete answers[_answerId]; - } - - /** - * @dev Prevents taking an action if the minimum number of responses has not - * been received for an answer. - * @param _answerId The the identifier of the answer that keeps track of the responses. - */ - modifier ensureMinResponsesReceived(uint256 _answerId) { - if (answers[_answerId].responses.length >= answers[_answerId].minimumResponses) { - _; - } - } - - /** - * @dev Prevents taking an action if not all responses are received for an answer. - * @param _answerId The the identifier of the answer that keeps track of the responses. - */ - modifier ensureAllResponsesReceived(uint256 _answerId) { - if (answers[_answerId].responses.length == answers[_answerId].maxResponses) { - _; - } - } - - /** - * @dev Prevents taking an action if a newer answer has been recorded. - * @param _answerId The current answer's identifier. - * Answer IDs are in ascending order. - */ - modifier ensureOnlyLatestAnswer(uint256 _answerId) { - if (latestCompletedAnswer <= _answerId) { - _; - } - } - - /** - * @dev Ensures corresponding number of oracles and jobs. - * @param _oracles The list of oracles. - * @param _jobIds The list of jobs. - */ - modifier validateAnswerRequirements( - uint256 _minimumResponses, - address[] _oracles, - bytes32[] _jobIds - ) { - require(_oracles.length <= MAX_ORACLE_COUNT, "cannot have more than 45 oracles"); - require(_oracles.length >= _minimumResponses, "must have at least as many oracles as responses"); - require(_oracles.length == _jobIds.length, "must have exactly as many oracles as job IDs"); - _; - } - - /** - * @dev Reverts if `msg.sender` is not authorized to make requests. - */ - modifier ensureAuthorizedRequester() { - require(authorizedRequesters[msg.sender] || msg.sender == owner, "Not an authorized address for creating requests"); - _; - } - -} diff --git a/contracts/src/v0.4/Chainlink.sol b/contracts/src/v0.4/Chainlink.sol deleted file mode 100644 index 1ab6e8bc0ac..00000000000 --- a/contracts/src/v0.4/Chainlink.sol +++ /dev/null @@ -1,126 +0,0 @@ -pragma solidity ^0.4.24; - -import { CBOR as CBOR_Chainlink } from "./vendor/CBOR.sol"; -import { Buffer as Buffer_Chainlink } from "./vendor/Buffer.sol"; - -/** - * @title Library for common Chainlink functions - * @dev Uses imported CBOR library for encoding to buffer - */ -library Chainlink { - uint256 internal constant defaultBufferSize = 256; // solhint-disable-line const-name-snakecase - - using CBOR_Chainlink for Buffer_Chainlink.buffer; - - struct Request { - bytes32 id; - address callbackAddress; - bytes4 callbackFunctionId; - uint256 nonce; - Buffer_Chainlink.buffer buf; - } - - /** - * @notice Initializes a Chainlink request - * @dev Sets the ID, callback address, and callback function signature on the request - * @param self The uninitialized request - * @param _id The Job Specification ID - * @param _callbackAddress The callback address - * @param _callbackFunction The callback function signature - * @return The initialized request - */ - function initialize( - Request memory self, - bytes32 _id, - address _callbackAddress, - bytes4 _callbackFunction - ) internal pure returns (Chainlink.Request memory) { - Buffer_Chainlink.init(self.buf, defaultBufferSize); - self.id = _id; - self.callbackAddress = _callbackAddress; - self.callbackFunctionId = _callbackFunction; - return self; - } - - /** - * @notice Sets the data for the buffer without encoding CBOR on-chain - * @dev CBOR can be closed with curly-brackets {} or they can be left off - * @param self The initialized request - * @param _data The CBOR data - */ - function setBuffer(Request memory self, bytes _data) - internal pure - { - Buffer_Chainlink.init(self.buf, _data.length); - Buffer_Chainlink.append(self.buf, _data); - } - - /** - * @notice Adds a string value to the request with a given key name - * @param self The initialized request - * @param _key The name of the key - * @param _value The string value to add - */ - function add(Request memory self, string _key, string _value) - internal pure - { - self.buf.encodeString(_key); - self.buf.encodeString(_value); - } - - /** - * @notice Adds a bytes value to the request with a given key name - * @param self The initialized request - * @param _key The name of the key - * @param _value The bytes value to add - */ - function addBytes(Request memory self, string _key, bytes _value) - internal pure - { - self.buf.encodeString(_key); - self.buf.encodeBytes(_value); - } - - /** - * @notice Adds a int256 value to the request with a given key name - * @param self The initialized request - * @param _key The name of the key - * @param _value The int256 value to add - */ - function addInt(Request memory self, string _key, int256 _value) - internal pure - { - self.buf.encodeString(_key); - self.buf.encodeInt(_value); - } - - /** - * @notice Adds a uint256 value to the request with a given key name - * @param self The initialized request - * @param _key The name of the key - * @param _value The uint256 value to add - */ - function addUint(Request memory self, string _key, uint256 _value) - internal pure - { - self.buf.encodeString(_key); - self.buf.encodeUInt(_value); - } - - /** - * @notice Adds an array of strings to the request with a given key name - * @param self The initialized request - * @param _key The name of the key - * @param _values The array of string values to add - */ - function addStringArray(Request memory self, string _key, string[] memory _values) - internal pure - { - self.buf.encodeString(_key); - self.buf.startArray(); - for (uint256 i = 0; i < _values.length; i++) { - self.buf.encodeString(_values[i]); - } - self.buf.endSequence(); - } -} diff --git a/contracts/src/v0.4/ChainlinkClient.sol b/contracts/src/v0.4/ChainlinkClient.sol deleted file mode 100644 index b62664cf9bc..00000000000 --- a/contracts/src/v0.4/ChainlinkClient.sol +++ /dev/null @@ -1,260 +0,0 @@ -pragma solidity ^0.4.24; - -import "./Chainlink.sol"; -import "./interfaces/ENSInterface.sol"; -import "./interfaces/LinkTokenInterface.sol"; -import "./interfaces/ChainlinkRequestInterface.sol"; -import "./interfaces/PointerInterface.sol"; -import { ENSResolver as ENSResolver_Chainlink } from "./vendor/ENSResolver.sol"; - -/** - * @title The ChainlinkClient contract - * @notice Contract writers can inherit this contract in order to create requests for the - * Chainlink network - */ -contract ChainlinkClient { - using Chainlink for Chainlink.Request; - - uint256 constant internal LINK = 10**18; - uint256 constant private AMOUNT_OVERRIDE = 0; - address constant private SENDER_OVERRIDE = 0x0; - uint256 constant private ARGS_VERSION = 1; - bytes32 constant private ENS_TOKEN_SUBNAME = keccak256("link"); - bytes32 constant private ENS_ORACLE_SUBNAME = keccak256("oracle"); - address constant private LINK_TOKEN_POINTER = 0xC89bD4E1632D3A43CB03AAAd5262cbe4038Bc571; - - ENSInterface private ens; - bytes32 private ensNode; - LinkTokenInterface private link; - ChainlinkRequestInterface private oracle; - uint256 private requests = 1; - mapping(bytes32 => address) private pendingRequests; - - event ChainlinkRequested(bytes32 indexed id); - event ChainlinkFulfilled(bytes32 indexed id); - event ChainlinkCancelled(bytes32 indexed id); - - /** - * @notice Creates a request that can hold additional parameters - * @param _specId The Job Specification ID that the request will be created for - * @param _callbackAddress The callback address that the response will be sent to - * @param _callbackFunctionSignature The callback function signature to use for the callback address - * @return A Chainlink Request struct in memory - */ - function buildChainlinkRequest( - bytes32 _specId, - address _callbackAddress, - bytes4 _callbackFunctionSignature - ) internal pure returns (Chainlink.Request memory) { - Chainlink.Request memory req; - return req.initialize(_specId, _callbackAddress, _callbackFunctionSignature); - } - - /** - * @notice Creates a Chainlink request to the stored oracle address - * @dev Calls `chainlinkRequestTo` with the stored oracle address - * @param _req The initialized Chainlink Request - * @param _payment The amount of LINK to send for the request - * @return The request ID - */ - function sendChainlinkRequest(Chainlink.Request memory _req, uint256 _payment) - internal - returns (bytes32) - { - return sendChainlinkRequestTo(oracle, _req, _payment); - } - - /** - * @notice Creates a Chainlink request to the specified oracle address - * @dev Generates and stores a request ID, increments the local nonce, and uses `transferAndCall` to - * send LINK which creates a request on the target oracle contract. - * Emits ChainlinkRequested event. - * @param _oracle The address of the oracle for the request - * @param _req The initialized Chainlink Request - * @param _payment The amount of LINK to send for the request - * @return The request ID - */ - function sendChainlinkRequestTo(address _oracle, Chainlink.Request memory _req, uint256 _payment) - internal - returns (bytes32 requestId) - { - requestId = keccak256(abi.encodePacked(this, requests)); - _req.nonce = requests; - pendingRequests[requestId] = _oracle; - emit ChainlinkRequested(requestId); - require(link.transferAndCall(_oracle, _payment, encodeRequest(_req)), "unable to transferAndCall to oracle"); - requests += 1; - - return requestId; - } - - /** - * @notice Allows a request to be cancelled if it has not been fulfilled - * @dev Requires keeping track of the expiration value emitted from the oracle contract. - * Deletes the request from the `pendingRequests` mapping. - * Emits ChainlinkCancelled event. - * @param _requestId The request ID - * @param _payment The amount of LINK sent for the request - * @param _callbackFunc The callback function specified for the request - * @param _expiration The time of the expiration for the request - */ - function cancelChainlinkRequest( - bytes32 _requestId, - uint256 _payment, - bytes4 _callbackFunc, - uint256 _expiration - ) - internal - { - ChainlinkRequestInterface requested = ChainlinkRequestInterface(pendingRequests[_requestId]); - delete pendingRequests[_requestId]; - emit ChainlinkCancelled(_requestId); - requested.cancelOracleRequest(_requestId, _payment, _callbackFunc, _expiration); - } - - /** - * @notice Sets the stored oracle address - * @param _oracle The address of the oracle contract - */ - function setChainlinkOracle(address _oracle) internal { - oracle = ChainlinkRequestInterface(_oracle); - } - - /** - * @notice Sets the LINK token address - * @param _link The address of the LINK token contract - */ - function setChainlinkToken(address _link) internal { - link = LinkTokenInterface(_link); - } - - /** - * @notice Sets the Chainlink token address for the public - * network as given by the Pointer contract - */ - function setPublicChainlinkToken() internal { - setChainlinkToken(PointerInterface(LINK_TOKEN_POINTER).getAddress()); - } - - /** - * @notice Retrieves the stored address of the LINK token - * @return The address of the LINK token - */ - function chainlinkTokenAddress() - internal - view - returns (address) - { - return address(link); - } - - /** - * @notice Retrieves the stored address of the oracle contract - * @return The address of the oracle contract - */ - function chainlinkOracleAddress() - internal - view - returns (address) - { - return address(oracle); - } - - /** - * @notice Allows for a request which was created on another contract to be fulfilled - * on this contract - * @param _oracle The address of the oracle contract that will fulfill the request - * @param _requestId The request ID used for the response - */ - function addChainlinkExternalRequest(address _oracle, bytes32 _requestId) - internal - notPendingRequest(_requestId) - { - pendingRequests[_requestId] = _oracle; - } - - /** - * @notice Sets the stored oracle and LINK token contracts with the addresses resolved by ENS - * @dev Accounts for subnodes having different resolvers - * @param _ens The address of the ENS contract - * @param _node The ENS node hash - */ - function useChainlinkWithENS(address _ens, bytes32 _node) - internal - { - ens = ENSInterface(_ens); - ensNode = _node; - bytes32 linkSubnode = keccak256(abi.encodePacked(ensNode, ENS_TOKEN_SUBNAME)); - ENSResolver_Chainlink resolver = ENSResolver_Chainlink(ens.resolver(linkSubnode)); - setChainlinkToken(resolver.addr(linkSubnode)); - updateChainlinkOracleWithENS(); - } - - /** - * @notice Sets the stored oracle contract with the address resolved by ENS - * @dev This may be called on its own as long as `useChainlinkWithENS` has been called previously - */ - function updateChainlinkOracleWithENS() - internal - { - bytes32 oracleSubnode = keccak256(abi.encodePacked(ensNode, ENS_ORACLE_SUBNAME)); - ENSResolver_Chainlink resolver = ENSResolver_Chainlink(ens.resolver(oracleSubnode)); - setChainlinkOracle(resolver.addr(oracleSubnode)); - } - - /** - * @notice Encodes the request to be sent to the oracle contract - * @dev The Chainlink node expects values to be in order for the request to be picked up. Order of types - * will be validated in the oracle contract. - * @param _req The initialized Chainlink Request - * @return The bytes payload for the `transferAndCall` method - */ - function encodeRequest(Chainlink.Request memory _req) - private - view - returns (bytes memory) - { - return abi.encodeWithSelector( - oracle.oracleRequest.selector, - SENDER_OVERRIDE, // Sender value - overridden by onTokenTransfer by the requesting contract's address - AMOUNT_OVERRIDE, // Amount value - overridden by onTokenTransfer by the actual amount of LINK sent - _req.id, - _req.callbackAddress, - _req.callbackFunctionId, - _req.nonce, - ARGS_VERSION, - _req.buf.buf); - } - - /** - * @notice Ensures that the fulfillment is valid for this contract - * @dev Use if the contract developer prefers methods instead of modifiers for validation - * @param _requestId The request ID for fulfillment - */ - function validateChainlinkCallback(bytes32 _requestId) - internal - recordChainlinkFulfillment(_requestId) - // solhint-disable-next-line no-empty-blocks - {} - - /** - * @dev Reverts if the sender is not the oracle of the request. - * Emits ChainlinkFulfilled event. - * @param _requestId The request ID for fulfillment - */ - modifier recordChainlinkFulfillment(bytes32 _requestId) { - require(msg.sender == pendingRequests[_requestId], "Source must be the oracle of the request"); - delete pendingRequests[_requestId]; - emit ChainlinkFulfilled(_requestId); - _; - } - - /** - * @dev Reverts if the request is already pending - * @param _requestId The request ID for fulfillment - */ - modifier notPendingRequest(bytes32 _requestId) { - require(pendingRequests[_requestId] == address(0), "Request is already pending"); - _; - } -} diff --git a/contracts/src/v0.4/ERC677Token.sol b/contracts/src/v0.4/ERC677Token.sol deleted file mode 100644 index d78ca1f52e6..00000000000 --- a/contracts/src/v0.4/ERC677Token.sol +++ /dev/null @@ -1,47 +0,0 @@ -pragma solidity ^0.4.11; - - -import "./interfaces/ERC677.sol"; -import "./interfaces/ERC677Receiver.sol"; - - -contract ERC677Token is ERC677 { - - /** - * @dev transfer token to a contract address with additional data if the recipient is a contact. - * @param _to The address to transfer to. - * @param _value The amount to be transferred. - * @param _data The extra data to be passed to the receiving contract. - */ - function transferAndCall(address _to, uint _value, bytes _data) - public - returns (bool success) - { - super.transfer(_to, _value); - Transfer(msg.sender, _to, _value, _data); - if (isContract(_to)) { - contractFallback(_to, _value, _data); - } - return true; - } - - - // PRIVATE - - function contractFallback(address _to, uint _value, bytes _data) - private - { - ERC677Receiver receiver = ERC677Receiver(_to); - receiver.onTokenTransfer(msg.sender, _value, _data); - } - - function isContract(address _addr) - private - returns (bool hasCode) - { - uint length; - assembly { length := extcodesize(_addr) } - return length > 0; - } - -} diff --git a/contracts/src/v0.4/LinkToken.sol b/contracts/src/v0.4/LinkToken.sol deleted file mode 100644 index ba2e7ba1ef0..00000000000 --- a/contracts/src/v0.4/LinkToken.sol +++ /dev/null @@ -1,83 +0,0 @@ -pragma solidity ^0.4.11; - - -import "./ERC677Token.sol"; -import { StandardToken as linkStandardToken } from "./vendor/StandardToken.sol"; - - -contract LinkToken is linkStandardToken, ERC677Token { - - uint public constant totalSupply = 10**27; - string public constant name = "ChainLink Token"; - uint8 public constant decimals = 18; - string public constant symbol = "LINK"; - - function LinkToken() - public - { - balances[msg.sender] = totalSupply; - } - - /** - * @dev transfer token to a specified address with additional data if the recipient is a contract. - * @param _to The address to transfer to. - * @param _value The amount to be transferred. - * @param _data The extra data to be passed to the receiving contract. - */ - function transferAndCall(address _to, uint _value, bytes _data) - public - validRecipient(_to) - returns (bool success) - { - return super.transferAndCall(_to, _value, _data); - } - - /** - * @dev transfer token to a specified address. - * @param _to The address to transfer to. - * @param _value The amount to be transferred. - */ - function transfer(address _to, uint _value) - public - validRecipient(_to) - returns (bool success) - { - return super.transfer(_to, _value); - } - - /** - * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. - * @param _spender The address which will spend the funds. - * @param _value The amount of tokens to be spent. - */ - function approve(address _spender, uint256 _value) - public - validRecipient(_spender) - returns (bool) - { - return super.approve(_spender, _value); - } - - /** - * @dev Transfer tokens from one address to another - * @param _from address The address which you want to send tokens from - * @param _to address The address which you want to transfer to - * @param _value uint256 the amount of tokens to be transferred - */ - function transferFrom(address _from, address _to, uint256 _value) - public - validRecipient(_to) - returns (bool) - { - return super.transferFrom(_from, _to, _value); - } - - - // MODIFIERS - - modifier validRecipient(address _recipient) { - require(_recipient != address(0) && _recipient != address(this)); - _; - } - -} diff --git a/contracts/src/v0.4/Migrations.sol b/contracts/src/v0.4/Migrations.sol deleted file mode 100644 index 4f01db5cab7..00000000000 --- a/contracts/src/v0.4/Migrations.sol +++ /dev/null @@ -1,23 +0,0 @@ -pragma solidity ^0.4.24; // solhint-disable-line compiler-fixed - -contract Migrations { - address public owner; - uint public last_completed_migration; - - modifier restricted() { - if (msg.sender == owner) _; - } - - constructor() public { - owner = msg.sender; - } - - function setCompleted(uint completed) public restricted { - last_completed_migration = completed; - } - - function upgrade(address new_address) public restricted { - Migrations upgraded = Migrations(new_address); - upgraded.setCompleted(last_completed_migration); - } -} diff --git a/contracts/src/v0.4/Oracle.sol b/contracts/src/v0.4/Oracle.sol deleted file mode 100644 index 1ee9fcc3b70..00000000000 --- a/contracts/src/v0.4/Oracle.sol +++ /dev/null @@ -1,320 +0,0 @@ -pragma solidity 0.4.24; - -import "./vendor/Ownable.sol"; -import "./vendor/SafeMathChainlink.sol"; -import "./interfaces/ChainlinkRequestInterface.sol"; -import "./interfaces/OracleInterface.sol"; -import "./interfaces/LinkTokenInterface.sol"; - -/** - * @title The Chainlink Oracle contract - * @notice Node operators can deploy this contract to fulfill requests sent to them - */ -contract Oracle is ChainlinkRequestInterface, OracleInterface, Ownable { - using SafeMathChainlink for uint256; - - uint256 constant public EXPIRY_TIME = 5 minutes; - uint256 constant private MINIMUM_CONSUMER_GAS_LIMIT = 400000; - // We initialize fields to 1 instead of 0 so that the first invocation - // does not cost more gas. - uint256 constant private ONE_FOR_CONSISTENT_GAS_COST = 1; - uint256 constant private SELECTOR_LENGTH = 4; - uint256 constant private EXPECTED_REQUEST_WORDS = 2; - uint256 constant private MINIMUM_REQUEST_LENGTH = SELECTOR_LENGTH + (32 * EXPECTED_REQUEST_WORDS); - - LinkTokenInterface internal LinkToken; - mapping(bytes32 => bytes32) private commitments; - mapping(address => bool) private authorizedNodes; - uint256 private withdrawableTokens = ONE_FOR_CONSISTENT_GAS_COST; - - event OracleRequest( - bytes32 indexed specId, - address requester, - bytes32 requestId, - uint256 payment, - address callbackAddr, - bytes4 callbackFunctionId, - uint256 cancelExpiration, - uint256 dataVersion, - bytes data - ); - - event CancelOracleRequest( - bytes32 indexed requestId - ); - - /** - * @notice Deploy with the address of the LINK token - * @dev Sets the LinkToken address for the imported LinkTokenInterface - * @param _link The address of the LINK token - */ - constructor(address _link) public Ownable() { - LinkToken = LinkTokenInterface(_link); // external but already deployed and unalterable - } - - /** - * @notice Called when LINK is sent to the contract via `transferAndCall` - * @dev The data payload's first 2 words will be overwritten by the `_sender` and `_amount` - * values to ensure correctness. Calls oracleRequest. - * @param _sender Address of the sender - * @param _amount Amount of LINK sent (specified in wei) - * @param _data Payload of the transaction - */ - function onTokenTransfer( - address _sender, - uint256 _amount, - bytes _data - ) - public - onlyLINK - validRequestLength(_data) - permittedFunctionsForLINK(_data) - { - assembly { // solhint-disable-line no-inline-assembly - mstore(add(_data, 36), _sender) // ensure correct sender is passed - mstore(add(_data, 68), _amount) // ensure correct amount is passed - } - // solhint-disable-next-line avoid-low-level-calls - require(address(this).delegatecall(_data), "Unable to create request"); // calls oracleRequest - } - - /** - * @notice Creates the Chainlink request - * @dev Stores the hash of the params as the on-chain commitment for the request. - * Emits OracleRequest event for the Chainlink node to detect. - * @param _sender The sender of the request - * @param _payment The amount of payment given (specified in wei) - * @param _specId The Job Specification ID - * @param _callbackAddress The callback address for the response - * @param _callbackFunctionId The callback function ID for the response - * @param _nonce The nonce sent by the requester - * @param _dataVersion The specified data version - * @param _data The CBOR payload of the request - */ - function oracleRequest( - address _sender, - uint256 _payment, - bytes32 _specId, - address _callbackAddress, - bytes4 _callbackFunctionId, - uint256 _nonce, - uint256 _dataVersion, - bytes _data - ) - external - onlyLINK - checkCallbackAddress(_callbackAddress) - { - bytes32 requestId = keccak256(abi.encodePacked(_sender, _nonce)); - require(commitments[requestId] == 0, "Must use a unique ID"); - // solhint-disable-next-line not-rely-on-time - uint256 expiration = now.add(EXPIRY_TIME); - - commitments[requestId] = keccak256( - abi.encodePacked( - _payment, - _callbackAddress, - _callbackFunctionId, - expiration - ) - ); - - emit OracleRequest( - _specId, - _sender, - requestId, - _payment, - _callbackAddress, - _callbackFunctionId, - expiration, - _dataVersion, - _data); - } - - /** - * @notice Called by the Chainlink node to fulfill requests - * @dev Given params must hash back to the commitment stored from `oracleRequest`. - * Will call the callback address' callback function without bubbling up error - * checking in a `require` so that the node can get paid. - * @param _requestId The fulfillment request ID that must match the requester's - * @param _payment The payment amount that will be released for the oracle (specified in wei) - * @param _callbackAddress The callback address to call for fulfillment - * @param _callbackFunctionId The callback function ID to use for fulfillment - * @param _expiration The expiration that the node should respond by before the requester can cancel - * @param _data The data to return to the consuming contract - * @return Status if the external call was successful - */ - function fulfillOracleRequest( - bytes32 _requestId, - uint256 _payment, - address _callbackAddress, - bytes4 _callbackFunctionId, - uint256 _expiration, - bytes32 _data - ) - external - onlyAuthorizedNode - isValidRequest(_requestId) - returns (bool) - { - bytes32 paramsHash = keccak256( - abi.encodePacked( - _payment, - _callbackAddress, - _callbackFunctionId, - _expiration - ) - ); - require(commitments[_requestId] == paramsHash, "Params do not match request ID"); - withdrawableTokens = withdrawableTokens.add(_payment); - delete commitments[_requestId]; - require(gasleft() >= MINIMUM_CONSUMER_GAS_LIMIT, "Must provide consumer enough gas"); - // All updates to the oracle's fulfillment should come before calling the - // callback(addr+functionId) as it is untrusted. - // See: https://solidity.readthedocs.io/en/develop/security-considerations.html#use-the-checks-effects-interactions-pattern - return _callbackAddress.call(_callbackFunctionId, _requestId, _data); // solhint-disable-line avoid-low-level-calls - } - - /** - * @notice Use this to check if a node is authorized for fulfilling requests - * @param _node The address of the Chainlink node - * @return The authorization status of the node - */ - function getAuthorizationStatus(address _node) external view returns (bool) { - return authorizedNodes[_node]; - } - - /** - * @notice Sets the fulfillment permission for a given node. Use `true` to allow, `false` to disallow. - * @param _node The address of the Chainlink node - * @param _allowed Bool value to determine if the node can fulfill requests - */ - function setFulfillmentPermission(address _node, bool _allowed) external onlyOwner { - authorizedNodes[_node] = _allowed; - } - - /** - * @notice Allows the node operator to withdraw earned LINK to a given address - * @dev The owner of the contract can be another wallet and does not have to be a Chainlink node - * @param _recipient The address to send the LINK token to - * @param _amount The amount to send (specified in wei) - */ - function withdraw(address _recipient, uint256 _amount) - external - onlyOwner - hasAvailableFunds(_amount) - { - withdrawableTokens = withdrawableTokens.sub(_amount); - assert(LinkToken.transfer(_recipient, _amount)); - } - - /** - * @notice Displays the amount of LINK that is available for the node operator to withdraw - * @dev We use `ONE_FOR_CONSISTENT_GAS_COST` in place of 0 in storage - * @return The amount of withdrawable LINK on the contract - */ - function withdrawable() external view onlyOwner returns (uint256) { - return withdrawableTokens.sub(ONE_FOR_CONSISTENT_GAS_COST); - } - - /** - * @notice Allows requesters to cancel requests sent to this oracle contract. Will transfer the LINK - * sent for the request back to the requester's address. - * @dev Given params must hash to a commitment stored on the contract in order for the request to be valid - * Emits CancelOracleRequest event. - * @param _requestId The request ID - * @param _payment The amount of payment given (specified in wei) - * @param _callbackFunc The requester's specified callback address - * @param _expiration The time of the expiration for the request - */ - function cancelOracleRequest( - bytes32 _requestId, - uint256 _payment, - bytes4 _callbackFunc, - uint256 _expiration - ) external { - bytes32 paramsHash = keccak256( - abi.encodePacked( - _payment, - msg.sender, - _callbackFunc, - _expiration) - ); - require(paramsHash == commitments[_requestId], "Params do not match request ID"); - // solhint-disable-next-line not-rely-on-time - require(_expiration <= now, "Request is not expired"); - - delete commitments[_requestId]; - emit CancelOracleRequest(_requestId); - - assert(LinkToken.transfer(msg.sender, _payment)); - } - - // MODIFIERS - - /** - * @dev Reverts if amount requested is greater than withdrawable balance - * @param _amount The given amount to compare to `withdrawableTokens` - */ - modifier hasAvailableFunds(uint256 _amount) { - require(withdrawableTokens >= _amount.add(ONE_FOR_CONSISTENT_GAS_COST), "Amount requested is greater than withdrawable balance"); - _; - } - - /** - * @dev Reverts if request ID does not exist - * @param _requestId The given request ID to check in stored `commitments` - */ - modifier isValidRequest(bytes32 _requestId) { - require(commitments[_requestId] != 0, "Must have a valid requestId"); - _; - } - - /** - * @dev Reverts if `msg.sender` is not authorized to fulfill requests - */ - modifier onlyAuthorizedNode() { - require(authorizedNodes[msg.sender] || msg.sender == owner, "Not an authorized node to fulfill requests"); - _; - } - - /** - * @dev Reverts if not sent from the LINK token - */ - modifier onlyLINK() { - require(msg.sender == address(LinkToken), "Must use LINK token"); - _; - } - - /** - * @dev Reverts if the given data does not begin with the `oracleRequest` function selector - * @param _data The data payload of the request - */ - modifier permittedFunctionsForLINK(bytes _data) { - bytes4 funcSelector; - assembly { // solhint-disable-line no-inline-assembly - funcSelector := mload(add(_data, 32)) - } - require(funcSelector == this.oracleRequest.selector, "Must use whitelisted functions"); - _; - } - - /** - * @dev Reverts if the callback address is the LINK token - * @param _to The callback address - */ - modifier checkCallbackAddress(address _to) { - require(_to != address(LinkToken), "Cannot callback to LINK"); - _; - } - - /** - * @dev Reverts if the given payload is less than needed to create a request - * @param _data The request payload - */ - modifier validRequestLength(bytes _data) { - require(_data.length >= MINIMUM_REQUEST_LENGTH, "Invalid request length"); - _; - } - -} diff --git a/contracts/src/v0.4/Pointer.sol b/contracts/src/v0.4/Pointer.sol deleted file mode 100644 index 40ff35f0934..00000000000 --- a/contracts/src/v0.4/Pointer.sol +++ /dev/null @@ -1,9 +0,0 @@ -pragma solidity 0.4.24; - -contract Pointer { - address public getAddress; - - constructor(address _addr) public { - getAddress = _addr; - } -} diff --git a/contracts/src/v0.4/interfaces/AggregatorInterface.sol b/contracts/src/v0.4/interfaces/AggregatorInterface.sol deleted file mode 100644 index d9eaf171711..00000000000 --- a/contracts/src/v0.4/interfaces/AggregatorInterface.sol +++ /dev/null @@ -1,12 +0,0 @@ -pragma solidity >=0.4.24; - -interface AggregatorInterface { - function latestAnswer() external view returns (int256); - function latestTimestamp() external view returns (uint256); - function latestRound() external view returns (uint256); - function getAnswer(uint256 roundId) external view returns (int256); - function getTimestamp(uint256 roundId) external view returns (uint256); - - event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 timestamp); - event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt); -} diff --git a/contracts/src/v0.4/interfaces/AggregatorV3Interface.sol b/contracts/src/v0.4/interfaces/AggregatorV3Interface.sol deleted file mode 100644 index f6b4849e995..00000000000 --- a/contracts/src/v0.4/interfaces/AggregatorV3Interface.sol +++ /dev/null @@ -1,33 +0,0 @@ -pragma solidity >=0.4.24; - -interface AggregatorV3Interface { - - function decimals() external view returns (uint8); - function description() external view returns (string memory); - function version() external view returns (uint256); - - // getRoundData and latestRoundData should both raise "No data present" - // if they do not have data to report, instead of returning unset values - // which could be misinterpreted as actual reported values. - function getRoundData(uint80 _roundId) - external - view - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - function latestRoundData() - external - view - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - -} diff --git a/contracts/src/v0.4/interfaces/ChainlinkRequestInterface.sol b/contracts/src/v0.4/interfaces/ChainlinkRequestInterface.sol deleted file mode 100644 index d61c38e7be1..00000000000 --- a/contracts/src/v0.4/interfaces/ChainlinkRequestInterface.sol +++ /dev/null @@ -1,21 +0,0 @@ -pragma solidity ^0.4.24; - -interface ChainlinkRequestInterface { - function oracleRequest( - address sender, - uint256 payment, - bytes32 id, - address callbackAddress, - bytes4 callbackFunctionId, - uint256 nonce, - uint256 version, - bytes data - ) external; - - function cancelOracleRequest( - bytes32 requestId, - uint256 payment, - bytes4 callbackFunctionId, - uint256 expiration - ) external; -} diff --git a/contracts/src/v0.4/interfaces/ENSInterface.sol b/contracts/src/v0.4/interfaces/ENSInterface.sol deleted file mode 100644 index f374a46b1fa..00000000000 --- a/contracts/src/v0.4/interfaces/ENSInterface.sol +++ /dev/null @@ -1,26 +0,0 @@ -pragma solidity ^0.4.24; - -interface ENSInterface { - - // Logged when the owner of a node assigns a new owner to a subnode. - event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner); - - // Logged when the owner of a node transfers ownership to a new account. - event Transfer(bytes32 indexed node, address owner); - - // Logged when the resolver for a node changes. - event NewResolver(bytes32 indexed node, address resolver); - - // Logged when the TTL of a node changes - event NewTTL(bytes32 indexed node, uint64 ttl); - - - function setSubnodeOwner(bytes32 node, bytes32 label, address owner) external; - function setResolver(bytes32 node, address resolver) external; - function setOwner(bytes32 node, address owner) external; - function setTTL(bytes32 node, uint64 ttl) external; - function owner(bytes32 node) external view returns (address); - function resolver(bytes32 node) external view returns (address); - function ttl(bytes32 node) external view returns (uint64); - -} diff --git a/contracts/src/v0.4/interfaces/ERC20.sol b/contracts/src/v0.4/interfaces/ERC20.sol deleted file mode 100644 index fd978c33e81..00000000000 --- a/contracts/src/v0.4/interfaces/ERC20.sol +++ /dev/null @@ -1,16 +0,0 @@ -pragma solidity ^0.4.11; - - -import { ERC20Basic as linkERC20Basic } from "./ERC20Basic.sol"; - - -/** - * @title ERC20 interface - * @dev see https://github.com/ethereum/EIPs/issues/20 - */ -contract ERC20 is linkERC20Basic { - function allowance(address owner, address spender) constant returns (uint256); - function transferFrom(address from, address to, uint256 value) returns (bool); - function approve(address spender, uint256 value) returns (bool); - event Approval(address indexed owner, address indexed spender, uint256 value); -} diff --git a/contracts/src/v0.4/interfaces/ERC20Basic.sol b/contracts/src/v0.4/interfaces/ERC20Basic.sol deleted file mode 100644 index 07ab02f0b82..00000000000 --- a/contracts/src/v0.4/interfaces/ERC20Basic.sol +++ /dev/null @@ -1,14 +0,0 @@ -pragma solidity ^0.4.11; - - -/** - * @title ERC20Basic - * @dev Simpler version of ERC20 interface - * @dev see https://github.com/ethereum/EIPs/issues/179 - */ -contract ERC20Basic { - uint256 public totalSupply; - function balanceOf(address who) constant returns (uint256); - function transfer(address to, uint256 value) returns (bool); - event Transfer(address indexed from, address indexed to, uint256 value); -} diff --git a/contracts/src/v0.4/interfaces/ERC677.sol b/contracts/src/v0.4/interfaces/ERC677.sol deleted file mode 100644 index 1e6714f8ccf..00000000000 --- a/contracts/src/v0.4/interfaces/ERC677.sol +++ /dev/null @@ -1,9 +0,0 @@ -pragma solidity ^0.4.8; - -import { ERC20 as linkERC20 } from "./ERC20.sol"; - -contract ERC677 is linkERC20 { - function transferAndCall(address to, uint value, bytes data) returns (bool success); - - event Transfer(address indexed from, address indexed to, uint value, bytes data); -} diff --git a/contracts/src/v0.4/interfaces/ERC677Receiver.sol b/contracts/src/v0.4/interfaces/ERC677Receiver.sol deleted file mode 100644 index 8a46d0b689d..00000000000 --- a/contracts/src/v0.4/interfaces/ERC677Receiver.sol +++ /dev/null @@ -1,6 +0,0 @@ -pragma solidity ^0.4.8; - - -contract ERC677Receiver { - function onTokenTransfer(address _sender, uint _value, bytes _data); -} diff --git a/contracts/src/v0.4/interfaces/FlagsInterface.sol b/contracts/src/v0.4/interfaces/FlagsInterface.sol deleted file mode 100644 index 5a0373e9992..00000000000 --- a/contracts/src/v0.4/interfaces/FlagsInterface.sol +++ /dev/null @@ -1,10 +0,0 @@ -pragma solidity >=0.4.24; - -interface FlagsInterface { - function getFlag(address) external view returns (bool); - function getFlags(address[] calldata) external view returns (bool[] memory); - function raiseFlag(address) external; - function raiseFlags(address[] calldata) external; - function lowerFlags(address[] calldata) external; - function setRaisingAccessController(address) external; -} diff --git a/contracts/src/v0.4/interfaces/LinkTokenInterface.sol b/contracts/src/v0.4/interfaces/LinkTokenInterface.sol deleted file mode 100644 index d4f813c39cf..00000000000 --- a/contracts/src/v0.4/interfaces/LinkTokenInterface.sol +++ /dev/null @@ -1,16 +0,0 @@ -pragma solidity ^0.4.24; - -interface LinkTokenInterface { - function allowance(address owner, address spender) external view returns (uint256 remaining); - function approve(address spender, uint256 value) external returns (bool success); - function balanceOf(address owner) external view returns (uint256 balance); - function decimals() external view returns (uint8 decimalPlaces); - function decreaseApproval(address spender, uint256 addedValue) external returns (bool success); - function increaseApproval(address spender, uint256 subtractedValue) external; - function name() external view returns (string tokenName); - function symbol() external view returns (string tokenSymbol); - function totalSupply() external view returns (uint256 totalTokensIssued); - function transfer(address to, uint256 value) external returns (bool success); - function transferAndCall(address to, uint256 value, bytes data) external returns (bool success); - function transferFrom(address from, address to, uint256 value) external returns (bool success); -} diff --git a/contracts/src/v0.4/interfaces/OracleInterface.sol b/contracts/src/v0.4/interfaces/OracleInterface.sol deleted file mode 100644 index 9a324454525..00000000000 --- a/contracts/src/v0.4/interfaces/OracleInterface.sol +++ /dev/null @@ -1,16 +0,0 @@ -pragma solidity ^0.4.24; - -interface OracleInterface { - function fulfillOracleRequest( - bytes32 requestId, - uint256 payment, - address callbackAddress, - bytes4 callbackFunctionId, - uint256 expiration, - bytes32 data - ) external returns (bool); - function getAuthorizationStatus(address node) external view returns (bool); - function setFulfillmentPermission(address node, bool allowed) external; - function withdraw(address recipient, uint256 amount) external; - function withdrawable() external view returns (uint256); -} diff --git a/contracts/src/v0.4/interfaces/PointerInterface.sol b/contracts/src/v0.4/interfaces/PointerInterface.sol deleted file mode 100644 index ba0d224c04d..00000000000 --- a/contracts/src/v0.4/interfaces/PointerInterface.sol +++ /dev/null @@ -1,5 +0,0 @@ -pragma solidity ^0.4.24; - -interface PointerInterface { - function getAddress() external view returns (address); -} diff --git a/contracts/src/v0.4/tests/BasicConsumer.sol b/contracts/src/v0.4/tests/BasicConsumer.sol deleted file mode 100644 index 42e5bfe2be6..00000000000 --- a/contracts/src/v0.4/tests/BasicConsumer.sol +++ /dev/null @@ -1,13 +0,0 @@ -pragma solidity 0.4.24; - -import "./Consumer.sol"; - -contract BasicConsumer is Consumer { - - constructor(address _link, address _oracle, bytes32 _specId) public { - setChainlinkToken(_link); - setChainlinkOracle(_oracle); - specId = _specId; - } - -} diff --git a/contracts/src/v0.4/tests/ConcreteChainlink.sol b/contracts/src/v0.4/tests/ConcreteChainlink.sol deleted file mode 100644 index da4756ddc53..00000000000 --- a/contracts/src/v0.4/tests/ConcreteChainlink.sol +++ /dev/null @@ -1,77 +0,0 @@ -pragma solidity 0.4.24; - -import "../Chainlink.sol"; -import { CBOR as CBOR_Chainlink } from "../vendor/CBOR.sol"; -import { Buffer as Buffer_Chainlink } from "../vendor/Buffer.sol"; - -contract ConcreteChainlink { - using Chainlink for Chainlink.Request; - using CBOR_Chainlink for Buffer_Chainlink.buffer; - - Chainlink.Request private req; - - event RequestData(bytes payload); - - function closeEvent() public { - emit RequestData(req.buf.buf); - } - - function setBuffer(bytes data) public { - Chainlink.Request memory r2 = req; - r2.setBuffer(data); - req = r2; - } - - function add(string _key, string _value) public { - Chainlink.Request memory r2 = req; - r2.add(_key, _value); - req = r2; - } - - function addBytes(string _key, bytes _value) public { - Chainlink.Request memory r2 = req; - r2.addBytes(_key, _value); - req = r2; - } - - function addInt(string _key, int256 _value) public { - Chainlink.Request memory r2 = req; - r2.addInt(_key, _value); - req = r2; - } - - function addUint(string _key, uint256 _value) public { - Chainlink.Request memory r2 = req; - r2.addUint(_key, _value); - req = r2; - } - - // Temporarily have method receive bytes32[] memory until experimental - // string[] memory can be invoked from truffle tests. - function addStringArray(string _key, bytes32[] memory _values) public { - string[] memory strings = new string[](_values.length); - for (uint256 i = 0; i < _values.length; i++) { - strings[i] = bytes32ToString(_values[i]); - } - Chainlink.Request memory r2 = req; - r2.addStringArray(_key, strings); - req = r2; - } - - function bytes32ToString(bytes32 x) private pure returns (string) { - bytes memory bytesString = new bytes(32); - uint charCount = 0; - for (uint j = 0; j < 32; j++) { - byte char = byte(bytes32(uint(x) * 2 ** (8 * j))); - if (char != 0) { - bytesString[charCount] = char; - charCount++; - } - } - bytes memory bytesStringTrimmed = new bytes(charCount); - for (j = 0; j < charCount; j++) { - bytesStringTrimmed[j] = bytesString[j]; - } - return string(bytesStringTrimmed); - } -} diff --git a/contracts/src/v0.4/tests/ConcreteChainlinked.sol b/contracts/src/v0.4/tests/ConcreteChainlinked.sol deleted file mode 100644 index bed787e9ac5..00000000000 --- a/contracts/src/v0.4/tests/ConcreteChainlinked.sol +++ /dev/null @@ -1,101 +0,0 @@ -pragma solidity 0.4.24; - -import "../Chainlinked.sol"; -import "../vendor/SafeMathChainlink.sol"; - -contract ConcreteChainlinked is Chainlinked { - using SafeMathChainlink for uint256; - - constructor(address _link, address _oracle) public { - setLinkToken(_link); - setOracle(_oracle); - } - - event Request( - bytes32 id, - address callbackAddress, - bytes4 callbackfunctionSelector, - bytes data - ); - - function publicNewRequest( - bytes32 _id, - address _address, - bytes _fulfillmentSignature - ) - public - { - Chainlink.Request memory req = newRequest( - _id, _address, bytes4(keccak256(_fulfillmentSignature))); - emit Request( - req.id, - req.callbackAddress, - req.callbackFunctionId, - req.buf.buf - ); - } - - function publicRequest( - bytes32 _id, - address _address, - bytes _fulfillmentSignature, - uint256 _wei - ) - public - { - Chainlink.Request memory req = newRequest( - _id, _address, bytes4(keccak256(_fulfillmentSignature))); - chainlinkRequest(req, _wei); - } - - function publicRequestRunTo( - address _oracle, - bytes32 _id, - address _address, - bytes _fulfillmentSignature, - uint256 _wei - ) - public - { - Chainlink.Request memory run = newRequest(_id, _address, bytes4(keccak256(_fulfillmentSignature))); - chainlinkRequestTo(_oracle, run, _wei); - } - - function publicCancelRequest( - bytes32 _requestId, - uint256 _payment, - bytes4 _callbackFunctionId, - uint256 _expiration - ) public { - cancelChainlinkRequest(_requestId, _payment, _callbackFunctionId, _expiration); - } - - function publicChainlinkToken() public view returns (address) { - return chainlinkToken(); - } - - function fulfillRequest(bytes32 _requestId, bytes32) - public - recordChainlinkFulfillment(_requestId) - {} // solhint-disable-line no-empty-blocks - - function publicFulfillChainlinkRequest(bytes32 _requestId, bytes32) public { - fulfillChainlinkRequest(_requestId); - } - - event LinkAmount(uint256 amount); - - function publicLINK(uint256 _amount) public { - emit LinkAmount(LINK.mul(_amount)); - } - - function publicOracleAddress() public view returns (address) { - return oracleAddress(); - } - - function publicAddExternalRequest(address _oracle, bytes32 _requestId) - public - { - addExternalRequest(_oracle, _requestId); - } -} diff --git a/contracts/src/v0.4/tests/Consumer.sol b/contracts/src/v0.4/tests/Consumer.sol deleted file mode 100644 index 9fe29dd1540..00000000000 --- a/contracts/src/v0.4/tests/Consumer.sol +++ /dev/null @@ -1,47 +0,0 @@ -pragma solidity 0.4.24; - -import "../ChainlinkClient.sol"; - -contract Consumer is ChainlinkClient { - bytes32 internal specId; - bytes32 public currentPrice; - - uint256 constant private ORACLE_PAYMENT = 1 * LINK; - - event RequestFulfilled( - bytes32 indexed requestId, // User-defined ID - bytes32 indexed price - ); - - function requestEthereumPrice(string _currency) public { - Chainlink.Request memory req = buildChainlinkRequest(specId, this, this.fulfill.selector); - req.add("get", "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD,EUR,JPY"); - string[] memory path = new string[](1); - path[0] = _currency; - req.addStringArray("path", path); - sendChainlinkRequest(req, ORACLE_PAYMENT); - } - - function cancelRequest( - bytes32 _requestId, - uint256 _payment, - bytes4 _callbackFunctionId, - uint256 _expiration - ) public { - cancelChainlinkRequest(_requestId, _payment, _callbackFunctionId, _expiration); - } - - function withdrawLink() public { - LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress()); - require(link.transfer(msg.sender, link.balanceOf(address(this))), "Unable to transfer"); - } - - function fulfill(bytes32 _requestId, bytes32 _price) - public - recordChainlinkFulfillment(_requestId) - { - emit RequestFulfilled(_requestId, _price); - currentPrice = _price; - } - -} diff --git a/contracts/src/v0.4/tests/EmptyOracle.sol b/contracts/src/v0.4/tests/EmptyOracle.sol deleted file mode 100644 index b437ef6173f..00000000000 --- a/contracts/src/v0.4/tests/EmptyOracle.sol +++ /dev/null @@ -1,19 +0,0 @@ -pragma solidity 0.4.24; - -import "../interfaces/ChainlinkRequestInterface.sol"; -import "../interfaces/OracleInterface.sol"; - -/* solhint-disable no-empty-blocks */ - -contract EmptyOracle is ChainlinkRequestInterface, OracleInterface { - - function cancelOracleRequest(bytes32, uint256, bytes4, uint256) external {} - function fulfillOracleRequest(bytes32, uint256, address, bytes4, uint256, bytes32) external returns (bool) {} - function getAuthorizationStatus(address) external view returns (bool) { return false; } - function onTokenTransfer(address, uint256, bytes) external pure {} - function oracleRequest(address, uint256, bytes32, address, bytes4, uint256, uint256, bytes) external {} - function setFulfillmentPermission(address, bool) external {} - function withdraw(address, uint256) external {} - function withdrawable() external view returns (uint256) {} - -} diff --git a/contracts/src/v0.4/tests/GetterSetter.sol b/contracts/src/v0.4/tests/GetterSetter.sol deleted file mode 100644 index fcd86c7d4fe..00000000000 --- a/contracts/src/v0.4/tests/GetterSetter.sol +++ /dev/null @@ -1,45 +0,0 @@ -pragma solidity 0.4.24; - -// GetterSetter is a contract to aid debugging and testing during development. -contract GetterSetter { - bytes32 public getBytes32; - uint256 public getUint256; - bytes32 public requestId; - bytes public getBytes; - - event SetBytes32(address indexed from, bytes32 indexed value); - event SetUint256(address indexed from, uint256 indexed value); - event SetBytes(address indexed from, bytes value); - - event Output(bytes32 b32, uint256 u256, bytes32 b322); - - function setBytes32(bytes32 _value) public { - getBytes32 = _value; - emit SetBytes32(msg.sender, _value); - } - - function requestedBytes32(bytes32 _requestId, bytes32 _value) public { - requestId = _requestId; - setBytes32(_value); - } - - function setBytes(bytes _value) public { - getBytes = _value; - emit SetBytes(msg.sender, _value); - } - - function requestedBytes(bytes32 _requestId, bytes _value) public { - requestId = _requestId; - setBytes(_value); - } - - function setUint256(uint256 _value) public { - getUint256 = _value; - emit SetUint256(msg.sender, _value); - } - - function requestedUint256(bytes32 _requestId, uint256 _value) public { - requestId = _requestId; - setUint256(_value); - } -} diff --git a/contracts/src/v0.4/tests/MaliciousChainlink.sol b/contracts/src/v0.4/tests/MaliciousChainlink.sol deleted file mode 100644 index 8a0d04851e0..00000000000 --- a/contracts/src/v0.4/tests/MaliciousChainlink.sol +++ /dev/null @@ -1,76 +0,0 @@ -pragma solidity 0.4.24; - -import { CBOR as CBOR_Chainlink } from "../vendor/CBOR.sol"; -import { Buffer as Buffer_Chainlink } from "../vendor/Buffer.sol"; - -library MaliciousChainlink { - using CBOR_Chainlink for Buffer_Chainlink.buffer; - - struct Request { - bytes32 specId; - address callbackAddress; - bytes4 callbackFunctionId; - uint256 nonce; - Buffer_Chainlink.buffer buf; - } - - struct WithdrawRequest { - bytes32 specId; - address callbackAddress; - bytes4 callbackFunctionId; - uint256 nonce; - Buffer_Chainlink.buffer buf; - } - - function initializeWithdraw( - WithdrawRequest memory self, - bytes32 _specId, - address _callbackAddress, - bytes4 _callbackFunction - ) internal pure returns (MaliciousChainlink.WithdrawRequest memory) { - Buffer_Chainlink.init(self.buf, 128); - self.specId = _specId; - self.callbackAddress = _callbackAddress; - self.callbackFunctionId = _callbackFunction; - return self; - } - - function add(Request memory self, string _key, string _value) - internal pure - { - self.buf.encodeString(_key); - self.buf.encodeString(_value); - } - - function addBytes(Request memory self, string _key, bytes _value) - internal pure - { - self.buf.encodeString(_key); - self.buf.encodeBytes(_value); - } - - function addInt(Request memory self, string _key, int256 _value) - internal pure - { - self.buf.encodeString(_key); - self.buf.encodeInt(_value); - } - - function addUint(Request memory self, string _key, uint256 _value) - internal pure - { - self.buf.encodeString(_key); - self.buf.encodeUInt(_value); - } - - function addStringArray(Request memory self, string _key, string[] memory _values) - internal pure - { - self.buf.encodeString(_key); - self.buf.startArray(); - for (uint256 i = 0; i < _values.length; i++) { - self.buf.encodeString(_values[i]); - } - self.buf.endSequence(); - } -} diff --git a/contracts/src/v0.4/tests/MaliciousChainlinked.sol b/contracts/src/v0.4/tests/MaliciousChainlinked.sol deleted file mode 100644 index b5b87958bb4..00000000000 --- a/contracts/src/v0.4/tests/MaliciousChainlinked.sol +++ /dev/null @@ -1,109 +0,0 @@ -pragma solidity 0.4.24; - -import "./MaliciousChainlink.sol"; -import "../Chainlinked.sol"; -import "../vendor/SafeMathChainlink.sol"; - -contract MaliciousChainlinked is Chainlinked { - using MaliciousChainlink for MaliciousChainlink.Request; - using MaliciousChainlink for MaliciousChainlink.WithdrawRequest; - using Chainlink for Chainlink.Request; - using SafeMathChainlink for uint256; - - uint256 private maliciousRequests = 1; - mapping(bytes32 => address) private maliciousPendingRequests; - - function newWithdrawRequest( - bytes32 _specId, - address _callbackAddress, - bytes4 _callbackFunction - ) internal pure returns (MaliciousChainlink.WithdrawRequest memory) { - MaliciousChainlink.WithdrawRequest memory req; - return req.initializeWithdraw(_specId, _callbackAddress, _callbackFunction); - } - - function chainlinkTargetRequest(address _target, Chainlink.Request memory _req, uint256 _amount) - internal - returns(bytes32 requestId) - { - requestId = keccak256(abi.encodePacked(_target, maliciousRequests)); - _req.nonce = maliciousRequests; - maliciousPendingRequests[requestId] = oracleAddress(); - emit ChainlinkRequested(requestId); - LinkTokenInterface link = LinkTokenInterface(chainlinkToken()); - require(link.transferAndCall(oracleAddress(), _amount, encodeTargetRequest(_req)), "Unable to transferAndCall to oracle"); - maliciousRequests += 1; - - return requestId; - } - - function chainlinkPriceRequest(Chainlink.Request memory _req, uint256 _amount) - internal - returns(bytes32 requestId) - { - requestId = keccak256(abi.encodePacked(this, maliciousRequests)); - _req.nonce = maliciousRequests; - maliciousPendingRequests[requestId] = oracleAddress(); - emit ChainlinkRequested(requestId); - LinkTokenInterface link = LinkTokenInterface(chainlinkToken()); - require(link.transferAndCall(oracleAddress(), _amount, encodePriceRequest(_req)), "Unable to transferAndCall to oracle"); - maliciousRequests += 1; - - return requestId; - } - - function chainlinkWithdrawRequest(MaliciousChainlink.WithdrawRequest memory _req, uint256 _wei) - internal - returns(bytes32 requestId) - { - requestId = keccak256(abi.encodePacked(this, maliciousRequests)); - _req.nonce = maliciousRequests; - maliciousPendingRequests[requestId] = oracleAddress(); - emit ChainlinkRequested(requestId); - LinkTokenInterface link = LinkTokenInterface(chainlinkToken()); - require(link.transferAndCall(oracleAddress(), _wei, encodeWithdrawRequest(_req)), "Unable to transferAndCall to oracle"); - maliciousRequests += 1; - return requestId; - } - - function encodeWithdrawRequest(MaliciousChainlink.WithdrawRequest memory _req) - internal pure returns (bytes memory) - { - return abi.encodeWithSelector( - bytes4(keccak256("withdraw(address,uint256)")), - _req.callbackAddress, - _req.callbackFunctionId, - _req.nonce, - _req.buf.buf); - } - - function encodeTargetRequest(Chainlink.Request memory _req) - internal pure returns (bytes memory) - { - return abi.encodeWithSelector( - bytes4(keccak256("oracleRequest(address,uint256,bytes32,address,bytes4,uint256,uint256,bytes)")), - 0, // overridden by onTokenTransfer - 0, // overridden by onTokenTransfer - _req.id, - _req.callbackAddress, - _req.callbackFunctionId, - _req.nonce, - 1, - _req.buf.buf); - } - - function encodePriceRequest(Chainlink.Request memory _req) - internal pure returns (bytes memory) - { - return abi.encodeWithSelector( - bytes4(keccak256("oracleRequest(address,uint256,bytes32,address,bytes4,uint256,uint256,bytes)")), - 0, // overridden by onTokenTransfer - 2000000000000000000, // overridden by onTokenTransfer - _req.id, - _req.callbackAddress, - _req.callbackFunctionId, - _req.nonce, - 1, - _req.buf.buf); - } -} diff --git a/contracts/src/v0.4/tests/MaliciousConsumer.sol b/contracts/src/v0.4/tests/MaliciousConsumer.sol deleted file mode 100644 index b7b41d62c73..00000000000 --- a/contracts/src/v0.4/tests/MaliciousConsumer.sol +++ /dev/null @@ -1,57 +0,0 @@ -pragma solidity 0.4.24; - - -import "../Chainlinked.sol"; -import "../vendor/SafeMathChainlink.sol"; - - -contract MaliciousConsumer is Chainlinked { - using SafeMathChainlink for uint256; - - uint256 constant private ORACLE_PAYMENT = 1 * LINK; - uint256 private expiration; - - constructor(address _link, address _oracle) public payable { - setLinkToken(_link); - setOracle(_oracle); - } - - function () public payable {} // solhint-disable-line no-empty-blocks - - function requestData(bytes32 _id, bytes _callbackFunc) public { - Chainlink.Request memory req = newRequest(_id, this, bytes4(keccak256(_callbackFunc))); - expiration = now.add(5 minutes); // solhint-disable-line not-rely-on-time - chainlinkRequest(req, ORACLE_PAYMENT); - } - - function assertFail(bytes32, bytes32) public pure { - assert(1 == 2); - } - - function cancelRequestOnFulfill(bytes32 _requestId, bytes32) public { - cancelChainlinkRequest( - _requestId, - ORACLE_PAYMENT, - this.cancelRequestOnFulfill.selector, - expiration); - } - - function remove() public { - selfdestruct(address(0)); - } - - function stealEthCall(bytes32 _requestId, bytes32) public recordChainlinkFulfillment(_requestId) { - require(address(this).call.value(100)(), "Call failed"); // solhint-disable-line avoid-call-value - } - - function stealEthSend(bytes32 _requestId, bytes32) public recordChainlinkFulfillment(_requestId) { - // solhint-disable-next-line check-send-result - require(address(this).send(100), "Send failed"); // solhint-disable-line multiple-sends - } - - function stealEthTransfer(bytes32 _requestId, bytes32) public recordChainlinkFulfillment(_requestId) { - address(this).transfer(100); - } - - function doesNothing(bytes32, bytes32) public pure {} // solhint-disable-line no-empty-blocks -} diff --git a/contracts/src/v0.4/tests/MaliciousRequester.sol b/contracts/src/v0.4/tests/MaliciousRequester.sol deleted file mode 100644 index ae6468f606c..00000000000 --- a/contracts/src/v0.4/tests/MaliciousRequester.sol +++ /dev/null @@ -1,52 +0,0 @@ -pragma solidity 0.4.24; - - -import "./MaliciousChainlinked.sol"; - - -contract MaliciousRequester is MaliciousChainlinked { - - uint256 constant private ORACLE_PAYMENT = 1 * LINK; - uint256 private expiration; - - constructor(address _link, address _oracle) public { - setLinkToken(_link); - setOracle(_oracle); - } - - function maliciousWithdraw() - public - { - MaliciousChainlink.WithdrawRequest memory req = newWithdrawRequest( - "specId", this, this.doesNothing.selector); - chainlinkWithdrawRequest(req, ORACLE_PAYMENT); - } - - function request(bytes32 _id, address _target, bytes _callbackFunc) public returns (bytes32 requestId) { - Chainlink.Request memory req = newRequest(_id, _target, bytes4(keccak256(_callbackFunc))); - expiration = now.add(5 minutes); // solhint-disable-line not-rely-on-time - requestId = chainlinkRequest(req, ORACLE_PAYMENT); - } - - function maliciousPrice(bytes32 _id) public returns (bytes32 requestId) { - Chainlink.Request memory req = newRequest(_id, this, this.doesNothing.selector); - requestId = chainlinkPriceRequest(req, ORACLE_PAYMENT); - } - - function maliciousTargetConsumer(address _target) public returns (bytes32 requestId) { - Chainlink.Request memory req = newRequest("specId", _target, bytes4(keccak256("fulfill(bytes32,bytes32)"))); - requestId = chainlinkTargetRequest(_target, req, ORACLE_PAYMENT); - } - - function maliciousRequestCancel(bytes32 _id, bytes _callbackFunc) public { - ChainlinkRequestInterface oracle = ChainlinkRequestInterface(oracleAddress()); - oracle.cancelOracleRequest( - request(_id, this, _callbackFunc), - ORACLE_PAYMENT, - this.maliciousRequestCancel.selector, - expiration - ); - } - - function doesNothing(bytes32, bytes32) public pure {} // solhint-disable-line no-empty-blocks -} diff --git a/contracts/src/v0.4/tests/UpdatableConsumer.sol b/contracts/src/v0.4/tests/UpdatableConsumer.sol deleted file mode 100644 index 933dbcbe701..00000000000 --- a/contracts/src/v0.4/tests/UpdatableConsumer.sol +++ /dev/null @@ -1,24 +0,0 @@ -pragma solidity 0.4.24; - -import "./Consumer.sol"; - -contract UpdatableConsumer is Consumer { - - constructor(bytes32 _specId, address _ens, bytes32 _node) public { - specId = _specId; - useChainlinkWithENS(_ens, _node); - } - - function updateOracle() public { - updateChainlinkOracleWithENS(); - } - - function getChainlinkToken() public view returns (address) { - return chainlinkTokenAddress(); - } - - function getOracle() public view returns (address) { - return chainlinkOracleAddress(); - } - -} diff --git a/contracts/src/v0.4/vendor/BasicToken.sol b/contracts/src/v0.4/vendor/BasicToken.sol deleted file mode 100644 index 48f985002cf..00000000000 --- a/contracts/src/v0.4/vendor/BasicToken.sol +++ /dev/null @@ -1,38 +0,0 @@ -pragma solidity ^0.4.24; - - -import { ERC20Basic as linkERC20Basic } from "../interfaces/ERC20Basic.sol"; -import { SafeMathChainlink as linkSafeMath } from "./SafeMathChainlink.sol"; - - -/** - * @title Basic token - * @dev Basic version of StandardToken, with no allowances. - */ -contract BasicToken is linkERC20Basic { - using linkSafeMath for uint256; - - mapping(address => uint256) balances; - - /** - * @dev transfer token for a specified address - * @param _to The address to transfer to. - * @param _value The amount to be transferred. - */ - function transfer(address _to, uint256 _value) returns (bool) { - balances[msg.sender] = balances[msg.sender].sub(_value); - balances[_to] = balances[_to].add(_value); - Transfer(msg.sender, _to, _value); - return true; - } - - /** - * @dev Gets the balance of the specified address. - * @param _owner The address to query the the balance of. - * @return An uint256 representing the amount owned by the passed address. - */ - function balanceOf(address _owner) constant returns (uint256 balance) { - return balances[_owner]; - } - -} diff --git a/contracts/src/v0.4/vendor/Buffer.sol b/contracts/src/v0.4/vendor/Buffer.sol deleted file mode 100644 index d25ae7c73ee..00000000000 --- a/contracts/src/v0.4/vendor/Buffer.sol +++ /dev/null @@ -1,301 +0,0 @@ -pragma solidity >0.4.18; - -/** -* @dev A library for working with mutable byte buffers in Solidity. -* -* Byte buffers are mutable and expandable, and provide a variety of primitives -* for writing to them. At any time you can fetch a bytes object containing the -* current contents of the buffer. The bytes object should not be stored between -* operations, as it may change due to resizing of the buffer. -*/ -library Buffer { - /** - * @dev Represents a mutable buffer. Buffers have a current value (buf) and - * a capacity. The capacity may be longer than the current value, in - * which case it can be extended without the need to allocate more memory. - */ - struct buffer { - bytes buf; - uint capacity; - } - - /** - * @dev Initializes a buffer with an initial capacity. - * @param buf The buffer to initialize. - * @param capacity The number of bytes of space to allocate the buffer. - * @return The buffer, for chaining. - */ - function init(buffer memory buf, uint capacity) internal pure returns(buffer memory) { - if (capacity % 32 != 0) { - capacity += 32 - (capacity % 32); - } - // Allocate space for the buffer data - buf.capacity = capacity; - assembly { - let ptr := mload(0x40) - mstore(buf, ptr) - mstore(ptr, 0) - mstore(0x40, add(32, add(ptr, capacity))) - } - return buf; - } - - /** - * @dev Initializes a new buffer from an existing bytes object. - * Changes to the buffer may mutate the original value. - * @param b The bytes object to initialize the buffer with. - * @return A new buffer. - */ - function fromBytes(bytes memory b) internal pure returns(buffer memory) { - buffer memory buf; - buf.buf = b; - buf.capacity = b.length; - return buf; - } - - function resize(buffer memory buf, uint capacity) private pure { - bytes memory oldbuf = buf.buf; - init(buf, capacity); - append(buf, oldbuf); - } - - function max(uint a, uint b) private pure returns(uint) { - if (a > b) { - return a; - } - return b; - } - - /** - * @dev Sets buffer length to 0. - * @param buf The buffer to truncate. - * @return The original buffer, for chaining.. - */ - function truncate(buffer memory buf) internal pure returns (buffer memory) { - assembly { - let bufptr := mload(buf) - mstore(bufptr, 0) - } - return buf; - } - - /** - * @dev Writes a byte string to a buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param off The start offset to write to. - * @param data The data to append. - * @param len The number of bytes to copy. - * @return The original buffer, for chaining. - */ - function write(buffer memory buf, uint off, bytes memory data, uint len) internal pure returns(buffer memory) { - require(len <= data.length); - - if (off + len > buf.capacity) { - resize(buf, max(buf.capacity, len + off) * 2); - } - - uint dest; - uint src; - assembly { - // Memory address of the buffer data - let bufptr := mload(buf) - // Length of existing buffer data - let buflen := mload(bufptr) - // Start address = buffer address + offset + sizeof(buffer length) - dest := add(add(bufptr, 32), off) - // Update buffer length if we're extending it - if gt(add(len, off), buflen) { - mstore(bufptr, add(len, off)) - } - src := add(data, 32) - } - - // Copy word-length chunks while possible - for (; len >= 32; len -= 32) { - assembly { - mstore(dest, mload(src)) - } - dest += 32; - src += 32; - } - - // Copy remaining bytes - uint mask = 256 ** (32 - len) - 1; - assembly { - let srcpart := and(mload(src), not(mask)) - let destpart := and(mload(dest), mask) - mstore(dest, or(destpart, srcpart)) - } - - return buf; - } - - /** - * @dev Appends a byte string to a buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @param len The number of bytes to copy. - * @return The original buffer, for chaining. - */ - function append(buffer memory buf, bytes memory data, uint len) internal pure returns (buffer memory) { - return write(buf, buf.buf.length, data, len); - } - - /** - * @dev Appends a byte string to a buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer, for chaining. - */ - function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) { - return write(buf, buf.buf.length, data, data.length); - } - - /** - * @dev Writes a byte to the buffer. Resizes if doing so would exceed the - * capacity of the buffer. - * @param buf The buffer to append to. - * @param off The offset to write the byte at. - * @param data The data to append. - * @return The original buffer, for chaining. - */ - function writeUint8(buffer memory buf, uint off, uint8 data) internal pure returns(buffer memory) { - if (off >= buf.capacity) { - resize(buf, buf.capacity * 2); - } - - assembly { - // Memory address of the buffer data - let bufptr := mload(buf) - // Length of existing buffer data - let buflen := mload(bufptr) - // Address = buffer address + sizeof(buffer length) + off - let dest := add(add(bufptr, off), 32) - mstore8(dest, data) - // Update buffer length if we extended it - if eq(off, buflen) { - mstore(bufptr, add(buflen, 1)) - } - } - return buf; - } - - /** - * @dev Appends a byte to the buffer. Resizes if doing so would exceed the - * capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer, for chaining. - */ - function appendUint8(buffer memory buf, uint8 data) internal pure returns(buffer memory) { - return writeUint8(buf, buf.buf.length, data); - } - - /** - * @dev Writes up to 32 bytes to the buffer. Resizes if doing so would - * exceed the capacity of the buffer. - * @param buf The buffer to append to. - * @param off The offset to write at. - * @param data The data to append. - * @param len The number of bytes to write (left-aligned). - * @return The original buffer, for chaining. - */ - function write(buffer memory buf, uint off, bytes32 data, uint len) private pure returns(buffer memory) { - if (len + off > buf.capacity) { - resize(buf, (len + off) * 2); - } - - uint mask = 256 ** len - 1; - // Right-align data - data = data >> (8 * (32 - len)); - assembly { - // Memory address of the buffer data - let bufptr := mload(buf) - // Address = buffer address + sizeof(buffer length) + off + len - let dest := add(add(bufptr, off), len) - mstore(dest, or(and(mload(dest), not(mask)), data)) - // Update buffer length if we extended it - if gt(add(off, len), mload(bufptr)) { - mstore(bufptr, add(off, len)) - } - } - return buf; - } - - /** - * @dev Writes a bytes20 to the buffer. Resizes if doing so would exceed the - * capacity of the buffer. - * @param buf The buffer to append to. - * @param off The offset to write at. - * @param data The data to append. - * @return The original buffer, for chaining. - */ - function writeBytes20(buffer memory buf, uint off, bytes20 data) internal pure returns (buffer memory) { - return write(buf, off, bytes32(data), 20); - } - - /** - * @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer, for chhaining. - */ - function appendBytes20(buffer memory buf, bytes20 data) internal pure returns (buffer memory) { - return write(buf, buf.buf.length, bytes32(data), 20); - } - - /** - * @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer, for chaining. - */ - function appendBytes32(buffer memory buf, bytes32 data) internal pure returns (buffer memory) { - return write(buf, buf.buf.length, data, 32); - } - - /** - * @dev Writes an integer to the buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param off The offset to write at. - * @param data The data to append. - * @param len The number of bytes to write (right-aligned). - * @return The original buffer, for chaining. - */ - function writeInt(buffer memory buf, uint off, uint data, uint len) private pure returns(buffer memory) { - if (len + off > buf.capacity) { - resize(buf, (len + off) * 2); - } - - uint mask = 256 ** len - 1; - assembly { - // Memory address of the buffer data - let bufptr := mload(buf) - // Address = buffer address + off + sizeof(buffer length) + len - let dest := add(add(bufptr, off), len) - mstore(dest, or(and(mload(dest), not(mask)), data)) - // Update buffer length if we extended it - if gt(add(off, len), mload(bufptr)) { - mstore(bufptr, add(off, len)) - } - } - return buf; - } - - /** - * @dev Appends a byte to the end of the buffer. Resizes if doing so would - * exceed the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer. - */ - function appendInt(buffer memory buf, uint data, uint len) internal pure returns(buffer memory) { - return writeInt(buf, buf.buf.length, data, len); - } -} diff --git a/contracts/src/v0.4/vendor/CBOR.sol b/contracts/src/v0.4/vendor/CBOR.sol deleted file mode 100644 index 9cce04ac56e..00000000000 --- a/contracts/src/v0.4/vendor/CBOR.sol +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >= 0.4.19 < 0.7.0; - -import { Buffer as BufferChainlink } from "./Buffer.sol"; - -library CBOR { - using BufferChainlink for BufferChainlink.buffer; - - uint8 private constant MAJOR_TYPE_INT = 0; - uint8 private constant MAJOR_TYPE_NEGATIVE_INT = 1; - uint8 private constant MAJOR_TYPE_BYTES = 2; - uint8 private constant MAJOR_TYPE_STRING = 3; - uint8 private constant MAJOR_TYPE_ARRAY = 4; - uint8 private constant MAJOR_TYPE_MAP = 5; - uint8 private constant MAJOR_TYPE_TAG = 6; - uint8 private constant MAJOR_TYPE_CONTENT_FREE = 7; - - uint8 private constant TAG_TYPE_BIGNUM = 2; - uint8 private constant TAG_TYPE_NEGATIVE_BIGNUM = 3; - - function encodeFixedNumeric(BufferChainlink.buffer memory buf, uint8 major, uint64 value) private pure { - if(value <= 23) { - buf.appendUint8(uint8((major << 5) | value)); - } else if(value <= 0xFF) { - buf.appendUint8(uint8((major << 5) | 24)); - buf.appendInt(value, 1); - } else if(value <= 0xFFFF) { - buf.appendUint8(uint8((major << 5) | 25)); - buf.appendInt(value, 2); - } else if(value <= 0xFFFFFFFF) { - buf.appendUint8(uint8((major << 5) | 26)); - buf.appendInt(value, 4); - } else { - buf.appendUint8(uint8((major << 5) | 27)); - buf.appendInt(value, 8); - } - } - - function encodeIndefiniteLengthType(BufferChainlink.buffer memory buf, uint8 major) private pure { - buf.appendUint8(uint8((major << 5) | 31)); - } - - function encodeUInt(BufferChainlink.buffer memory buf, uint value) internal pure { - if(value > 0xFFFFFFFFFFFFFFFF) { - encodeBigNum(buf, value); - } else { - encodeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(value)); - } - } - - function encodeInt(BufferChainlink.buffer memory buf, int value) internal pure { - if(value < -0x10000000000000000) { - encodeSignedBigNum(buf, value); - } else if(value > 0xFFFFFFFFFFFFFFFF) { - encodeBigNum(buf, uint(value)); - } else if(value >= 0) { - encodeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(value)); - } else { - encodeFixedNumeric(buf, MAJOR_TYPE_NEGATIVE_INT, uint64(-1 - value)); - } - } - - function encodeBytes(BufferChainlink.buffer memory buf, bytes memory value) internal pure { - encodeFixedNumeric(buf, MAJOR_TYPE_BYTES, uint64(value.length)); - buf.append(value); - } - - function encodeBigNum(BufferChainlink.buffer memory buf, uint value) internal pure { - buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_BIGNUM)); - encodeBytes(buf, abi.encode(value)); - } - - function encodeSignedBigNum(BufferChainlink.buffer memory buf, int input) internal pure { - buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_NEGATIVE_BIGNUM)); - encodeBytes(buf, abi.encode(uint(-1 - input))); - } - - function encodeString(BufferChainlink.buffer memory buf, string memory value) internal pure { - encodeFixedNumeric(buf, MAJOR_TYPE_STRING, uint64(bytes(value).length)); - buf.append(bytes(value)); - } - - function startArray(BufferChainlink.buffer memory buf) internal pure { - encodeIndefiniteLengthType(buf, MAJOR_TYPE_ARRAY); - } - - function startMap(BufferChainlink.buffer memory buf) internal pure { - encodeIndefiniteLengthType(buf, MAJOR_TYPE_MAP); - } - - function endSequence(BufferChainlink.buffer memory buf) internal pure { - encodeIndefiniteLengthType(buf, MAJOR_TYPE_CONTENT_FREE); - } -} diff --git a/contracts/src/v0.4/vendor/ENS.sol b/contracts/src/v0.4/vendor/ENS.sol deleted file mode 100644 index 36e4ad4ae69..00000000000 --- a/contracts/src/v0.4/vendor/ENS.sol +++ /dev/null @@ -1,26 +0,0 @@ -pragma solidity ^0.4.24; - -interface ENS { - - // Logged when the owner of a node assigns a new owner to a subnode. - event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner); - - // Logged when the owner of a node transfers ownership to a new account. - event Transfer(bytes32 indexed node, address owner); - - // Logged when the resolver for a node changes. - event NewResolver(bytes32 indexed node, address resolver); - - // Logged when the TTL of a node changes - event NewTTL(bytes32 indexed node, uint64 ttl); - - - function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public; - function setResolver(bytes32 node, address resolver) public; - function setOwner(bytes32 node, address owner) public; - function setTTL(bytes32 node, uint64 ttl) public; - function owner(bytes32 node) public view returns (address); - function resolver(bytes32 node) public view returns (address); - function ttl(bytes32 node) public view returns (uint64); - -} diff --git a/contracts/src/v0.4/vendor/ENSRegistry.sol b/contracts/src/v0.4/vendor/ENSRegistry.sol deleted file mode 100644 index 95a54cd5211..00000000000 --- a/contracts/src/v0.4/vendor/ENSRegistry.sol +++ /dev/null @@ -1,99 +0,0 @@ -pragma solidity ^0.4.24; - -import "./ENS.sol"; - -/** - * The ENS registry contract. - */ -contract ENSRegistry is ENS { - struct Record { - address owner; - address resolver; - uint64 ttl; - } - - mapping (bytes32 => Record) records; - - // Permits modifications only by the owner of the specified node. - modifier only_owner(bytes32 node) { - require(records[node].owner == msg.sender); - _; - } - - /** - * @dev Constructs a new ENS registrar. - */ - constructor() public { - records[0x0].owner = msg.sender; - } - - /** - * @dev Transfers ownership of a node to a new address. May only be called by the current owner of the node. - * @param node The node to transfer ownership of. - * @param owner The address of the new owner. - */ - function setOwner(bytes32 node, address owner) public only_owner(node) { - emit Transfer(node, owner); - records[node].owner = owner; - } - - /** - * @dev Transfers ownership of a subnode keccak256(node, label) to a new address. May only be called by the owner of the parent node. - * @param node The parent node. - * @param label The hash of the label specifying the subnode. - * @param owner The address of the new owner. - */ - function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public only_owner(node) { - bytes32 subnode = keccak256(abi.encodePacked(node, label)); - emit NewOwner(node, label, owner); - records[subnode].owner = owner; - } - - /** - * @dev Sets the resolver address for the specified node. - * @param node The node to update. - * @param resolver The address of the resolver. - */ - function setResolver(bytes32 node, address resolver) public only_owner(node) { - emit NewResolver(node, resolver); - records[node].resolver = resolver; - } - - /** - * @dev Sets the TTL for the specified node. - * @param node The node to update. - * @param ttl The TTL in seconds. - */ - function setTTL(bytes32 node, uint64 ttl) public only_owner(node) { - emit NewTTL(node, ttl); - records[node].ttl = ttl; - } - - /** - * @dev Returns the address that owns the specified node. - * @param node The specified node. - * @return address of the owner. - */ - function owner(bytes32 node) public view returns (address) { - return records[node].owner; - } - - /** - * @dev Returns the address of the resolver for the specified node. - * @param node The specified node. - * @return address of the resolver. - */ - function resolver(bytes32 node) public view returns (address) { - return records[node].resolver; - } - - /** - * @dev Returns the TTL of a node, and any records associated with it. - * @param node The specified node. - * @return ttl of the node. - */ - function ttl(bytes32 node) public view returns (uint64) { - return records[node].ttl; - } - -} diff --git a/contracts/src/v0.4/vendor/ENSResolver.sol b/contracts/src/v0.4/vendor/ENSResolver.sol deleted file mode 100644 index c5149bf9903..00000000000 --- a/contracts/src/v0.4/vendor/ENSResolver.sol +++ /dev/null @@ -1,5 +0,0 @@ -pragma solidity 0.4.24; - -contract ENSResolver { - function addr(bytes32 node) public view returns (address); -} diff --git a/contracts/src/v0.4/vendor/Ownable.sol b/contracts/src/v0.4/vendor/Ownable.sol deleted file mode 100644 index 1fbf571bf7c..00000000000 --- a/contracts/src/v0.4/vendor/Ownable.sol +++ /dev/null @@ -1,64 +0,0 @@ -pragma solidity ^0.4.24; - - -/** - * @title Ownable - * @dev The Ownable contract has an owner address, and provides basic authorization control - * functions, this simplifies the implementation of "user permissions". - */ -contract Ownable { - address public owner; - - - event OwnershipRenounced(address indexed previousOwner); - event OwnershipTransferred( - address indexed previousOwner, - address indexed newOwner - ); - - - /** - * @dev The Ownable constructor sets the original `owner` of the contract to the sender - * account. - */ - constructor() public { - owner = msg.sender; - } - - /** - * @dev Throws if called by any account other than the owner. - */ - modifier onlyOwner() { - require(msg.sender == owner); - _; - } - - /** - * @dev Allows the current owner to relinquish control of the contract. - * @notice Renouncing to ownership will leave the contract without an owner. - * It will not be possible to call the functions with the `onlyOwner` - * modifier anymore. - */ - function renounceOwnership() public onlyOwner { - emit OwnershipRenounced(owner); - owner = address(0); - } - - /** - * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param _newOwner The address to transfer ownership to. - */ - function transferOwnership(address _newOwner) public onlyOwner { - _transferOwnership(_newOwner); - } - - /** - * @dev Transfers control of the contract to a newOwner. - * @param _newOwner The address to transfer ownership to. - */ - function _transferOwnership(address _newOwner) internal { - require(_newOwner != address(0)); - emit OwnershipTransferred(owner, _newOwner); - owner = _newOwner; - } -} diff --git a/contracts/src/v0.4/vendor/PublicResolver.sol b/contracts/src/v0.4/vendor/PublicResolver.sol deleted file mode 100644 index 50a01fdf92a..00000000000 --- a/contracts/src/v0.4/vendor/PublicResolver.sol +++ /dev/null @@ -1,238 +0,0 @@ -pragma solidity ^0.4.24; - -import "./ENS.sol"; - -/** - * A simple resolver anyone can use; only allows the owner of a node to set its - * address. - */ -contract PublicResolver { - - bytes4 constant INTERFACE_META_ID = 0x01ffc9a7; - bytes4 constant ADDR_INTERFACE_ID = 0x3b3b57de; - bytes4 constant CONTENT_INTERFACE_ID = 0xd8389dc5; - bytes4 constant NAME_INTERFACE_ID = 0x691f3431; - bytes4 constant ABI_INTERFACE_ID = 0x2203ab56; - bytes4 constant PUBKEY_INTERFACE_ID = 0xc8690233; - bytes4 constant TEXT_INTERFACE_ID = 0x59d1d43c; - bytes4 constant MULTIHASH_INTERFACE_ID = 0xe89401a1; - - event AddrChanged(bytes32 indexed node, address a); - event ContentChanged(bytes32 indexed node, bytes32 hash); - event NameChanged(bytes32 indexed node, string name); - event ABIChanged(bytes32 indexed node, uint256 indexed contentType); - event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y); - event TextChanged(bytes32 indexed node, string indexedKey, string key); - event MultihashChanged(bytes32 indexed node, bytes hash); - - struct PublicKey { - bytes32 x; - bytes32 y; - } - - struct Record { - address addr; - bytes32 content; - string name; - PublicKey pubkey; - mapping(string=>string) text; - mapping(uint256=>bytes) abis; - bytes multihash; - } - - ENS ens; - - mapping (bytes32 => Record) records; - - modifier only_owner(bytes32 node) { - require(ens.owner(node) == msg.sender); - _; - } - - /** - * Constructor. - * @param ensAddr The ENS registrar contract. - */ - constructor(ENS ensAddr) public { - ens = ensAddr; - } - - /** - * Sets the address associated with an ENS node. - * May only be called by the owner of that node in the ENS registry. - * @param node The node to update. - * @param addr The address to set. - */ - function setAddr(bytes32 node, address addr) public only_owner(node) { - records[node].addr = addr; - emit AddrChanged(node, addr); - } - - /** - * Sets the content hash associated with an ENS node. - * May only be called by the owner of that node in the ENS registry. - * Note that this resource type is not standardized, and will likely change - * in future to a resource type based on multihash. - * @param node The node to update. - * @param hash The content hash to set - */ - function setContent(bytes32 node, bytes32 hash) public only_owner(node) { - records[node].content = hash; - emit ContentChanged(node, hash); - } - - /** - * Sets the multihash associated with an ENS node. - * May only be called by the owner of that node in the ENS registry. - * @param node The node to update. - * @param hash The multihash to set - */ - function setMultihash(bytes32 node, bytes hash) public only_owner(node) { - records[node].multihash = hash; - emit MultihashChanged(node, hash); - } - - /** - * Sets the name associated with an ENS node, for reverse records. - * May only be called by the owner of that node in the ENS registry. - * @param node The node to update. - * @param name The name to set. - */ - function setName(bytes32 node, string name) public only_owner(node) { - records[node].name = name; - emit NameChanged(node, name); - } - - /** - * Sets the ABI associated with an ENS node. - * Nodes may have one ABI of each content type. To remove an ABI, set it to - * the empty string. - * @param node The node to update. - * @param contentType The content type of the ABI - * @param data The ABI data. - */ - function setABI(bytes32 node, uint256 contentType, bytes data) public only_owner(node) { - // Content types must be powers of 2 - require(((contentType - 1) & contentType) == 0); - - records[node].abis[contentType] = data; - emit ABIChanged(node, contentType); - } - - /** - * Sets the SECP256k1 public key associated with an ENS node. - * @param node The ENS node to query - * @param x the X coordinate of the curve point for the public key. - * @param y the Y coordinate of the curve point for the public key. - */ - function setPubkey(bytes32 node, bytes32 x, bytes32 y) public only_owner(node) { - records[node].pubkey = PublicKey(x, y); - emit PubkeyChanged(node, x, y); - } - - /** - * Sets the text data associated with an ENS node and key. - * May only be called by the owner of that node in the ENS registry. - * @param node The node to update. - * @param key The key to set. - * @param value The text data value to set. - */ - function setText(bytes32 node, string key, string value) public only_owner(node) { - records[node].text[key] = value; - emit TextChanged(node, key, key); - } - - /** - * Returns the text data associated with an ENS node and key. - * @param node The ENS node to query. - * @param key The text data key to query. - * @return The associated text data. - */ - function text(bytes32 node, string key) public view returns (string) { - return records[node].text[key]; - } - - /** - * Returns the SECP256k1 public key associated with an ENS node. - * Defined in EIP 619. - * @param node The ENS node to query - * @return x, y the X and Y coordinates of the curve point for the public key. - */ - function pubkey(bytes32 node) public view returns (bytes32 x, bytes32 y) { - return (records[node].pubkey.x, records[node].pubkey.y); - } - - /** - * Returns the ABI associated with an ENS node. - * Defined in EIP205. - * @param node The ENS node to query - * @param contentTypes A bitwise OR of the ABI formats accepted by the caller. - * @return contentType The content type of the return value - * @return data The ABI data - */ - function ABI(bytes32 node, uint256 contentTypes) public view returns (uint256 contentType, bytes data) { - Record storage record = records[node]; - for (contentType = 1; contentType <= contentTypes; contentType <<= 1) { - if ((contentType & contentTypes) != 0 && record.abis[contentType].length > 0) { - data = record.abis[contentType]; - return; - } - } - contentType = 0; - } - - /** - * Returns the name associated with an ENS node, for reverse records. - * Defined in EIP181. - * @param node The ENS node to query. - * @return The associated name. - */ - function name(bytes32 node) public view returns (string) { - return records[node].name; - } - - /** - * Returns the content hash associated with an ENS node. - * Note that this resource type is not standardized, and will likely change - * in future to a resource type based on multihash. - * @param node The ENS node to query. - * @return The associated content hash. - */ - function content(bytes32 node) public view returns (bytes32) { - return records[node].content; - } - - /** - * Returns the multihash associated with an ENS node. - * @param node The ENS node to query. - * @return The associated multihash. - */ - function multihash(bytes32 node) public view returns (bytes) { - return records[node].multihash; - } - - /** - * Returns the address associated with an ENS node. - * @param node The ENS node to query. - * @return The associated address. - */ - function addr(bytes32 node) public view returns (address) { - return records[node].addr; - } - - /** - * Returns true if the resolver implements the interface specified by the provided hash. - * @param interfaceID The ID of the interface to check for. - * @return True if the contract implements the requested interface. - */ - function supportsInterface(bytes4 interfaceID) public pure returns (bool) { - return interfaceID == ADDR_INTERFACE_ID || - interfaceID == CONTENT_INTERFACE_ID || - interfaceID == NAME_INTERFACE_ID || - interfaceID == ABI_INTERFACE_ID || - interfaceID == PUBKEY_INTERFACE_ID || - interfaceID == TEXT_INTERFACE_ID || - interfaceID == MULTIHASH_INTERFACE_ID || - interfaceID == INTERFACE_META_ID; - } -} diff --git a/contracts/src/v0.4/vendor/SafeMathChainlink.sol b/contracts/src/v0.4/vendor/SafeMathChainlink.sol deleted file mode 100644 index bd1f5b077f7..00000000000 --- a/contracts/src/v0.4/vendor/SafeMathChainlink.sol +++ /dev/null @@ -1,52 +0,0 @@ -pragma solidity ^0.4.11; - - -/** - * @title SafeMath - * @dev Math operations with safety checks that throw on error - */ -library SafeMathChainlink { - - /** - * @dev Multiplies two numbers, throws on overflow. - */ - function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) { - // Gas optimization: this is cheaper than asserting 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 - if (_a == 0) { - return 0; - } - - c = _a * _b; - assert(c / _a == _b); - return c; - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function div(uint256 _a, uint256 _b) internal pure returns (uint256) { - // assert(_b > 0); // Solidity automatically throws when dividing by 0 - // uint256 c = _a / _b; - // assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold - return _a / _b; - } - - /** - * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). - */ - function sub(uint256 _a, uint256 _b) internal pure returns (uint256) { - assert(_b <= _a); - return _a - _b; - } - - /** - * @dev Adds two numbers, throws on overflow. - */ - function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) { - c = _a + _b; - assert(c >= _a); - return c; - } -} diff --git a/contracts/src/v0.4/vendor/SignedSafeMath.sol b/contracts/src/v0.4/vendor/SignedSafeMath.sol deleted file mode 100644 index 307463a039a..00000000000 --- a/contracts/src/v0.4/vendor/SignedSafeMath.sol +++ /dev/null @@ -1,60 +0,0 @@ -pragma solidity 0.4.24; - -/** - * @title SignedSafeMath - * @dev Signed math operations with safety checks that revert on error. - */ -library SignedSafeMath { - int256 constant private _INT256_MIN = -2**255; - - /** - * @dev Multiplies two signed integers, reverts on overflow. - */ - function mul(int256 a, int256 b) internal pure returns (int256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - require(!(a == -1 && b == _INT256_MIN), "SignedSafeMath: multiplication overflow"); - - int256 c = a * b; - require(c / a == b, "SignedSafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Integer division of two signed integers truncating the quotient, reverts on division by zero. - */ - function div(int256 a, int256 b) internal pure returns (int256) { - require(b != 0, "SignedSafeMath: division by zero"); - require(!(b == -1 && a == _INT256_MIN), "SignedSafeMath: division overflow"); - - int256 c = a / b; - - return c; - } - - /** - * @dev Subtracts two signed integers, reverts on overflow. - */ - function sub(int256 a, int256 b) internal pure returns (int256) { - int256 c = a - b; - require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow"); - - return c; - } - - /** - * @dev Adds two signed integers, reverts on overflow. - */ - function add(int256 a, int256 b) internal pure returns (int256) { - int256 c = a + b; - require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow"); - - return c; - } -} diff --git a/contracts/src/v0.4/vendor/StandardToken.sol b/contracts/src/v0.4/vendor/StandardToken.sol deleted file mode 100644 index 7f2b4134a52..00000000000 --- a/contracts/src/v0.4/vendor/StandardToken.sol +++ /dev/null @@ -1,85 +0,0 @@ -pragma solidity ^0.4.11; - - -import { BasicToken as linkBasicToken } from "./BasicToken.sol"; -import { ERC20 as linkERC20 } from "../interfaces/ERC20.sol"; - - -/** - * @title Standard ERC20 token - * - * @dev Implementation of the basic standard token. - * @dev https://github.com/ethereum/EIPs/issues/20 - * @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol - */ -contract StandardToken is linkERC20, linkBasicToken { - - mapping (address => mapping (address => uint256)) allowed; - - - /** - * @dev Transfer tokens from one address to another - * @param _from address The address which you want to send tokens from - * @param _to address The address which you want to transfer to - * @param _value uint256 the amount of tokens to be transferred - */ - function transferFrom(address _from, address _to, uint256 _value) returns (bool) { - var _allowance = allowed[_from][msg.sender]; - - // Check is not needed because sub(_allowance, _value) will already throw if this condition is not met - // require (_value <= _allowance); - - balances[_from] = balances[_from].sub(_value); - balances[_to] = balances[_to].add(_value); - allowed[_from][msg.sender] = _allowance.sub(_value); - Transfer(_from, _to, _value); - return true; - } - - /** - * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. - * @param _spender The address which will spend the funds. - * @param _value The amount of tokens to be spent. - */ - function approve(address _spender, uint256 _value) returns (bool) { - allowed[msg.sender][_spender] = _value; - Approval(msg.sender, _spender, _value); - return true; - } - - /** - * @dev Function to check the amount of tokens that an owner allowed to a spender. - * @param _owner address The address which owns the funds. - * @param _spender address The address which will spend the funds. - * @return A uint256 specifying the amount of tokens still available for the spender. - */ - function allowance(address _owner, address _spender) constant returns (uint256 remaining) { - return allowed[_owner][_spender]; - } - - /* - * approve should be called when allowed[_spender] == 0. To increment - * allowed value is better to use this function to avoid 2 calls (and wait until - * the first transaction is mined) - * From MonolithDAO Token.sol - */ - function increaseApproval (address _spender, uint _addedValue) - returns (bool success) { - allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue); - Approval(msg.sender, _spender, allowed[msg.sender][_spender]); - return true; - } - - function decreaseApproval (address _spender, uint _subtractedValue) - returns (bool success) { - uint oldValue = allowed[msg.sender][_spender]; - if (_subtractedValue > oldValue) { - allowed[msg.sender][_spender] = 0; - } else { - allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue); - } - Approval(msg.sender, _spender, allowed[msg.sender][_spender]); - return true; - } - -} diff --git a/contracts/src/v0.5/Chainlink.sol b/contracts/src/v0.5/Chainlink.sol deleted file mode 100644 index 422604801ed..00000000000 --- a/contracts/src/v0.5/Chainlink.sol +++ /dev/null @@ -1,126 +0,0 @@ -pragma solidity ^0.5.0; - -import { CBOR as CBOR_Chainlink } from "./vendor/CBOR.sol"; -import { Buffer as Buffer_Chainlink } from "./vendor/Buffer.sol"; - -/** - * @title Library for common Chainlink functions - * @dev Uses imported CBOR library for encoding to buffer - */ -library Chainlink { - uint256 internal constant defaultBufferSize = 256; // solhint-disable-line const-name-snakecase - - using CBOR_Chainlink for Buffer_Chainlink.buffer; - - struct Request { - bytes32 id; - address callbackAddress; - bytes4 callbackFunctionId; - uint256 nonce; - Buffer_Chainlink.buffer buf; - } - - /** - * @notice Initializes a Chainlink request - * @dev Sets the ID, callback address, and callback function signature on the request - * @param self The uninitialized request - * @param _id The Job Specification ID - * @param _callbackAddress The callback address - * @param _callbackFunction The callback function signature - * @return The initialized request - */ - function initialize( - Request memory self, - bytes32 _id, - address _callbackAddress, - bytes4 _callbackFunction - ) internal pure returns (Chainlink.Request memory) { - Buffer_Chainlink.init(self.buf, defaultBufferSize); - self.id = _id; - self.callbackAddress = _callbackAddress; - self.callbackFunctionId = _callbackFunction; - return self; - } - - /** - * @notice Sets the data for the buffer without encoding CBOR on-chain - * @dev CBOR can be closed with curly-brackets {} or they can be left off - * @param self The initialized request - * @param _data The CBOR data - */ - function setBuffer(Request memory self, bytes memory _data) - internal pure - { - Buffer_Chainlink.init(self.buf, _data.length); - Buffer_Chainlink.append(self.buf, _data); - } - - /** - * @notice Adds a string value to the request with a given key name - * @param self The initialized request - * @param _key The name of the key - * @param _value The string value to add - */ - function add(Request memory self, string memory _key, string memory _value) - internal pure - { - self.buf.encodeString(_key); - self.buf.encodeString(_value); - } - - /** - * @notice Adds a bytes value to the request with a given key name - * @param self The initialized request - * @param _key The name of the key - * @param _value The bytes value to add - */ - function addBytes(Request memory self, string memory _key, bytes memory _value) - internal pure - { - self.buf.encodeString(_key); - self.buf.encodeBytes(_value); - } - - /** - * @notice Adds a int256 value to the request with a given key name - * @param self The initialized request - * @param _key The name of the key - * @param _value The int256 value to add - */ - function addInt(Request memory self, string memory _key, int256 _value) - internal pure - { - self.buf.encodeString(_key); - self.buf.encodeInt(_value); - } - - /** - * @notice Adds a uint256 value to the request with a given key name - * @param self The initialized request - * @param _key The name of the key - * @param _value The uint256 value to add - */ - function addUint(Request memory self, string memory _key, uint256 _value) - internal pure - { - self.buf.encodeString(_key); - self.buf.encodeUInt(_value); - } - - /** - * @notice Adds an array of strings to the request with a given key name - * @param self The initialized request - * @param _key The name of the key - * @param _values The array of string values to add - */ - function addStringArray(Request memory self, string memory _key, string[] memory _values) - internal pure - { - self.buf.encodeString(_key); - self.buf.startArray(); - for (uint256 i = 0; i < _values.length; i++) { - self.buf.encodeString(_values[i]); - } - self.buf.endSequence(); - } -} diff --git a/contracts/src/v0.5/ChainlinkClient.sol b/contracts/src/v0.5/ChainlinkClient.sol deleted file mode 100644 index 2c4f7946a48..00000000000 --- a/contracts/src/v0.5/ChainlinkClient.sol +++ /dev/null @@ -1,261 +0,0 @@ -pragma solidity ^0.5.0; - -import "./Chainlink.sol"; -import "./interfaces/ENSInterface.sol"; -import "./interfaces/LinkTokenInterface.sol"; -import "./interfaces/ChainlinkRequestInterface.sol"; -import "./interfaces/PointerInterface.sol"; -import { ENSResolver as ENSResolver_Chainlink } from "./vendor/ENSResolver.sol"; - -/** - * @title The ChainlinkClient contract - * @notice Contract writers can inherit this contract in order to create requests for the - * Chainlink network - */ -contract ChainlinkClient { - using Chainlink for Chainlink.Request; - - uint256 constant internal LINK = 10**18; - uint256 constant private AMOUNT_OVERRIDE = 0; - address constant private SENDER_OVERRIDE = address(0); - uint256 constant private ARGS_VERSION = 1; - bytes32 constant private ENS_TOKEN_SUBNAME = keccak256("link"); - bytes32 constant private ENS_ORACLE_SUBNAME = keccak256("oracle"); - address constant private LINK_TOKEN_POINTER = 0xC89bD4E1632D3A43CB03AAAd5262cbe4038Bc571; - - ENSInterface private ens; - bytes32 private ensNode; - LinkTokenInterface private link; - ChainlinkRequestInterface private oracle; - uint256 private requestCount = 1; - mapping(bytes32 => address) private pendingRequests; - - event ChainlinkRequested(bytes32 indexed id); - event ChainlinkFulfilled(bytes32 indexed id); - event ChainlinkCancelled(bytes32 indexed id); - - /** - * @notice Creates a request that can hold additional parameters - * @param _specId The Job Specification ID that the request will be created for - * @param _callbackAddress The callback address that the response will be sent to - * @param _callbackFunctionSignature The callback function signature to use for the callback address - * @return A Chainlink Request struct in memory - */ - function buildChainlinkRequest( - bytes32 _specId, - address _callbackAddress, - bytes4 _callbackFunctionSignature - ) internal pure returns (Chainlink.Request memory) { - Chainlink.Request memory req; - return req.initialize(_specId, _callbackAddress, _callbackFunctionSignature); - } - - /** - * @notice Creates a Chainlink request to the stored oracle address - * @dev Calls `chainlinkRequestTo` with the stored oracle address - * @param _req The initialized Chainlink Request - * @param _payment The amount of LINK to send for the request - * @return The request ID - */ - function sendChainlinkRequest(Chainlink.Request memory _req, uint256 _payment) - internal - returns (bytes32) - { - return sendChainlinkRequestTo(address(oracle), _req, _payment); - } - - /** - * @notice Creates a Chainlink request to the specified oracle address - * @dev Generates and stores a request ID, increments the local nonce, and uses `transferAndCall` to - * send LINK which creates a request on the target oracle contract. - * Emits ChainlinkRequested event. - * @param _oracle The address of the oracle for the request - * @param _req The initialized Chainlink Request - * @param _payment The amount of LINK to send for the request - * @return The request ID - */ - function sendChainlinkRequestTo(address _oracle, Chainlink.Request memory _req, uint256 _payment) - internal - returns (bytes32 requestId) - { - requestId = keccak256(abi.encodePacked(this, requestCount)); - _req.nonce = requestCount; - pendingRequests[requestId] = _oracle; - emit ChainlinkRequested(requestId); - require(link.transferAndCall(_oracle, _payment, encodeRequest(_req)), "unable to transferAndCall to oracle"); - requestCount += 1; - - return requestId; - } - - /** - * @notice Allows a request to be cancelled if it has not been fulfilled - * @dev Requires keeping track of the expiration value emitted from the oracle contract. - * Deletes the request from the `pendingRequests` mapping. - * Emits ChainlinkCancelled event. - * @param _requestId The request ID - * @param _payment The amount of LINK sent for the request - * @param _callbackFunc The callback function specified for the request - * @param _expiration The time of the expiration for the request - */ - function cancelChainlinkRequest( - bytes32 _requestId, - uint256 _payment, - bytes4 _callbackFunc, - uint256 _expiration - ) - internal - { - ChainlinkRequestInterface requested = ChainlinkRequestInterface(pendingRequests[_requestId]); - delete pendingRequests[_requestId]; - emit ChainlinkCancelled(_requestId); - requested.cancelOracleRequest(_requestId, _payment, _callbackFunc, _expiration); - } - - /** - * @notice Sets the stored oracle address - * @param _oracle The address of the oracle contract - */ - function setChainlinkOracle(address _oracle) internal { - oracle = ChainlinkRequestInterface(_oracle); - } - - /** - * @notice Sets the LINK token address - * @param _link The address of the LINK token contract - */ - function setChainlinkToken(address _link) internal { - link = LinkTokenInterface(_link); - } - - /** - * @notice Sets the Chainlink token address for the public - * network as given by the Pointer contract - */ - function setPublicChainlinkToken() internal { - setChainlinkToken(PointerInterface(LINK_TOKEN_POINTER).getAddress()); - } - - /** - * @notice Retrieves the stored address of the LINK token - * @return The address of the LINK token - */ - function chainlinkTokenAddress() - internal - view - returns (address) - { - return address(link); - } - - /** - * @notice Retrieves the stored address of the oracle contract - * @return The address of the oracle contract - */ - function chainlinkOracleAddress() - internal - view - returns (address) - { - return address(oracle); - } - - /** - * @notice Allows for a request which was created on another contract to be fulfilled - * on this contract - * @param _oracle The address of the oracle contract that will fulfill the request - * @param _requestId The request ID used for the response - */ - function addChainlinkExternalRequest(address _oracle, bytes32 _requestId) - internal - notPendingRequest(_requestId) - { - pendingRequests[_requestId] = _oracle; - } - - /** - * @notice Sets the stored oracle and LINK token contracts with the addresses resolved by ENS - * @dev Accounts for subnodes having different resolvers - * @param _ens The address of the ENS contract - * @param _node The ENS node hash - */ - function useChainlinkWithENS(address _ens, bytes32 _node) - internal - { - ens = ENSInterface(_ens); - ensNode = _node; - bytes32 linkSubnode = keccak256(abi.encodePacked(ensNode, ENS_TOKEN_SUBNAME)); - ENSResolver_Chainlink resolver = ENSResolver_Chainlink(ens.resolver(linkSubnode)); - setChainlinkToken(resolver.addr(linkSubnode)); - updateChainlinkOracleWithENS(); - } - - /** - * @notice Sets the stored oracle contract with the address resolved by ENS - * @dev This may be called on its own as long as `useChainlinkWithENS` has been called previously - */ - function updateChainlinkOracleWithENS() - internal - { - bytes32 oracleSubnode = keccak256(abi.encodePacked(ensNode, ENS_ORACLE_SUBNAME)); - ENSResolver_Chainlink resolver = ENSResolver_Chainlink(ens.resolver(oracleSubnode)); - setChainlinkOracle(resolver.addr(oracleSubnode)); - } - - /** - * @notice Encodes the request to be sent to the oracle contract - * @dev The Chainlink node expects values to be in order for the request to be picked up. Order of types - * will be validated in the oracle contract. - * @param _req The initialized Chainlink Request - * @return The bytes payload for the `transferAndCall` method - */ - function encodeRequest(Chainlink.Request memory _req) - private - view - returns (bytes memory) - { - return abi.encodeWithSelector( - oracle.oracleRequest.selector, - SENDER_OVERRIDE, // Sender value - overridden by onTokenTransfer by the requesting contract's address - AMOUNT_OVERRIDE, // Amount value - overridden by onTokenTransfer by the actual amount of LINK sent - _req.id, - _req.callbackAddress, - _req.callbackFunctionId, - _req.nonce, - ARGS_VERSION, - _req.buf.buf); - } - - /** - * @notice Ensures that the fulfillment is valid for this contract - * @dev Use if the contract developer prefers methods instead of modifiers for validation - * @param _requestId The request ID for fulfillment - */ - function validateChainlinkCallback(bytes32 _requestId) - internal - recordChainlinkFulfillment(_requestId) - // solhint-disable-next-line no-empty-blocks - {} - - /** - * @dev Reverts if the sender is not the oracle of the request. - * Emits ChainlinkFulfilled event. - * @param _requestId The request ID for fulfillment - */ - modifier recordChainlinkFulfillment(bytes32 _requestId) { - require(msg.sender == pendingRequests[_requestId], - "Source must be the oracle of the request"); - delete pendingRequests[_requestId]; - emit ChainlinkFulfilled(_requestId); - _; - } - - /** - * @dev Reverts if the request is already pending - * @param _requestId The request ID for fulfillment - */ - modifier notPendingRequest(bytes32 _requestId) { - require(pendingRequests[_requestId] == address(0), "Request is already pending"); - _; - } -} diff --git a/contracts/src/v0.5/LinkTokenReceiver.sol b/contracts/src/v0.5/LinkTokenReceiver.sol deleted file mode 100644 index 6d4cb923e79..00000000000 --- a/contracts/src/v0.5/LinkTokenReceiver.sol +++ /dev/null @@ -1,70 +0,0 @@ -pragma solidity ^0.5.0; - -contract LinkTokenReceiver { - - bytes4 constant private ORACLE_REQUEST_SELECTOR = 0x40429946; - uint256 constant private SELECTOR_LENGTH = 4; - uint256 constant private EXPECTED_REQUEST_WORDS = 2; - uint256 constant private MINIMUM_REQUEST_LENGTH = SELECTOR_LENGTH + (32 * EXPECTED_REQUEST_WORDS); - /** - * @notice Called when LINK is sent to the contract via `transferAndCall` - * @dev The data payload's first 2 words will be overwritten by the `_sender` and `_amount` - * values to ensure correctness. Calls oracleRequest. - * @param _sender Address of the sender - * @param _amount Amount of LINK sent (specified in wei) - * @param _data Payload of the transaction - */ - function onTokenTransfer( - address _sender, - uint256 _amount, - bytes memory _data - ) - public - onlyLINK - validRequestLength(_data) - permittedFunctionsForLINK(_data) - { - assembly { - // solhint-disable-next-line avoid-low-level-calls - mstore(add(_data, 36), _sender) // ensure correct sender is passed - // solhint-disable-next-line avoid-low-level-calls - mstore(add(_data, 68), _amount) // ensure correct amount is passed - } - // solhint-disable-next-line avoid-low-level-calls - (bool success, ) = address(this).delegatecall(_data); // calls oracleRequest - require(success, "Unable to create request"); - } - - function getChainlinkToken() public view returns (address); - - /** - * @dev Reverts if not sent from the LINK token - */ - modifier onlyLINK() { - require(msg.sender == getChainlinkToken(), "Must use LINK token"); - _; - } - - /** - * @dev Reverts if the given data does not begin with the `oracleRequest` function selector - * @param _data The data payload of the request - */ - modifier permittedFunctionsForLINK(bytes memory _data) { - bytes4 funcSelector; - assembly { - // solhint-disable-next-line avoid-low-level-calls - funcSelector := mload(add(_data, 32)) - } - require(funcSelector == ORACLE_REQUEST_SELECTOR, "Must use whitelisted functions"); - _; - } - - /** - * @dev Reverts if the given payload is less than needed to create a request - * @param _data The request payload - */ - modifier validRequestLength(bytes memory _data) { - require(_data.length >= MINIMUM_REQUEST_LENGTH, "Invalid request length"); - _; - } -} \ No newline at end of file diff --git a/contracts/src/v0.5/Median.sol b/contracts/src/v0.5/Median.sol deleted file mode 100644 index 5f7533726ec..00000000000 --- a/contracts/src/v0.5/Median.sol +++ /dev/null @@ -1,108 +0,0 @@ -pragma solidity ^0.5.0; - -import "./vendor/SafeMathChainlink.sol"; -import "./vendor/SignedSafeMath.sol"; - -library Median { - using SafeMathChainlink for uint256; - using SignedSafeMath for int256; - - /** - * @dev Returns the sorted middle, or the average of the two middle indexed - * items if the array has an even number of elements - * @param _list The list of elements to compare - */ - function calculate(int256[] memory _list) - internal - pure - returns (int256) - { - uint256 answerLength = _list.length; - uint256 middleIndex = answerLength.div(2); - if (answerLength % 2 == 0) { - int256 median1 = quickselect(copy(_list), middleIndex); - int256 median2 = quickselect(_list, middleIndex.add(1)); // quickselect is 1 indexed - int256 remainder = (median1 % 2 + median2 % 2) / 2; - return (median1 / 2).add(median2 / 2).add(remainder); // signed integers are not supported by SafeMath - } else { - return quickselect(_list, middleIndex.add(1)); // quickselect is 1 indexed - } - } - - /** - * @dev Returns the kth value of the ordered array - * See: http://www.cs.yale.edu/homes/aspnes/pinewiki/QuickSelect.html - * @param _a The list of elements to pull from - * @param _k The index, 1 based, of the elements you want to pull from when ordered - */ - function quickselect(int256[] memory _a, uint256 _k) - private - pure - returns (int256) - { - int256[] memory a = _a; - uint256 k = _k; - uint256 aLen = a.length; - int256[] memory a1 = new int256[](aLen); - int256[] memory a2 = new int256[](aLen); - uint256 a1Len; - uint256 a2Len; - int256 pivot; - uint256 i; - - while (true) { - pivot = a[aLen.div(2)]; - a1Len = 0; - a2Len = 0; - for (i = 0; i < aLen; i++) { - if (a[i] < pivot) { - a1[a1Len] = a[i]; - a1Len++; - } else if (a[i] > pivot) { - a2[a2Len] = a[i]; - a2Len++; - } - } - if (k <= a1Len) { - aLen = a1Len; - (a, a1) = swap(a, a1); - } else if (k > (aLen.sub(a2Len))) { - k = k.sub(aLen.sub(a2Len)); - aLen = a2Len; - (a, a2) = swap(a, a2); - } else { - return pivot; - } - } - } - - /** - * @dev Swaps the pointers to two uint256 arrays in memory - * @param _a The pointer to the first in memory array - * @param _b The pointer to the second in memory array - */ - function swap(int256[] memory _a, int256[] memory _b) - private - pure - returns(int256[] memory, int256[] memory) - { - return (_b, _a); - } - - /** - * @dev Makes an in memory copy of the array passed in - * @param _list The pointer to the array to be copied - */ - function copy(int256[] memory _list) - private - pure - returns(int256[] memory) - { - int256[] memory list2 = new int256[](_list.length); - for (uint256 i = 0; i < _list.length; i++) { - list2[i] = _list[i]; - } - return list2; - } - -} diff --git a/contracts/src/v0.5/Migrations.sol b/contracts/src/v0.5/Migrations.sol deleted file mode 100644 index d62541cd0d1..00000000000 --- a/contracts/src/v0.5/Migrations.sol +++ /dev/null @@ -1,23 +0,0 @@ -pragma solidity ^0.5.0; // solhint-disable-line compiler-fixed - -contract Migrations { - address public owner; - uint public last_completed_migration; - - modifier restricted() { - if (msg.sender == owner) _; - } - - constructor() public { - owner = msg.sender; - } - - function setCompleted(uint completed) public restricted { - last_completed_migration = completed; - } - - function upgrade(address new_address) public restricted { - Migrations upgraded = Migrations(new_address); - upgraded.setCompleted(last_completed_migration); - } -} diff --git a/contracts/src/v0.5/Oracle.sol b/contracts/src/v0.5/Oracle.sol deleted file mode 100644 index 186695d2555..00000000000 --- a/contracts/src/v0.5/Oracle.sol +++ /dev/null @@ -1,273 +0,0 @@ -pragma solidity ^0.5.0; - -import "./LinkTokenReceiver.sol"; -import "./interfaces/ChainlinkRequestInterface.sol"; -import "./interfaces/OracleInterface.sol"; -import "./interfaces/LinkTokenInterface.sol"; -import "./interfaces/WithdrawalInterface.sol"; -import "./vendor/Ownable.sol"; -import "./vendor/SafeMathChainlink.sol"; - -/** - * @title The Chainlink Oracle contract - * @notice Node operators can deploy this contract to fulfill requests sent to them - */ -contract Oracle is ChainlinkRequestInterface, OracleInterface, Ownable, LinkTokenReceiver, WithdrawalInterface { - using SafeMathChainlink for uint256; - - uint256 constant public EXPIRY_TIME = 5 minutes; - uint256 constant private MINIMUM_CONSUMER_GAS_LIMIT = 400000; - // We initialize fields to 1 instead of 0 so that the first invocation - // does not cost more gas. - uint256 constant private ONE_FOR_CONSISTENT_GAS_COST = 1; - - LinkTokenInterface internal LinkToken; - mapping(bytes32 => bytes32) private commitments; - mapping(address => bool) private authorizedNodes; - uint256 private withdrawableTokens = ONE_FOR_CONSISTENT_GAS_COST; - - event OracleRequest( - bytes32 indexed specId, - address requester, - bytes32 requestId, - uint256 payment, - address callbackAddr, - bytes4 callbackFunctionId, - uint256 cancelExpiration, - uint256 dataVersion, - bytes data - ); - - event CancelOracleRequest( - bytes32 indexed requestId - ); - - /** - * @notice Deploy with the address of the LINK token - * @dev Sets the LinkToken address for the imported LinkTokenInterface - * @param _link The address of the LINK token - */ - constructor(address _link) public Ownable() { - LinkToken = LinkTokenInterface(_link); // external but already deployed and unalterable - } - - /** - * @notice Creates the Chainlink request - * @dev Stores the hash of the params as the on-chain commitment for the request. - * Emits OracleRequest event for the Chainlink node to detect. - * @param _sender The sender of the request - * @param _payment The amount of payment given (specified in wei) - * @param _specId The Job Specification ID - * @param _callbackAddress The callback address for the response - * @param _callbackFunctionId The callback function ID for the response - * @param _nonce The nonce sent by the requester - * @param _dataVersion The specified data version - * @param _data The CBOR payload of the request - */ - function oracleRequest( - address _sender, - uint256 _payment, - bytes32 _specId, - address _callbackAddress, - bytes4 _callbackFunctionId, - uint256 _nonce, - uint256 _dataVersion, - bytes calldata _data - ) - external - onlyLINK - checkCallbackAddress(_callbackAddress) - { - bytes32 requestId = keccak256(abi.encodePacked(_sender, _nonce)); - require(commitments[requestId] == 0, "Must use a unique ID"); - // solhint-disable-next-line not-rely-on-time - uint256 expiration = now.add(EXPIRY_TIME); - - commitments[requestId] = keccak256( - abi.encodePacked( - _payment, - _callbackAddress, - _callbackFunctionId, - expiration - ) - ); - - emit OracleRequest( - _specId, - _sender, - requestId, - _payment, - _callbackAddress, - _callbackFunctionId, - expiration, - _dataVersion, - _data); - } - - /** - * @notice Called by the Chainlink node to fulfill requests - * @dev Given params must hash back to the commitment stored from `oracleRequest`. - * Will call the callback address' callback function without bubbling up error - * checking in a `require` so that the node can get paid. - * @param _requestId The fulfillment request ID that must match the requester's - * @param _payment The payment amount that will be released for the oracle (specified in wei) - * @param _callbackAddress The callback address to call for fulfillment - * @param _callbackFunctionId The callback function ID to use for fulfillment - * @param _expiration The expiration that the node should respond by before the requester can cancel - * @param _data The data to return to the consuming contract - * @return Status if the external call was successful - */ - function fulfillOracleRequest( - bytes32 _requestId, - uint256 _payment, - address _callbackAddress, - bytes4 _callbackFunctionId, - uint256 _expiration, - bytes32 _data - ) - external - onlyAuthorizedNode - isValidRequest(_requestId) - returns (bool) - { - bytes32 paramsHash = keccak256( - abi.encodePacked( - _payment, - _callbackAddress, - _callbackFunctionId, - _expiration - ) - ); - require(commitments[_requestId] == paramsHash, "Params do not match request ID"); - withdrawableTokens = withdrawableTokens.add(_payment); - delete commitments[_requestId]; - require(gasleft() >= MINIMUM_CONSUMER_GAS_LIMIT, "Must provide consumer enough gas"); - // All updates to the oracle's fulfillment should come before calling the - // callback(addr+functionId) as it is untrusted. - // See: https://solidity.readthedocs.io/en/develop/security-considerations.html#use-the-checks-effects-interactions-pattern - (bool success, ) = _callbackAddress.call(abi.encodeWithSelector(_callbackFunctionId, _requestId, _data)); // solhint-disable-line avoid-low-level-calls - return success; - } - - /** - * @notice Use this to check if a node is authorized for fulfilling requests - * @param _node The address of the Chainlink node - * @return The authorization status of the node - */ - function getAuthorizationStatus(address _node) external view returns (bool) { - return authorizedNodes[_node]; - } - - /** - * @notice Sets the fulfillment permission for a given node. Use `true` to allow, `false` to disallow. - * @param _node The address of the Chainlink node - * @param _allowed Bool value to determine if the node can fulfill requests - */ - function setFulfillmentPermission(address _node, bool _allowed) external onlyOwner { - authorizedNodes[_node] = _allowed; - } - - /** - * @notice Allows the node operator to withdraw earned LINK to a given address - * @dev The owner of the contract can be another wallet and does not have to be a Chainlink node - * @param _recipient The address to send the LINK token to - * @param _amount The amount to send (specified in wei) - */ - function withdraw(address _recipient, uint256 _amount) - external - onlyOwner - hasAvailableFunds(_amount) - { - withdrawableTokens = withdrawableTokens.sub(_amount); - assert(LinkToken.transfer(_recipient, _amount)); - } - - /** - * @notice Displays the amount of LINK that is available for the node operator to withdraw - * @dev We use `ONE_FOR_CONSISTENT_GAS_COST` in place of 0 in storage - * @return The amount of withdrawable LINK on the contract - */ - function withdrawable() external view onlyOwner returns (uint256) { - return withdrawableTokens.sub(ONE_FOR_CONSISTENT_GAS_COST); - } - - /** - * @notice Allows requesters to cancel requests sent to this oracle contract. Will transfer the LINK - * sent for the request back to the requester's address. - * @dev Given params must hash to a commitment stored on the contract in order for the request to be valid - * Emits CancelOracleRequest event. - * @param _requestId The request ID - * @param _payment The amount of payment given (specified in wei) - * @param _callbackFunc The requester's specified callback address - * @param _expiration The time of the expiration for the request - */ - function cancelOracleRequest( - bytes32 _requestId, - uint256 _payment, - bytes4 _callbackFunc, - uint256 _expiration - ) external { - bytes32 paramsHash = keccak256( - abi.encodePacked( - _payment, - msg.sender, - _callbackFunc, - _expiration) - ); - require(paramsHash == commitments[_requestId], "Params do not match request ID"); - // solhint-disable-next-line not-rely-on-time - require(_expiration <= now, "Request is not expired"); - - delete commitments[_requestId]; - emit CancelOracleRequest(_requestId); - - assert(LinkToken.transfer(msg.sender, _payment)); - } - - /** - * @notice Returns the address of the LINK token - * @dev This is the public implementation for chainlinkTokenAddress, which is - * an internal method of the ChainlinkClient contract - */ - function getChainlinkToken() public view returns (address) { - return address(LinkToken); - } - - // MODIFIERS - - /** - * @dev Reverts if amount requested is greater than withdrawable balance - * @param _amount The given amount to compare to `withdrawableTokens` - */ - modifier hasAvailableFunds(uint256 _amount) { - require(withdrawableTokens >= _amount.add(ONE_FOR_CONSISTENT_GAS_COST), "Amount requested is greater than withdrawable balance"); - _; - } - - /** - * @dev Reverts if request ID does not exist - * @param _requestId The given request ID to check in stored `commitments` - */ - modifier isValidRequest(bytes32 _requestId) { - require(commitments[_requestId] != 0, "Must have a valid requestId"); - _; - } - - /** - * @dev Reverts if `msg.sender` is not authorized to fulfill requests - */ - modifier onlyAuthorizedNode() { - require(authorizedNodes[msg.sender] || msg.sender == owner(), "Not an authorized node to fulfill requests"); - _; - } - - /** - * @dev Reverts if the callback address is the LINK token - * @param _to The callback address - */ - modifier checkCallbackAddress(address _to) { - require(_to != address(LinkToken), "Cannot callback to LINK"); - _; - } - -} diff --git a/contracts/src/v0.5/dev/Coordinator.sol b/contracts/src/v0.5/dev/Coordinator.sol deleted file mode 100644 index 23bdfb699ab..00000000000 --- a/contracts/src/v0.5/dev/Coordinator.sol +++ /dev/null @@ -1,411 +0,0 @@ -pragma solidity 0.5.0; - -import "./CoordinatorInterface.sol"; -import "../interfaces/ChainlinkRequestInterface.sol"; -import "../interfaces/LinkTokenInterface.sol"; -import "../vendor/SafeMathChainlink.sol"; -import "./ServiceAgreementDecoder.sol"; -import "./OracleSignaturesDecoder.sol"; - - -/** - * @title The Chainlink Coordinator handles oracle service agreements between one or more oracles - */ -contract Coordinator is ChainlinkRequestInterface, CoordinatorInterface, ServiceAgreementDecoder, OracleSignaturesDecoder { - using SafeMathChainlink for uint256; - - uint256 constant public EXPIRY_TIME = 5 minutes; - LinkTokenInterface internal LINK; - - struct Callback { - bytes32 sAId; - uint256 amount; - address addr; - bytes4 functionId; - uint64 cancelExpiration; - uint8 responseCount; - mapping(address => uint256) responses; - } - - mapping(bytes32 => Callback) private callbacks; - mapping(bytes32 => mapping(address => bool)) private allowedOracles; - mapping(bytes32 => ServiceAgreement) public serviceAgreements; - mapping(address => uint256) public withdrawableTokens; - - /** - * @notice Deploy with the address of the LINK token - * @dev Sets the LinkToken address for the imported LinkTokenInterface - * @param _link The address of the LINK token - */ - constructor(address _link) public { - LINK = LinkTokenInterface(_link); - } - - event OracleRequest( - bytes32 indexed sAId, - address requester, - bytes32 requestId, - uint256 payment, - address callbackAddr, - bytes4 callbackFunctionId, - uint256 cancelExpiration, - uint256 dataVersion, - bytes data - ); - - event NewServiceAgreement( - bytes32 indexed said, - bytes32 indexed requestDigest - ); - - event CancelOracleRequest( - bytes32 internalId - ); - - /** - * @notice Creates the Chainlink request - * @dev Stores the params on-chain in a callback for the request. - * Emits OracleRequest event for Chainlink nodes to detect. - * @param _sender The sender of the request - * @param _amount The amount of payment given (specified in wei) - * @param _sAId The Service Agreement ID - * @param _callbackAddress The callback address for the response - * @param _callbackFunctionId The callback function ID for the response - * @param _nonce The nonce sent by the requester - * @param _dataVersion The specified data version - * @param _data The CBOR payload of the request - */ - function oracleRequest( - address _sender, - uint256 _amount, - bytes32 _sAId, - address _callbackAddress, - bytes4 _callbackFunctionId, - uint256 _nonce, - uint256 _dataVersion, - bytes calldata _data - ) - external - onlyLINK - sufficientLINK(_amount, _sAId) - checkCallbackAddress(_callbackAddress) - // checkServiceAgreementPresence(_sAId) // TODO: exhausts the stack - { - bytes32 requestId = keccak256(abi.encodePacked(_sender, _nonce)); - require(callbacks[requestId].cancelExpiration == 0, "Must use a unique ID"); - callbacks[requestId].sAId = _sAId; - callbacks[requestId].amount = _amount; - callbacks[requestId].addr = _callbackAddress; - callbacks[requestId].functionId = _callbackFunctionId; - // solhint-disable-next-line not-rely-on-time - callbacks[requestId].cancelExpiration = uint64(now.add(EXPIRY_TIME)); - - emit OracleRequest( - _sAId, - _sender, - requestId, - _amount, - _callbackAddress, - _callbackFunctionId, - now.add(EXPIRY_TIME), // solhint-disable-line not-rely-on-time - _dataVersion, - _data); - } - - /** - * @notice Stores a Service Agreement which has been signed by the given oracles - * @dev Validates that each oracle has a valid signature. - * Emits NewServiceAgreement event. - * @return The Service Agreement ID - */ - function initiateServiceAgreement( - bytes memory _serviceAgreementData, - bytes memory _oracleSignaturesData - ) - public - returns (bytes32 serviceAgreementID) - { - - ServiceAgreement memory _agreement = decodeServiceAgreement(_serviceAgreementData); - OracleSignatures memory _signatures = decodeOracleSignatures(_oracleSignaturesData); - - require( - _agreement.oracles.length == _signatures.vs.length && - _signatures.vs.length == _signatures.rs.length && - _signatures.rs.length == _signatures.ss.length, - "Must pass in as many signatures as oracles" - ); - // solhint-disable-next-line not-rely-on-time - require(_agreement.endAt > block.timestamp, - "ServiceAgreement must end in the future"); - require(serviceAgreements[serviceAgreementID].endAt == 0, - "serviceAgreement already initiated"); - serviceAgreementID = getId(_agreement); - - registerOracleSignatures( - serviceAgreementID, - _agreement.oracles, - _signatures - ); - - serviceAgreements[serviceAgreementID] = _agreement; - emit NewServiceAgreement(serviceAgreementID, _agreement.requestDigest); - // solhint-disable-next-line avoid-low-level-calls - (bool ok, bytes memory response) = _agreement.aggregator.call( - abi.encodeWithSelector( - _agreement.aggInitiateJobSelector, - serviceAgreementID, - _serviceAgreementData - ) - ); - require(ok, "Aggregator failed to initiate Service Agreement"); - require(response.length > 0, "probably wrong address/selector"); - (bool success, bytes memory message) = abi.decode(response, (bool, bytes)); - if ((!success) && message.length == 0) { - // Revert with a non-empty message to give user a hint where to look - require(success, "initiation failed; empty message"); - } - require(success, string(message)); - } - - /** - * @dev Validates that each signer address matches for the given oracles - * @param _serviceAgreementID Service agreement ID - * @param _oracles Array of oracle addresses which agreed to the service agreement - * @param _signatures contains the collected parts(v, r, and s) of each oracle's signature. - */ - function registerOracleSignatures( - bytes32 _serviceAgreementID, - address[] memory _oracles, - OracleSignatures memory _signatures - ) - private - { - for (uint i = 0; i < _oracles.length; i++) { - address signer = getOracleAddressFromSASignature( - _serviceAgreementID, - _signatures.vs[i], - _signatures.rs[i], - _signatures.ss[i] - ); - require(_oracles[i] == signer, "Invalid oracle signature specified in SA"); - allowedOracles[_serviceAgreementID][_oracles[i]] = true; - } - - } - - /** - * @dev Recovers the address of the signer for a service agreement - * @param _serviceAgreementID Service agreement ID - * @param _v Recovery ID of the oracle signature - * @param _r First 32 bytes of the oracle signature - * @param _s Second 32 bytes of the oracle signature - * @return The address of the signer - */ - function getOracleAddressFromSASignature( - bytes32 _serviceAgreementID, - uint8 _v, - bytes32 _r, - bytes32 _s - ) - private pure returns (address) - { - bytes32 prefixedHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _serviceAgreementID)); - return ecrecover(prefixedHash, _v, _r, _s); - } - - /** - * @notice Called by the Chainlink node to fulfill requests - * @dev Response must have a valid callback, and will delete the associated callback storage - * before calling the external contract. - * @param _requestId The fulfillment request ID that must match the requester's - * @param _data The data to return to the consuming contract - * @return Status if the external call was successful - */ - function fulfillOracleRequest( - bytes32 _requestId, - bytes32 _data - ) external isValidRequest(_requestId) returns (bool) { - Callback memory callback = callbacks[_requestId]; - ServiceAgreement memory sA = serviceAgreements[callback.sAId]; - // solhint-disable-next-line avoid-low-level-calls - (bool ok, bytes memory aggResponse) = sA.aggregator.call( - abi.encodeWithSelector( - sA.aggFulfillSelector, _requestId, callback.sAId, msg.sender, _data)); - require(ok, "aggregator.fulfill failed"); - require(aggResponse.length > 0, "probably wrong address/selector"); - (bool aggSuccess, bool aggComplete, bytes memory response, int256[] memory paymentAmounts) = abi.decode( // solhint-disable-line - aggResponse, (bool, bool, bytes, int256[])); - require(aggSuccess, string(response)); - if (aggComplete) { - require(paymentAmounts.length == sA.oracles.length, "wrong paymentAmounts.length"); - for (uint256 oIdx = 0; oIdx < sA.oracles.length; oIdx++) { // pay oracles - withdrawableTokens[sA.oracles[oIdx]] = uint256(int256( - withdrawableTokens[sA.oracles[oIdx]]) + paymentAmounts[oIdx]); - } // solhint-disable-next-line avoid-low-level-calls - (bool success,) = callback.addr.call(abi.encodeWithSelector( // report final result - callback.functionId, _requestId, abi.decode(response, (bytes32)))); - return success; - } - return true; - } - - /** - * @dev Allows the oracle operator to withdraw their LINK - * @param _recipient is the address the funds will be sent to - * @param _amount is the amount of LINK transferred from the Coordinator contract - */ - function withdraw(address _recipient, uint256 _amount) - external - hasAvailableFunds(_amount) - { - withdrawableTokens[msg.sender] = withdrawableTokens[msg.sender].sub(_amount); - assert(LINK.transfer(_recipient, _amount)); - } - - /** - * @dev Necessary to implement ChainlinkRequestInterface - */ - function cancelOracleRequest(bytes32, uint256, bytes4, uint256) - external - {} // solhint-disable-line no-empty-blocks - - /** - * @notice Called when LINK is sent to the contract via `transferAndCall` - * @dev The data payload's first 2 words will be overwritten by the `_sender` and `_amount` - * values to ensure correctness. Calls oracleRequest. - * @param _sender Address of the sender - * @param _amount Amount of LINK sent (specified in wei) - * @param _data Payload of the transaction - */ - function onTokenTransfer( - address _sender, - uint256 _amount, - bytes memory _data - ) - public - onlyLINK - permittedFunctionsForLINK - { - assembly { // solhint-disable-line no-inline-assembly - mstore(add(_data, 36), _sender) // ensure correct sender is passed - mstore(add(_data, 68), _amount) // ensure correct amount is passed - } - // solhint-disable-next-line avoid-low-level-calls - (bool success,) = address(this).delegatecall(_data); // calls oracleRequest or depositFunds - require(success, "Unable to create request"); - } - - /** - * @notice Retrieve the Service Agreement ID for the given parameters - * @param _agreementData contains all of the terms of the service agreement that can be verified on-chain. - * @return The Service Agreement ID, a keccak256 hash of the input params - */ - function getId(bytes memory _agreementData) public pure returns (bytes32) - { - ServiceAgreement memory _agreement = decodeServiceAgreement(_agreementData); - return getId(_agreement); - } - - function getId(ServiceAgreement memory _agreement) internal pure returns (bytes32) - { - return keccak256( - abi.encodePacked( - _agreement.payment, - _agreement.expiration, - _agreement.endAt, - _agreement.oracles, - _agreement.requestDigest, - _agreement.aggregator, - _agreement.aggInitiateJobSelector, - _agreement.aggFulfillSelector - )); - } - - /** - * @notice Called when LINK is sent to the contract via `transferAndCall` - * @param _sender Address of the sender - * @param _amount Amount of LINK sent (specified in wei) - */ - function depositFunds(address _sender, uint256 _amount) external onlyLINK - { - withdrawableTokens[_sender] = withdrawableTokens[_sender].add(_amount); - } - - /** - * @param _account Address to check balance of - * @return Balance of account (specified in wei) - */ - function balanceOf(address _account) public view returns (uint256) - { - return withdrawableTokens[_account]; - } - - /** - * @dev Reverts if the callback address is the LINK token - * @param _to The callback address - */ - modifier checkCallbackAddress(address _to) { - require(_to != address(LINK), "Cannot callback to LINK"); - _; - } - - /** - * @dev Reverts if amount requested is greater than withdrawable balance - * @param _amount The given amount to compare to `withdrawableTokens` - */ - modifier hasAvailableFunds(uint256 _amount) { - require(withdrawableTokens[msg.sender] >= _amount, "Amount requested is greater than withdrawable balance"); - _; - } - - /** - * @dev Reverts if request ID does not exist - * @param _requestId The given request ID to check in stored `callbacks` - */ - modifier isValidRequest(bytes32 _requestId) { - require(callbacks[_requestId].addr != address(0), "Must have a valid requestId"); - require(allowedOracles[callbacks[_requestId].sAId][msg.sender], "Oracle not recognized on service agreement"); - _; - } - - /** - * @dev Reverts if amount is not at least what was agreed upon in the service agreement - * @param _amount The payment for the request - * @param _sAId The service agreement ID which the request is for - */ - modifier sufficientLINK(uint256 _amount, bytes32 _sAId) { - require(_amount >= serviceAgreements[_sAId].payment, "Below agreed payment"); - _; - } - - /** - * @dev Reverts if the given data does not begin with the `oracleRequest` or - * `depositFunds` function selector - */ - modifier permittedFunctionsForLINK() { - bytes4[1] memory funcSelector; - assembly { // solhint-disable-line no-inline-assembly - calldatacopy(funcSelector, 132, 4) // grab function selector from calldata - } - require( - funcSelector[0] == this.oracleRequest.selector || funcSelector[0] == this.depositFunds.selector, - "Must use whitelisted functions" - ); - _; - } - - modifier checkServiceAgreementPresence(bytes32 _sAId) { - require(uint256(serviceAgreements[_sAId].requestDigest) != 0, - "Must reference an existing ServiceAgreement"); - _; - } - - /** - * @dev Reverts if not sent from the LINK token - */ - modifier onlyLINK() { - require(msg.sender == address(LINK), "Must use LINK token"); - _; - } -} diff --git a/contracts/src/v0.5/dev/CoordinatorInterface.sol b/contracts/src/v0.5/dev/CoordinatorInterface.sol deleted file mode 100644 index 1678a95c19f..00000000000 --- a/contracts/src/v0.5/dev/CoordinatorInterface.sol +++ /dev/null @@ -1,14 +0,0 @@ -pragma solidity 0.5.0; - -contract CoordinatorInterface { - - function initiateServiceAgreement( - bytes memory _serviceAgreementData, - bytes memory _oracleSignaturesData) - public returns (bytes32); - - function fulfillOracleRequest( - bytes32 _requestId, - bytes32 _aggregatorArgs) - external returns (bool); -} diff --git a/contracts/src/v0.5/dev/OracleSignaturesDecoder.sol b/contracts/src/v0.5/dev/OracleSignaturesDecoder.sol deleted file mode 100644 index 1c2776b6828..00000000000 --- a/contracts/src/v0.5/dev/OracleSignaturesDecoder.sol +++ /dev/null @@ -1,24 +0,0 @@ -pragma solidity 0.5.0; - -contract OracleSignaturesDecoder { - - struct OracleSignatures { - uint8[] vs; - bytes32[] rs; - bytes32[] ss; - } - - function decodeOracleSignatures( - bytes memory _oracleSignaturesData - ) - internal - pure - returns(OracleSignatures memory) - { - // solhint-disable indent - OracleSignatures memory signatures; - ( signatures.vs, signatures.rs, signatures.ss) = - abi.decode(_oracleSignaturesData, ( uint8[], bytes32[], bytes32[] )); - return signatures; - } -} diff --git a/contracts/src/v0.5/dev/SchnorrSECP256K1.sol b/contracts/src/v0.5/dev/SchnorrSECP256K1.sol deleted file mode 100644 index 192c88403eb..00000000000 --- a/contracts/src/v0.5/dev/SchnorrSECP256K1.sol +++ /dev/null @@ -1,147 +0,0 @@ -pragma solidity ^0.5.0; - -//////////////////////////////////////////////////////////////////////////////// -// XXX: Do not use in production until this code has been audited. -//////////////////////////////////////////////////////////////////////////////// - -contract SchnorrSECP256K1 { - // See https://en.bitcoin.it/wiki/Secp256k1 for this constant. - uint256 constant public Q = // Group order of secp256k1 - // solium-disable-next-line indentation - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141; - // solium-disable-next-line zeppelin/no-arithmetic-operations - uint256 constant public HALF_Q = (Q >> 1) + 1; - - /** ************************************************************************** - @notice verifySignature returns true iff passed a valid Schnorr signature. - - @dev See https://en.wikipedia.org/wiki/Schnorr_signature for reference. - - @dev In what follows, let d be your secret key, PK be your public key, - PKx be the x ordinate of your public key, and PKyp be the parity bit for - the y ordinate (i.e., 0 if PKy is even, 1 if odd.) - ************************************************************************** - @dev TO CREATE A VALID SIGNATURE FOR THIS METHOD - - @dev First PKx must be less than HALF_Q. Then follow these instructions - (see evm/test/schnorr_test.js, for an example of carrying them out): - @dev 1. Hash the target message to a uint256, called msgHash here, using - keccak256 - - @dev 2. Pick k uniformly and cryptographically securely randomly from - {0,...,Q-1}. It is critical that k remains confidential, as your - private key can be reconstructed from k and the signature. - - @dev 3. Compute k*g in the secp256k1 group, where g is the group - generator. (This is the same as computing the public key from the - secret key k. But it's OK if k*g's x ordinate is greater than - HALF_Q.) - - @dev 4. Compute the ethereum address for k*g. This is the lower 160 bits - of the keccak hash of the concatenated affine coordinates of k*g, - as 32-byte big-endians. (For instance, you could pass k to - ethereumjs-utils's privateToAddress to compute this, though that - should be strictly a development convenience, not for handling - live secrets, unless you've locked your javascript environment - down very carefully.) Call this address - nonceTimesGeneratorAddress. - - @dev 5. Compute e=uint256(keccak256(PKx as a 32-byte big-endian - ‖ PKyp as a single byte - ‖ msgHash - ‖ nonceTimesGeneratorAddress)) - This value e is called "msgChallenge" in verifySignature's source - code below. Here "‖" means concatenation of the listed byte - arrays. - - @dev 6. Let x be your secret key. Compute s = (k - d * e) % Q. Add Q to - it, if it's negative. This is your signature. (d is your secret - key.) - ************************************************************************** - @dev TO VERIFY A SIGNATURE - - @dev Given a signature (s, e) of msgHash, constructed as above, compute - S=e*PK+s*generator in the secp256k1 group law, and then the ethereum - address of S, as described in step 4. Call that - nonceTimesGeneratorAddress. Then call the verifySignature method as: - - @dev verifySignature(PKx, PKyp, s, msgHash, - nonceTimesGeneratorAddress) - ************************************************************************** - @dev This signging scheme deviates slightly from the classical Schnorr - signature, in that the address of k*g is used in place of k*g itself, - both when calculating e and when verifying sum S as described in the - verification paragraph above. This reduces the difficulty of - brute-forcing a signature by trying random secp256k1 points in place of - k*g in the signature verification process from 256 bits to 160 bits. - However, the difficulty of cracking the public key using "baby-step, - giant-step" is only 128 bits, so this weakening constitutes no compromise - in the security of the signatures or the key. - - @dev The constraint signingPubKeyX < HALF_Q comes from Eq. (281), p. 24 - of Yellow Paper version 78d7b9a. ecrecover only accepts "s" inputs less - than HALF_Q, to protect against a signature- malleability vulnerability in - ECDSA. Schnorr does not have this vulnerability, but we must account for - ecrecover's defense anyway. And since we are abusing ecrecover by putting - signingPubKeyX in ecrecover's "s" argument the constraint applies to - signingPubKeyX, even though it represents a value in the base field, and - has no natural relationship to the order of the curve's cyclic group. - ************************************************************************** - @param signingPubKeyX is the x ordinate of the public key. This must be - less than HALF_Q. - @param pubKeyYParity is 0 if the y ordinate of the public key is even, 1 - if it's odd. - @param signature is the actual signature, described as s in the above - instructions. - @param msgHash is a 256-bit hash of the message being signed. - @param nonceTimesGeneratorAddress is the ethereum address of k*g in the - above instructions - ************************************************************************** - @return True if passed a valid signature, false otherwise. */ - function verifySignature( - uint256 signingPubKeyX, - uint8 pubKeyYParity, - uint256 signature, - uint256 msgHash, - address nonceTimesGeneratorAddress) external pure returns (bool) { - require(signingPubKeyX < HALF_Q, "Public-key x >= HALF_Q"); - // Avoid signature malleability from multiple representations for ℤ/Qℤ elts - require(signature < Q, "signature must be reduced modulo Q"); - - // Forbid trivial inputs, to avoid ecrecover edge cases. The main thing to - // avoid is something which causes ecrecover to return 0x0: then trivial - // signatures could be constructed with the nonceTimesGeneratorAddress input - // set to 0x0. - // - // solium-disable-next-line indentation - require(nonceTimesGeneratorAddress != address(0) && signingPubKeyX > 0 && - signature > 0 && msgHash > 0, "no zero inputs allowed"); - - // solium-disable-next-line indentation - uint256 msgChallenge = // "e" - // solium-disable-next-line indentation - uint256(keccak256(abi.encodePacked(signingPubKeyX, pubKeyYParity, - msgHash, nonceTimesGeneratorAddress)) - ); - - // Verify msgChallenge * signingPubKey + signature * generator == - // nonce * generator - // - // https://ethresear.ch/t/you-can-kinda-abuse-ecrecover-to-do-ecmul-in-secp256k1-today/2384/9 - // The point corresponding to the address returned by - // ecrecover(-s*r,v,r,e*r) is (r⁻¹ mod Q)*(e*r*R-(-s)*r*g)=e*R+s*g, where R - // is the (v,r) point. See https://crypto.stackexchange.com/a/18106 - // - // solium-disable-next-line indentation - address recoveredAddress = ecrecover( - // solium-disable-next-line zeppelin/no-arithmetic-operations - bytes32(Q - mulmod(signingPubKeyX, signature, Q)), - // https://ethereum.github.io/yellowpaper/paper.pdf p. 24, "The - // value 27 represents an even y value and 28 represents an odd - // y value." - (pubKeyYParity == 0) ? 27 : 28, - bytes32(signingPubKeyX), - bytes32(mulmod(msgChallenge, signingPubKeyX, Q))); - return nonceTimesGeneratorAddress == recoveredAddress; - } -} diff --git a/contracts/src/v0.5/dev/ServiceAgreementDecoder.sol b/contracts/src/v0.5/dev/ServiceAgreementDecoder.sol deleted file mode 100644 index 9267b77d3bb..00000000000 --- a/contracts/src/v0.5/dev/ServiceAgreementDecoder.sol +++ /dev/null @@ -1,59 +0,0 @@ -pragma solidity 0.5.0; - -contract ServiceAgreementDecoder { - - struct ServiceAgreement { - uint256 payment; - uint256 expiration; - uint256 endAt; - address[] oracles; - // This effectively functions as an ID tag for the off-chain job of the - // service agreement. It is calculated as the keccak256 hash of the - // normalized JSON request to create the ServiceAgreement, but that identity - // is unused, and its value is essentially arbitrary. - bytes32 requestDigest; - // Specification of aggregator interface. See ../tests/MeanAggregator.sol - // for example - address aggregator; - // Selectors for the interface methods must be specified, because their - // arguments can vary from aggregator to aggregator. - // - // Function selector for aggregator initiateJob method - bytes4 aggInitiateJobSelector; - // Function selector for aggregator fulfill method - bytes4 aggFulfillSelector; - } - - function decodeServiceAgreement( - bytes memory _serviceAgreementData - ) - internal - pure - returns(ServiceAgreement memory) - { - // solhint-disable indent - ServiceAgreement memory agreement; - - ( agreement.payment, - agreement.expiration, - agreement.endAt, - agreement.oracles, - agreement.requestDigest, - agreement.aggregator, - agreement.aggInitiateJobSelector, - agreement.aggFulfillSelector) = - abi.decode( - _serviceAgreementData, - ( uint256, - uint256, - uint256, - address[], - bytes32, - address, - bytes4, - bytes4 ) - ); - - return agreement; - } -} diff --git a/contracts/src/v0.5/interfaces/AggregatorInterface.sol b/contracts/src/v0.5/interfaces/AggregatorInterface.sol deleted file mode 100644 index d9bd107dc29..00000000000 --- a/contracts/src/v0.5/interfaces/AggregatorInterface.sol +++ /dev/null @@ -1,12 +0,0 @@ -pragma solidity >=0.5.0; - -interface AggregatorInterface { - function latestAnswer() external view returns (int256); - function latestTimestamp() external view returns (uint256); - function latestRound() external view returns (uint256); - function getAnswer(uint256 roundId) external view returns (int256); - function getTimestamp(uint256 roundId) external view returns (uint256); - - event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 timestamp); - event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt); -} diff --git a/contracts/src/v0.5/interfaces/AggregatorV2V3Interface.sol b/contracts/src/v0.5/interfaces/AggregatorV2V3Interface.sol deleted file mode 100644 index 0024711ba42..00000000000 --- a/contracts/src/v0.5/interfaces/AggregatorV2V3Interface.sol +++ /dev/null @@ -1,56 +0,0 @@ -pragma solidity >=0.5.0; - -import "./AggregatorInterface.sol"; -import "./AggregatorV3Interface.sol"; - -/** - * @title The V2 & V3 Aggregator Interface - * @notice Solidity V0.5 does not allow interfaces to inherit from other - * interfaces so this contract is a combination of v0.5 AggregatorInterface.sol - * and v0.5 AggregatorV3Interface.sol. - */ -interface AggregatorV2V3Interface { - // - // V2 Interface: - // - function latestAnswer() external view returns (int256); - function latestTimestamp() external view returns (uint256); - function latestRound() external view returns (uint256); - function getAnswer(uint256 roundId) external view returns (int256); - function getTimestamp(uint256 roundId) external view returns (uint256); - - event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 timestamp); - event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt); - - // - // V3 Interface: - // - function decimals() external view returns (uint8); - function description() external view returns (string memory); - function version() external view returns (uint256); - - // getRoundData and latestRoundData should both raise "No data present" - // if they do not have data to report, instead of returning unset values - // which could be misinterpreted as actual reported values. - function getRoundData(uint80 _roundId) - external - view - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - function latestRoundData() - external - view - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - -} diff --git a/contracts/src/v0.5/interfaces/AggregatorV3Interface.sol b/contracts/src/v0.5/interfaces/AggregatorV3Interface.sol deleted file mode 100644 index af8f83de475..00000000000 --- a/contracts/src/v0.5/interfaces/AggregatorV3Interface.sol +++ /dev/null @@ -1,33 +0,0 @@ -pragma solidity >=0.5.0; - -interface AggregatorV3Interface { - - function decimals() external view returns (uint8); - function description() external view returns (string memory); - function version() external view returns (uint256); - - // getRoundData and latestRoundData should both raise "No data present" - // if they do not have data to report, instead of returning unset values - // which could be misinterpreted as actual reported values. - function getRoundData(uint80 _roundId) - external - view - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - function latestRoundData() - external - view - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - -} diff --git a/contracts/src/v0.5/interfaces/ChainlinkRequestInterface.sol b/contracts/src/v0.5/interfaces/ChainlinkRequestInterface.sol deleted file mode 100644 index b58705bb3a8..00000000000 --- a/contracts/src/v0.5/interfaces/ChainlinkRequestInterface.sol +++ /dev/null @@ -1,21 +0,0 @@ -pragma solidity ^0.5.0; - -interface ChainlinkRequestInterface { - function oracleRequest( - address sender, - uint256 requestPrice, - bytes32 serviceAgreementID, - address callbackAddress, - bytes4 callbackFunctionId, - uint256 nonce, - uint256 dataVersion, - bytes calldata data - ) external; - - function cancelOracleRequest( - bytes32 requestId, - uint256 payment, - bytes4 callbackFunctionId, - uint256 expiration - ) external; -} diff --git a/contracts/src/v0.5/interfaces/ENSInterface.sol b/contracts/src/v0.5/interfaces/ENSInterface.sol deleted file mode 100644 index 1aee391a4b8..00000000000 --- a/contracts/src/v0.5/interfaces/ENSInterface.sol +++ /dev/null @@ -1,26 +0,0 @@ -pragma solidity ^0.5.0; - -interface ENSInterface { - - // Logged when the owner of a node assigns a new owner to a subnode. - event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner); - - // Logged when the owner of a node transfers ownership to a new account. - event Transfer(bytes32 indexed node, address owner); - - // Logged when the resolver for a node changes. - event NewResolver(bytes32 indexed node, address resolver); - - // Logged when the TTL of a node changes - event NewTTL(bytes32 indexed node, uint64 ttl); - - - function setSubnodeOwner(bytes32 node, bytes32 label, address _owner) external; - function setResolver(bytes32 node, address _resolver) external; - function setOwner(bytes32 node, address _owner) external; - function setTTL(bytes32 node, uint64 _ttl) external; - function owner(bytes32 node) external view returns (address); - function resolver(bytes32 node) external view returns (address); - function ttl(bytes32 node) external view returns (uint64); - -} diff --git a/contracts/src/v0.5/interfaces/FlagsInterface.sol b/contracts/src/v0.5/interfaces/FlagsInterface.sol deleted file mode 100644 index 8820329780f..00000000000 --- a/contracts/src/v0.5/interfaces/FlagsInterface.sol +++ /dev/null @@ -1,10 +0,0 @@ -pragma solidity >=0.5.0; - -interface FlagsInterface { - function getFlag(address) external view returns (bool); - function getFlags(address[] calldata) external view returns (bool[] memory); - function raiseFlag(address) external; - function raiseFlags(address[] calldata) external; - function lowerFlags(address[] calldata) external; - function setRaisingAccessController(address) external; -} diff --git a/contracts/src/v0.5/interfaces/LinkTokenInterface.sol b/contracts/src/v0.5/interfaces/LinkTokenInterface.sol deleted file mode 100644 index 6865956fd07..00000000000 --- a/contracts/src/v0.5/interfaces/LinkTokenInterface.sol +++ /dev/null @@ -1,16 +0,0 @@ -pragma solidity ^0.5.0; - -interface LinkTokenInterface { - function allowance(address owner, address spender) external view returns (uint256 remaining); - function approve(address spender, uint256 value) external returns (bool success); - function balanceOf(address owner) external view returns (uint256 balance); - function decimals() external view returns (uint8 decimalPlaces); - function decreaseApproval(address spender, uint256 addedValue) external returns (bool success); - function increaseApproval(address spender, uint256 subtractedValue) external; - function name() external view returns (string memory tokenName); - function symbol() external view returns (string memory tokenSymbol); - function totalSupply() external view returns (uint256 totalTokensIssued); - function transfer(address to, uint256 value) external returns (bool success); - function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool success); - function transferFrom(address from, address to, uint256 value) external returns (bool success); -} diff --git a/contracts/src/v0.5/interfaces/OracleInterface.sol b/contracts/src/v0.5/interfaces/OracleInterface.sol deleted file mode 100644 index b6847e5a2ec..00000000000 --- a/contracts/src/v0.5/interfaces/OracleInterface.sol +++ /dev/null @@ -1,16 +0,0 @@ -pragma solidity ^0.5.0; - -interface OracleInterface { - function fulfillOracleRequest( - bytes32 requestId, - uint256 payment, - address callbackAddress, - bytes4 callbackFunctionId, - uint256 expiration, - bytes32 data - ) external returns (bool); - function getAuthorizationStatus(address node) external view returns (bool); - function setFulfillmentPermission(address node, bool allowed) external; - function withdraw(address recipient, uint256 amount) external; - function withdrawable() external view returns (uint256); -} diff --git a/contracts/src/v0.5/interfaces/PointerInterface.sol b/contracts/src/v0.5/interfaces/PointerInterface.sol deleted file mode 100644 index 2f3013c6d42..00000000000 --- a/contracts/src/v0.5/interfaces/PointerInterface.sol +++ /dev/null @@ -1,5 +0,0 @@ -pragma solidity ^0.5.0; - -interface PointerInterface { - function getAddress() external view returns (address); -} diff --git a/contracts/src/v0.5/interfaces/WithdrawalInterface.sol b/contracts/src/v0.5/interfaces/WithdrawalInterface.sol deleted file mode 100644 index d8eab0ab722..00000000000 --- a/contracts/src/v0.5/interfaces/WithdrawalInterface.sol +++ /dev/null @@ -1,16 +0,0 @@ -pragma solidity ^0.5.0; - -interface WithdrawalInterface { - /** - * @notice transfer LINK held by the contract belonging to msg.sender to - * another address - * @param recipient is the address to send the LINK to - * @param amount is the amount of LINK to send - */ - function withdraw(address recipient, uint256 amount) external; - - /** - * @notice query the available amount of LINK to withdraw by msg.sender - */ - function withdrawable() external view returns (uint256); -} diff --git a/contracts/src/v0.5/tests/BasicConsumer.sol b/contracts/src/v0.5/tests/BasicConsumer.sol deleted file mode 100644 index bf1b7636e23..00000000000 --- a/contracts/src/v0.5/tests/BasicConsumer.sol +++ /dev/null @@ -1,13 +0,0 @@ -pragma solidity ^0.5.0; - -import "./Consumer.sol"; - -contract BasicConsumer is Consumer { - - constructor(address _link, address _oracle, bytes32 _specId) public { - setChainlinkToken(_link); - setChainlinkOracle(_oracle); - specId = _specId; - } - -} diff --git a/contracts/src/v0.5/tests/ChainlinkTestHelper.sol b/contracts/src/v0.5/tests/ChainlinkTestHelper.sol deleted file mode 100644 index e760b838224..00000000000 --- a/contracts/src/v0.5/tests/ChainlinkTestHelper.sol +++ /dev/null @@ -1,75 +0,0 @@ -pragma solidity ^0.5.0; - -import "../Chainlink.sol"; - -contract ChainlinkTestHelper { - using Chainlink for Chainlink.Request; - using CBOR_Chainlink for Buffer_Chainlink.buffer; - - Chainlink.Request private req; - - event RequestData(bytes payload); - - function closeEvent() public { - emit RequestData(req.buf.buf); - } - - function setBuffer(bytes memory data) public { - Chainlink.Request memory r2 = req; - r2.setBuffer(data); - req = r2; - } - - function add(string memory _key, string memory _value) public { - Chainlink.Request memory r2 = req; - r2.add(_key, _value); - req = r2; - } - - function addBytes(string memory _key, bytes memory _value) public { - Chainlink.Request memory r2 = req; - r2.addBytes(_key, _value); - req = r2; - } - - function addInt(string memory _key, int256 _value) public { - Chainlink.Request memory r2 = req; - r2.addInt(_key, _value); - req = r2; - } - - function addUint(string memory _key, uint256 _value) public { - Chainlink.Request memory r2 = req; - r2.addUint(_key, _value); - req = r2; - } - - // Temporarily have method receive bytes32[] memory until experimental - // string[] memory can be invoked from truffle tests. - function addStringArray(string memory _key, bytes32[] memory _values) public { - string[] memory strings = new string[](_values.length); - for (uint256 i = 0; i < _values.length; i++) { - strings[i] = bytes32ToString(_values[i]); - } - Chainlink.Request memory r2 = req; - r2.addStringArray(_key, strings); - req = r2; - } - - function bytes32ToString(bytes32 x) private pure returns (string memory) { - bytes memory bytesString = new bytes(32); - uint charCount = 0; - for (uint j = 0; j < 32; j++) { - byte char = byte(bytes32(uint(x) * 2 ** (8 * j))); - if (char != 0) { - bytesString[charCount] = char; - charCount++; - } - } - bytes memory bytesStringTrimmed = new bytes(charCount); - for (uint j = 0; j < charCount; j++) { - bytesStringTrimmed[j] = bytesString[j]; - } - return string(bytesStringTrimmed); - } -} diff --git a/contracts/src/v0.5/tests/Consumer.sol b/contracts/src/v0.5/tests/Consumer.sol deleted file mode 100644 index e937c175385..00000000000 --- a/contracts/src/v0.5/tests/Consumer.sol +++ /dev/null @@ -1,55 +0,0 @@ -pragma solidity ^0.5.0; - -import "../ChainlinkClient.sol"; - -contract Consumer is ChainlinkClient { - bytes32 internal specId; - bytes32 public currentPrice; - - event RequestFulfilled( - bytes32 indexed requestId, // User-defined ID - bytes32 indexed price - ); - - function requestEthereumPrice(string memory _currency, uint256 _payment) public { - requestEthereumPriceByCallback(_currency, _payment, address(this)); - } - - function requestEthereumPriceByCallback(string memory _currency, uint256 _payment, address _callback) public { - Chainlink.Request memory req = buildChainlinkRequest(specId, _callback, this.fulfill.selector); - req.add("get", "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD,EUR,JPY"); - string[] memory path = new string[](1); - path[0] = _currency; - req.addStringArray("path", path); - sendChainlinkRequest(req, _payment); - } - - function cancelRequest( - address _oracle, - bytes32 _requestId, - uint256 _payment, - bytes4 _callbackFunctionId, - uint256 _expiration - ) public { - ChainlinkRequestInterface requested = ChainlinkRequestInterface(_oracle); - requested.cancelOracleRequest(_requestId, _payment, _callbackFunctionId, _expiration); - } - - function withdrawLink() public { - LinkTokenInterface _link = LinkTokenInterface(chainlinkTokenAddress()); - require(_link.transfer(msg.sender, _link.balanceOf(address(this))), "Unable to transfer"); - } - - function addExternalRequest(address _oracle, bytes32 _requestId) external { - addChainlinkExternalRequest(_oracle, _requestId); - } - - function fulfill(bytes32 _requestId, bytes32 _price) - public - recordChainlinkFulfillment(_requestId) - { - emit RequestFulfilled(_requestId, _price); - currentPrice = _price; - } - -} diff --git a/contracts/src/v0.5/tests/EmptyAggregator.sol b/contracts/src/v0.5/tests/EmptyAggregator.sol deleted file mode 100644 index 02331f3102f..00000000000 --- a/contracts/src/v0.5/tests/EmptyAggregator.sol +++ /dev/null @@ -1,34 +0,0 @@ -pragma solidity 0.5.0; - -import "../dev/CoordinatorInterface.sol"; - -/// Used to check the basic aggregator/coordinator interactions. It does nothing -/// but emit its messages as certain types of events. -contract EmptyAggregator { - - event InitiatedJob(bytes32 said); - - function initiateJob( - bytes32 _saId, bytes memory _serviceAgreementData) - public returns (bool success, bytes memory _) { - emit InitiatedJob(_saId); - success = true; - } - - event Fulfilled( - bytes32 requestId, - address oracle, - bool success, - bool complete, - bytes fulfillment); - - function fulfill(bytes32 _requestId, bytes32 _saId, address _oracle, - bytes32 _fulfillment) - public returns (bool success, bool complete, bytes memory response, - int256[] memory paymentAmounts) { - success = true; - complete = true; - response = abi.encode(_fulfillment); - emit Fulfilled(_requestId, _oracle, success, complete, response); - } -} diff --git a/contracts/src/v0.5/tests/MaliciousChainlinkClient.sol b/contracts/src/v0.5/tests/MaliciousChainlinkClient.sol deleted file mode 100644 index ff5b07060c1..00000000000 --- a/contracts/src/v0.5/tests/MaliciousChainlinkClient.sol +++ /dev/null @@ -1,109 +0,0 @@ -pragma solidity 0.5.0; - -import "./MaliciousChainlink.sol"; -import "../ChainlinkClient.sol"; -import "../vendor/SafeMathChainlink.sol"; - -contract MaliciousChainlinkClient is ChainlinkClient { - using MaliciousChainlink for MaliciousChainlink.Request; - using MaliciousChainlink for MaliciousChainlink.WithdrawRequest; - using Chainlink for Chainlink.Request; - using SafeMathChainlink for uint256; - - uint256 private maliciousRequests = 1; - mapping(bytes32 => address) private maliciousPendingRequests; - - function newWithdrawRequest( - bytes32 _specId, - address _callbackAddress, - bytes4 _callbackFunction - ) internal pure returns (MaliciousChainlink.WithdrawRequest memory) { - MaliciousChainlink.WithdrawRequest memory req; - return req.initializeWithdraw(_specId, _callbackAddress, _callbackFunction); - } - - function chainlinkTargetRequest(address _target, Chainlink.Request memory _req, uint256 _amount) - internal - returns(bytes32 requestId) - { - requestId = keccak256(abi.encodePacked(_target, maliciousRequests)); - _req.nonce = maliciousRequests; - maliciousPendingRequests[requestId] = chainlinkOracleAddress(); - emit ChainlinkRequested(requestId); - LinkTokenInterface _link = LinkTokenInterface(chainlinkTokenAddress()); - require(_link.transferAndCall(chainlinkOracleAddress(), _amount, encodeTargetRequest(_req)), "Unable to transferAndCall to oracle"); - maliciousRequests += 1; - - return requestId; - } - - function chainlinkPriceRequest(Chainlink.Request memory _req, uint256 _amount) - internal - returns(bytes32 requestId) - { - requestId = keccak256(abi.encodePacked(this, maliciousRequests)); - _req.nonce = maliciousRequests; - maliciousPendingRequests[requestId] = chainlinkOracleAddress(); - emit ChainlinkRequested(requestId); - LinkTokenInterface _link = LinkTokenInterface(chainlinkTokenAddress()); - require(_link.transferAndCall(chainlinkOracleAddress(), _amount, encodePriceRequest(_req)), "Unable to transferAndCall to oracle"); - maliciousRequests += 1; - - return requestId; - } - - function chainlinkWithdrawRequest(MaliciousChainlink.WithdrawRequest memory _req, uint256 _wei) - internal - returns(bytes32 requestId) - { - requestId = keccak256(abi.encodePacked(this, maliciousRequests)); - _req.nonce = maliciousRequests; - maliciousPendingRequests[requestId] = chainlinkOracleAddress(); - emit ChainlinkRequested(requestId); - LinkTokenInterface _link = LinkTokenInterface(chainlinkTokenAddress()); - require(_link.transferAndCall(chainlinkOracleAddress(), _wei, encodeWithdrawRequest(_req)), "Unable to transferAndCall to oracle"); - maliciousRequests += 1; - return requestId; - } - - function encodeWithdrawRequest(MaliciousChainlink.WithdrawRequest memory _req) - internal pure returns (bytes memory) - { - return abi.encodeWithSelector( - bytes4(keccak256("withdraw(address,uint256)")), - _req.callbackAddress, - _req.callbackFunctionId, - _req.nonce, - _req.buf.buf); - } - - function encodeTargetRequest(Chainlink.Request memory _req) - internal pure returns (bytes memory) - { - return abi.encodeWithSelector( - bytes4(keccak256("oracleRequest(address,uint256,bytes32,address,bytes4,uint256,uint256,bytes)")), - 0, // overridden by onTokenTransfer - 0, // overridden by onTokenTransfer - _req.id, - _req.callbackAddress, - _req.callbackFunctionId, - _req.nonce, - 1, - _req.buf.buf); - } - - function encodePriceRequest(Chainlink.Request memory _req) - internal pure returns (bytes memory) - { - return abi.encodeWithSelector( - bytes4(keccak256("oracleRequest(address,uint256,bytes32,address,bytes4,uint256,uint256,bytes)")), - 0, // overridden by onTokenTransfer - 2000000000000000000, // overridden by onTokenTransfer - _req.id, - _req.callbackAddress, - _req.callbackFunctionId, - _req.nonce, - 1, - _req.buf.buf); - } -} diff --git a/contracts/src/v0.5/tests/MaliciousConsumer.sol b/contracts/src/v0.5/tests/MaliciousConsumer.sol deleted file mode 100644 index c14a4ac46c0..00000000000 --- a/contracts/src/v0.5/tests/MaliciousConsumer.sol +++ /dev/null @@ -1,57 +0,0 @@ -pragma solidity 0.5.0; - -import "../ChainlinkClient.sol"; -import "../vendor/SafeMathChainlink.sol"; - -contract MaliciousConsumer is ChainlinkClient { - using SafeMathChainlink for uint256; - - uint256 constant private ORACLE_PAYMENT = 1 * LINK; - uint256 private expiration; - - constructor(address _link, address _oracle) public payable { - setChainlinkToken(_link); - setChainlinkOracle(_oracle); - } - - function () external payable {} // solhint-disable-line no-empty-blocks - - function requestData(bytes32 _id, bytes memory _callbackFunc) public { - Chainlink.Request memory req = buildChainlinkRequest(_id, address(this), bytes4(keccak256(_callbackFunc))); - expiration = now.add(5 minutes); // solhint-disable-line not-rely-on-time - sendChainlinkRequest(req, ORACLE_PAYMENT); - } - - function assertFail(bytes32, bytes32) public pure { - assert(1 == 2); - } - - function cancelRequestOnFulfill(bytes32 _requestId, bytes32) public { - cancelChainlinkRequest( - _requestId, - ORACLE_PAYMENT, - this.cancelRequestOnFulfill.selector, - expiration); - } - - function remove() public { - selfdestruct(address(0)); - } - - function stealEthCall(bytes32 _requestId, bytes32) public recordChainlinkFulfillment(_requestId) { - (bool success,) = address(this).call.value(100)(""); // solhint-disable-line avoid-call-value - require(success, "Call failed"); - } - - function stealEthSend(bytes32 _requestId, bytes32) public recordChainlinkFulfillment(_requestId) { - // solhint-disable-next-line check-send-result - bool success = address(this).send(100); // solhint-disable-line multiple-sends - require(success, "Send failed"); - } - - function stealEthTransfer(bytes32 _requestId, bytes32) public recordChainlinkFulfillment(_requestId) { - address(this).transfer(100); - } - - function doesNothing(bytes32, bytes32) public pure {} // solhint-disable-line no-empty-blocks -} diff --git a/contracts/src/v0.5/tests/MaliciousRequester.sol b/contracts/src/v0.5/tests/MaliciousRequester.sol deleted file mode 100644 index 53067c82524..00000000000 --- a/contracts/src/v0.5/tests/MaliciousRequester.sol +++ /dev/null @@ -1,52 +0,0 @@ -pragma solidity 0.5.0; - - -import "./MaliciousChainlinkClient.sol"; - - -contract MaliciousRequester is MaliciousChainlinkClient { - - uint256 constant private ORACLE_PAYMENT = 1 * LINK; - uint256 private expiration; - - constructor(address _link, address _oracle) public { - setChainlinkToken(_link); - setChainlinkOracle(_oracle); - } - - function maliciousWithdraw() - public - { - MaliciousChainlink.WithdrawRequest memory req = newWithdrawRequest( - "specId", address(this), this.doesNothing.selector); - chainlinkWithdrawRequest(req, ORACLE_PAYMENT); - } - - function request(bytes32 _id, address _target, bytes memory _callbackFunc) public returns (bytes32 requestId) { - Chainlink.Request memory req = buildChainlinkRequest(_id, _target, bytes4(keccak256(_callbackFunc))); - expiration = now.add(5 minutes); // solhint-disable-line not-rely-on-time - requestId = sendChainlinkRequest(req, ORACLE_PAYMENT); - } - - function maliciousPrice(bytes32 _id) public returns (bytes32 requestId) { - Chainlink.Request memory req = buildChainlinkRequest(_id, address(this), this.doesNothing.selector); - requestId = chainlinkPriceRequest(req, ORACLE_PAYMENT); - } - - function maliciousTargetConsumer(address _target) public returns (bytes32 requestId) { - Chainlink.Request memory req = buildChainlinkRequest("specId", _target, bytes4(keccak256("fulfill(bytes32,bytes32)"))); - requestId = chainlinkTargetRequest(_target, req, ORACLE_PAYMENT); - } - - function maliciousRequestCancel(bytes32 _id, bytes memory _callbackFunc) public { - ChainlinkRequestInterface _oracle = ChainlinkRequestInterface(chainlinkOracleAddress()); - _oracle.cancelOracleRequest( - request(_id, address(this), _callbackFunc), - ORACLE_PAYMENT, - this.maliciousRequestCancel.selector, - expiration - ); - } - - function doesNothing(bytes32, bytes32) public pure {} // solhint-disable-line no-empty-blocks -} diff --git a/contracts/src/v0.5/tests/MeanAggregator.sol b/contracts/src/v0.5/tests/MeanAggregator.sol deleted file mode 100644 index 4c15858df7c..00000000000 --- a/contracts/src/v0.5/tests/MeanAggregator.sol +++ /dev/null @@ -1,75 +0,0 @@ -pragma solidity 0.5.0; - -import "../dev/CoordinatorInterface.sol"; -import "../dev/ServiceAgreementDecoder.sol"; - -/// Computes the mean of the values the oracles pass it via fulfill method -contract MeanAggregator is ServiceAgreementDecoder { - - // Relies on Coordinator's authorization of the oracles (no need to track - // oracle authorization in this contract.) - - mapping(bytes32 /* service agreement ID */ => uint256) payment; - mapping(bytes32 /* service agreement ID */ => address[]) oracles; - mapping(bytes32 /* request ID */ => uint256) numberReported; - mapping(bytes32 /* request ID */ => mapping(address => uint256)) reportingOrder; - - // Current total for given request, divided by number of oracles reporting - mapping(bytes32 /* request ID */ => uint256) average; - // Remainder of total for given request from division by number of oracles. - mapping(bytes32 /* request ID */ => uint256) remainder; - - function initiateJob( - bytes32 _sAId, bytes memory _serviceAgreementData) - public returns (bool success, bytes memory message) { - ServiceAgreement memory serviceAgreement = decodeServiceAgreement(_serviceAgreementData); - - if (oracles[_sAId].length != 0) { - return (false, bytes("job already initiated")); - } - if (serviceAgreement.oracles.length == 0) { - return (false, bytes("must depend on at least one oracle")); - } - oracles[_sAId] = serviceAgreement.oracles; - payment[_sAId] = serviceAgreement.payment; - success = true; - } - - function fulfill(bytes32 _requestId, bytes32 _sAId, address _oracle, - bytes32 _value) public - returns (bool success, bool complete, bytes memory response, - int256[] memory paymentAmounts) { - if (reportingOrder[_requestId][_oracle] != 0 || - numberReported[_requestId] == oracles[_sAId].length) { - return (false, false, "oracle already reported", paymentAmounts); - } - uint256 oDividend = uint256(_value) / oracles[_sAId].length; - uint256 oRemainder = uint256(_value) % oracles[_sAId].length; - uint256 newRemainder = remainder[_requestId] + oRemainder; - uint256 newAverage = average[_requestId] + oDividend + (newRemainder / oracles[_sAId].length); - assert(newAverage >= average[_requestId]); // No overflow - average[_requestId] = newAverage; - remainder[_requestId] = newRemainder % oracles[_sAId].length; - numberReported[_requestId] += 1; - reportingOrder[_requestId][_oracle] = numberReported[_requestId]; - success = true; - complete = (numberReported[_requestId] == oracles[_sAId].length); - if (complete) { - response = abi.encode(average[_requestId]); - paymentAmounts = calculatePayments(_sAId, _requestId); - } - } - - function calculatePayments(bytes32 _sAId, bytes32 _requestId) private returns (int256[] memory paymentAmounts) { - paymentAmounts = new int256[](oracles[_sAId].length); - uint256 numOracles = oracles[_sAId].length; - uint256 totalPayment = payment[_sAId]; - for (uint256 oIdx = 0; oIdx < oracles[_sAId].length; oIdx++) { - // Linearly-decaying payout determined by each oracle's reportingIdx - uint256 reportingIdx = reportingOrder[_requestId][oracles[_sAId][oIdx]] - 1; - paymentAmounts[oIdx] = int256(2*(totalPayment/numOracles) - ( - (totalPayment * ((2*reportingIdx) + 1)) / (numOracles**2))); - delete reportingOrder[_requestId][oracles[_sAId][oIdx]]; - } - } -} diff --git a/contracts/src/v0.5/tests/MedianTestHelper.sol b/contracts/src/v0.5/tests/MedianTestHelper.sol deleted file mode 100644 index 073873174a5..00000000000 --- a/contracts/src/v0.5/tests/MedianTestHelper.sol +++ /dev/null @@ -1,15 +0,0 @@ -pragma solidity ^0.5.0; - -import "../Median.sol"; - -contract MedianTestHelper { - - function publicGet(int256[] memory _list) - public - pure - returns (int256) - { - return Median.calculate(_list); - } - -} diff --git a/contracts/src/v0.5/tests/ServiceAgreementConsumer.sol b/contracts/src/v0.5/tests/ServiceAgreementConsumer.sol deleted file mode 100644 index 9be23e9ee8e..00000000000 --- a/contracts/src/v0.5/tests/ServiceAgreementConsumer.sol +++ /dev/null @@ -1,30 +0,0 @@ -pragma solidity 0.5.0; - -import "../ChainlinkClient.sol"; - -contract ServiceAgreementConsumer is ChainlinkClient { - uint256 constant private ORACLE_PAYMENT = 1 * LINK; - - bytes32 internal sAId; - bytes32 public currentPrice; - - constructor(address _link, address _coordinator, bytes32 _sAId) public { - setChainlinkToken(_link); - setChainlinkOracle(_coordinator); - sAId = _sAId; - } - - function requestEthereumPrice(string memory _currency) public { - Chainlink.Request memory req = buildChainlinkRequest(sAId, address(this), this.fulfill.selector); - req.add("get", "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD,EUR,JPY"); - req.add("path", _currency); - sendChainlinkRequest(req, ORACLE_PAYMENT); - } - - function fulfill(bytes32 _requestId, bytes32 _price) - public - recordChainlinkFulfillment(_requestId) - { - currentPrice = _price; - } -} diff --git a/contracts/src/v0.5/vendor/Buffer.sol b/contracts/src/v0.5/vendor/Buffer.sol deleted file mode 100644 index ef740574ec8..00000000000 --- a/contracts/src/v0.5/vendor/Buffer.sol +++ /dev/null @@ -1,301 +0,0 @@ -pragma solidity ^0.5.0; - -/** -* @dev A library for working with mutable byte buffers in Solidity. -* -* Byte buffers are mutable and expandable, and provide a variety of primitives -* for writing to them. At any time you can fetch a bytes object containing the -* current contents of the buffer. The bytes object should not be stored between -* operations, as it may change due to resizing of the buffer. -*/ -library Buffer { - /** - * @dev Represents a mutable buffer. Buffers have a current value (buf) and - * a capacity. The capacity may be longer than the current value, in - * which case it can be extended without the need to allocate more memory. - */ - struct buffer { - bytes buf; - uint capacity; - } - - /** - * @dev Initializes a buffer with an initial capacity. - * @param buf The buffer to initialize. - * @param capacity The number of bytes of space to allocate the buffer. - * @return The buffer, for chaining. - */ - function init(buffer memory buf, uint capacity) internal pure returns(buffer memory) { - if (capacity % 32 != 0) { - capacity += 32 - (capacity % 32); - } - // Allocate space for the buffer data - buf.capacity = capacity; - assembly { - let ptr := mload(0x40) - mstore(buf, ptr) - mstore(ptr, 0) - mstore(0x40, add(32, add(ptr, capacity))) - } - return buf; - } - - /** - * @dev Initializes a new buffer from an existing bytes object. - * Changes to the buffer may mutate the original value. - * @param b The bytes object to initialize the buffer with. - * @return A new buffer. - */ - function fromBytes(bytes memory b) internal pure returns(buffer memory) { - buffer memory buf; - buf.buf = b; - buf.capacity = b.length; - return buf; - } - - function resize(buffer memory buf, uint capacity) private pure { - bytes memory oldbuf = buf.buf; - init(buf, capacity); - append(buf, oldbuf); - } - - function max(uint a, uint b) private pure returns(uint) { - if (a > b) { - return a; - } - return b; - } - - /** - * @dev Sets buffer length to 0. - * @param buf The buffer to truncate. - * @return The original buffer, for chaining.. - */ - function truncate(buffer memory buf) internal pure returns (buffer memory) { - assembly { - let bufptr := mload(buf) - mstore(bufptr, 0) - } - return buf; - } - - /** - * @dev Writes a byte string to a buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param off The start offset to write to. - * @param data The data to append. - * @param len The number of bytes to copy. - * @return The original buffer, for chaining. - */ - function write(buffer memory buf, uint off, bytes memory data, uint len) internal pure returns(buffer memory) { - require(len <= data.length); - - if (off + len > buf.capacity) { - resize(buf, max(buf.capacity, len + off) * 2); - } - - uint dest; - uint src; - assembly { - // Memory address of the buffer data - let bufptr := mload(buf) - // Length of existing buffer data - let buflen := mload(bufptr) - // Start address = buffer address + offset + sizeof(buffer length) - dest := add(add(bufptr, 32), off) - // Update buffer length if we're extending it - if gt(add(len, off), buflen) { - mstore(bufptr, add(len, off)) - } - src := add(data, 32) - } - - // Copy word-length chunks while possible - for (; len >= 32; len -= 32) { - assembly { - mstore(dest, mload(src)) - } - dest += 32; - src += 32; - } - - // Copy remaining bytes - uint mask = 256 ** (32 - len) - 1; - assembly { - let srcpart := and(mload(src), not(mask)) - let destpart := and(mload(dest), mask) - mstore(dest, or(destpart, srcpart)) - } - - return buf; - } - - /** - * @dev Appends a byte string to a buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @param len The number of bytes to copy. - * @return The original buffer, for chaining. - */ - function append(buffer memory buf, bytes memory data, uint len) internal pure returns (buffer memory) { - return write(buf, buf.buf.length, data, len); - } - - /** - * @dev Appends a byte string to a buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer, for chaining. - */ - function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) { - return write(buf, buf.buf.length, data, data.length); - } - - /** - * @dev Writes a byte to the buffer. Resizes if doing so would exceed the - * capacity of the buffer. - * @param buf The buffer to append to. - * @param off The offset to write the byte at. - * @param data The data to append. - * @return The original buffer, for chaining. - */ - function writeUint8(buffer memory buf, uint off, uint8 data) internal pure returns(buffer memory) { - if (off >= buf.capacity) { - resize(buf, buf.capacity * 2); - } - - assembly { - // Memory address of the buffer data - let bufptr := mload(buf) - // Length of existing buffer data - let buflen := mload(bufptr) - // Address = buffer address + sizeof(buffer length) + off - let dest := add(add(bufptr, off), 32) - mstore8(dest, data) - // Update buffer length if we extended it - if eq(off, buflen) { - mstore(bufptr, add(buflen, 1)) - } - } - return buf; - } - - /** - * @dev Appends a byte to the buffer. Resizes if doing so would exceed the - * capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer, for chaining. - */ - function appendUint8(buffer memory buf, uint8 data) internal pure returns(buffer memory) { - return writeUint8(buf, buf.buf.length, data); - } - - /** - * @dev Writes up to 32 bytes to the buffer. Resizes if doing so would - * exceed the capacity of the buffer. - * @param buf The buffer to append to. - * @param off The offset to write at. - * @param data The data to append. - * @param len The number of bytes to write (left-aligned). - * @return The original buffer, for chaining. - */ - function write(buffer memory buf, uint off, bytes32 data, uint len) private pure returns(buffer memory) { - if (len + off > buf.capacity) { - resize(buf, (len + off) * 2); - } - - uint mask = 256 ** len - 1; - // Right-align data - data = data >> (8 * (32 - len)); - assembly { - // Memory address of the buffer data - let bufptr := mload(buf) - // Address = buffer address + sizeof(buffer length) + off + len - let dest := add(add(bufptr, off), len) - mstore(dest, or(and(mload(dest), not(mask)), data)) - // Update buffer length if we extended it - if gt(add(off, len), mload(bufptr)) { - mstore(bufptr, add(off, len)) - } - } - return buf; - } - - /** - * @dev Writes a bytes20 to the buffer. Resizes if doing so would exceed the - * capacity of the buffer. - * @param buf The buffer to append to. - * @param off The offset to write at. - * @param data The data to append. - * @return The original buffer, for chaining. - */ - function writeBytes20(buffer memory buf, uint off, bytes20 data) internal pure returns (buffer memory) { - return write(buf, off, bytes32(data), 20); - } - - /** - * @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer, for chhaining. - */ - function appendBytes20(buffer memory buf, bytes20 data) internal pure returns (buffer memory) { - return write(buf, buf.buf.length, bytes32(data), 20); - } - - /** - * @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer, for chaining. - */ - function appendBytes32(buffer memory buf, bytes32 data) internal pure returns (buffer memory) { - return write(buf, buf.buf.length, data, 32); - } - - /** - * @dev Writes an integer to the buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param off The offset to write at. - * @param data The data to append. - * @param len The number of bytes to write (right-aligned). - * @return The original buffer, for chaining. - */ - function writeInt(buffer memory buf, uint off, uint data, uint len) private pure returns(buffer memory) { - if (len + off > buf.capacity) { - resize(buf, (len + off) * 2); - } - - uint mask = 256 ** len - 1; - assembly { - // Memory address of the buffer data - let bufptr := mload(buf) - // Address = buffer address + off + sizeof(buffer length) + len - let dest := add(add(bufptr, off), len) - mstore(dest, or(and(mload(dest), not(mask)), data)) - // Update buffer length if we extended it - if gt(add(off, len), mload(bufptr)) { - mstore(bufptr, add(off, len)) - } - } - return buf; - } - - /** - * @dev Appends a byte to the end of the buffer. Resizes if doing so would - * exceed the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer. - */ - function appendInt(buffer memory buf, uint data, uint len) internal pure returns(buffer memory) { - return writeInt(buf, buf.buf.length, data, len); - } -} \ No newline at end of file diff --git a/contracts/src/v0.5/vendor/CBOR.sol b/contracts/src/v0.5/vendor/CBOR.sol deleted file mode 100644 index 9cce04ac56e..00000000000 --- a/contracts/src/v0.5/vendor/CBOR.sol +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >= 0.4.19 < 0.7.0; - -import { Buffer as BufferChainlink } from "./Buffer.sol"; - -library CBOR { - using BufferChainlink for BufferChainlink.buffer; - - uint8 private constant MAJOR_TYPE_INT = 0; - uint8 private constant MAJOR_TYPE_NEGATIVE_INT = 1; - uint8 private constant MAJOR_TYPE_BYTES = 2; - uint8 private constant MAJOR_TYPE_STRING = 3; - uint8 private constant MAJOR_TYPE_ARRAY = 4; - uint8 private constant MAJOR_TYPE_MAP = 5; - uint8 private constant MAJOR_TYPE_TAG = 6; - uint8 private constant MAJOR_TYPE_CONTENT_FREE = 7; - - uint8 private constant TAG_TYPE_BIGNUM = 2; - uint8 private constant TAG_TYPE_NEGATIVE_BIGNUM = 3; - - function encodeFixedNumeric(BufferChainlink.buffer memory buf, uint8 major, uint64 value) private pure { - if(value <= 23) { - buf.appendUint8(uint8((major << 5) | value)); - } else if(value <= 0xFF) { - buf.appendUint8(uint8((major << 5) | 24)); - buf.appendInt(value, 1); - } else if(value <= 0xFFFF) { - buf.appendUint8(uint8((major << 5) | 25)); - buf.appendInt(value, 2); - } else if(value <= 0xFFFFFFFF) { - buf.appendUint8(uint8((major << 5) | 26)); - buf.appendInt(value, 4); - } else { - buf.appendUint8(uint8((major << 5) | 27)); - buf.appendInt(value, 8); - } - } - - function encodeIndefiniteLengthType(BufferChainlink.buffer memory buf, uint8 major) private pure { - buf.appendUint8(uint8((major << 5) | 31)); - } - - function encodeUInt(BufferChainlink.buffer memory buf, uint value) internal pure { - if(value > 0xFFFFFFFFFFFFFFFF) { - encodeBigNum(buf, value); - } else { - encodeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(value)); - } - } - - function encodeInt(BufferChainlink.buffer memory buf, int value) internal pure { - if(value < -0x10000000000000000) { - encodeSignedBigNum(buf, value); - } else if(value > 0xFFFFFFFFFFFFFFFF) { - encodeBigNum(buf, uint(value)); - } else if(value >= 0) { - encodeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(value)); - } else { - encodeFixedNumeric(buf, MAJOR_TYPE_NEGATIVE_INT, uint64(-1 - value)); - } - } - - function encodeBytes(BufferChainlink.buffer memory buf, bytes memory value) internal pure { - encodeFixedNumeric(buf, MAJOR_TYPE_BYTES, uint64(value.length)); - buf.append(value); - } - - function encodeBigNum(BufferChainlink.buffer memory buf, uint value) internal pure { - buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_BIGNUM)); - encodeBytes(buf, abi.encode(value)); - } - - function encodeSignedBigNum(BufferChainlink.buffer memory buf, int input) internal pure { - buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_NEGATIVE_BIGNUM)); - encodeBytes(buf, abi.encode(uint(-1 - input))); - } - - function encodeString(BufferChainlink.buffer memory buf, string memory value) internal pure { - encodeFixedNumeric(buf, MAJOR_TYPE_STRING, uint64(bytes(value).length)); - buf.append(bytes(value)); - } - - function startArray(BufferChainlink.buffer memory buf) internal pure { - encodeIndefiniteLengthType(buf, MAJOR_TYPE_ARRAY); - } - - function startMap(BufferChainlink.buffer memory buf) internal pure { - encodeIndefiniteLengthType(buf, MAJOR_TYPE_MAP); - } - - function endSequence(BufferChainlink.buffer memory buf) internal pure { - encodeIndefiniteLengthType(buf, MAJOR_TYPE_CONTENT_FREE); - } -} diff --git a/contracts/src/v0.5/vendor/ENSResolver.sol b/contracts/src/v0.5/vendor/ENSResolver.sol deleted file mode 100644 index b80fd6d57ff..00000000000 --- a/contracts/src/v0.5/vendor/ENSResolver.sol +++ /dev/null @@ -1,5 +0,0 @@ -pragma solidity ^0.5.0; - -contract ENSResolver { - function addr(bytes32 node) public view returns (address); -} diff --git a/contracts/src/v0.5/vendor/Ownable.sol b/contracts/src/v0.5/vendor/Ownable.sol deleted file mode 100644 index 4d0929a9bf6..00000000000 --- a/contracts/src/v0.5/vendor/Ownable.sol +++ /dev/null @@ -1,65 +0,0 @@ -pragma solidity ^0.5.0; - -/** - * @dev Contract module which provides a basic access control mechanism, where - * there is an account (an owner) that can be granted exclusive access to - * specific functions. - * - * This module is used through inheritance. It will make available the modifier - * `onlyOwner`, which can be aplied to your functions to restrict their use to - * the owner. - * - * This contract has been modified to remove the revokeOwnership function - */ -contract Ownable { - address private _owner; - - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); - - /** - * @dev Initializes the contract setting the deployer as the initial owner. - */ - constructor () internal { - _owner = msg.sender; - emit OwnershipTransferred(address(0), _owner); - } - - /** - * @dev Returns the address of the current owner. - */ - function owner() public view returns (address) { - return _owner; - } - - /** - * @dev Throws if called by any account other than the owner. - */ - modifier onlyOwner() { - require(isOwner(), "Ownable: caller is not the owner"); - _; - } - - /** - * @dev Returns true if the caller is the current owner. - */ - function isOwner() public view returns (bool) { - return msg.sender == _owner; - } - - /** - * @dev Transfers ownership of the contract to a new account (`newOwner`). - * Can only be called by the current owner. - */ - function transferOwnership(address newOwner) public onlyOwner { - _transferOwnership(newOwner); - } - - /** - * @dev Transfers ownership of the contract to a new account (`newOwner`). - */ - function _transferOwnership(address newOwner) internal { - require(newOwner != address(0), "Ownable: new owner is the zero address"); - emit OwnershipTransferred(_owner, newOwner); - _owner = newOwner; - } -} diff --git a/contracts/src/v0.5/vendor/SafeMathChainlink.sol b/contracts/src/v0.5/vendor/SafeMathChainlink.sol deleted file mode 100644 index da85c972b10..00000000000 --- a/contracts/src/v0.5/vendor/SafeMathChainlink.sol +++ /dev/null @@ -1,107 +0,0 @@ -pragma solidity ^0.5.0; - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMathChainlink { - /** - * @dev Returns the addition of two unsigned integers, reverting on - * overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on - * overflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot overflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - require(b <= a, "SafeMath: subtraction overflow"); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on - * overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. Reverts on - * division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, "SafeMath: division by zero"); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - require(b != 0, "SafeMath: modulo by zero"); - return a % b; - } -} diff --git a/contracts/src/v0.5/vendor/SignedSafeMath.sol b/contracts/src/v0.5/vendor/SignedSafeMath.sol deleted file mode 100644 index 68889f1f183..00000000000 --- a/contracts/src/v0.5/vendor/SignedSafeMath.sol +++ /dev/null @@ -1,22 +0,0 @@ -pragma solidity ^0.5.0; - -library SignedSafeMath { - - /** - * @dev Adds two int256s and makes sure the result doesn't overflow. Signed - * integers aren't supported by the SafeMath library, thus this method - * @param _a The first number to be added - * @param _a The second number to be added - */ - function add(int256 _a, int256 _b) - internal - pure - returns (int256) - { - // solium-disable-next-line zeppelin/no-arithmetic-operations - int256 c = _a + _b; - require((_b >= 0 && c >= _a) || (_b < 0 && c < _a), "SignedSafeMath: addition overflow"); - - return c; - } -} \ No newline at end of file diff --git a/contracts/src/v0.6/AggregatorFacade.sol b/contracts/src/v0.6/AggregatorFacade.sol deleted file mode 100644 index deae4cfb411..00000000000 --- a/contracts/src/v0.6/AggregatorFacade.sol +++ /dev/null @@ -1,208 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.6.6; - -import "./interfaces/AggregatorV2V3Interface.sol"; - -/** - * @title A facade forAggregator versions to conform to the new v0.6 - * Aggregator V3 interface. - */ -contract AggregatorFacade is AggregatorV2V3Interface { - - AggregatorInterface public aggregator; - uint8 public override decimals; - string public override description; - - uint256 constant public override version = 2; - - // An error specific to the Aggregator V3 Interface, to prevent possible - // confusion around accidentally reading unset values as reported values. - string constant private V3_NO_DATA_ERROR = "No data present"; - - constructor( - address _aggregator, - uint8 _decimals, - string memory _description - ) public { - aggregator = AggregatorInterface(_aggregator); - decimals = _decimals; - description = _description; - } - - /** - * @notice get the latest completed round where the answer was updated - * @dev #[deprecated]. Use latestRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended latestRoundData - * instead which includes better verification information. - */ - function latestRound() - external - view - virtual - override - returns (uint256) - { - return aggregator.latestRound(); - } - - /** - * @notice Reads the current answer from aggregator delegated to. - * - * @dev #[deprecated] Use latestRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended latestRoundData - * instead which includes better verification information. - */ - function latestAnswer() - external - view - virtual - override - returns (int256) - { - return aggregator.latestAnswer(); - } - - /** - * @notice Reads the last updated height from aggregator delegated to. - * - * @dev #[deprecated] Use latestRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended latestRoundData - * instead which includes better verification information. - */ - function latestTimestamp() - external - view - virtual - override - returns (uint256) - { - return aggregator.latestTimestamp(); - } - - /** - * @notice get data about the latest round. Consumers are encouraged to check - * that they're receiving fresh data by inspecting the updatedAt value. - * @return roundId is the round ID for which data was retrieved - * @return answer is the answer for the given round - * @return startedAt is always equal to updatedAt because the underlying - * Aggregator contract does not expose this information. - * @return updatedAt is the timestamp when the round last was updated (i.e. - * answer was last computed) - * @return answeredInRound is always equal to roundId because the underlying - * Aggregator contract does not expose this information. - * @dev Note that for rounds that haven't yet received responses from all - * oracles, answer and updatedAt may change between queries. - */ - function latestRoundData() - external - view - virtual - override - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - return _getRoundData(uint80(aggregator.latestRound())); - } - - /** - * @notice get past rounds answers - * @param _roundId the answer number to retrieve the answer for - * - * @dev #[deprecated] Use getRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended getRoundData - * instead which includes better verification information. - */ - function getAnswer(uint256 _roundId) - external - view - virtual - override - returns (int256) - { - return aggregator.getAnswer(_roundId); - } - - /** - * @notice get block timestamp when an answer was last updated - * @param _roundId the answer number to retrieve the updated timestamp for - * - * @dev #[deprecated] Use getRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended getRoundData - * instead which includes better verification information. - */ - function getTimestamp(uint256 _roundId) - external - view - virtual - override - returns (uint256) - { - return aggregator.getTimestamp(_roundId); - } - - /** - * @notice get data about a round. Consumers are encouraged to check - * that they're receiving fresh data by inspecting the updatedAt value. - * @param _roundId the round ID to retrieve the round data for - * @return roundId is the round ID for which data was retrieved - * @return answer is the answer for the given round - * @return startedAt is always equal to updatedAt because the underlying - * Aggregator contract does not expose this information. - * @return updatedAt is the timestamp when the round last was updated (i.e. - * answer was last computed) - * @return answeredInRound is always equal to roundId because the underlying - * Aggregator contract does not expose this information. - * @dev Note that for rounds that haven't yet received responses from all - * oracles, answer and updatedAt may change between queries. - */ - function getRoundData(uint80 _roundId) - external - view - virtual - override - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - return _getRoundData(_roundId); - } - - - /* - * Internal - */ - - function _getRoundData(uint80 _roundId) - internal - view - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - answer = aggregator.getAnswer(_roundId); - updatedAt = uint64(aggregator.getTimestamp(_roundId)); - - require(updatedAt > 0, V3_NO_DATA_ERROR); - - return (_roundId, answer, updatedAt, updatedAt, _roundId); - } - -} diff --git a/contracts/src/v0.6/AggregatorProxy.sol b/contracts/src/v0.6/AggregatorProxy.sol deleted file mode 100644 index 73de22050c0..00000000000 --- a/contracts/src/v0.6/AggregatorProxy.sol +++ /dev/null @@ -1,445 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.6.6; - -import "./Owned.sol"; -import "./interfaces/AggregatorV2V3Interface.sol"; - -/** - * @title A trusted proxy for updating where current answers are read from - * @notice This contract provides a consistent address for the - * CurrentAnwerInterface but delegates where it reads from to the owner, who is - * trusted to update it. - */ -contract AggregatorProxy is AggregatorV2V3Interface, Owned { - - struct Phase { - uint16 id; - AggregatorV2V3Interface aggregator; - } - Phase private currentPhase; - AggregatorV2V3Interface public proposedAggregator; - mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; - - uint256 constant private PHASE_OFFSET = 64; - uint256 constant private PHASE_SIZE = 16; - uint256 constant private MAX_ID = 2**(PHASE_OFFSET+PHASE_SIZE) - 1; - - constructor(address _aggregator) public Owned() { - setAggregator(_aggregator); - } - - /** - * @notice Reads the current answer from aggregator delegated to. - * - * @dev #[deprecated] Use latestRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended latestRoundData - * instead which includes better verification information. - */ - function latestAnswer() - public - view - virtual - override - returns (int256 answer) - { - return currentPhase.aggregator.latestAnswer(); - } - - /** - * @notice Reads the last updated height from aggregator delegated to. - * - * @dev #[deprecated] Use latestRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended latestRoundData - * instead which includes better verification information. - */ - function latestTimestamp() - public - view - virtual - override - returns (uint256 updatedAt) - { - return currentPhase.aggregator.latestTimestamp(); - } - - /** - * @notice get past rounds answers - * @param _roundId the answer number to retrieve the answer for - * - * @dev #[deprecated] Use getRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended getRoundData - * instead which includes better verification information. - */ - function getAnswer(uint256 _roundId) - public - view - virtual - override - returns (int256 answer) - { - if (_roundId > MAX_ID) return 0; - - (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); - AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; - if (address(aggregator) == address(0)) return 0; - - return aggregator.getAnswer(aggregatorRoundId); - } - - /** - * @notice get block timestamp when an answer was last updated - * @param _roundId the answer number to retrieve the updated timestamp for - * - * @dev #[deprecated] Use getRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended getRoundData - * instead which includes better verification information. - */ - function getTimestamp(uint256 _roundId) - public - view - virtual - override - returns (uint256 updatedAt) - { - if (_roundId > MAX_ID) return 0; - - (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); - AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; - if (address(aggregator) == address(0)) return 0; - - return aggregator.getTimestamp(aggregatorRoundId); - } - - /** - * @notice get the latest completed round where the answer was updated. This - * ID includes the proxy's phase, to make sure round IDs increase even when - * switching to a newly deployed aggregator. - * - * @dev #[deprecated] Use latestRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended latestRoundData - * instead which includes better verification information. - */ - function latestRound() - public - view - virtual - override - returns (uint256 roundId) - { - Phase memory phase = currentPhase; // cache storage reads - return addPhase(phase.id, uint64(phase.aggregator.latestRound())); - } - - /** - * @notice get data about a round. Consumers are encouraged to check - * that they're receiving fresh data by inspecting the updatedAt and - * answeredInRound return values. - * Note that different underlying implementations of AggregatorV3Interface - * have slightly different semantics for some of the return values. Consumers - * should determine what implementations they expect to receive - * data from and validate that they can properly handle return data from all - * of them. - * @param _roundId the requested round ID as presented through the proxy, this - * is made up of the aggregator's round ID with the phase ID encoded in the - * two highest order bytes - * @return roundId is the round ID from the aggregator for which the data was - * retrieved combined with an phase to ensure that round IDs get larger as - * time moves forward. - * @return answer is the answer for the given round - * @return startedAt is the timestamp when the round was started. - * (Only some AggregatorV3Interface implementations return meaningful values) - * @return updatedAt is the timestamp when the round last was updated (i.e. - * answer was last computed) - * @return answeredInRound is the round ID of the round in which the answer - * was computed. - * (Only some AggregatorV3Interface implementations return meaningful values) - * @dev Note that answer and updatedAt may change between queries. - */ - function getRoundData(uint80 _roundId) - public - view - virtual - override - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); - - ( - roundId, - answer, - startedAt, - updatedAt, - answeredInRound - ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); - - return addPhaseIds(roundId, answer, startedAt, updatedAt, answeredInRound, phaseId); - } - - /** - * @notice get data about the latest round. Consumers are encouraged to check - * that they're receiving fresh data by inspecting the updatedAt and - * answeredInRound return values. - * Note that different underlying implementations of AggregatorV3Interface - * have slightly different semantics for some of the return values. Consumers - * should determine what implementations they expect to receive - * data from and validate that they can properly handle return data from all - * of them. - * @return roundId is the round ID from the aggregator for which the data was - * retrieved combined with an phase to ensure that round IDs get larger as - * time moves forward. - * @return answer is the answer for the given round - * @return startedAt is the timestamp when the round was started. - * (Only some AggregatorV3Interface implementations return meaningful values) - * @return updatedAt is the timestamp when the round last was updated (i.e. - * answer was last computed) - * @return answeredInRound is the round ID of the round in which the answer - * was computed. - * (Only some AggregatorV3Interface implementations return meaningful values) - * @dev Note that answer and updatedAt may change between queries. - */ - function latestRoundData() - public - view - virtual - override - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - Phase memory current = currentPhase; // cache storage reads - - ( - roundId, - answer, - startedAt, - updatedAt, - answeredInRound - ) = current.aggregator.latestRoundData(); - - return addPhaseIds(roundId, answer, startedAt, updatedAt, answeredInRound, current.id); - } - - /** - * @notice Used if an aggregator contract has been proposed. - * @param _roundId the round ID to retrieve the round data for - * @return roundId is the round ID for which data was retrieved - * @return answer is the answer for the given round - * @return startedAt is the timestamp when the round was started. - * (Only some AggregatorV3Interface implementations return meaningful values) - * @return updatedAt is the timestamp when the round last was updated (i.e. - * answer was last computed) - * @return answeredInRound is the round ID of the round in which the answer - * was computed. - */ - function proposedGetRoundData(uint80 _roundId) - public - view - virtual - hasProposal() - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - return proposedAggregator.getRoundData(_roundId); - } - - /** - * @notice Used if an aggregator contract has been proposed. - * @return roundId is the round ID for which data was retrieved - * @return answer is the answer for the given round - * @return startedAt is the timestamp when the round was started. - * (Only some AggregatorV3Interface implementations return meaningful values) - * @return updatedAt is the timestamp when the round last was updated (i.e. - * answer was last computed) - * @return answeredInRound is the round ID of the round in which the answer - * was computed. - */ - function proposedLatestRoundData() - public - view - virtual - hasProposal() - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - return proposedAggregator.latestRoundData(); - } - - /** - * @notice returns the current phase's aggregator address. - */ - function aggregator() - external - view - returns (address) - { - return address(currentPhase.aggregator); - } - - /** - * @notice returns the current phase's ID. - */ - function phaseId() - external - view - returns (uint16) - { - return currentPhase.id; - } - - /** - * @notice represents the number of decimals the aggregator responses represent. - */ - function decimals() - external - view - override - returns (uint8) - { - return currentPhase.aggregator.decimals(); - } - - /** - * @notice the version number representing the type of aggregator the proxy - * points to. - */ - function version() - external - view - override - returns (uint256) - { - return currentPhase.aggregator.version(); - } - - /** - * @notice returns the description of the aggregator the proxy points to. - */ - function description() - external - view - override - returns (string memory) - { - return currentPhase.aggregator.description(); - } - - /** - * @notice Allows the owner to propose a new address for the aggregator - * @param _aggregator The new address for the aggregator contract - */ - function proposeAggregator(address _aggregator) - external - onlyOwner() - { - proposedAggregator = AggregatorV2V3Interface(_aggregator); - } - - /** - * @notice Allows the owner to confirm and change the address - * to the proposed aggregator - * @dev Reverts if the given address doesn't match what was previously - * proposed - * @param _aggregator The new address for the aggregator contract - */ - function confirmAggregator(address _aggregator) - external - onlyOwner() - { - require(_aggregator == address(proposedAggregator), "Invalid proposed aggregator"); - delete proposedAggregator; - setAggregator(_aggregator); - } - - - /* - * Internal - */ - - function setAggregator(address _aggregator) - internal - { - uint16 id = currentPhase.id + 1; - currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); - phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); - } - - function addPhase( - uint16 _phase, - uint64 _originalId - ) - internal - pure - returns (uint80) - { - return uint80(uint256(_phase) << PHASE_OFFSET | _originalId); - } - - function parseIds( - uint256 _roundId - ) - internal - pure - returns (uint16, uint64) - { - uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); - uint64 aggregatorRoundId = uint64(_roundId); - - return (phaseId, aggregatorRoundId); - } - - function addPhaseIds( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound, - uint16 phaseId - ) - internal - pure - returns (uint80, int256, uint256, uint256, uint80) - { - return ( - addPhase(phaseId, uint64(roundId)), - answer, - startedAt, - updatedAt, - addPhase(phaseId, uint64(answeredInRound)) - ); - } - - /* - * Modifiers - */ - - modifier hasProposal() { - require(address(proposedAggregator) != address(0), "No proposed aggregator present"); - _; - } - -} \ No newline at end of file diff --git a/contracts/src/v0.6/BlockhashStore.sol b/contracts/src/v0.6/BlockhashStore.sol deleted file mode 100644 index 2da687fb53e..00000000000 --- a/contracts/src/v0.6/BlockhashStore.sol +++ /dev/null @@ -1,80 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.6.6; - -import "./ChainSpecificUtil.sol"; - -/** - * @title BlockhashStore - * @notice This contract provides a way to access blockhashes older than - * the 256 block limit imposed by the BLOCKHASH opcode. - * You may assume that any blockhash stored by the contract is correct. - * Note that the contract depends on the format of serialized Ethereum - * blocks. If a future hardfork of Ethereum changes that format, the - * logic in this contract may become incorrect and an updated version - * would have to be deployed. - */ -contract BlockhashStore { - - mapping(uint => bytes32) internal s_blockhashes; - - /** - * @notice stores blockhash of a given block, assuming it is available through BLOCKHASH - * @param n the number of the block whose blockhash should be stored - */ - function store(uint256 n) public { - bytes32 h = ChainSpecificUtil.getBlockhash(n); - require(h != 0x0, "blockhash(n) failed"); - s_blockhashes[n] = h; - } - - - /** - * @notice stores blockhash of the earliest block still available through BLOCKHASH. - */ - function storeEarliest() external { - store(ChainSpecificUtil.getBlockNumber() - 256); - } - - /** - * @notice stores blockhash after verifying blockheader of child/subsequent block - * @param n the number of the block whose blockhash should be stored - * @param header the rlp-encoded blockheader of block n+1. We verify its correctness by checking - * that it hashes to a stored blockhash, and then extract parentHash to get the n-th blockhash. - */ - function storeVerifyHeader(uint256 n, bytes memory header) public { - require(keccak256(header) == s_blockhashes[n + 1], "header has unknown blockhash"); - - // At this point, we know that header is the correct blockheader for block n+1. - - // The header is an rlp-encoded list. The head item of that list is the 32-byte blockhash of the parent block. - // Based on how rlp works, we know that blockheaders always have the following form: - // 0xf9____a0PARENTHASH... - // ^ ^ ^ - // | | | - // | | +--- PARENTHASH is 32 bytes. rlpenc(PARENTHASH) is 0xa || PARENTHASH. - // | | - // | +--- 2 bytes containing the sum of the lengths of the encoded list items - // | - // +--- 0xf9 because we have a list and (sum of lengths of encoded list items) fits exactly into two bytes. - // - // As a consequence, the PARENTHASH is always at offset 4 of the rlp-encoded block header. - - bytes32 parentHash; - assembly { - parentHash := mload(add(header, 36)) // 36 = 32 byte offset for length prefix of ABI-encoded array - // + 4 byte offset of PARENTHASH (see above) - } - - s_blockhashes[n] = parentHash; - } - - /** - * @notice gets a blockhash from the store. If no hash is known, this function reverts. - * @param n the number of the block whose blockhash should be returned - */ - function getBlockhash(uint256 n) external view returns (bytes32) { - bytes32 h = s_blockhashes[n]; - require(h != 0x0, "blockhash not found in store"); - return h; - } -} diff --git a/contracts/src/v0.6/ChainSpecificUtil.sol b/contracts/src/v0.6/ChainSpecificUtil.sol deleted file mode 100644 index 462531e8af6..00000000000 --- a/contracts/src/v0.6/ChainSpecificUtil.sol +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import {ArbSys} from "./vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; - -//@dev A library that abstracts out opcodes that behave differently across chains. -//@dev The methods below return values that are pertinent to the given chain. -//@dev For instance, ChainSpecificUtil.getBlockNumber() returns L2 block number in L2 chains -library ChainSpecificUtil { - address private constant ARBSYS_ADDR = - address(0x0000000000000000000000000000000000000064); - ArbSys private constant ARBSYS = ArbSys(ARBSYS_ADDR); - uint256 private constant ARB_MAINNET_CHAIN_ID = 42161; - uint256 private constant ARB_GOERLI_TESTNET_CHAIN_ID = 421613; - - function getBlockhash(uint256 blockNumber) internal view returns (bytes32) { - uint256 chainid = getChainID(); - if ( - chainid == ARB_MAINNET_CHAIN_ID || - chainid == ARB_GOERLI_TESTNET_CHAIN_ID - ) { - if ((getBlockNumber() - blockNumber) > 256 || blockNumber >= getBlockNumber()) { - return ""; - } - return ARBSYS.arbBlockHash(blockNumber); - } - return blockhash(blockNumber); - } - - function getBlockNumber() internal view returns (uint256) { - uint256 chainid = getChainID(); - if ( - chainid == ARB_MAINNET_CHAIN_ID || - chainid == ARB_GOERLI_TESTNET_CHAIN_ID - ) { - return ARBSYS.arbBlockNumber(); - } - return block.number; - } - - function getChainID() internal pure returns (uint256) { - uint256 id; - assembly { - id := chainid() - } - return id; - } -} diff --git a/contracts/src/v0.6/Chainlink.sol b/contracts/src/v0.6/Chainlink.sol deleted file mode 100644 index 2665e675634..00000000000 --- a/contracts/src/v0.6/Chainlink.sol +++ /dev/null @@ -1,127 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import { CBORChainlink } from "./vendor/CBORChainlink.sol"; -import { BufferChainlink } from "./vendor/BufferChainlink.sol"; - -/** - * @title Library for common Chainlink functions - * @dev Uses imported CBOR library for encoding to buffer - */ -library Chainlink { - uint256 internal constant defaultBufferSize = 256; // solhint-disable-line const-name-snakecase - - using CBORChainlink for BufferChainlink.buffer; - - struct Request { - bytes32 id; - address callbackAddress; - bytes4 callbackFunctionId; - uint256 nonce; - BufferChainlink.buffer buf; - } - - /** - * @notice Initializes a Chainlink request - * @dev Sets the ID, callback address, and callback function signature on the request - * @param self The uninitialized request - * @param _id The Job Specification ID - * @param _callbackAddress The callback address - * @param _callbackFunction The callback function signature - * @return The initialized request - */ - function initialize( - Request memory self, - bytes32 _id, - address _callbackAddress, - bytes4 _callbackFunction - ) internal pure returns (Chainlink.Request memory) { - BufferChainlink.init(self.buf, defaultBufferSize); - self.id = _id; - self.callbackAddress = _callbackAddress; - self.callbackFunctionId = _callbackFunction; - return self; - } - - /** - * @notice Sets the data for the buffer without encoding CBOR on-chain - * @dev CBOR can be closed with curly-brackets {} or they can be left off - * @param self The initialized request - * @param _data The CBOR data - */ - function setBuffer(Request memory self, bytes memory _data) - internal pure - { - BufferChainlink.init(self.buf, _data.length); - BufferChainlink.append(self.buf, _data); - } - - /** - * @notice Adds a string value to the request with a given key name - * @param self The initialized request - * @param _key The name of the key - * @param _value The string value to add - */ - function add(Request memory self, string memory _key, string memory _value) - internal pure - { - self.buf.encodeString(_key); - self.buf.encodeString(_value); - } - - /** - * @notice Adds a bytes value to the request with a given key name - * @param self The initialized request - * @param _key The name of the key - * @param _value The bytes value to add - */ - function addBytes(Request memory self, string memory _key, bytes memory _value) - internal pure - { - self.buf.encodeString(_key); - self.buf.encodeBytes(_value); - } - - /** - * @notice Adds a int256 value to the request with a given key name - * @param self The initialized request - * @param _key The name of the key - * @param _value The int256 value to add - */ - function addInt(Request memory self, string memory _key, int256 _value) - internal pure - { - self.buf.encodeString(_key); - self.buf.encodeInt(_value); - } - - /** - * @notice Adds a uint256 value to the request with a given key name - * @param self The initialized request - * @param _key The name of the key - * @param _value The uint256 value to add - */ - function addUint(Request memory self, string memory _key, uint256 _value) - internal pure - { - self.buf.encodeString(_key); - self.buf.encodeUInt(_value); - } - - /** - * @notice Adds an array of strings to the request with a given key name - * @param self The initialized request - * @param _key The name of the key - * @param _values The array of string values to add - */ - function addStringArray(Request memory self, string memory _key, string[] memory _values) - internal pure - { - self.buf.encodeString(_key); - self.buf.startArray(); - for (uint256 i = 0; i < _values.length; i++) { - self.buf.encodeString(_values[i]); - } - self.buf.endSequence(); - } -} diff --git a/contracts/src/v0.6/ChainlinkClient.sol b/contracts/src/v0.6/ChainlinkClient.sol deleted file mode 100644 index 079e05ef5f1..00000000000 --- a/contracts/src/v0.6/ChainlinkClient.sol +++ /dev/null @@ -1,262 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import "./Chainlink.sol"; -import "./interfaces/ENSInterface.sol"; -import "./interfaces/LinkTokenInterface.sol"; -import "./interfaces/ChainlinkRequestInterface.sol"; -import "./interfaces/PointerInterface.sol"; -import { ENSResolver as ENSResolver_Chainlink } from "./vendor/ENSResolver.sol"; - -/** - * @title The ChainlinkClient contract - * @notice Contract writers can inherit this contract in order to create requests for the - * Chainlink network - */ -contract ChainlinkClient { - using Chainlink for Chainlink.Request; - - uint256 constant internal LINK = 10**18; - uint256 constant private AMOUNT_OVERRIDE = 0; - address constant private SENDER_OVERRIDE = address(0); - uint256 constant private ARGS_VERSION = 1; - bytes32 constant private ENS_TOKEN_SUBNAME = keccak256("link"); - bytes32 constant private ENS_ORACLE_SUBNAME = keccak256("oracle"); - address constant private LINK_TOKEN_POINTER = 0xC89bD4E1632D3A43CB03AAAd5262cbe4038Bc571; - - ENSInterface private ens; - bytes32 private ensNode; - LinkTokenInterface private link; - ChainlinkRequestInterface private oracle; - uint256 private requestCount = 1; - mapping(bytes32 => address) private pendingRequests; - - event ChainlinkRequested(bytes32 indexed id); - event ChainlinkFulfilled(bytes32 indexed id); - event ChainlinkCancelled(bytes32 indexed id); - - /** - * @notice Creates a request that can hold additional parameters - * @param _specId The Job Specification ID that the request will be created for - * @param _callbackAddress The callback address that the response will be sent to - * @param _callbackFunctionSignature The callback function signature to use for the callback address - * @return A Chainlink Request struct in memory - */ - function buildChainlinkRequest( - bytes32 _specId, - address _callbackAddress, - bytes4 _callbackFunctionSignature - ) internal pure returns (Chainlink.Request memory) { - Chainlink.Request memory req; - return req.initialize(_specId, _callbackAddress, _callbackFunctionSignature); - } - - /** - * @notice Creates a Chainlink request to the stored oracle address - * @dev Calls `chainlinkRequestTo` with the stored oracle address - * @param _req The initialized Chainlink Request - * @param _payment The amount of LINK to send for the request - * @return requestId The request ID - */ - function sendChainlinkRequest(Chainlink.Request memory _req, uint256 _payment) - internal - returns (bytes32) - { - return sendChainlinkRequestTo(address(oracle), _req, _payment); - } - - /** - * @notice Creates a Chainlink request to the specified oracle address - * @dev Generates and stores a request ID, increments the local nonce, and uses `transferAndCall` to - * send LINK which creates a request on the target oracle contract. - * Emits ChainlinkRequested event. - * @param _oracle The address of the oracle for the request - * @param _req The initialized Chainlink Request - * @param _payment The amount of LINK to send for the request - * @return requestId The request ID - */ - function sendChainlinkRequestTo(address _oracle, Chainlink.Request memory _req, uint256 _payment) - internal - returns (bytes32 requestId) - { - requestId = keccak256(abi.encodePacked(this, requestCount)); - _req.nonce = requestCount; - pendingRequests[requestId] = _oracle; - emit ChainlinkRequested(requestId); - require(link.transferAndCall(_oracle, _payment, encodeRequest(_req)), "unable to transferAndCall to oracle"); - requestCount += 1; - - return requestId; - } - - /** - * @notice Allows a request to be cancelled if it has not been fulfilled - * @dev Requires keeping track of the expiration value emitted from the oracle contract. - * Deletes the request from the `pendingRequests` mapping. - * Emits ChainlinkCancelled event. - * @param _requestId The request ID - * @param _payment The amount of LINK sent for the request - * @param _callbackFunc The callback function specified for the request - * @param _expiration The time of the expiration for the request - */ - function cancelChainlinkRequest( - bytes32 _requestId, - uint256 _payment, - bytes4 _callbackFunc, - uint256 _expiration - ) - internal - { - ChainlinkRequestInterface requested = ChainlinkRequestInterface(pendingRequests[_requestId]); - delete pendingRequests[_requestId]; - emit ChainlinkCancelled(_requestId); - requested.cancelOracleRequest(_requestId, _payment, _callbackFunc, _expiration); - } - - /** - * @notice Sets the stored oracle address - * @param _oracle The address of the oracle contract - */ - function setChainlinkOracle(address _oracle) internal { - oracle = ChainlinkRequestInterface(_oracle); - } - - /** - * @notice Sets the LINK token address - * @param _link The address of the LINK token contract - */ - function setChainlinkToken(address _link) internal { - link = LinkTokenInterface(_link); - } - - /** - * @notice Sets the Chainlink token address for the public - * network as given by the Pointer contract - */ - function setPublicChainlinkToken() internal { - setChainlinkToken(PointerInterface(LINK_TOKEN_POINTER).getAddress()); - } - - /** - * @notice Retrieves the stored address of the LINK token - * @return The address of the LINK token - */ - function chainlinkTokenAddress() - internal - view - returns (address) - { - return address(link); - } - - /** - * @notice Retrieves the stored address of the oracle contract - * @return The address of the oracle contract - */ - function chainlinkOracleAddress() - internal - view - returns (address) - { - return address(oracle); - } - - /** - * @notice Allows for a request which was created on another contract to be fulfilled - * on this contract - * @param _oracle The address of the oracle contract that will fulfill the request - * @param _requestId The request ID used for the response - */ - function addChainlinkExternalRequest(address _oracle, bytes32 _requestId) - internal - notPendingRequest(_requestId) - { - pendingRequests[_requestId] = _oracle; - } - - /** - * @notice Sets the stored oracle and LINK token contracts with the addresses resolved by ENS - * @dev Accounts for subnodes having different resolvers - * @param _ens The address of the ENS contract - * @param _node The ENS node hash - */ - function useChainlinkWithENS(address _ens, bytes32 _node) - internal - { - ens = ENSInterface(_ens); - ensNode = _node; - bytes32 linkSubnode = keccak256(abi.encodePacked(ensNode, ENS_TOKEN_SUBNAME)); - ENSResolver_Chainlink resolver = ENSResolver_Chainlink(ens.resolver(linkSubnode)); - setChainlinkToken(resolver.addr(linkSubnode)); - updateChainlinkOracleWithENS(); - } - - /** - * @notice Sets the stored oracle contract with the address resolved by ENS - * @dev This may be called on its own as long as `useChainlinkWithENS` has been called previously - */ - function updateChainlinkOracleWithENS() - internal - { - bytes32 oracleSubnode = keccak256(abi.encodePacked(ensNode, ENS_ORACLE_SUBNAME)); - ENSResolver_Chainlink resolver = ENSResolver_Chainlink(ens.resolver(oracleSubnode)); - setChainlinkOracle(resolver.addr(oracleSubnode)); - } - - /** - * @notice Encodes the request to be sent to the oracle contract - * @dev The Chainlink node expects values to be in order for the request to be picked up. Order of types - * will be validated in the oracle contract. - * @param _req The initialized Chainlink Request - * @return The bytes payload for the `transferAndCall` method - */ - function encodeRequest(Chainlink.Request memory _req) - private - view - returns (bytes memory) - { - return abi.encodeWithSelector( - oracle.oracleRequest.selector, - SENDER_OVERRIDE, // Sender value - overridden by onTokenTransfer by the requesting contract's address - AMOUNT_OVERRIDE, // Amount value - overridden by onTokenTransfer by the actual amount of LINK sent - _req.id, - _req.callbackAddress, - _req.callbackFunctionId, - _req.nonce, - ARGS_VERSION, - _req.buf.buf); - } - - /** - * @notice Ensures that the fulfillment is valid for this contract - * @dev Use if the contract developer prefers methods instead of modifiers for validation - * @param _requestId The request ID for fulfillment - */ - function validateChainlinkCallback(bytes32 _requestId) - internal - recordChainlinkFulfillment(_requestId) - // solhint-disable-next-line no-empty-blocks - {} - - /** - * @dev Reverts if the sender is not the oracle of the request. - * Emits ChainlinkFulfilled event. - * @param _requestId The request ID for fulfillment - */ - modifier recordChainlinkFulfillment(bytes32 _requestId) { - require(msg.sender == pendingRequests[_requestId], - "Source must be the oracle of the request"); - delete pendingRequests[_requestId]; - emit ChainlinkFulfilled(_requestId); - _; - } - - /** - * @dev Reverts if the request is already pending - * @param _requestId The request ID for fulfillment - */ - modifier notPendingRequest(bytes32 _requestId) { - require(pendingRequests[_requestId] == address(0), "Request is already pending"); - _; - } -} diff --git a/contracts/src/v0.6/CheckedMath.sol b/contracts/src/v0.6/CheckedMath.sol deleted file mode 100644 index 3f622797f7e..00000000000 --- a/contracts/src/v0.6/CheckedMath.sol +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-License-Identifier: MIT -// Adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/97894a140d2a698e5a0f913648a8f56d62277a70/contracts/math/SignedSafeMath.sol - -pragma solidity ^0.6.0; - -library CheckedMath { - - int256 constant internal INT256_MIN = -2**255; - - /** - * @dev Subtracts two signed integers, returns false 2nd param on overflow. - */ - function add( - int256 a, - int256 b - ) - internal - pure - returns (int256 result, bool ok) - { - int256 c = a + b; - if ((b >= 0 && c < a) || (b < 0 && c >= a)) return (0, false); - - return (c, true); - } - - /** - * @dev Subtracts two signed integers, returns false 2nd param on overflow. - */ - function sub( - int256 a, - int256 b - ) - internal - pure - returns (int256 result, bool ok) - { - int256 c = a - b; - if ((b < 0 && c <= a) || (b >= 0 && c > a)) return (0, false); - - return (c, true); - } - - - /** - * @dev Multiplies two signed integers, returns false 2nd param on overflow. - */ - function mul( - int256 a, - int256 b - ) - internal - pure - returns (int256 result, bool ok) - { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) return (0, true); - if (a == -1 && b == INT256_MIN) return (0, false); - - int256 c = a * b; - if (!(c / a == b)) return (0, false); - - return (c, true); - } - - /** - * @dev Divides two signed integers, returns false 2nd param on overflow. - */ - function div( - int256 a, - int256 b - ) - internal - pure - returns (int256 result, bool ok) - { - if (b == 0) return (0, false); - if (b == -1 && a == INT256_MIN) return (0, false); - - int256 c = a / b; - - return (c, true); - } - -} diff --git a/contracts/src/v0.6/Denominations.sol b/contracts/src/v0.6/Denominations.sol deleted file mode 100644 index 339997d3479..00000000000 --- a/contracts/src/v0.6/Denominations.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.6.0; - -library Denominations { - address public constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; - address public constant BTC = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB; - - // Fiat currencies follow https://en.wikipedia.org/wiki/ISO_4217 - address public constant USD = address(840); - address public constant GBP = address(826); - address public constant EUR = address(978); - address public constant JPY = address(392); - address public constant KRW = address(410); - address public constant CNY = address(156); - address public constant AUD = address(36); - address public constant CAD = address(124); - address public constant CHF = address(756); - address public constant ARS = address(32); - address public constant PHP = address(608); - address public constant NZD = address(554); - address public constant SGD = address(702); - address public constant NGN = address(566); - address public constant ZAR = address(710); - address public constant RUB = address(643); - address public constant INR = address(356); - address public constant BRL = address(986); -} diff --git a/contracts/src/v0.6/DeviationFlaggingValidator.sol b/contracts/src/v0.6/DeviationFlaggingValidator.sol deleted file mode 100644 index be2b2b1af8e..00000000000 --- a/contracts/src/v0.6/DeviationFlaggingValidator.sol +++ /dev/null @@ -1,160 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.6.6; - -import "./Owned.sol"; -import "./CheckedMath.sol"; -import "./interfaces/AggregatorValidatorInterface.sol"; -import "./interfaces/FlagsInterface.sol"; - -/** - * @title The Deviation Flagging Validator contract - * @notice Checks the current value against the previous value, and makes sure - * that it does not deviate outside of some relative range. If the deviation - * threshold is passed then the validator raises a flag on the designated - * flag contract. - */ -contract DeviationFlaggingValidator is Owned, AggregatorValidatorInterface { - using CheckedMath for int256; - - uint32 constant public THRESHOLD_MULTIPLIER = 100000; - - uint32 public flaggingThreshold; - FlagsInterface public flags; - - event FlaggingThresholdUpdated( - uint24 indexed previous, - uint24 indexed current - ); - event FlagsAddressUpdated( - address indexed previous, - address indexed current - ); - - int256 constant private INT256_MIN = -2**255; - - /** - * @notice sets up the validator with its threshold and flag address. - * @param _flags sets the address of the flags contract - * @param _flaggingThreshold sets the threshold that will trigger a flag to be - * raised. Setting the value of 100,000 is equivalent to tolerating a 100% - * change compared to the previous price. - */ - constructor( - address _flags, - uint24 _flaggingThreshold - ) - public - { - setFlagsAddress(_flags); - setFlaggingThreshold(_flaggingThreshold); - } - - /** - * @notice checks whether the parameters count as valid by comparing the - * difference change to the flagging threshold. - * @param _previousRoundId is ignored. - * @param _previousAnswer is used as the median of the difference with the - * current answer to determine if the deviation threshold has been exceeded. - * @param _roundId is ignored. - * @param _answer is the latest answer which is compared for a ratio of change - * to make sure it has not exceeded the flagging threshold. - */ - function validate( - uint256 _previousRoundId, - int256 _previousAnswer, - uint256 _roundId, - int256 _answer - ) - external - override - returns (bool) - { - if (!isValid(_previousRoundId, _previousAnswer, _roundId, _answer)) { - flags.raiseFlag(msg.sender); - return false; - } - - return true; - } - - /** - * @notice checks whether the parameters count as valid by comparing the - * difference change to the flagging threshold and raises a flag on the - * flagging contract if so. - * @param _previousAnswer is used as the median of the difference with the - * current answer to determine if the deviation threshold has been exceeded. - * @param _answer is the current answer which is compared for a ratio of - * change * to make sure it has not exceeded the flagging threshold. - */ - function isValid( - uint256 , - int256 _previousAnswer, - uint256 , - int256 _answer - ) - public - view - returns (bool) - { - if (_previousAnswer == 0) return true; - - (int256 change, bool changeOk) = _previousAnswer.sub(_answer); - (int256 ratioNumerator, bool numOk) = change.mul(THRESHOLD_MULTIPLIER); - (int256 ratio, bool ratioOk) = ratioNumerator.div(_previousAnswer); - (uint256 absRatio, bool absOk) = abs(ratio); - - return changeOk && numOk && ratioOk && absOk && absRatio <= flaggingThreshold; - } - - /** - * @notice updates the flagging threshold - * @param _flaggingThreshold sets the threshold that will trigger a flag to be - * raised. Setting the value of 100,000 is equivalent to tolerating a 100% - * change compared to the previous price. - */ - function setFlaggingThreshold(uint24 _flaggingThreshold) - public - onlyOwner() - { - uint24 previousFT = uint24(flaggingThreshold); - - if (previousFT != _flaggingThreshold) { - flaggingThreshold = _flaggingThreshold; - - emit FlaggingThresholdUpdated(previousFT, _flaggingThreshold); - } - } - - /** - * @notice updates the flagging contract address for raising flags - * @param _flags sets the address of the flags contract - */ - function setFlagsAddress(address _flags) - public - onlyOwner() - { - address previous = address(flags); - - if (previous != _flags) { - flags = FlagsInterface(_flags); - - emit FlagsAddressUpdated(previous, _flags); - } - } - - - // PRIVATE - - function abs( - int256 value - ) - private - pure - returns (uint256, bool) - { - if (value >= 0) return (uint256(value), true); - if (value == CheckedMath.INT256_MIN) return (0, false); - return (uint256(value * -1), true); - } - -} diff --git a/contracts/src/v0.6/EACAggregatorProxy.sol b/contracts/src/v0.6/EACAggregatorProxy.sol deleted file mode 100644 index f1c0e8bcfd4..00000000000 --- a/contracts/src/v0.6/EACAggregatorProxy.sol +++ /dev/null @@ -1,282 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.6.6; - -import "./AggregatorProxy.sol"; -import "./interfaces/AccessControllerInterface.sol"; - -/** - * @title External Access Controlled Aggregator Proxy - * @notice A trusted proxy for updating where current answers are read from - * @notice This contract provides a consistent address for the - * Aggregator and AggregatorV3Interface but delegates where it reads from to the owner, who is - * trusted to update it. - * @notice Only access enabled addresses are allowed to access getters for - * aggregated answers and round information. - */ -contract EACAggregatorProxy is AggregatorProxy { - - AccessControllerInterface public accessController; - - constructor( - address _aggregator, - address _accessController - ) - public - AggregatorProxy(_aggregator) - { - setController(_accessController); - } - - /** - * @notice Allows the owner to update the accessController contract address. - * @param _accessController The new address for the accessController contract - */ - function setController(address _accessController) - public - onlyOwner() - { - accessController = AccessControllerInterface(_accessController); - } - - /** - * @notice Reads the current answer from aggregator delegated to. - * @dev overridden function to add the checkAccess() modifier - * - * @dev #[deprecated] Use latestRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended latestRoundData - * instead which includes better verification information. - */ - function latestAnswer() - public - view - override - checkAccess() - returns (int256) - { - return super.latestAnswer(); - } - - /** - * @notice get the latest completed round where the answer was updated. This - * ID includes the proxy's phase, to make sure round IDs increase even when - * switching to a newly deployed aggregator. - * - * @dev #[deprecated] Use latestRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended latestRoundData - * instead which includes better verification information. - */ - function latestTimestamp() - public - view - override - checkAccess() - returns (uint256) - { - return super.latestTimestamp(); - } - - /** - * @notice get past rounds answers - * @param _roundId the answer number to retrieve the answer for - * @dev overridden function to add the checkAccess() modifier - * - * @dev #[deprecated] Use getRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended getRoundData - * instead which includes better verification information. - */ - function getAnswer(uint256 _roundId) - public - view - override - checkAccess() - returns (int256) - { - return super.getAnswer(_roundId); - } - - /** - * @notice get block timestamp when an answer was last updated - * @param _roundId the answer number to retrieve the updated timestamp for - * @dev overridden function to add the checkAccess() modifier - * - * @dev #[deprecated] Use getRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended getRoundData - * instead which includes better verification information. - */ - function getTimestamp(uint256 _roundId) - public - view - override - checkAccess() - returns (uint256) - { - return super.getTimestamp(_roundId); - } - - /** - * @notice get the latest completed round where the answer was updated - * @dev overridden function to add the checkAccess() modifier - * - * @dev #[deprecated] Use latestRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended latestRoundData - * instead which includes better verification information. - */ - function latestRound() - public - view - override - checkAccess() - returns (uint256) - { - return super.latestRound(); - } - - /** - * @notice get data about a round. Consumers are encouraged to check - * that they're receiving fresh data by inspecting the updatedAt and - * answeredInRound return values. - * Note that different underlying implementations of AggregatorV3Interface - * have slightly different semantics for some of the return values. Consumers - * should determine what implementations they expect to receive - * data from and validate that they can properly handle return data from all - * of them. - * @param _roundId the round ID to retrieve the round data for - * @return roundId is the round ID from the aggregator for which the data was - * retrieved combined with a phase to ensure that round IDs get larger as - * time moves forward. - * @return answer is the answer for the given round - * @return startedAt is the timestamp when the round was started. - * (Only some AggregatorV3Interface implementations return meaningful values) - * @return updatedAt is the timestamp when the round last was updated (i.e. - * answer was last computed) - * @return answeredInRound is the round ID of the round in which the answer - * was computed. - * (Only some AggregatorV3Interface implementations return meaningful values) - * @dev Note that answer and updatedAt may change between queries. - */ - function getRoundData(uint80 _roundId) - public - view - checkAccess() - override - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - return super.getRoundData(_roundId); - } - - /** - * @notice get data about the latest round. Consumers are encouraged to check - * that they're receiving fresh data by inspecting the updatedAt and - * answeredInRound return values. - * Note that different underlying implementations of AggregatorV3Interface - * have slightly different semantics for some of the return values. Consumers - * should determine what implementations they expect to receive - * data from and validate that they can properly handle return data from all - * of them. - * @return roundId is the round ID from the aggregator for which the data was - * retrieved combined with a phase to ensure that round IDs get larger as - * time moves forward. - * @return answer is the answer for the given round - * @return startedAt is the timestamp when the round was started. - * (Only some AggregatorV3Interface implementations return meaningful values) - * @return updatedAt is the timestamp when the round last was updated (i.e. - * answer was last computed) - * @return answeredInRound is the round ID of the round in which the answer - * was computed. - * (Only some AggregatorV3Interface implementations return meaningful values) - * @dev Note that answer and updatedAt may change between queries. - */ - function latestRoundData() - public - view - checkAccess() - override - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - return super.latestRoundData(); - } - - /** - * @notice Used if an aggregator contract has been proposed. - * @param _roundId the round ID to retrieve the round data for - * @return roundId is the round ID for which data was retrieved - * @return answer is the answer for the given round - * @return startedAt is the timestamp when the round was started. - * (Only some AggregatorV3Interface implementations return meaningful values) - * @return updatedAt is the timestamp when the round last was updated (i.e. - * answer was last computed) - * @return answeredInRound is the round ID of the round in which the answer - * was computed. - */ - function proposedGetRoundData(uint80 _roundId) - public - view - checkAccess() - hasProposal() - override - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - return super.proposedGetRoundData(_roundId); - } - - /** - * @notice Used if an aggregator contract has been proposed. - * @return roundId is the round ID for which data was retrieved - * @return answer is the answer for the given round - * @return startedAt is the timestamp when the round was started. - * (Only some AggregatorV3Interface implementations return meaningful values) - * @return updatedAt is the timestamp when the round last was updated (i.e. - * answer was last computed) - * @return answeredInRound is the round ID of the round in which the answer - * was computed. - */ - function proposedLatestRoundData() - public - view - checkAccess() - hasProposal() - override - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - return super.proposedLatestRoundData(); - } - - /** - * @dev reverts if the caller does not have access by the accessController - * contract or is the contract itself. - */ - modifier checkAccess() { - AccessControllerInterface ac = accessController; - require(address(ac) == address(0) || ac.hasAccess(msg.sender, msg.data), "No access"); - _; - } -} \ No newline at end of file diff --git a/contracts/src/v0.6/Flags.sol b/contracts/src/v0.6/Flags.sol deleted file mode 100644 index ce8c9d5fda2..00000000000 --- a/contracts/src/v0.6/Flags.sol +++ /dev/null @@ -1,174 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.6.6; - - -import "./SimpleReadAccessController.sol"; -import "./interfaces/AccessControllerInterface.sol"; -import "./interfaces/FlagsInterface.sol"; - - -/** - * @title The Flags contract - * @notice Allows flags to signal to any reader on the access control list. - * The owner can set flags, or designate other addresses to set flags. The - * owner must turn the flags off, other setters cannot. An expected pattern is - * to allow addresses to raise flags on themselves, so if you are subscribing to - * FlagOn events you should filter for addresses you care about. - */ -contract Flags is FlagsInterface, SimpleReadAccessController { - - AccessControllerInterface public raisingAccessController; - - mapping(address => bool) private flags; - - event FlagRaised( - address indexed subject - ); - event FlagLowered( - address indexed subject - ); - event RaisingAccessControllerUpdated( - address indexed previous, - address indexed current - ); - - /** - * @param racAddress address for the raising access controller. - */ - constructor( - address racAddress - ) - public - { - setRaisingAccessController(racAddress); - } - - /** - * @notice read the warning flag status of a contract address. - * @param subject The contract address being checked for a flag. - * @return A true value indicates that a flag was raised and a - * false value indicates that no flag was raised. - */ - function getFlag(address subject) - external - view - override - checkAccess() - returns (bool) - { - return flags[subject]; - } - - /** - * @notice read the warning flag status of a contract address. - * @param subjects An array of addresses being checked for a flag. - * @return An array of bools where a true value for any flag indicates that - * a flag was raised and a false value indicates that no flag was raised. - */ - function getFlags(address[] calldata subjects) - external - view - override - checkAccess() - returns (bool[] memory) - { - bool[] memory responses = new bool[](subjects.length); - for (uint256 i = 0; i < subjects.length; i++) { - responses[i] = flags[subjects[i]]; - } - return responses; - } - - /** - * @notice enable the warning flag for an address. - * Access is controlled by raisingAccessController, except for owner - * who always has access. - * @param subject The contract address whose flag is being raised - */ - function raiseFlag(address subject) - external - override - { - require(allowedToRaiseFlags(), "Not allowed to raise flags"); - - tryToRaiseFlag(subject); - } - - /** - * @notice enable the warning flags for multiple addresses. - * Access is controlled by raisingAccessController, except for owner - * who always has access. - * @param subjects List of the contract addresses whose flag is being raised - */ - function raiseFlags(address[] calldata subjects) - external - override - { - require(allowedToRaiseFlags(), "Not allowed to raise flags"); - - for (uint256 i = 0; i < subjects.length; i++) { - tryToRaiseFlag(subjects[i]); - } - } - - /** - * @notice allows owner to disable the warning flags for multiple addresses. - * @param subjects List of the contract addresses whose flag is being lowered - */ - function lowerFlags(address[] calldata subjects) - external - override - onlyOwner() - { - for (uint256 i = 0; i < subjects.length; i++) { - address subject = subjects[i]; - - if (flags[subject]) { - flags[subject] = false; - emit FlagLowered(subject); - } - } - } - - /** - * @notice allows owner to change the access controller for raising flags. - * @param racAddress new address for the raising access controller. - */ - function setRaisingAccessController( - address racAddress - ) - public - override - onlyOwner() - { - address previous = address(raisingAccessController); - - if (previous != racAddress) { - raisingAccessController = AccessControllerInterface(racAddress); - - emit RaisingAccessControllerUpdated(previous, racAddress); - } - } - - - // PRIVATE - - function allowedToRaiseFlags() - private - view - returns (bool) - { - return msg.sender == owner || - raisingAccessController.hasAccess(msg.sender, msg.data); - } - - function tryToRaiseFlag(address subject) - private - { - if (!flags[subject]) { - flags[subject] = true; - emit FlagRaised(subject); - } - } - -} diff --git a/contracts/src/v0.6/FluxAggregator.sol b/contracts/src/v0.6/FluxAggregator.sol deleted file mode 100644 index afe4731a6a7..00000000000 --- a/contracts/src/v0.6/FluxAggregator.sol +++ /dev/null @@ -1,1053 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.6.6; - -import "./Median.sol"; -import "./Owned.sol"; -import "./SafeMath128.sol"; -import "./SafeMath32.sol"; -import "./SafeMath64.sol"; -import "./interfaces/AggregatorV2V3Interface.sol"; -import "./interfaces/AggregatorValidatorInterface.sol"; -import "./interfaces/LinkTokenInterface.sol"; -import "./vendor/SafeMathChainlink.sol"; - -/** - * @title The Prepaid Aggregator contract - * @notice Handles aggregating data pushed in from off-chain, and unlocks - * payment for oracles as they report. Oracles' submissions are gathered in - * rounds, with each round aggregating the submissions for each oracle into a - * single answer. The latest aggregated answer is exposed as well as historical - * answers and their updated at timestamp. - */ -contract FluxAggregator is AggregatorV2V3Interface, Owned { - using SafeMathChainlink for uint256; - using SafeMath128 for uint128; - using SafeMath64 for uint64; - using SafeMath32 for uint32; - - struct Round { - int256 answer; - uint64 startedAt; - uint64 updatedAt; - uint32 answeredInRound; - } - - struct RoundDetails { - int256[] submissions; - uint32 maxSubmissions; - uint32 minSubmissions; - uint32 timeout; - uint128 paymentAmount; - } - - struct OracleStatus { - uint128 withdrawable; - uint32 startingRound; - uint32 endingRound; - uint32 lastReportedRound; - uint32 lastStartedRound; - int256 latestSubmission; - uint16 index; - address admin; - address pendingAdmin; - } - - struct Requester { - bool authorized; - uint32 delay; - uint32 lastStartedRound; - } - - struct Funds { - uint128 available; - uint128 allocated; - } - - LinkTokenInterface public linkToken; - AggregatorValidatorInterface public validator; - - // Round related params - uint128 public paymentAmount; - uint32 public maxSubmissionCount; - uint32 public minSubmissionCount; - uint32 public restartDelay; - uint32 public timeout; - uint8 public override decimals; - string public override description; - - int256 immutable public minSubmissionValue; - int256 immutable public maxSubmissionValue; - - uint256 constant public override version = 3; - - /** - * @notice To ensure owner isn't withdrawing required funds as oracles are - * submitting updates, we enforce that the contract maintains a minimum - * reserve of RESERVE_ROUNDS * oracleCount() LINK earmarked for payment to - * oracles. (Of course, this doesn't prevent the contract from running out of - * funds without the owner's intervention.) - */ - uint256 constant private RESERVE_ROUNDS = 2; - uint256 constant private MAX_ORACLE_COUNT = 77; - uint32 constant private ROUND_MAX = 2**32-1; - uint256 private constant VALIDATOR_GAS_LIMIT = 100000; - // An error specific to the Aggregator V3 Interface, to prevent possible - // confusion around accidentally reading unset values as reported values. - string constant private V3_NO_DATA_ERROR = "No data present"; - - uint32 private reportingRoundId; - uint32 internal latestRoundId; - mapping(address => OracleStatus) private oracles; - mapping(uint32 => Round) internal rounds; - mapping(uint32 => RoundDetails) internal details; - mapping(address => Requester) internal requesters; - address[] private oracleAddresses; - Funds private recordedFunds; - - event AvailableFundsUpdated( - uint256 indexed amount - ); - event RoundDetailsUpdated( - uint128 indexed paymentAmount, - uint32 indexed minSubmissionCount, - uint32 indexed maxSubmissionCount, - uint32 restartDelay, - uint32 timeout // measured in seconds - ); - event OraclePermissionsUpdated( - address indexed oracle, - bool indexed whitelisted - ); - event OracleAdminUpdated( - address indexed oracle, - address indexed newAdmin - ); - event OracleAdminUpdateRequested( - address indexed oracle, - address admin, - address newAdmin - ); - event SubmissionReceived( - int256 indexed submission, - uint32 indexed round, - address indexed oracle - ); - event RequesterPermissionsSet( - address indexed requester, - bool authorized, - uint32 delay - ); - event ValidatorUpdated( - address indexed previous, - address indexed current - ); - - /** - * @notice set up the aggregator with initial configuration - * @param _link The address of the LINK token - * @param _paymentAmount The amount paid of LINK paid to each oracle per submission, in wei (units of 10⁻¹⁸ LINK) - * @param _timeout is the number of seconds after the previous round that are - * allowed to lapse before allowing an oracle to skip an unfinished round - * @param _validator is an optional contract address for validating - * external validation of answers - * @param _minSubmissionValue is an immutable check for a lower bound of what - * submission values are accepted from an oracle - * @param _maxSubmissionValue is an immutable check for an upper bound of what - * submission values are accepted from an oracle - * @param _decimals represents the number of decimals to offset the answer by - * @param _description a short description of what is being reported - */ - constructor( - address _link, - uint128 _paymentAmount, - uint32 _timeout, - address _validator, - int256 _minSubmissionValue, - int256 _maxSubmissionValue, - uint8 _decimals, - string memory _description - ) public { - linkToken = LinkTokenInterface(_link); - updateFutureRounds(_paymentAmount, 0, 0, 0, _timeout); - setValidator(_validator); - minSubmissionValue = _minSubmissionValue; - maxSubmissionValue = _maxSubmissionValue; - decimals = _decimals; - description = _description; - rounds[0].updatedAt = uint64(block.timestamp.sub(uint256(_timeout))); - } - - /** - * @notice called by oracles when they have witnessed a need to update - * @param _roundId is the ID of the round this submission pertains to - * @param _submission is the updated data that the oracle is submitting - */ - function submit(uint256 _roundId, int256 _submission) - external - { - bytes memory error = validateOracleRound(msg.sender, uint32(_roundId)); - require(_submission >= minSubmissionValue, "value below minSubmissionValue"); - require(_submission <= maxSubmissionValue, "value above maxSubmissionValue"); - require(error.length == 0, string(error)); - - oracleInitializeNewRound(uint32(_roundId)); - recordSubmission(_submission, uint32(_roundId)); - (bool updated, int256 newAnswer) = updateRoundAnswer(uint32(_roundId)); - payOracle(uint32(_roundId)); - deleteRoundDetails(uint32(_roundId)); - if (updated) { - validateAnswer(uint32(_roundId), newAnswer); - } - } - - /** - * @notice called by the owner to remove and add new oracles as well as - * update the round related parameters that pertain to total oracle count - * @param _removed is the list of addresses for the new Oracles being removed - * @param _added is the list of addresses for the new Oracles being added - * @param _addedAdmins is the admin addresses for the new respective _added - * list. Only this address is allowed to access the respective oracle's funds - * @param _minSubmissions is the new minimum submission count for each round - * @param _maxSubmissions is the new maximum submission count for each round - * @param _restartDelay is the number of rounds an Oracle has to wait before - * they can initiate a round - */ - function changeOracles( - address[] calldata _removed, - address[] calldata _added, - address[] calldata _addedAdmins, - uint32 _minSubmissions, - uint32 _maxSubmissions, - uint32 _restartDelay - ) - external - onlyOwner() - { - for (uint256 i = 0; i < _removed.length; i++) { - removeOracle(_removed[i]); - } - - require(_added.length == _addedAdmins.length, "need same oracle and admin count"); - require(uint256(oracleCount()).add(_added.length) <= MAX_ORACLE_COUNT, "max oracles allowed"); - - for (uint256 i = 0; i < _added.length; i++) { - addOracle(_added[i], _addedAdmins[i]); - } - - updateFutureRounds(paymentAmount, _minSubmissions, _maxSubmissions, _restartDelay, timeout); - } - - /** - * @notice update the round and payment related parameters for subsequent - * rounds - * @param _paymentAmount is the payment amount for subsequent rounds - * @param _minSubmissions is the new minimum submission count for each round - * @param _maxSubmissions is the new maximum submission count for each round - * @param _restartDelay is the number of rounds an Oracle has to wait before - * they can initiate a round - */ - function updateFutureRounds( - uint128 _paymentAmount, - uint32 _minSubmissions, - uint32 _maxSubmissions, - uint32 _restartDelay, - uint32 _timeout - ) - public - onlyOwner() - { - uint32 oracleNum = oracleCount(); // Save on storage reads - require(_maxSubmissions >= _minSubmissions, "max must equal/exceed min"); - require(oracleNum >= _maxSubmissions, "max cannot exceed total"); - require(oracleNum == 0 || oracleNum > _restartDelay, "delay cannot exceed total"); - require(recordedFunds.available >= requiredReserve(_paymentAmount), "insufficient funds for payment"); - if (oracleCount() > 0) { - require(_minSubmissions > 0, "min must be greater than 0"); - } - - paymentAmount = _paymentAmount; - minSubmissionCount = _minSubmissions; - maxSubmissionCount = _maxSubmissions; - restartDelay = _restartDelay; - timeout = _timeout; - - emit RoundDetailsUpdated( - paymentAmount, - _minSubmissions, - _maxSubmissions, - _restartDelay, - _timeout - ); - } - - /** - * @notice the amount of payment yet to be withdrawn by oracles - */ - function allocatedFunds() - external - view - returns (uint128) - { - return recordedFunds.allocated; - } - - /** - * @notice the amount of future funding available to oracles - */ - function availableFunds() - external - view - returns (uint128) - { - return recordedFunds.available; - } - - /** - * @notice recalculate the amount of LINK available for payouts - */ - function updateAvailableFunds() - public - { - Funds memory funds = recordedFunds; - - uint256 nowAvailable = linkToken.balanceOf(address(this)).sub(funds.allocated); - - if (funds.available != nowAvailable) { - recordedFunds.available = uint128(nowAvailable); - emit AvailableFundsUpdated(nowAvailable); - } - } - - /** - * @notice returns the number of oracles - */ - function oracleCount() public view returns (uint8) { - return uint8(oracleAddresses.length); - } - - /** - * @notice returns an array of addresses containing the oracles on contract - */ - function getOracles() external view returns (address[] memory) { - return oracleAddresses; - } - - /** - * @notice get the most recently reported answer - * - * @dev #[deprecated] Use latestRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended latestRoundData - * instead which includes better verification information. - */ - function latestAnswer() - public - view - virtual - override - returns (int256) - { - return rounds[latestRoundId].answer; - } - - /** - * @notice get the most recent updated at timestamp - * - * @dev #[deprecated] Use latestRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended latestRoundData - * instead which includes better verification information. - */ - function latestTimestamp() - public - view - virtual - override - returns (uint256) - { - return rounds[latestRoundId].updatedAt; - } - - /** - * @notice get the ID of the last updated round - * - * @dev #[deprecated] Use latestRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended latestRoundData - * instead which includes better verification information. - */ - function latestRound() - public - view - virtual - override - returns (uint256) - { - return latestRoundId; - } - - /** - * @notice get past rounds answers - * @param _roundId the round number to retrieve the answer for - * - * @dev #[deprecated] Use getRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended getRoundData - * instead which includes better verification information. - */ - function getAnswer(uint256 _roundId) - public - view - virtual - override - returns (int256) - { - if (validRoundId(_roundId)) { - return rounds[uint32(_roundId)].answer; - } - return 0; - } - - /** - * @notice get timestamp when an answer was last updated - * @param _roundId the round number to retrieve the updated timestamp for - * - * @dev #[deprecated] Use getRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended getRoundData - * instead which includes better verification information. - */ - function getTimestamp(uint256 _roundId) - public - view - virtual - override - returns (uint256) - { - if (validRoundId(_roundId)) { - return rounds[uint32(_roundId)].updatedAt; - } - return 0; - } - - /** - * @notice get data about a round. Consumers are encouraged to check - * that they're receiving fresh data by inspecting the updatedAt and - * answeredInRound return values. - * @param _roundId the round ID to retrieve the round data for - * @return roundId is the round ID for which data was retrieved - * @return answer is the answer for the given round - * @return startedAt is the timestamp when the round was started. This is 0 - * if the round hasn't been started yet. - * @return updatedAt is the timestamp when the round last was updated (i.e. - * answer was last computed) - * @return answeredInRound is the round ID of the round in which the answer - * was computed. answeredInRound may be smaller than roundId when the round - * timed out. answeredInRound is equal to roundId when the round didn't time out - * and was completed regularly. - * @dev Note that for in-progress rounds (i.e. rounds that haven't yet received - * maxSubmissions) answer and updatedAt may change between queries. - */ - function getRoundData(uint80 _roundId) - public - view - virtual - override - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - Round memory r = rounds[uint32(_roundId)]; - - require(r.answeredInRound > 0 && validRoundId(_roundId), V3_NO_DATA_ERROR); - - return ( - _roundId, - r.answer, - r.startedAt, - r.updatedAt, - r.answeredInRound - ); - } - - /** - * @notice get data about the latest round. Consumers are encouraged to check - * that they're receiving fresh data by inspecting the updatedAt and - * answeredInRound return values. Consumers are encouraged to - * use this more fully featured method over the "legacy" latestRound/ - * latestAnswer/latestTimestamp functions. Consumers are encouraged to check - * that they're receiving fresh data by inspecting the updatedAt and - * answeredInRound return values. - * @return roundId is the round ID for which data was retrieved - * @return answer is the answer for the given round - * @return startedAt is the timestamp when the round was started. This is 0 - * if the round hasn't been started yet. - * @return updatedAt is the timestamp when the round last was updated (i.e. - * answer was last computed) - * @return answeredInRound is the round ID of the round in which the answer - * was computed. answeredInRound may be smaller than roundId when the round - * timed out. answeredInRound is equal to roundId when the round didn't time - * out and was completed regularly. - * @dev Note that for in-progress rounds (i.e. rounds that haven't yet - * received maxSubmissions) answer and updatedAt may change between queries. - */ - function latestRoundData() - public - view - virtual - override - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - return getRoundData(latestRoundId); - } - - - /** - * @notice query the available amount of LINK for an oracle to withdraw - */ - function withdrawablePayment(address _oracle) - external - view - returns (uint256) - { - return oracles[_oracle].withdrawable; - } - - /** - * @notice transfers the oracle's LINK to another address. Can only be called - * by the oracle's admin. - * @param _oracle is the oracle whose LINK is transferred - * @param _recipient is the address to send the LINK to - * @param _amount is the amount of LINK to send - */ - function withdrawPayment(address _oracle, address _recipient, uint256 _amount) - external - { - require(oracles[_oracle].admin == msg.sender, "only callable by admin"); - - // Safe to downcast _amount because the total amount of LINK is less than 2^128. - uint128 amount = uint128(_amount); - uint128 available = oracles[_oracle].withdrawable; - require(available >= amount, "insufficient withdrawable funds"); - - oracles[_oracle].withdrawable = available.sub(amount); - recordedFunds.allocated = recordedFunds.allocated.sub(amount); - - assert(linkToken.transfer(_recipient, uint256(amount))); - } - - /** - * @notice transfers the owner's LINK to another address - * @param _recipient is the address to send the LINK to - * @param _amount is the amount of LINK to send - */ - function withdrawFunds(address _recipient, uint256 _amount) - external - onlyOwner() - { - uint256 available = uint256(recordedFunds.available); - require(available.sub(requiredReserve(paymentAmount)) >= _amount, "insufficient reserve funds"); - require(linkToken.transfer(_recipient, _amount), "token transfer failed"); - updateAvailableFunds(); - } - - /** - * @notice get the admin address of an oracle - * @param _oracle is the address of the oracle whose admin is being queried - */ - function getAdmin(address _oracle) - external - view - returns (address) - { - return oracles[_oracle].admin; - } - - /** - * @notice transfer the admin address for an oracle - * @param _oracle is the address of the oracle whose admin is being transferred - * @param _newAdmin is the new admin address - */ - function transferAdmin(address _oracle, address _newAdmin) - external - { - require(oracles[_oracle].admin == msg.sender, "only callable by admin"); - oracles[_oracle].pendingAdmin = _newAdmin; - - emit OracleAdminUpdateRequested(_oracle, msg.sender, _newAdmin); - } - - /** - * @notice accept the admin address transfer for an oracle - * @param _oracle is the address of the oracle whose admin is being transferred - */ - function acceptAdmin(address _oracle) - external - { - require(oracles[_oracle].pendingAdmin == msg.sender, "only callable by pending admin"); - oracles[_oracle].pendingAdmin = address(0); - oracles[_oracle].admin = msg.sender; - - emit OracleAdminUpdated(_oracle, msg.sender); - } - - /** - * @notice allows non-oracles to request a new round - */ - function requestNewRound() - external - returns (uint80) - { - require(requesters[msg.sender].authorized, "not authorized requester"); - - uint32 current = reportingRoundId; - require(rounds[current].updatedAt > 0 || timedOut(current), "prev round must be supersedable"); - - uint32 newRoundId = current.add(1); - requesterInitializeNewRound(newRoundId); - return newRoundId; - } - - /** - * @notice allows the owner to specify new non-oracles to start new rounds - * @param _requester is the address to set permissions for - * @param _authorized is a boolean specifying whether they can start new rounds or not - * @param _delay is the number of rounds the requester must wait before starting another round - */ - function setRequesterPermissions(address _requester, bool _authorized, uint32 _delay) - external - onlyOwner() - { - if (requesters[_requester].authorized == _authorized) return; - - if (_authorized) { - requesters[_requester].authorized = _authorized; - requesters[_requester].delay = _delay; - } else { - delete requesters[_requester]; - } - - emit RequesterPermissionsSet(_requester, _authorized, _delay); - } - - /** - * @notice called through LINK's transferAndCall to update available funds - * in the same transaction as the funds were transferred to the aggregator - * @param _data is mostly ignored. It is checked for length, to be sure - * nothing strange is passed in. - */ - function onTokenTransfer(address, uint256, bytes calldata _data) - external - { - require(_data.length == 0, "transfer doesn't accept calldata"); - updateAvailableFunds(); - } - - /** - * @notice a method to provide all current info oracles need. Intended only - * only to be callable by oracles. Not for use by contracts to read state. - * @param _oracle the address to look up information for. - */ - function oracleRoundState(address _oracle, uint32 _queriedRoundId) - external - view - returns ( - bool _eligibleToSubmit, - uint32 _roundId, - int256 _latestSubmission, - uint64 _startedAt, - uint64 _timeout, - uint128 _availableFunds, - uint8 _oracleCount, - uint128 _paymentAmount - ) - { - require(msg.sender == tx.origin, "off-chain reading only"); - - if (_queriedRoundId > 0) { - Round storage round = rounds[_queriedRoundId]; - RoundDetails storage details = details[_queriedRoundId]; - return ( - eligibleForSpecificRound(_oracle, _queriedRoundId), - _queriedRoundId, - oracles[_oracle].latestSubmission, - round.startedAt, - details.timeout, - recordedFunds.available, - oracleCount(), - (round.startedAt > 0 ? details.paymentAmount : paymentAmount) - ); - } else { - return oracleRoundStateSuggestRound(_oracle); - } - } - - /** - * @notice method to update the address which does external data validation. - * @param _newValidator designates the address of the new validation contract. - */ - function setValidator(address _newValidator) - public - onlyOwner() - { - address previous = address(validator); - - if (previous != _newValidator) { - validator = AggregatorValidatorInterface(_newValidator); - - emit ValidatorUpdated(previous, _newValidator); - } - } - - - /** - * Private - */ - - function initializeNewRound(uint32 _roundId) - private - { - updateTimedOutRoundInfo(_roundId.sub(1)); - - reportingRoundId = _roundId; - RoundDetails memory nextDetails = RoundDetails( - new int256[](0), - maxSubmissionCount, - minSubmissionCount, - timeout, - paymentAmount - ); - details[_roundId] = nextDetails; - rounds[_roundId].startedAt = uint64(block.timestamp); - - emit NewRound(_roundId, msg.sender, rounds[_roundId].startedAt); - } - - function oracleInitializeNewRound(uint32 _roundId) - private - { - if (!newRound(_roundId)) return; - uint256 lastStarted = oracles[msg.sender].lastStartedRound; // cache storage reads - if (_roundId <= lastStarted + restartDelay && lastStarted != 0) return; - - initializeNewRound(_roundId); - - oracles[msg.sender].lastStartedRound = _roundId; - } - - function requesterInitializeNewRound(uint32 _roundId) - private - { - if (!newRound(_roundId)) return; - uint256 lastStarted = requesters[msg.sender].lastStartedRound; // cache storage reads - require(_roundId > lastStarted + requesters[msg.sender].delay || lastStarted == 0, "must delay requests"); - - initializeNewRound(_roundId); - - requesters[msg.sender].lastStartedRound = _roundId; - } - - function updateTimedOutRoundInfo(uint32 _roundId) - private - { - if (!timedOut(_roundId)) return; - - uint32 prevId = _roundId.sub(1); - rounds[_roundId].answer = rounds[prevId].answer; - rounds[_roundId].answeredInRound = rounds[prevId].answeredInRound; - rounds[_roundId].updatedAt = uint64(block.timestamp); - - delete details[_roundId]; - } - - function eligibleForSpecificRound(address _oracle, uint32 _queriedRoundId) - private - view - returns (bool _eligible) - { - if (rounds[_queriedRoundId].startedAt > 0) { - return acceptingSubmissions(_queriedRoundId) && validateOracleRound(_oracle, _queriedRoundId).length == 0; - } else { - return delayed(_oracle, _queriedRoundId) && validateOracleRound(_oracle, _queriedRoundId).length == 0; - } - } - - function oracleRoundStateSuggestRound(address _oracle) - private - view - returns ( - bool _eligibleToSubmit, - uint32 _roundId, - int256 _latestSubmission, - uint64 _startedAt, - uint64 _timeout, - uint128 _availableFunds, - uint8 _oracleCount, - uint128 _paymentAmount - ) - { - Round storage round = rounds[0]; - OracleStatus storage oracle = oracles[_oracle]; - - bool shouldSupersede = oracle.lastReportedRound == reportingRoundId || !acceptingSubmissions(reportingRoundId); - // Instead of nudging oracles to submit to the next round, the inclusion of - // the shouldSupersede bool in the if condition pushes them towards - // submitting in a currently open round. - if (supersedable(reportingRoundId) && shouldSupersede) { - _roundId = reportingRoundId.add(1); - round = rounds[_roundId]; - - _paymentAmount = paymentAmount; - _eligibleToSubmit = delayed(_oracle, _roundId); - } else { - _roundId = reportingRoundId; - round = rounds[_roundId]; - - _paymentAmount = details[_roundId].paymentAmount; - _eligibleToSubmit = acceptingSubmissions(_roundId); - } - - if (validateOracleRound(_oracle, _roundId).length != 0) { - _eligibleToSubmit = false; - } - - return ( - _eligibleToSubmit, - _roundId, - oracle.latestSubmission, - round.startedAt, - details[_roundId].timeout, - recordedFunds.available, - oracleCount(), - _paymentAmount - ); - } - - function updateRoundAnswer(uint32 _roundId) - internal - returns (bool, int256) - { - if (details[_roundId].submissions.length < details[_roundId].minSubmissions) { - return (false, 0); - } - - int256 newAnswer = Median.calculateInplace(details[_roundId].submissions); - rounds[_roundId].answer = newAnswer; - rounds[_roundId].updatedAt = uint64(block.timestamp); - rounds[_roundId].answeredInRound = _roundId; - latestRoundId = _roundId; - - emit AnswerUpdated(newAnswer, _roundId, now); - - return (true, newAnswer); - } - - function validateAnswer( - uint32 _roundId, - int256 _newAnswer - ) - private - { - AggregatorValidatorInterface av = validator; // cache storage reads - if (address(av) == address(0)) return; - - uint32 prevRound = _roundId.sub(1); - uint32 prevAnswerRoundId = rounds[prevRound].answeredInRound; - int256 prevRoundAnswer = rounds[prevRound].answer; - // We do not want the validator to ever prevent reporting, so we limit its - // gas usage and catch any errors that may arise. - try av.validate{gas: VALIDATOR_GAS_LIMIT}( - prevAnswerRoundId, - prevRoundAnswer, - _roundId, - _newAnswer - ) {} catch {} - } - - function payOracle(uint32 _roundId) - private - { - uint128 payment = details[_roundId].paymentAmount; - Funds memory funds = recordedFunds; - funds.available = funds.available.sub(payment); - funds.allocated = funds.allocated.add(payment); - recordedFunds = funds; - oracles[msg.sender].withdrawable = oracles[msg.sender].withdrawable.add(payment); - - emit AvailableFundsUpdated(funds.available); - } - - function recordSubmission(int256 _submission, uint32 _roundId) - private - { - require(acceptingSubmissions(_roundId), "round not accepting submissions"); - - details[_roundId].submissions.push(_submission); - oracles[msg.sender].lastReportedRound = _roundId; - oracles[msg.sender].latestSubmission = _submission; - - emit SubmissionReceived(_submission, _roundId, msg.sender); - } - - function deleteRoundDetails(uint32 _roundId) - private - { - if (details[_roundId].submissions.length < details[_roundId].maxSubmissions) return; - - delete details[_roundId]; - } - - function timedOut(uint32 _roundId) - private - view - returns (bool) - { - uint64 startedAt = rounds[_roundId].startedAt; - uint32 roundTimeout = details[_roundId].timeout; - return startedAt > 0 && roundTimeout > 0 && startedAt.add(roundTimeout) < block.timestamp; - } - - function getStartingRound(address _oracle) - private - view - returns (uint32) - { - uint32 currentRound = reportingRoundId; - if (currentRound != 0 && currentRound == oracles[_oracle].endingRound) { - return currentRound; - } - return currentRound.add(1); - } - - function previousAndCurrentUnanswered(uint32 _roundId, uint32 _rrId) - private - view - returns (bool) - { - return _roundId.add(1) == _rrId && rounds[_rrId].updatedAt == 0; - } - - function requiredReserve(uint256 payment) - private - view - returns (uint256) - { - return payment.mul(oracleCount()).mul(RESERVE_ROUNDS); - } - - function addOracle( - address _oracle, - address _admin - ) - private - { - require(!oracleEnabled(_oracle), "oracle already enabled"); - - require(_admin != address(0), "cannot set admin to 0"); - require(oracles[_oracle].admin == address(0) || oracles[_oracle].admin == _admin, "owner cannot overwrite admin"); - - oracles[_oracle].startingRound = getStartingRound(_oracle); - oracles[_oracle].endingRound = ROUND_MAX; - oracles[_oracle].index = uint16(oracleAddresses.length); - oracleAddresses.push(_oracle); - oracles[_oracle].admin = _admin; - - emit OraclePermissionsUpdated(_oracle, true); - emit OracleAdminUpdated(_oracle, _admin); - } - - function removeOracle( - address _oracle - ) - private - { - require(oracleEnabled(_oracle), "oracle not enabled"); - - oracles[_oracle].endingRound = reportingRoundId.add(1); - address tail = oracleAddresses[uint256(oracleCount()).sub(1)]; - uint16 index = oracles[_oracle].index; - oracles[tail].index = index; - delete oracles[_oracle].index; - oracleAddresses[index] = tail; - oracleAddresses.pop(); - - emit OraclePermissionsUpdated(_oracle, false); - } - - function validateOracleRound(address _oracle, uint32 _roundId) - private - view - returns (bytes memory) - { - // cache storage reads - uint32 startingRound = oracles[_oracle].startingRound; - uint32 rrId = reportingRoundId; - - if (startingRound == 0) return "not enabled oracle"; - if (startingRound > _roundId) return "not yet enabled oracle"; - if (oracles[_oracle].endingRound < _roundId) return "no longer allowed oracle"; - if (oracles[_oracle].lastReportedRound >= _roundId) return "cannot report on previous rounds"; - if (_roundId != rrId && _roundId != rrId.add(1) && !previousAndCurrentUnanswered(_roundId, rrId)) return "invalid round to report"; - if (_roundId != 1 && !supersedable(_roundId.sub(1))) return "previous round not supersedable"; - } - - function supersedable(uint32 _roundId) - private - view - returns (bool) - { - return rounds[_roundId].updatedAt > 0 || timedOut(_roundId); - } - - function oracleEnabled(address _oracle) - private - view - returns (bool) - { - return oracles[_oracle].endingRound == ROUND_MAX; - } - - function acceptingSubmissions(uint32 _roundId) - private - view - returns (bool) - { - return details[_roundId].maxSubmissions != 0; - } - - function delayed(address _oracle, uint32 _roundId) - private - view - returns (bool) - { - uint256 lastStarted = oracles[_oracle].lastStartedRound; - return _roundId > lastStarted + restartDelay || lastStarted == 0; - } - - function newRound(uint32 _roundId) - private - view - returns (bool) - { - return _roundId == reportingRoundId.add(1); - } - - function validRoundId(uint256 _roundId) - private - pure - returns (bool) - { - return _roundId <= ROUND_MAX; - } - -} diff --git a/contracts/src/v0.6/KeeperBase.sol b/contracts/src/v0.6/KeeperBase.sol deleted file mode 100644 index ce9eccff196..00000000000 --- a/contracts/src/v0.6/KeeperBase.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -contract KeeperBase { - /** - * @notice method that allows it to be simulated via eth_call by checking that - * the sender is the zero address. - */ - function preventExecution() internal view { - require(tx.origin == address(0), "only for simulated backend"); - } - - /** - * @notice modifier that allows it to be simulated via eth_call by checking - * that the sender is the zero address. - */ - modifier cannotExecute() { - preventExecution(); - _; - } -} diff --git a/contracts/src/v0.6/KeeperCompatible.sol b/contracts/src/v0.6/KeeperCompatible.sol deleted file mode 100644 index 2a7ad60b0a0..00000000000 --- a/contracts/src/v0.6/KeeperCompatible.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import "./KeeperBase.sol"; -import "./interfaces/KeeperCompatibleInterface.sol"; - -abstract contract KeeperCompatible is KeeperBase, KeeperCompatibleInterface {} diff --git a/contracts/src/v0.6/LinkTokenReceiver.sol b/contracts/src/v0.6/LinkTokenReceiver.sol deleted file mode 100644 index 6009f6a5a61..00000000000 --- a/contracts/src/v0.6/LinkTokenReceiver.sol +++ /dev/null @@ -1,71 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -abstract contract LinkTokenReceiver { - - bytes4 constant private ORACLE_REQUEST_SELECTOR = 0x40429946; - uint256 constant private SELECTOR_LENGTH = 4; - uint256 constant private EXPECTED_REQUEST_WORDS = 2; - uint256 constant private MINIMUM_REQUEST_LENGTH = SELECTOR_LENGTH + (32 * EXPECTED_REQUEST_WORDS); - /** - * @notice Called when LINK is sent to the contract via `transferAndCall` - * @dev The data payload's first 2 words will be overwritten by the `_sender` and `_amount` - * values to ensure correctness. Calls oracleRequest. - * @param _sender Address of the sender - * @param _amount Amount of LINK sent (specified in wei) - * @param _data Payload of the transaction - */ - function onTokenTransfer( - address _sender, - uint256 _amount, - bytes memory _data - ) - public - onlyLINK - validRequestLength(_data) - permittedFunctionsForLINK(_data) - { - assembly { - // solhint-disable-next-line avoid-low-level-calls - mstore(add(_data, 36), _sender) // ensure correct sender is passed - // solhint-disable-next-line avoid-low-level-calls - mstore(add(_data, 68), _amount) // ensure correct amount is passed - } - // solhint-disable-next-line avoid-low-level-calls - (bool success, ) = address(this).delegatecall(_data); // calls oracleRequest - require(success, "Unable to create request"); - } - - function getChainlinkToken() public view virtual returns (address); - - /** - * @dev Reverts if not sent from the LINK token - */ - modifier onlyLINK() { - require(msg.sender == getChainlinkToken(), "Must use LINK token"); - _; - } - - /** - * @dev Reverts if the given data does not begin with the `oracleRequest` function selector - * @param _data The data payload of the request - */ - modifier permittedFunctionsForLINK(bytes memory _data) { - bytes4 funcSelector; - assembly { - // solhint-disable-next-line avoid-low-level-calls - funcSelector := mload(add(_data, 32)) - } - require(funcSelector == ORACLE_REQUEST_SELECTOR, "Must use whitelisted functions"); - _; - } - - /** - * @dev Reverts if the given payload is less than needed to create a request - * @param _data The request payload - */ - modifier validRequestLength(bytes memory _data) { - require(_data.length >= MINIMUM_REQUEST_LENGTH, "Invalid request length"); - _; - } -} diff --git a/contracts/src/v0.6/Median.sol b/contracts/src/v0.6/Median.sol deleted file mode 100644 index d75b5b625ae..00000000000 --- a/contracts/src/v0.6/Median.sol +++ /dev/null @@ -1,248 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import "./vendor/SafeMathChainlink.sol"; -import "./SignedSafeMath.sol"; - -library Median { - using SignedSafeMath for int256; - - int256 constant INT_MAX = 2**255-1; - - /** - * @notice Returns the sorted middle, or the average of the two middle indexed items if the - * array has an even number of elements. - * @dev The list passed as an argument isn't modified. - * @dev This algorithm has expected runtime O(n), but for adversarially chosen inputs - * the runtime is O(n^2). - * @param list The list of elements to compare - */ - function calculate(int256[] memory list) - internal - pure - returns (int256) - { - return calculateInplace(copy(list)); - } - - /** - * @notice See documentation for function calculate. - * @dev The list passed as an argument may be permuted. - */ - function calculateInplace(int256[] memory list) - internal - pure - returns (int256) - { - require(0 < list.length, "list must not be empty"); - uint256 len = list.length; - uint256 middleIndex = len / 2; - if (len % 2 == 0) { - int256 median1; - int256 median2; - (median1, median2) = quickselectTwo(list, 0, len - 1, middleIndex - 1, middleIndex); - return SignedSafeMath.avg(median1, median2); - } else { - return quickselect(list, 0, len - 1, middleIndex); - } - } - - /** - * @notice Maximum length of list that shortSelectTwo can handle - */ - uint256 constant SHORTSELECTTWO_MAX_LENGTH = 7; - - /** - * @notice Select the k1-th and k2-th element from list of length at most 7 - * @dev Uses an optimal sorting network - */ - function shortSelectTwo( - int256[] memory list, - uint256 lo, - uint256 hi, - uint256 k1, - uint256 k2 - ) - private - pure - returns (int256 k1th, int256 k2th) - { - // Uses an optimal sorting network (https://en.wikipedia.org/wiki/Sorting_network) - // for lists of length 7. Network layout is taken from - // http://jgamble.ripco.net/cgi-bin/nw.cgi?inputs=7&algorithm=hibbard&output=svg - - uint256 len = hi + 1 - lo; - int256 x0 = list[lo + 0]; - int256 x1 = 1 < len ? list[lo + 1] : INT_MAX; - int256 x2 = 2 < len ? list[lo + 2] : INT_MAX; - int256 x3 = 3 < len ? list[lo + 3] : INT_MAX; - int256 x4 = 4 < len ? list[lo + 4] : INT_MAX; - int256 x5 = 5 < len ? list[lo + 5] : INT_MAX; - int256 x6 = 6 < len ? list[lo + 6] : INT_MAX; - - if (x0 > x1) {(x0, x1) = (x1, x0);} - if (x2 > x3) {(x2, x3) = (x3, x2);} - if (x4 > x5) {(x4, x5) = (x5, x4);} - if (x0 > x2) {(x0, x2) = (x2, x0);} - if (x1 > x3) {(x1, x3) = (x3, x1);} - if (x4 > x6) {(x4, x6) = (x6, x4);} - if (x1 > x2) {(x1, x2) = (x2, x1);} - if (x5 > x6) {(x5, x6) = (x6, x5);} - if (x0 > x4) {(x0, x4) = (x4, x0);} - if (x1 > x5) {(x1, x5) = (x5, x1);} - if (x2 > x6) {(x2, x6) = (x6, x2);} - if (x1 > x4) {(x1, x4) = (x4, x1);} - if (x3 > x6) {(x3, x6) = (x6, x3);} - if (x2 > x4) {(x2, x4) = (x4, x2);} - if (x3 > x5) {(x3, x5) = (x5, x3);} - if (x3 > x4) {(x3, x4) = (x4, x3);} - - uint256 index1 = k1 - lo; - if (index1 == 0) {k1th = x0;} - else if (index1 == 1) {k1th = x1;} - else if (index1 == 2) {k1th = x2;} - else if (index1 == 3) {k1th = x3;} - else if (index1 == 4) {k1th = x4;} - else if (index1 == 5) {k1th = x5;} - else if (index1 == 6) {k1th = x6;} - else {revert("k1 out of bounds");} - - uint256 index2 = k2 - lo; - if (k1 == k2) {return (k1th, k1th);} - else if (index2 == 0) {return (k1th, x0);} - else if (index2 == 1) {return (k1th, x1);} - else if (index2 == 2) {return (k1th, x2);} - else if (index2 == 3) {return (k1th, x3);} - else if (index2 == 4) {return (k1th, x4);} - else if (index2 == 5) {return (k1th, x5);} - else if (index2 == 6) {return (k1th, x6);} - else {revert("k2 out of bounds");} - } - - /** - * @notice Selects the k-th ranked element from list, looking only at indices between lo and hi - * (inclusive). Modifies list in-place. - */ - function quickselect(int256[] memory list, uint256 lo, uint256 hi, uint256 k) - private - pure - returns (int256 kth) - { - require(lo <= k); - require(k <= hi); - while (lo < hi) { - if (hi - lo < SHORTSELECTTWO_MAX_LENGTH) { - int256 ignore; - (kth, ignore) = shortSelectTwo(list, lo, hi, k, k); - return kth; - } - uint256 pivotIndex = partition(list, lo, hi); - if (k <= pivotIndex) { - // since pivotIndex < (original hi passed to partition), - // termination is guaranteed in this case - hi = pivotIndex; - } else { - // since (original lo passed to partition) <= pivotIndex, - // termination is guaranteed in this case - lo = pivotIndex + 1; - } - } - return list[lo]; - } - - /** - * @notice Selects the k1-th and k2-th ranked elements from list, looking only at indices between - * lo and hi (inclusive). Modifies list in-place. - */ - function quickselectTwo( - int256[] memory list, - uint256 lo, - uint256 hi, - uint256 k1, - uint256 k2 - ) - internal // for testing - pure - returns (int256 k1th, int256 k2th) - { - require(k1 < k2); - require(lo <= k1 && k1 <= hi); - require(lo <= k2 && k2 <= hi); - - while (true) { - if (hi - lo < SHORTSELECTTWO_MAX_LENGTH) { - return shortSelectTwo(list, lo, hi, k1, k2); - } - uint256 pivotIdx = partition(list, lo, hi); - if (k2 <= pivotIdx) { - hi = pivotIdx; - } else if (pivotIdx < k1) { - lo = pivotIdx + 1; - } else { - assert(k1 <= pivotIdx && pivotIdx < k2); - k1th = quickselect(list, lo, pivotIdx, k1); - k2th = quickselect(list, pivotIdx + 1, hi, k2); - return (k1th, k2th); - } - } - } - - /** - * @notice Partitions list in-place using Hoare's partitioning scheme. - * Only elements of list between indices lo and hi (inclusive) will be modified. - * Returns an index i, such that: - * - lo <= i < hi - * - forall j in [lo, i]. list[j] <= list[i] - * - forall j in [i, hi]. list[i] <= list[j] - */ - function partition(int256[] memory list, uint256 lo, uint256 hi) - private - pure - returns (uint256) - { - // We don't care about overflow of the addition, because it would require a list - // larger than any feasible computer's memory. - int256 pivot = list[(lo + hi) / 2]; - lo -= 1; // this can underflow. that's intentional. - hi += 1; - while (true) { - do { - lo += 1; - } while (list[lo] < pivot); - do { - hi -= 1; - } while (list[hi] > pivot); - if (lo < hi) { - (list[lo], list[hi]) = (list[hi], list[lo]); - } else { - // Let orig_lo and orig_hi be the original values of lo and hi passed to partition. - // Then, hi < orig_hi, because hi decreases *strictly* monotonically - // in each loop iteration and - // - either list[orig_hi] > pivot, in which case the first loop iteration - // will achieve hi < orig_hi; - // - or list[orig_hi] <= pivot, in which case at least two loop iterations are - // needed: - // - lo will have to stop at least once in the interval - // [orig_lo, (orig_lo + orig_hi)/2] - // - (orig_lo + orig_hi)/2 < orig_hi - return hi; - } - } - } - - /** - * @notice Makes an in-memory copy of the array passed in - * @param list Reference to the array to be copied - */ - function copy(int256[] memory list) - private - pure - returns(int256[] memory) - { - int256[] memory list2 = new int256[](list.length); - for (uint256 i = 0; i < list.length; i++) { - list2[i] = list[i]; - } - return list2; - } -} diff --git a/contracts/src/v0.6/Oracle.sol b/contracts/src/v0.6/Oracle.sol deleted file mode 100644 index 967114f7f87..00000000000 --- a/contracts/src/v0.6/Oracle.sol +++ /dev/null @@ -1,303 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.6.6; - -import "./LinkTokenReceiver.sol"; -import "./interfaces/ChainlinkRequestInterface.sol"; -import "./interfaces/OracleInterface.sol"; -import "./interfaces/LinkTokenInterface.sol"; -import "./interfaces/WithdrawalInterface.sol"; -import "./vendor/Ownable.sol"; -import "./vendor/SafeMathChainlink.sol"; - -/** - * @title The Chainlink Oracle contract - * @notice Node operators can deploy this contract to fulfill requests sent to them - */ -contract Oracle is ChainlinkRequestInterface, OracleInterface, Ownable, LinkTokenReceiver, WithdrawalInterface { - using SafeMathChainlink for uint256; - - uint256 constant public EXPIRY_TIME = 5 minutes; - uint256 constant private MINIMUM_CONSUMER_GAS_LIMIT = 400000; - // We initialize fields to 1 instead of 0 so that the first invocation - // does not cost more gas. - uint256 constant private ONE_FOR_CONSISTENT_GAS_COST = 1; - - LinkTokenInterface internal LinkToken; - mapping(bytes32 => bytes32) private commitments; - mapping(address => bool) private authorizedNodes; - uint256 private withdrawableTokens = ONE_FOR_CONSISTENT_GAS_COST; - - event OracleRequest( - bytes32 indexed specId, - address requester, - bytes32 requestId, - uint256 payment, - address callbackAddr, - bytes4 callbackFunctionId, - uint256 cancelExpiration, - uint256 dataVersion, - bytes data - ); - - event CancelOracleRequest( - bytes32 indexed requestId - ); - - /** - * @notice Deploy with the address of the LINK token - * @dev Sets the LinkToken address for the imported LinkTokenInterface - * @param _link The address of the LINK token - */ - constructor(address _link) - public - Ownable() - { - LinkToken = LinkTokenInterface(_link); // external but already deployed and unalterable - } - - /** - * @notice Creates the Chainlink request - * @dev Stores the hash of the params as the on-chain commitment for the request. - * Emits OracleRequest event for the Chainlink node to detect. - * @param _sender The sender of the request - * @param _payment The amount of payment given (specified in wei) - * @param _specId The Job Specification ID - * @param _callbackAddress The callback address for the response - * @param _callbackFunctionId The callback function ID for the response - * @param _nonce The nonce sent by the requester - * @param _dataVersion The specified data version - * @param _data The CBOR payload of the request - */ - function oracleRequest( - address _sender, - uint256 _payment, - bytes32 _specId, - address _callbackAddress, - bytes4 _callbackFunctionId, - uint256 _nonce, - uint256 _dataVersion, - bytes calldata _data - ) - external - override - onlyLINK() - checkCallbackAddress(_callbackAddress) - { - bytes32 requestId = keccak256(abi.encodePacked(_sender, _nonce)); - require(commitments[requestId] == 0, "Must use a unique ID"); - // solhint-disable-next-line not-rely-on-time - uint256 expiration = now.add(EXPIRY_TIME); - - commitments[requestId] = keccak256( - abi.encodePacked( - _payment, - _callbackAddress, - _callbackFunctionId, - expiration - ) - ); - - emit OracleRequest( - _specId, - _sender, - requestId, - _payment, - _callbackAddress, - _callbackFunctionId, - expiration, - _dataVersion, - _data); - } - - /** - * @notice Called by the Chainlink node to fulfill requests - * @dev Given params must hash back to the commitment stored from `oracleRequest`. - * Will call the callback address' callback function without bubbling up error - * checking in a `require` so that the node can get paid. - * @param _requestId The fulfillment request ID that must match the requester's - * @param _payment The payment amount that will be released for the oracle (specified in wei) - * @param _callbackAddress The callback address to call for fulfillment - * @param _callbackFunctionId The callback function ID to use for fulfillment - * @param _expiration The expiration that the node should respond by before the requester can cancel - * @param _data The data to return to the consuming contract - * @return Status if the external call was successful - */ - function fulfillOracleRequest( - bytes32 _requestId, - uint256 _payment, - address _callbackAddress, - bytes4 _callbackFunctionId, - uint256 _expiration, - bytes32 _data - ) - external - onlyAuthorizedNode - override - isValidRequest(_requestId) - returns (bool) - { - bytes32 paramsHash = keccak256( - abi.encodePacked( - _payment, - _callbackAddress, - _callbackFunctionId, - _expiration - ) - ); - require(commitments[_requestId] == paramsHash, "Params do not match request ID"); - withdrawableTokens = withdrawableTokens.add(_payment); - delete commitments[_requestId]; - require(gasleft() >= MINIMUM_CONSUMER_GAS_LIMIT, "Must provide consumer enough gas"); - // All updates to the oracle's fulfillment should come before calling the - // callback(addr+functionId) as it is untrusted. - // See: https://solidity.readthedocs.io/en/develop/security-considerations.html#use-the-checks-effects-interactions-pattern - (bool success, ) = _callbackAddress.call(abi.encodeWithSelector(_callbackFunctionId, _requestId, _data)); // solhint-disable-line avoid-low-level-calls - return success; - } - - /** - * @notice Use this to check if a node is authorized for fulfilling requests - * @param _node The address of the Chainlink node - * @return The authorization status of the node - */ - function getAuthorizationStatus(address _node) - external - view - override - returns (bool) - { - return authorizedNodes[_node]; - } - - /** - * @notice Sets the fulfillment permission for a given node. Use `true` to allow, `false` to disallow. - * @param _node The address of the Chainlink node - * @param _allowed Bool value to determine if the node can fulfill requests - */ - function setFulfillmentPermission(address _node, bool _allowed) - external - override - onlyOwner() - { - authorizedNodes[_node] = _allowed; - } - - /** - * @notice Allows the node operator to withdraw earned LINK to a given address - * @dev The owner of the contract can be another wallet and does not have to be a Chainlink node - * @param _recipient The address to send the LINK token to - * @param _amount The amount to send (specified in wei) - */ - function withdraw(address _recipient, uint256 _amount) - external - override(OracleInterface, WithdrawalInterface) - onlyOwner - hasAvailableFunds(_amount) - { - withdrawableTokens = withdrawableTokens.sub(_amount); - assert(LinkToken.transfer(_recipient, _amount)); - } - - /** - * @notice Displays the amount of LINK that is available for the node operator to withdraw - * @dev We use `ONE_FOR_CONSISTENT_GAS_COST` in place of 0 in storage - * @return The amount of withdrawable LINK on the contract - */ - function withdrawable() - external - view - override(OracleInterface, WithdrawalInterface) - onlyOwner() - returns (uint256) - { - return withdrawableTokens.sub(ONE_FOR_CONSISTENT_GAS_COST); - } - - /** - * @notice Allows requesters to cancel requests sent to this oracle contract. Will transfer the LINK - * sent for the request back to the requester's address. - * @dev Given params must hash to a commitment stored on the contract in order for the request to be valid - * Emits CancelOracleRequest event. - * @param _requestId The request ID - * @param _payment The amount of payment given (specified in wei) - * @param _callbackFunc The requester's specified callback address - * @param _expiration The time of the expiration for the request - */ - function cancelOracleRequest( - bytes32 _requestId, - uint256 _payment, - bytes4 _callbackFunc, - uint256 _expiration - ) - external - override - { - bytes32 paramsHash = keccak256( - abi.encodePacked( - _payment, - msg.sender, - _callbackFunc, - _expiration) - ); - require(paramsHash == commitments[_requestId], "Params do not match request ID"); - // solhint-disable-next-line not-rely-on-time - require(_expiration <= now, "Request is not expired"); - - delete commitments[_requestId]; - emit CancelOracleRequest(_requestId); - - assert(LinkToken.transfer(msg.sender, _payment)); - } - - /** - * @notice Returns the address of the LINK token - * @dev This is the public implementation for chainlinkTokenAddress, which is - * an internal method of the ChainlinkClient contract - */ - function getChainlinkToken() - public - view - override - returns (address) - { - return address(LinkToken); - } - - // MODIFIERS - - /** - * @dev Reverts if amount requested is greater than withdrawable balance - * @param _amount The given amount to compare to `withdrawableTokens` - */ - modifier hasAvailableFunds(uint256 _amount) { - require(withdrawableTokens >= _amount.add(ONE_FOR_CONSISTENT_GAS_COST), "Amount requested is greater than withdrawable balance"); - _; - } - - /** - * @dev Reverts if request ID does not exist - * @param _requestId The given request ID to check in stored `commitments` - */ - modifier isValidRequest(bytes32 _requestId) { - require(commitments[_requestId] != 0, "Must have a valid requestId"); - _; - } - - /** - * @dev Reverts if `msg.sender` is not authorized to fulfill requests - */ - modifier onlyAuthorizedNode() { - require(authorizedNodes[msg.sender] || msg.sender == owner(), "Not an authorized node to fulfill requests"); - _; - } - - /** - * @dev Reverts if the callback address is the LINK token - * @param _to The callback address - */ - modifier checkCallbackAddress(address _to) { - require(_to != address(LinkToken), "Cannot callback to LINK"); - _; - } - -} diff --git a/contracts/src/v0.6/Owned.sol b/contracts/src/v0.6/Owned.sol deleted file mode 100644 index 0dc7c4660b6..00000000000 --- a/contracts/src/v0.6/Owned.sol +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >0.6.0 <0.8.0; - -/** - * @title The Owned contract - * @notice A contract with helpers for basic contract ownership. - */ -contract Owned { - - address public owner; - address private pendingOwner; - - event OwnershipTransferRequested( - address indexed from, - address indexed to - ); - event OwnershipTransferred( - address indexed from, - address indexed to - ); - - constructor() public { - owner = msg.sender; - } - - /** - * @dev Allows an owner to begin transferring ownership to a new address, - * pending. - */ - function transferOwnership(address _to) - external - onlyOwner() - { - pendingOwner = _to; - - emit OwnershipTransferRequested(owner, _to); - } - - /** - * @dev Allows an ownership transfer to be completed by the recipient. - */ - function acceptOwnership() - external - { - require(msg.sender == pendingOwner, "Must be proposed owner"); - - address oldOwner = owner; - owner = msg.sender; - pendingOwner = address(0); - - emit OwnershipTransferred(oldOwner, msg.sender); - } - - /** - * @dev Reverts if called by anyone other than the contract owner. - */ - modifier onlyOwner() { - require(msg.sender == owner, "Only callable by owner"); - _; - } - -} diff --git a/contracts/src/v0.6/SafeMath128.sol b/contracts/src/v0.6/SafeMath128.sol deleted file mode 100644 index c79665bcf87..00000000000 --- a/contracts/src/v0.6/SafeMath128.sol +++ /dev/null @@ -1,111 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - * - * This library is a version of Open Zeppelin's SafeMath, modified to support - * unsigned 128 bit integers. - */ -library SafeMath128 { - /** - * @dev Returns the addition of two unsigned integers, reverting on - * overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint128 a, uint128 b) internal pure returns (uint128) { - uint128 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on - * overflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot overflow. - */ - function sub(uint128 a, uint128 b) internal pure returns (uint128) { - require(b <= a, "SafeMath: subtraction overflow"); - uint128 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on - * overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint128 a, uint128 b) internal pure returns (uint128) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 - if (a == 0) { - return 0; - } - - uint128 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. Reverts on - * division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint128 a, uint128 b) internal pure returns (uint128) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, "SafeMath: division by zero"); - uint128 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint128 a, uint128 b) internal pure returns (uint128) { - require(b != 0, "SafeMath: modulo by zero"); - return a % b; - } -} diff --git a/contracts/src/v0.6/SafeMath32.sol b/contracts/src/v0.6/SafeMath32.sol deleted file mode 100644 index 21944bb0d80..00000000000 --- a/contracts/src/v0.6/SafeMath32.sol +++ /dev/null @@ -1,111 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - * - * This library is a version of Open Zeppelin's SafeMath, modified to support - * unsigned 32 bit integers. - */ -library SafeMath32 { - /** - * @dev Returns the addition of two unsigned integers, reverting on - * overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint32 a, uint32 b) internal pure returns (uint32) { - uint32 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on - * overflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot overflow. - */ - function sub(uint32 a, uint32 b) internal pure returns (uint32) { - require(b <= a, "SafeMath: subtraction overflow"); - uint32 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on - * overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint32 a, uint32 b) internal pure returns (uint32) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 - if (a == 0) { - return 0; - } - - uint32 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. Reverts on - * division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint32 a, uint32 b) internal pure returns (uint32) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, "SafeMath: division by zero"); - uint32 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint32 a, uint32 b) internal pure returns (uint32) { - require(b != 0, "SafeMath: modulo by zero"); - return a % b; - } -} diff --git a/contracts/src/v0.6/SafeMath64.sol b/contracts/src/v0.6/SafeMath64.sol deleted file mode 100644 index 2bb3b79121b..00000000000 --- a/contracts/src/v0.6/SafeMath64.sol +++ /dev/null @@ -1,111 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - * - * This library is a version of Open Zeppelin's SafeMath, modified to support - * unsigned 64 bit integers. - */ -library SafeMath64 { - /** - * @dev Returns the addition of two unsigned integers, reverting on - * overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint64 a, uint64 b) internal pure returns (uint64) { - uint64 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on - * overflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot overflow. - */ - function sub(uint64 a, uint64 b) internal pure returns (uint64) { - require(b <= a, "SafeMath: subtraction overflow"); - uint64 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on - * overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint64 a, uint64 b) internal pure returns (uint64) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 - if (a == 0) { - return 0; - } - - uint64 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. Reverts on - * division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint64 a, uint64 b) internal pure returns (uint64) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, "SafeMath: division by zero"); - uint64 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint64 a, uint64 b) internal pure returns (uint64) { - require(b != 0, "SafeMath: modulo by zero"); - return a % b; - } -} diff --git a/contracts/src/v0.6/SignedSafeMath.sol b/contracts/src/v0.6/SignedSafeMath.sol deleted file mode 100644 index 32941de704a..00000000000 --- a/contracts/src/v0.6/SignedSafeMath.sol +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -library SignedSafeMath { - int256 constant private _INT256_MIN = -2**255; - - /** - * @dev Multiplies two signed integers, reverts on overflow. - */ - function mul(int256 a, int256 b) internal pure returns (int256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - require(!(a == -1 && b == _INT256_MIN), "SignedSafeMath: multiplication overflow"); - - int256 c = a * b; - require(c / a == b, "SignedSafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Integer division of two signed integers truncating the quotient, reverts on division by zero. - */ - function div(int256 a, int256 b) internal pure returns (int256) { - require(b != 0, "SignedSafeMath: division by zero"); - require(!(b == -1 && a == _INT256_MIN), "SignedSafeMath: division overflow"); - - int256 c = a / b; - - return c; - } - - /** - * @dev Subtracts two signed integers, reverts on overflow. - */ - function sub(int256 a, int256 b) internal pure returns (int256) { - int256 c = a - b; - require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow"); - - return c; - } - - /** - * @dev Adds two signed integers, reverts on overflow. - */ - function add(int256 a, int256 b) internal pure returns (int256) { - int256 c = a + b; - require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow"); - - return c; - } - - /** - * @notice Computes average of two signed integers, ensuring that the computation - * doesn't overflow. - * @dev If the result is not an integer, it is rounded towards zero. For example, - * avg(-3, -4) = -3 - */ - function avg(int256 _a, int256 _b) - internal - pure - returns (int256) - { - if ((_a < 0 && _b > 0) || (_a > 0 && _b < 0)) { - return add(_a, _b) / 2; - } - int256 remainder = (_a % 2 + _b % 2) / 2; - return add(add(_a / 2, _b / 2), remainder); - } -} diff --git a/contracts/src/v0.6/SimpleReadAccessController.sol b/contracts/src/v0.6/SimpleReadAccessController.sol deleted file mode 100644 index fbd714a1c7b..00000000000 --- a/contracts/src/v0.6/SimpleReadAccessController.sol +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import "./SimpleWriteAccessController.sol"; - -/** - * @title SimpleReadAccessController - * @notice Gives access to: - * - any externally owned account (note that off-chain actors can always read - * any contract storage regardless of on-chain access control measures, so this - * does not weaken the access control while improving usability) - * - accounts explicitly added to an access list - * @dev SimpleReadAccessController is not suitable for access controlling writes - * since it grants any externally owned account access! See - * SimpleWriteAccessController for that. - */ -contract SimpleReadAccessController is SimpleWriteAccessController { - - /** - * @notice Returns the access of an address - * @param _user The address to query - */ - function hasAccess( - address _user, - bytes memory _calldata - ) - public - view - virtual - override - returns (bool) - { - return super.hasAccess(_user, _calldata) || _user == tx.origin; - } - -} diff --git a/contracts/src/v0.6/SimpleWriteAccessController.sol b/contracts/src/v0.6/SimpleWriteAccessController.sol deleted file mode 100644 index 02a6db7b166..00000000000 --- a/contracts/src/v0.6/SimpleWriteAccessController.sol +++ /dev/null @@ -1,112 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >0.6.0 <0.8.0; - -import "./Owned.sol"; -import "./interfaces/AccessControllerInterface.sol"; - -/** - * @title SimpleWriteAccessController - * @notice Gives access to accounts explicitly added to an access list by the - * controller's owner. - * @dev does not make any special permissions for externally, see - * SimpleReadAccessController for that. - */ -contract SimpleWriteAccessController is AccessControllerInterface, Owned { - - bool public checkEnabled; - mapping(address => bool) internal accessList; - - event AddedAccess(address user); - event RemovedAccess(address user); - event CheckAccessEnabled(); - event CheckAccessDisabled(); - - constructor() - public - { - checkEnabled = true; - } - - /** - * @notice Returns the access of an address - * @param _user The address to query - */ - function hasAccess( - address _user, - bytes memory - ) - public - view - virtual - override - returns (bool) - { - return accessList[_user] || !checkEnabled; - } - - /** - * @notice Adds an address to the access list - * @param _user The address to add - */ - function addAccess(address _user) - external - onlyOwner() - { - if (!accessList[_user]) { - accessList[_user] = true; - - emit AddedAccess(_user); - } - } - - /** - * @notice Removes an address from the access list - * @param _user The address to remove - */ - function removeAccess(address _user) - external - onlyOwner() - { - if (accessList[_user]) { - accessList[_user] = false; - - emit RemovedAccess(_user); - } - } - - /** - * @notice makes the access check enforced - */ - function enableAccessCheck() - external - onlyOwner() - { - if (!checkEnabled) { - checkEnabled = true; - - emit CheckAccessEnabled(); - } - } - - /** - * @notice makes the access check unenforced - */ - function disableAccessCheck() - external - onlyOwner() - { - if (checkEnabled) { - checkEnabled = false; - - emit CheckAccessDisabled(); - } - } - - /** - * @dev reverts if the caller does not have access - */ - modifier checkAccess() { - require(hasAccess(msg.sender, msg.data), "No access"); - _; - } -} diff --git a/contracts/src/v0.6/VRF.sol b/contracts/src/v0.6/VRF.sol deleted file mode 100644 index 9cbb145e3b8..00000000000 --- a/contracts/src/v0.6/VRF.sol +++ /dev/null @@ -1,533 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.6.6; - -/** **************************************************************************** - * @notice Verification of verifiable-random-function (VRF) proofs, following - * @notice https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vrf-05#section-5.3 - * @notice See https://eprint.iacr.org/2017/099.pdf for security proofs. - - * @dev Bibliographic references: - - * @dev Goldberg, et al., "Verifiable Random Functions (VRFs)", Internet Draft - * @dev draft-irtf-cfrg-vrf-05, IETF, Aug 11 2019, - * @dev https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vrf-05 - - * @dev Papadopoulos, et al., "Making NSEC5 Practical for DNSSEC", Cryptology - * @dev ePrint Archive, Report 2017/099, https://eprint.iacr.org/2017/099.pdf - * **************************************************************************** - * @dev USAGE - - * @dev The main entry point is randomValueFromVRFProof. See its docstring. - * **************************************************************************** - * @dev PURPOSE - - * @dev Reggie the Random Oracle (not his real job) wants to provide randomness - * @dev to Vera the verifier in such a way that Vera can be sure he's not - * @dev making his output up to suit himself. Reggie provides Vera a public key - * @dev to which he knows the secret key. Each time Vera provides a seed to - * @dev Reggie, he gives back a value which is computed completely - * @dev deterministically from the seed and the secret key. - - * @dev Reggie provides a proof by which Vera can verify that the output was - * @dev correctly computed once Reggie tells it to her, but without that proof, - * @dev the output is computationally indistinguishable to her from a uniform - * @dev random sample from the output space. - - * @dev The purpose of this contract is to perform that verification. - * **************************************************************************** - * @dev DESIGN NOTES - - * @dev The VRF algorithm verified here satisfies the full unqiqueness, full - * @dev collision resistance, and full pseudorandomness security properties. - * @dev See "SECURITY PROPERTIES" below, and - * @dev https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vrf-05#section-3 - - * @dev An elliptic curve point is generally represented in the solidity code - * @dev as a uint256[2], corresponding to its affine coordinates in - * @dev GF(FIELD_SIZE). - - * @dev For the sake of efficiency, this implementation deviates from the spec - * @dev in some minor ways: - - * @dev - Keccak hash rather than the SHA256 hash recommended in - * @dev https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vrf-05#section-5.5 - * @dev Keccak costs much less gas on the EVM, and provides similar security. - - * @dev - Secp256k1 curve instead of the P-256 or ED25519 curves recommended in - * @dev https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vrf-05#section-5.5 - * @dev For curve-point multiplication, it's much cheaper to abuse ECRECOVER - - * @dev - hashToCurve recursively hashes until it finds a curve x-ordinate. On - * @dev the EVM, this is slightly more efficient than the recommendation in - * @dev https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vrf-05#section-5.4.1.1 - * @dev step 5, to concatenate with a nonce then hash, and rehash with the - * @dev nonce updated until a valid x-ordinate is found. - - * @dev - hashToCurve does not include a cipher version string or the byte 0x1 - * @dev in the hash message, as recommended in step 5.B of the draft - * @dev standard. They are unnecessary here because no variation in the - * @dev cipher suite is allowed. - - * @dev - Similarly, the hash input in scalarFromCurvePoints does not include a - * @dev commitment to the cipher suite, either, which differs from step 2 of - * @dev https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vrf-05#section-5.4.3 - * @dev . Also, the hash input is the concatenation of the uncompressed - * @dev points, not the compressed points as recommended in step 3. - - * @dev - In the calculation of the challenge value "c", the "u" value (i.e. - * @dev the value computed by Reggie as the nonce times the secp256k1 - * @dev generator point, see steps 5 and 7 of - * @dev https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vrf-05#section-5.3 - * @dev ) is replaced by its ethereum address, i.e. the lower 160 bits of the - * @dev keccak hash of the original u. This is because we only verify the - * @dev calculation of u up to its address, by abusing ECRECOVER. - * **************************************************************************** - * @dev SECURITY PROPERTIES - - * @dev Here are the security properties for this VRF: - - * @dev Full uniqueness: For any seed and valid VRF public key, there is - * @dev exactly one VRF output which can be proved to come from that seed, in - * @dev the sense that the proof will pass verifyVRFProof. - - * @dev Full collision resistance: It's cryptographically infeasible to find - * @dev two seeds with same VRF output from a fixed, valid VRF key - - * @dev Full pseudorandomness: Absent the proofs that the VRF outputs are - * @dev derived from a given seed, the outputs are computationally - * @dev indistinguishable from randomness. - - * @dev https://eprint.iacr.org/2017/099.pdf, Appendix B contains the proofs - * @dev for these properties. - - * @dev For secp256k1, the key validation described in section - * @dev https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vrf-05#section-5.6 - * @dev is unnecessary, because secp256k1 has cofactor 1, and the - * @dev representation of the public key used here (affine x- and y-ordinates - * @dev of the secp256k1 point on the standard y^2=x^3+7 curve) cannot refer to - * @dev the point at infinity. - * **************************************************************************** - * @dev OTHER SECURITY CONSIDERATIONS - * - * @dev The seed input to the VRF could in principle force an arbitrary amount - * @dev of work in hashToCurve, by requiring extra rounds of hashing and - * @dev checking whether that's yielded the x ordinate of a secp256k1 point. - * @dev However, under the Random Oracle Model the probability of choosing a - * @dev point which forces n extra rounds in hashToCurve is 2⁻ⁿ. The base cost - * @dev for calling hashToCurve is about 25,000 gas, and each round of checking - * @dev for a valid x ordinate costs about 15,555 gas, so to find a seed for - * @dev which hashToCurve would cost more than 2,017,000 gas, one would have to - * @dev try, in expectation, about 2¹²⁸ seeds, which is infeasible for any - * @dev foreseeable computational resources. (25,000 + 128 * 15,555 < 2,017,000.) - - * @dev Since the gas block limit for the Ethereum main net is 10,000,000 gas, - * @dev this means it is infeasible for an adversary to prevent correct - * @dev operation of this contract by choosing an adverse seed. - - * @dev (See TestMeasureHashToCurveGasCost for verification of the gas cost for - * @dev hashToCurve.) - - * @dev It may be possible to make a secure constant-time hashToCurve function. - * @dev See notes in hashToCurve docstring. -*/ -contract VRF { - - // See https://www.secg.org/sec2-v2.pdf, section 2.4.1, for these constants. - uint256 constant private GROUP_ORDER = // Number of points in Secp256k1 - // solium-disable-next-line indentation - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141; - // Prime characteristic of the galois field over which Secp256k1 is defined - uint256 constant private FIELD_SIZE = - // solium-disable-next-line indentation - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F; - uint256 constant private WORD_LENGTH_BYTES = 0x20; - - // (base^exponent) % FIELD_SIZE - // Cribbed from https://medium.com/@rbkhmrcr/precompiles-solidity-e5d29bd428c4 - function bigModExp(uint256 base, uint256 exponent) - internal view returns (uint256 exponentiation) { - uint256 callResult; - uint256[6] memory bigModExpContractInputs; - bigModExpContractInputs[0] = WORD_LENGTH_BYTES; // Length of base - bigModExpContractInputs[1] = WORD_LENGTH_BYTES; // Length of exponent - bigModExpContractInputs[2] = WORD_LENGTH_BYTES; // Length of modulus - bigModExpContractInputs[3] = base; - bigModExpContractInputs[4] = exponent; - bigModExpContractInputs[5] = FIELD_SIZE; - uint256[1] memory output; - assembly { // solhint-disable-line no-inline-assembly - callResult := staticcall( - not(0), // Gas cost: no limit - 0x05, // Bigmodexp contract address - bigModExpContractInputs, - 0xc0, // Length of input segment: 6*0x20-bytes - output, - 0x20 // Length of output segment - ) - } - if (callResult == 0) {revert("bigModExp failure!");} - return output[0]; - } - - // Let q=FIELD_SIZE. q % 4 = 3, ∴ x≡r^2 mod q ⇒ x^SQRT_POWER≡±r mod q. See - // https://en.wikipedia.org/wiki/Modular_square_root#Prime_or_prime_power_modulus - uint256 constant private SQRT_POWER = (FIELD_SIZE + 1) >> 2; - - // Computes a s.t. a^2 = x in the field. Assumes a exists - function squareRoot(uint256 x) internal view returns (uint256) { - return bigModExp(x, SQRT_POWER); - } - - // The value of y^2 given that (x,y) is on secp256k1. - function ySquared(uint256 x) internal pure returns (uint256) { - // Curve is y^2=x^3+7. See section 2.4.1 of https://www.secg.org/sec2-v2.pdf - uint256 xCubed = mulmod(x, mulmod(x, x, FIELD_SIZE), FIELD_SIZE); - return addmod(xCubed, 7, FIELD_SIZE); - } - - // True iff p is on secp256k1 - function isOnCurve(uint256[2] memory p) internal pure returns (bool) { - return ySquared(p[0]) == mulmod(p[1], p[1], FIELD_SIZE); - } - - // Hash x uniformly into {0, ..., FIELD_SIZE-1}. - function fieldHash(bytes memory b) internal pure returns (uint256 x_) { - x_ = uint256(keccak256(b)); - // Rejecting if x >= FIELD_SIZE corresponds to step 2.1 in section 2.3.4 of - // http://www.secg.org/sec1-v2.pdf , which is part of the definition of - // string_to_point in the IETF draft - while (x_ >= FIELD_SIZE) { - x_ = uint256(keccak256(abi.encodePacked(x_))); - } - } - - // Hash b to a random point which hopefully lies on secp256k1. The y ordinate - // is always even, due to - // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vrf-05#section-5.4.1.1 - // step 5.C, which references arbitrary_string_to_point, defined in - // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vrf-05#section-5.5 as - // returning the point with given x ordinate, and even y ordinate. - function newCandidateSecp256k1Point(bytes memory b) - internal view returns (uint256[2] memory p) { - p[0] = fieldHash(b); - p[1] = squareRoot(ySquared(p[0])); - if (p[1] % 2 == 1) { - p[1] = FIELD_SIZE - p[1]; - } - } - - // Domain-separation tag for initial hash in hashToCurve. Corresponds to - // vrf.go/hashToCurveHashPrefix - uint256 constant HASH_TO_CURVE_HASH_PREFIX = 1; - - // Cryptographic hash function onto the curve. - // - // Corresponds to algorithm in section 5.4.1.1 of the draft standard. (But see - // DESIGN NOTES above for slight differences.) - // - // TODO(alx): Implement a bounded-computation hash-to-curve, as described in - // "Construction of Rational Points on Elliptic Curves over Finite Fields" - // http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.831.5299&rep=rep1&type=pdf - // and suggested by - // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-01#section-5.2.2 - // (Though we can't used exactly that because secp256k1's j-invariant is 0.) - // - // This would greatly simplify the analysis in "OTHER SECURITY CONSIDERATIONS" - // https://www.pivotaltracker.com/story/show/171120900 - function hashToCurve(uint256[2] memory pk, uint256 input) - internal view returns (uint256[2] memory rv) { - rv = newCandidateSecp256k1Point(abi.encodePacked(HASH_TO_CURVE_HASH_PREFIX, - pk, input)); - while (!isOnCurve(rv)) { - rv = newCandidateSecp256k1Point(abi.encodePacked(rv[0])); - } - } - - /** ********************************************************************* - * @notice Check that product==scalar*multiplicand - * - * @dev Based on Vitalik Buterin's idea in ethresear.ch post cited below. - * - * @param multiplicand: secp256k1 point - * @param scalar: non-zero GF(GROUP_ORDER) scalar - * @param product: secp256k1 expected to be multiplier * multiplicand - * @return verifies true iff product==scalar*multiplicand, with cryptographically high probability - */ - function ecmulVerify(uint256[2] memory multiplicand, uint256 scalar, - uint256[2] memory product) internal pure returns(bool verifies) - { - require(scalar != 0); // Rules out an ecrecover failure case - uint256 x = multiplicand[0]; // x ordinate of multiplicand - uint8 v = multiplicand[1] % 2 == 0 ? 27 : 28; // parity of y ordinate - // https://ethresear.ch/t/you-can-kinda-abuse-ecrecover-to-do-ecmul-in-secp256k1-today/2384/9 - // Point corresponding to address ecrecover(0, v, x, s=scalar*x) is - // (x⁻¹ mod GROUP_ORDER) * (scalar * x * multiplicand - 0 * g), i.e. - // scalar*multiplicand. See https://crypto.stackexchange.com/a/18106 - bytes32 scalarTimesX = bytes32(mulmod(scalar, x, GROUP_ORDER)); - address actual = ecrecover(bytes32(0), v, bytes32(x), scalarTimesX); - // Explicit conversion to address takes bottom 160 bits - address expected = address(uint256(keccak256(abi.encodePacked(product)))); - return (actual == expected); - } - - // Returns x1/z1-x2/z2=(x1z2-x2z1)/(z1z2) in projective coordinates on P¹(𝔽ₙ) - function projectiveSub(uint256 x1, uint256 z1, uint256 x2, uint256 z2) - internal pure returns(uint256 x3, uint256 z3) { - uint256 num1 = mulmod(z2, x1, FIELD_SIZE); - uint256 num2 = mulmod(FIELD_SIZE - x2, z1, FIELD_SIZE); - (x3, z3) = (addmod(num1, num2, FIELD_SIZE), mulmod(z1, z2, FIELD_SIZE)); - } - - // Returns x1/z1*x2/z2=(x1x2)/(z1z2), in projective coordinates on P¹(𝔽ₙ) - function projectiveMul(uint256 x1, uint256 z1, uint256 x2, uint256 z2) - internal pure returns(uint256 x3, uint256 z3) { - (x3, z3) = (mulmod(x1, x2, FIELD_SIZE), mulmod(z1, z2, FIELD_SIZE)); - } - - /** ************************************************************************** - @notice Computes elliptic-curve sum, in projective co-ordinates - - @dev Using projective coordinates avoids costly divisions - - @dev To use this with p and q in affine coordinates, call - @dev projectiveECAdd(px, py, qx, qy). This will return - @dev the addition of (px, py, 1) and (qx, qy, 1), in the - @dev secp256k1 group. - - @dev This can be used to calculate the z which is the inverse to zInv - @dev in isValidVRFOutput. But consider using a faster - @dev re-implementation such as ProjectiveECAdd in the golang vrf package. - - @dev This function assumes [px,py,1],[qx,qy,1] are valid projective - coordinates of secp256k1 points. That is safe in this contract, - because this method is only used by linearCombination, which checks - points are on the curve via ecrecover. - ************************************************************************** - @param px The first affine coordinate of the first summand - @param py The second affine coordinate of the first summand - @param qx The first affine coordinate of the second summand - @param qy The second affine coordinate of the second summand - - (px,py) and (qx,qy) must be distinct, valid secp256k1 points. - ************************************************************************** - Return values are projective coordinates of [px,py,1]+[qx,qy,1] as points - on secp256k1, in P²(𝔽ₙ) - @return sx - @return sy - @return sz - */ - function projectiveECAdd(uint256 px, uint256 py, uint256 qx, uint256 qy) - internal pure returns(uint256 sx, uint256 sy, uint256 sz) { - // See "Group law for E/K : y^2 = x^3 + ax + b", in section 3.1.2, p. 80, - // "Guide to Elliptic Curve Cryptography" by Hankerson, Menezes and Vanstone - // We take the equations there for (sx,sy), and homogenize them to - // projective coordinates. That way, no inverses are required, here, and we - // only need the one inverse in affineECAdd. - - // We only need the "point addition" equations from Hankerson et al. Can - // skip the "point doubling" equations because p1 == p2 is cryptographically - // impossible, and require'd not to be the case in linearCombination. - - // Add extra "projective coordinate" to the two points - (uint256 z1, uint256 z2) = (1, 1); - - // (lx, lz) = (qy-py)/(qx-px), i.e., gradient of secant line. - uint256 lx = addmod(qy, FIELD_SIZE - py, FIELD_SIZE); - uint256 lz = addmod(qx, FIELD_SIZE - px, FIELD_SIZE); - - uint256 dx; // Accumulates denominator from sx calculation - // sx=((qy-py)/(qx-px))^2-px-qx - (sx, dx) = projectiveMul(lx, lz, lx, lz); // ((qy-py)/(qx-px))^2 - (sx, dx) = projectiveSub(sx, dx, px, z1); // ((qy-py)/(qx-px))^2-px - (sx, dx) = projectiveSub(sx, dx, qx, z2); // ((qy-py)/(qx-px))^2-px-qx - - uint256 dy; // Accumulates denominator from sy calculation - // sy=((qy-py)/(qx-px))(px-sx)-py - (sy, dy) = projectiveSub(px, z1, sx, dx); // px-sx - (sy, dy) = projectiveMul(sy, dy, lx, lz); // ((qy-py)/(qx-px))(px-sx) - (sy, dy) = projectiveSub(sy, dy, py, z1); // ((qy-py)/(qx-px))(px-sx)-py - - if (dx != dy) { // Cross-multiply to put everything over a common denominator - sx = mulmod(sx, dy, FIELD_SIZE); - sy = mulmod(sy, dx, FIELD_SIZE); - sz = mulmod(dx, dy, FIELD_SIZE); - } else { // Already over a common denominator, use that for z ordinate - sz = dx; - } - } - - // p1+p2, as affine points on secp256k1. - // - // invZ must be the inverse of the z returned by projectiveECAdd(p1, p2). - // It is computed off-chain to save gas. - // - // p1 and p2 must be distinct, because projectiveECAdd doesn't handle - // point doubling. - function affineECAdd( - uint256[2] memory p1, uint256[2] memory p2, - uint256 invZ) internal pure returns (uint256[2] memory) { - uint256 x; - uint256 y; - uint256 z; - (x, y, z) = projectiveECAdd(p1[0], p1[1], p2[0], p2[1]); - require(mulmod(z, invZ, FIELD_SIZE) == 1, "invZ must be inverse of z"); - // Clear the z ordinate of the projective representation by dividing through - // by it, to obtain the affine representation - return [mulmod(x, invZ, FIELD_SIZE), mulmod(y, invZ, FIELD_SIZE)]; - } - - // True iff address(c*p+s*g) == lcWitness, where g is generator. (With - // cryptographically high probability.) - function verifyLinearCombinationWithGenerator( - uint256 c, uint256[2] memory p, uint256 s, address lcWitness) - internal pure returns (bool) { - // Rule out ecrecover failure modes which return address 0. - require(lcWitness != address(0), "bad witness"); - uint8 v = (p[1] % 2 == 0) ? 27 : 28; // parity of y-ordinate of p - bytes32 pseudoHash = bytes32(GROUP_ORDER - mulmod(p[0], s, GROUP_ORDER)); // -s*p[0] - bytes32 pseudoSignature = bytes32(mulmod(c, p[0], GROUP_ORDER)); // c*p[0] - // https://ethresear.ch/t/you-can-kinda-abuse-ecrecover-to-do-ecmul-in-secp256k1-today/2384/9 - // The point corresponding to the address returned by - // ecrecover(-s*p[0],v,p[0],c*p[0]) is - // (p[0]⁻¹ mod GROUP_ORDER)*(c*p[0]-(-s)*p[0]*g)=c*p+s*g. - // See https://crypto.stackexchange.com/a/18106 - // https://bitcoin.stackexchange.com/questions/38351/ecdsa-v-r-s-what-is-v - address computed = ecrecover(pseudoHash, v, bytes32(p[0]), pseudoSignature); - return computed == lcWitness; - } - - // c*p1 + s*p2. Requires cp1Witness=c*p1 and sp2Witness=s*p2. Also - // requires cp1Witness != sp2Witness (which is fine for this application, - // since it is cryptographically impossible for them to be equal. In the - // (cryptographically impossible) case that a prover accidentally derives - // a proof with equal c*p1 and s*p2, they should retry with a different - // proof nonce.) Assumes that all points are on secp256k1 - // (which is checked in verifyVRFProof below.) - function linearCombination( - uint256 c, uint256[2] memory p1, uint256[2] memory cp1Witness, - uint256 s, uint256[2] memory p2, uint256[2] memory sp2Witness, - uint256 zInv) - internal pure returns (uint256[2] memory) { - require((cp1Witness[0] - sp2Witness[0]) % FIELD_SIZE != 0, - "points in sum must be distinct"); - require(ecmulVerify(p1, c, cp1Witness), "First multiplication check failed"); - require(ecmulVerify(p2, s, sp2Witness), "Second multiplication check failed"); - return affineECAdd(cp1Witness, sp2Witness, zInv); - } - - // Domain-separation tag for the hash taken in scalarFromCurvePoints. - // Corresponds to scalarFromCurveHashPrefix in vrf.go - uint256 constant SCALAR_FROM_CURVE_POINTS_HASH_PREFIX = 2; - - // Pseudo-random number from inputs. Matches vrf.go/scalarFromCurvePoints, and - // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vrf-05#section-5.4.3 - // The draft calls (in step 7, via the definition of string_to_int, in - // https://datatracker.ietf.org/doc/html/rfc8017#section-4.2 ) for taking the - // first hash without checking that it corresponds to a number less than the - // group order, which will lead to a slight bias in the sample. - // - // TODO(alx): We could save a bit of gas by following the standard here and - // using the compressed representation of the points, if we collated the y - // parities into a single bytes32. - // https://www.pivotaltracker.com/story/show/171120588 - function scalarFromCurvePoints( - uint256[2] memory hash, uint256[2] memory pk, uint256[2] memory gamma, - address uWitness, uint256[2] memory v) - internal pure returns (uint256 s) { - return uint256( - keccak256(abi.encodePacked(SCALAR_FROM_CURVE_POINTS_HASH_PREFIX, - hash, pk, gamma, v, uWitness))); - } - - // True if (gamma, c, s) is a correctly constructed randomness proof from pk - // and seed. zInv must be the inverse of the third ordinate from - // projectiveECAdd applied to cGammaWitness and sHashWitness. Corresponds to - // section 5.3 of the IETF draft. - // - // TODO(alx): Since I'm only using pk in the ecrecover call, I could only pass - // the x ordinate, and the parity of the y ordinate in the top bit of uWitness - // (which I could make a uint256 without using any extra space.) Would save - // about 2000 gas. https://www.pivotaltracker.com/story/show/170828567 - function verifyVRFProof( - uint256[2] memory pk, uint256[2] memory gamma, uint256 c, uint256 s, - uint256 seed, address uWitness, uint256[2] memory cGammaWitness, - uint256[2] memory sHashWitness, uint256 zInv) - internal view { - require(isOnCurve(pk), "public key is not on curve"); - require(isOnCurve(gamma), "gamma is not on curve"); - require(isOnCurve(cGammaWitness), "cGammaWitness is not on curve"); - require(isOnCurve(sHashWitness), "sHashWitness is not on curve"); - // Step 5. of IETF draft section 5.3 (pk corresponds to 5.3's Y, and here - // we use the address of u instead of u itself. Also, here we add the - // terms instead of taking the difference, and in the proof consruction in - // vrf.GenerateProof, we correspondingly take the difference instead of - // taking the sum as they do in step 7 of section 5.1.) - require( - verifyLinearCombinationWithGenerator(c, pk, s, uWitness), - "addr(c*pk+s*g)≠_uWitness" - ); - // Step 4. of IETF draft section 5.3 (pk corresponds to Y, seed to alpha_string) - uint256[2] memory hash = hashToCurve(pk, seed); - // Step 6. of IETF draft section 5.3, but see note for step 5 about +/- terms - uint256[2] memory v = linearCombination( - c, gamma, cGammaWitness, s, hash, sHashWitness, zInv); - // Steps 7. and 8. of IETF draft section 5.3 - uint256 derivedC = scalarFromCurvePoints(hash, pk, gamma, uWitness, v); - require(c == derivedC, "invalid proof"); - } - - // Domain-separation tag for the hash used as the final VRF output. - // Corresponds to vrfRandomOutputHashPrefix in vrf.go - uint256 constant VRF_RANDOM_OUTPUT_HASH_PREFIX = 3; - - // Length of proof marshaled to bytes array. Shows layout of proof - uint public constant PROOF_LENGTH = 64 + // PublicKey (uncompressed format.) - 64 + // Gamma - 32 + // C - 32 + // S - 32 + // Seed - 0 + // Dummy entry: The following elements are included for gas efficiency: - 32 + // uWitness (gets padded to 256 bits, even though it's only 160) - 64 + // cGammaWitness - 64 + // sHashWitness - 32; // zInv (Leave Output out, because that can be efficiently calculated) - - /* *************************************************************************** - * @notice Returns proof's output, if proof is valid. Otherwise reverts - - * @param proof A binary-encoded proof, as output by vrf.Proof.MarshalForSolidityVerifier - * - * Throws if proof is invalid, otherwise: - * @return output i.e., the random output implied by the proof - * *************************************************************************** - * @dev See the calculation of PROOF_LENGTH for the binary layout of proof. - */ - function randomValueFromVRFProof(bytes memory proof) - internal view returns (uint256 output) { - require(proof.length == PROOF_LENGTH, "wrong proof length"); - - uint256[2] memory pk; // parse proof contents into these variables - uint256[2] memory gamma; - // c, s and seed combined (prevents "stack too deep" compilation error) - uint256[3] memory cSSeed; - address uWitness; - uint256[2] memory cGammaWitness; - uint256[2] memory sHashWitness; - uint256 zInv; - (pk, gamma, cSSeed, uWitness, cGammaWitness, sHashWitness, zInv) = abi.decode( - proof, (uint256[2], uint256[2], uint256[3], address, uint256[2], - uint256[2], uint256)); - verifyVRFProof( - pk, - gamma, - cSSeed[0], // c - cSSeed[1], // s - cSSeed[2], // seed - uWitness, - cGammaWitness, - sHashWitness, - zInv - ); - output = uint256(keccak256(abi.encode(VRF_RANDOM_OUTPUT_HASH_PREFIX, gamma))); - } -} diff --git a/contracts/src/v0.6/VRFConsumerBase.sol b/contracts/src/v0.6/VRFConsumerBase.sol deleted file mode 100644 index ca1c3811b3b..00000000000 --- a/contracts/src/v0.6/VRFConsumerBase.sol +++ /dev/null @@ -1,202 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import "./vendor/SafeMathChainlink.sol"; - -import "./interfaces/LinkTokenInterface.sol"; - -import "./VRFRequestIDBase.sol"; - -/** **************************************************************************** - * @notice Interface for contracts using VRF randomness - * ***************************************************************************** - * @dev PURPOSE - * - * @dev Reggie the Random Oracle (not his real job) wants to provide randomness - * @dev to Vera the verifier in such a way that Vera can be sure he's not - * @dev making his output up to suit himself. Reggie provides Vera a public key - * @dev to which he knows the secret key. Each time Vera provides a seed to - * @dev Reggie, he gives back a value which is computed completely - * @dev deterministically from the seed and the secret key. - * - * @dev Reggie provides a proof by which Vera can verify that the output was - * @dev correctly computed once Reggie tells it to her, but without that proof, - * @dev the output is indistinguishable to her from a uniform random sample - * @dev from the output space. - * - * @dev The purpose of this contract is to make it easy for unrelated contracts - * @dev to talk to Vera the verifier about the work Reggie is doing, to provide - * @dev simple access to a verifiable source of randomness. - * ***************************************************************************** - * @dev USAGE - * - * @dev Calling contracts must inherit from VRFConsumerBase, and can - * @dev initialize VRFConsumerBase's attributes in their constructor as - * @dev shown: - * - * @dev contract VRFConsumer { - * @dev constructor(, address _vrfCoordinator, address _link) - * @dev VRFConsumerBase(_vrfCoordinator, _link) public { - * @dev - * @dev } - * @dev } - * - * @dev The oracle will have given you an ID for the VRF keypair they have - * @dev committed to (let's call it keyHash), and have told you the minimum LINK - * @dev price for VRF service. Make sure your contract has sufficient LINK, and - * @dev call requestRandomness(keyHash, fee, seed), where seed is the input you - * @dev want to generate randomness from. - * - * @dev Once the VRFCoordinator has received and validated the oracle's response - * @dev to your request, it will call your contract's fulfillRandomness method. - * - * @dev The randomness argument to fulfillRandomness is the actual random value - * @dev generated from your seed. - * - * @dev The requestId argument is generated from the keyHash and the seed by - * @dev makeRequestId(keyHash, seed). If your contract could have concurrent - * @dev requests open, you can use the requestId to track which seed is - * @dev associated with which randomness. See VRFRequestIDBase.sol for more - * @dev details. (See "SECURITY CONSIDERATIONS" for principles to keep in mind, - * @dev if your contract could have multiple requests in flight simultaneously.) - * - * @dev Colliding `requestId`s are cryptographically impossible as long as seeds - * @dev differ. (Which is critical to making unpredictable randomness! See the - * @dev next section.) - * - * ***************************************************************************** - * @dev SECURITY CONSIDERATIONS - * - * @dev A method with the ability to call your fulfillRandomness method directly - * @dev could spoof a VRF response with any random value, so it's critical that - * @dev it cannot be directly called by anything other than this base contract - * @dev (specifically, by the VRFConsumerBase.rawFulfillRandomness method). - * - * @dev For your users to trust that your contract's random behavior is free - * @dev from malicious interference, it's best if you can write it so that all - * @dev behaviors implied by a VRF response are executed *during* your - * @dev fulfillRandomness method. If your contract must store the response (or - * @dev anything derived from it) and use it later, you must ensure that any - * @dev user-significant behavior which depends on that stored value cannot be - * @dev manipulated by a subsequent VRF request. - * - * @dev Similarly, both miners and the VRF oracle itself have some influence - * @dev over the order in which VRF responses appear on the blockchain, so if - * @dev your contract could have multiple VRF requests in flight simultaneously, - * @dev you must ensure that the order in which the VRF responses arrive cannot - * @dev be used to manipulate your contract's user-significant behavior. - * - * @dev Since the ultimate input to the VRF is mixed with the block hash of the - * @dev block in which the request is made, user-provided seeds have no impact - * @dev on its economic security properties. They are only included for API - * @dev compatability with previous versions of this contract. - * - * @dev Since the block hash of the block which contains the requestRandomness - * @dev call is mixed into the input to the VRF *last*, a sufficiently powerful - * @dev miner could, in principle, fork the blockchain to evict the block - * @dev containing the request, forcing the request to be included in a - * @dev different block with a different hash, and therefore a different input - * @dev to the VRF. However, such an attack would incur a substantial economic - * @dev cost. This cost scales with the number of blocks the VRF oracle waits - * @dev until it calls responds to a request. - */ -abstract contract VRFConsumerBase is VRFRequestIDBase { - - using SafeMathChainlink for uint256; - - /** - * @notice fulfillRandomness handles the VRF response. Your contract must - * @notice implement it. See "SECURITY CONSIDERATIONS" above for important - * @notice principles to keep in mind when implementing your fulfillRandomness - * @notice method. - * - * @dev VRFConsumerBase expects its subcontracts to have a method with this - * @dev signature, and will call it once it has verified the proof - * @dev associated with the randomness. (It is triggered via a call to - * @dev rawFulfillRandomness, below.) - * - * @param requestId The Id initially returned by requestRandomness - * @param randomness the VRF output - */ - function fulfillRandomness(bytes32 requestId, uint256 randomness) - internal virtual; - - /** - * @dev In order to keep backwards compatibility we have kept the user - * seed field around. We remove the use of it because given that the blockhash - * enters later, it overrides whatever randomness the used seed provides. - * Given that it adds no security, and can easily lead to misunderstandings, - * we have removed it from usage and can now provide a simpler API. - */ - uint256 constant private USER_SEED_PLACEHOLDER = 0; - - /** - * @notice requestRandomness initiates a request for VRF output given _seed - * - * @dev The fulfillRandomness method receives the output, once it's provided - * @dev by the Oracle, and verified by the vrfCoordinator. - * - * @dev The _keyHash must already be registered with the VRFCoordinator, and - * @dev the _fee must exceed the fee specified during registration of the - * @dev _keyHash. - * - * @dev The _seed parameter is vestigial, and is kept only for API - * @dev compatibility with older versions. It can't *hurt* to mix in some of - * @dev your own randomness, here, but it's not necessary because the VRF - * @dev oracle will mix the hash of the block containing your request into the - * @dev VRF seed it ultimately uses. - * - * @param _keyHash ID of public key against which randomness is generated - * @param _fee The amount of LINK to send with the request - * - * @return requestId unique ID for this request - * - * @dev The returned requestId can be used to distinguish responses to - * @dev concurrent requests. It is passed as the first argument to - * @dev fulfillRandomness. - */ - function requestRandomness(bytes32 _keyHash, uint256 _fee) - internal returns (bytes32 requestId) - { - LINK.transferAndCall(vrfCoordinator, _fee, abi.encode(_keyHash, USER_SEED_PLACEHOLDER)); - // This is the seed passed to VRFCoordinator. The oracle will mix this with - // the hash of the block containing this request to obtain the seed/input - // which is finally passed to the VRF cryptographic machinery. - uint256 vRFSeed = makeVRFInputSeed(_keyHash, USER_SEED_PLACEHOLDER, address(this), nonces[_keyHash]); - // nonces[_keyHash] must stay in sync with - // VRFCoordinator.nonces[_keyHash][this], which was incremented by the above - // successful LINK.transferAndCall (in VRFCoordinator.randomnessRequest). - // This provides protection against the user repeating their input seed, - // which would result in a predictable/duplicate output, if multiple such - // requests appeared in the same block. - nonces[_keyHash] = nonces[_keyHash].add(1); - return makeRequestId(_keyHash, vRFSeed); - } - - LinkTokenInterface immutable internal LINK; - address immutable private vrfCoordinator; - - // Nonces for each VRF key from which randomness has been requested. - // - // Must stay in sync with VRFCoordinator[_keyHash][this] - mapping(bytes32 /* keyHash */ => uint256 /* nonce */) private nonces; - - /** - * @param _vrfCoordinator address of VRFCoordinator contract - * @param _link address of LINK token contract - * - * @dev https://docs.chain.link/docs/link-token-contracts - */ - constructor(address _vrfCoordinator, address _link) public { - vrfCoordinator = _vrfCoordinator; - LINK = LinkTokenInterface(_link); - } - - // rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF - // proof. rawFulfillRandomness then calls fulfillRandomness, after validating - // the origin of the call - function rawFulfillRandomness(bytes32 requestId, uint256 randomness) external { - require(msg.sender == vrfCoordinator, "Only VRFCoordinator can fulfill"); - fulfillRandomness(requestId, randomness); - } -} diff --git a/contracts/src/v0.6/VRFCoordinator.sol b/contracts/src/v0.6/VRFCoordinator.sol deleted file mode 100644 index 9d1bcaf052a..00000000000 --- a/contracts/src/v0.6/VRFCoordinator.sol +++ /dev/null @@ -1,307 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.6.6; - -import "./vendor/SafeMathChainlink.sol"; - -import "./interfaces/LinkTokenInterface.sol"; -import "./interfaces/BlockHashStoreInterface.sol"; - -import "./vendor/Ownable.sol"; - -import "./VRF.sol"; -import "./VRFRequestIDBase.sol"; -import "./VRFConsumerBase.sol"; - -/** - * @title VRFCoordinator coordinates on-chain verifiable-randomness requests - * @title with off-chain responses - */ -contract VRFCoordinator is VRF, VRFRequestIDBase, Ownable { - - using SafeMathChainlink for uint256; - - LinkTokenInterface internal LINK; - BlockHashStoreInterface internal blockHashStore; - - constructor(address _link, address _blockHashStore) public { - LINK = LinkTokenInterface(_link); - blockHashStore = BlockHashStoreInterface(_blockHashStore); - } - - struct Callback { // Tracks an ongoing request - address callbackContract; // Requesting contract, which will receive response - // Amount of LINK paid at request time. Total LINK = 1e9 * 1e18 < 2^96, so - // this representation is adequate, and saves a word of storage when this - // field follows the 160-bit callbackContract address. - uint96 randomnessFee; - // Commitment to seed passed to oracle by this contract, and the number of - // the block in which the request appeared. This is the keccak256 of the - // concatenation of those values. Storing this commitment saves a word of - // storage. - bytes32 seedAndBlockNum; - } - - struct ServiceAgreement { // Tracks oracle commitments to VRF service - address vRFOracle; // Oracle committing to respond with VRF service - uint96 fee; // Minimum payment for oracle response. Total LINK=1e9*1e18<2^96 - bytes32 jobID; // ID of corresponding chainlink job in oracle's DB - } - - mapping(bytes32 /* (provingKey, seed) */ => Callback) public callbacks; - mapping(bytes32 /* provingKey */ => ServiceAgreement) - public serviceAgreements; - mapping(address /* oracle */ => uint256 /* LINK balance */) - public withdrawableTokens; - mapping(bytes32 /* provingKey */ => mapping(address /* consumer */ => uint256)) - private nonces; - - // The oracle only needs the jobID to look up the VRF, but specifying public - // key as well prevents a malicious oracle from inducing VRF outputs from - // another oracle by reusing the jobID. - event RandomnessRequest( - bytes32 keyHash, - uint256 seed, - bytes32 indexed jobID, - address sender, - uint256 fee, - bytes32 requestID); - - event NewServiceAgreement(bytes32 keyHash, uint256 fee); - - event RandomnessRequestFulfilled(bytes32 requestId, uint256 output); - - /** - * @notice Commits calling address to serve randomness - * @param _fee minimum LINK payment required to serve randomness - * @param _oracle the address of the Chainlink node with the proving key and job - * @param _publicProvingKey public key used to prove randomness - * @param _jobID ID of the corresponding chainlink job in the oracle's db - */ - function registerProvingKey( - uint256 _fee, address _oracle, uint256[2] calldata _publicProvingKey, bytes32 _jobID - ) - external - onlyOwner() - { - bytes32 keyHash = hashOfKey(_publicProvingKey); - address oldVRFOracle = serviceAgreements[keyHash].vRFOracle; - require(oldVRFOracle == address(0), "please register a new key"); - require(_oracle != address(0), "_oracle must not be 0x0"); - serviceAgreements[keyHash].vRFOracle = _oracle; - serviceAgreements[keyHash].jobID = _jobID; - // Yes, this revert message doesn't fit in a word - require(_fee <= 1e9 ether, - "you can't charge more than all the LINK in the world, greedy"); - serviceAgreements[keyHash].fee = uint96(_fee); - emit NewServiceAgreement(keyHash, _fee); - } - - /** - * @notice Called by LINK.transferAndCall, on successful LINK transfer - * - * @dev To invoke this, use the requestRandomness method in VRFConsumerBase. - * - * @dev The VRFCoordinator will call back to the calling contract when the - * @dev oracle responds, on the method fulfillRandomness. See - * @dev VRFConsumerBase.fulfilRandomness for its signature. Your consuming - * @dev contract should inherit from VRFConsumerBase, and implement - * @dev fulfilRandomness. - * - * @param _sender address: who sent the LINK (must be a contract) - * @param _fee amount of LINK sent - * @param _data abi-encoded call to randomnessRequest - */ - function onTokenTransfer(address _sender, uint256 _fee, bytes memory _data) - public - onlyLINK - { - (bytes32 keyHash, uint256 seed) = abi.decode(_data, (bytes32, uint256)); - randomnessRequest(keyHash, seed, _fee, _sender); - } - - /** - * @notice creates the chainlink request for randomness - * - * @param _keyHash ID of the VRF public key against which to generate output - * @param _consumerSeed Input to the VRF, from which randomness is generated - * @param _feePaid Amount of LINK sent with request. Must exceed fee for key - * @param _sender Requesting contract; to be called back with VRF output - * - * @dev _consumerSeed is mixed with key hash, sender address and nonce to - * @dev obtain preSeed, which is passed to VRF oracle, which mixes it with the - * @dev hash of the block containing this request, to compute the final seed. - * - * @dev The requestId used to store the request data is constructed from the - * @dev preSeed and keyHash. - */ - function randomnessRequest( - bytes32 _keyHash, - uint256 _consumerSeed, - uint256 _feePaid, - address _sender - ) - internal - sufficientLINK(_feePaid, _keyHash) - { - uint256 nonce = nonces[_keyHash][_sender]; - uint256 preSeed = makeVRFInputSeed(_keyHash, _consumerSeed, _sender, nonce); - bytes32 requestId = makeRequestId(_keyHash, preSeed); - // Cryptographically guaranteed by preSeed including an increasing nonce - assert(callbacks[requestId].callbackContract == address(0)); - callbacks[requestId].callbackContract = _sender; - assert(_feePaid < 1e27); // Total LINK fits in uint96 - callbacks[requestId].randomnessFee = uint96(_feePaid); - callbacks[requestId].seedAndBlockNum = keccak256(abi.encodePacked( - preSeed, block.number)); - emit RandomnessRequest(_keyHash, preSeed, serviceAgreements[_keyHash].jobID, - _sender, _feePaid, requestId); - nonces[_keyHash][_sender] = nonces[_keyHash][_sender].add(1); - } - - // Offsets into fulfillRandomnessRequest's _proof of various values - // - // Public key. Skips byte array's length prefix. - uint256 public constant PUBLIC_KEY_OFFSET = 0x20; - // Seed is 7th word in proof, plus word for length, (6+1)*0x20=0xe0 - uint256 public constant PRESEED_OFFSET = 0xe0; - - /** - * @notice Called by the chainlink node to fulfill requests - * - * @param _proof the proof of randomness. Actual random output built from this - * - * @dev The structure of _proof corresponds to vrf.MarshaledOnChainResponse, - * @dev in the node source code. I.e., it is a vrf.MarshaledProof with the - * @dev seed replaced by the preSeed, followed by the hash of the requesting - * @dev block. - */ - function fulfillRandomnessRequest(bytes memory _proof) public { - (bytes32 currentKeyHash, Callback memory callback, bytes32 requestId, - uint256 randomness) = getRandomnessFromProof(_proof); - - // Pay oracle - address oadd = serviceAgreements[currentKeyHash].vRFOracle; - withdrawableTokens[oadd] = withdrawableTokens[oadd].add( - callback.randomnessFee); - - // Forget request. Must precede callback (prevents reentrancy) - delete callbacks[requestId]; - callBackWithRandomness(requestId, randomness, callback.callbackContract); - - emit RandomnessRequestFulfilled(requestId, randomness); - } - - function callBackWithRandomness(bytes32 requestId, uint256 randomness, - address consumerContract) internal { - // Dummy variable; allows access to method selector in next line. See - // https://github.com/ethereum/solidity/issues/3506#issuecomment-553727797 - VRFConsumerBase v; - bytes memory resp = abi.encodeWithSelector( - v.rawFulfillRandomness.selector, requestId, randomness); - // The bound b here comes from https://eips.ethereum.org/EIPS/eip-150. The - // actual gas available to the consuming contract will be b-floor(b/64). - // This is chosen to leave the consuming contract ~200k gas, after the cost - // of the call itself. - uint256 b = 206000; - require(gasleft() >= b, "not enough gas for consumer"); - // A low-level call is necessary, here, because we don't want the consuming - // contract to be able to revert this execution, and thus deny the oracle - // payment for a valid randomness response. This also necessitates the above - // check on the gasleft, as otherwise there would be no indication if the - // callback method ran out of gas. - // - // solhint-disable-next-line avoid-low-level-calls - (bool success,) = consumerContract.call(resp); - // Avoid unused-local-variable warning. (success is only present to prevent - // a warning that the return value of consumerContract.call is unused.) - (success); - } - - function getRandomnessFromProof(bytes memory _proof) - internal view returns (bytes32 currentKeyHash, Callback memory callback, - bytes32 requestId, uint256 randomness) { - // blockNum follows proof, which follows length word (only direct-number - // constants are allowed in assembly, so have to compute this in code) - uint256 BLOCKNUM_OFFSET = 0x20 + PROOF_LENGTH; - // _proof.length skips the initial length word, so not including the - // blocknum in this length check balances out. - require(_proof.length == BLOCKNUM_OFFSET, "wrong proof length"); - uint256[2] memory publicKey; - uint256 preSeed; - uint256 blockNum; - assembly { // solhint-disable-line no-inline-assembly - publicKey := add(_proof, PUBLIC_KEY_OFFSET) - preSeed := mload(add(_proof, PRESEED_OFFSET)) - blockNum := mload(add(_proof, BLOCKNUM_OFFSET)) - } - currentKeyHash = hashOfKey(publicKey); - requestId = makeRequestId(currentKeyHash, preSeed); - callback = callbacks[requestId]; - require(callback.callbackContract != address(0), "no corresponding request"); - require(callback.seedAndBlockNum == keccak256(abi.encodePacked(preSeed, - blockNum)), "wrong preSeed or block num"); - - bytes32 blockHash = blockhash(blockNum); - if (blockHash == bytes32(0)) { - blockHash = blockHashStore.getBlockhash(blockNum); - require(blockHash != bytes32(0), "please prove blockhash"); - } - // The seed actually used by the VRF machinery, mixing in the blockhash - uint256 actualSeed = uint256(keccak256(abi.encodePacked(preSeed, blockHash))); - // solhint-disable-next-line no-inline-assembly - assembly { // Construct the actual proof from the remains of _proof - mstore(add(_proof, PRESEED_OFFSET), actualSeed) - mstore(_proof, PROOF_LENGTH) - } - randomness = VRF.randomValueFromVRFProof(_proof); // Reverts on failure - } - - /** - * @dev Allows the oracle operator to withdraw their LINK - * @param _recipient is the address the funds will be sent to - * @param _amount is the amount of LINK transferred from the Coordinator contract - */ - function withdraw(address _recipient, uint256 _amount) - external - hasAvailableFunds(_amount) - { - withdrawableTokens[msg.sender] = withdrawableTokens[msg.sender].sub(_amount); - assert(LINK.transfer(_recipient, _amount)); - } - - /** - * @notice Returns the serviceAgreements key associated with this public key - * @param _publicKey the key to return the address for - */ - function hashOfKey(uint256[2] memory _publicKey) public pure returns (bytes32) { - return keccak256(abi.encodePacked(_publicKey)); - } - - /** - * @dev Reverts if amount is not at least what was agreed upon in the service agreement - * @param _feePaid The payment for the request - * @param _keyHash The key which the request is for - */ - modifier sufficientLINK(uint256 _feePaid, bytes32 _keyHash) { - require(_feePaid >= serviceAgreements[_keyHash].fee, "Below agreed payment"); - _; - } - -/** - * @dev Reverts if not sent from the LINK token - */ - modifier onlyLINK() { - require(msg.sender == address(LINK), "Must use LINK token"); - _; - } - - /** - * @dev Reverts if amount requested is greater than withdrawable balance - * @param _amount The given amount to compare to `withdrawableTokens` - */ - modifier hasAvailableFunds(uint256 _amount) { - require(withdrawableTokens[msg.sender] >= _amount, "can't withdraw more than balance"); - _; - } - -} diff --git a/contracts/src/v0.6/VRFRequestIDBase.sol b/contracts/src/v0.6/VRFRequestIDBase.sol deleted file mode 100644 index 2668ead3200..00000000000 --- a/contracts/src/v0.6/VRFRequestIDBase.sol +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -contract VRFRequestIDBase { - - /** - * @notice returns the seed which is actually input to the VRF coordinator - * - * @dev To prevent repetition of VRF output due to repetition of the - * @dev user-supplied seed, that seed is combined in a hash with the - * @dev user-specific nonce, and the address of the consuming contract. The - * @dev risk of repetition is mostly mitigated by inclusion of a blockhash in - * @dev the final seed, but the nonce does protect against repetition in - * @dev requests which are included in a single block. - * - * @param _userSeed VRF seed input provided by user - * @param _requester Address of the requesting contract - * @param _nonce User-specific nonce at the time of the request - */ - function makeVRFInputSeed(bytes32 _keyHash, uint256 _userSeed, - address _requester, uint256 _nonce) - internal pure returns (uint256) - { - return uint256(keccak256(abi.encode(_keyHash, _userSeed, _requester, _nonce))); - } - - /** - * @notice Returns the id for this request - * @param _keyHash The serviceAgreement ID to be used for this request - * @param _vRFInputSeed The seed to be passed directly to the VRF - * @return The id for this request - * - * @dev Note that _vRFInputSeed is not the seed passed by the consuming - * @dev contract, but the one generated by makeVRFInputSeed - */ - function makeRequestId( - bytes32 _keyHash, uint256 _vRFInputSeed) internal pure returns (bytes32) { - return keccak256(abi.encodePacked(_keyHash, _vRFInputSeed)); - } -} diff --git a/contracts/src/v0.6/examples/VRFD20.sol b/contracts/src/v0.6/examples/VRFD20.sol deleted file mode 100644 index 0e4c041759c..00000000000 --- a/contracts/src/v0.6/examples/VRFD20.sol +++ /dev/null @@ -1,172 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.6.6; - -import "../VRFConsumerBase.sol"; -import "../Owned.sol"; - -/** - * @notice A Chainlink VRF consumer which uses randomness to mimic the rolling - * of a 20 sided die - * @dev This is only an example implementation and not necessarily suitable for mainnet. - */ -contract VRFD20 is VRFConsumerBase, Owned { - using SafeMathChainlink for uint256; - - uint256 private constant ROLL_IN_PROGRESS = 42; - - bytes32 private s_keyHash; - uint256 private s_fee; - mapping(bytes32 => address) private s_rollers; - mapping(address => uint256) private s_results; - - event DiceRolled(bytes32 indexed requestId, address indexed roller); - event DiceLanded(bytes32 indexed requestId, uint256 indexed result); - - /** - * @notice Constructor inherits VRFConsumerBase - * - * @dev NETWORK: KOVAN - * @dev Chainlink VRF Coordinator address: 0xdD3782915140c8f3b190B5D67eAc6dc5760C46E9 - * @dev LINK token address: 0xa36085F69e2889c224210F603D836748e7dC0088 - * @dev Key Hash: 0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4 - * @dev Fee: 0.1 LINK (100000000000000000) - * - * @param vrfCoordinator address of the VRF Coordinator - * @param link address of the LINK token - * @param keyHash bytes32 representing the hash of the VRF job - * @param fee uint256 fee to pay the VRF oracle - */ - constructor(address vrfCoordinator, address link, bytes32 keyHash, uint256 fee) - public - VRFConsumerBase(vrfCoordinator, link) - { - s_keyHash = keyHash; - s_fee = fee; - } - - /** - * @notice Requests randomness from a user-provided seed - * @dev Warning: if the VRF response is delayed, avoid calling requestRandomness repeatedly - * as that would give miners/VRF operators latitude about which VRF response arrives first. - * @dev You must review your implementation details with extreme care. - * - * @param roller address of the roller - */ - function rollDice(address roller) public onlyOwner returns (bytes32 requestId) { - require(LINK.balanceOf(address(this)) >= s_fee, "Not enough LINK to pay fee"); - require(s_results[roller] == 0, "Already rolled"); - requestId = requestRandomness(s_keyHash, s_fee); - s_rollers[requestId] = roller; - s_results[roller] = ROLL_IN_PROGRESS; - emit DiceRolled(requestId, roller); - } - - /** - * @notice Callback function used by VRF Coordinator to return the random number - * to this contract. - * @dev Some action on the contract state should be taken here, like storing the result. - * @dev WARNING: take care to avoid having multiple VRF requests in flight if their order of arrival would result - * in contract states with different outcomes. Otherwise miners or the VRF operator would could take advantage - * by controlling the order. - * @dev The VRF Coordinator will only send this function verified responses, and the parent VRFConsumerBase - * contract ensures that this method only receives randomness from the designated VRFCoordinator. - * - * @param requestId bytes32 - * @param randomness The random result returned by the oracle - */ - function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override { - uint256 d20Value = randomness.mod(20).add(1); - s_results[s_rollers[requestId]] = d20Value; - emit DiceLanded(requestId, d20Value); - } - - /** - * @notice Get the house assigned to the player once the address has rolled - * @param player address - * @return house as a string - */ - function house(address player) public view returns (string memory) { - require(s_results[player] != 0, "Dice not rolled"); - require(s_results[player] != ROLL_IN_PROGRESS, "Roll in progress"); - return getHouseName(s_results[player]); - } - - /** - * @notice Withdraw LINK from this contract. - * @dev this is an example only, and in a real contract withdrawals should - * happen according to the established withdrawal pattern: - * https://docs.soliditylang.org/en/v0.4.24/common-patterns.html#withdrawal-from-contracts - * @param to the address to withdraw LINK to - * @param value the amount of LINK to withdraw - */ - function withdrawLINK(address to, uint256 value) public onlyOwner { - require(LINK.transfer(to, value), "Not enough LINK"); - } - - /** - * @notice Set the key hash for the oracle - * - * @param keyHash bytes32 - */ - function setKeyHash(bytes32 keyHash) public onlyOwner { - s_keyHash = keyHash; - } - - /** - * @notice Get the current key hash - * - * @return bytes32 - */ - function keyHash() public view returns (bytes32) { - return s_keyHash; - } - - /** - * @notice Set the oracle fee for requesting randomness - * - * @param fee uint256 - */ - function setFee(uint256 fee) public onlyOwner { - s_fee = fee; - } - - /** - * @notice Get the current fee - * - * @return uint256 - */ - function fee() public view returns (uint256) { - return s_fee; - } - - /** - * @notice Get the house name from the id - * @param id uint256 - * @return house name string - */ - function getHouseName(uint256 id) private pure returns (string memory) { - string[20] memory houseNames = [ - "Targaryen", - "Lannister", - "Stark", - "Tyrell", - "Baratheon", - "Martell", - "Tully", - "Bolton", - "Greyjoy", - "Arryn", - "Frey", - "Mormont", - "Tarley", - "Dayne", - "Umber", - "Valeryon", - "Manderly", - "Clegane", - "Glover", - "Karstark" - ]; - return houseNames[id.sub(1)]; - } -} diff --git a/contracts/src/v0.6/interfaces/AccessControllerInterface.sol b/contracts/src/v0.6/interfaces/AccessControllerInterface.sol deleted file mode 100644 index 4bf48bb2aee..00000000000 --- a/contracts/src/v0.6/interfaces/AccessControllerInterface.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >0.6.0 <0.8.0; - -interface AccessControllerInterface { - function hasAccess(address user, bytes calldata data) external view returns (bool); -} diff --git a/contracts/src/v0.6/interfaces/AggregatorInterface.sol b/contracts/src/v0.6/interfaces/AggregatorInterface.sol deleted file mode 100644 index 4f48160b4ac..00000000000 --- a/contracts/src/v0.6/interfaces/AggregatorInterface.sol +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -interface AggregatorInterface { - function latestAnswer() - external - view - returns ( - int256 - ); - - function latestTimestamp() - external - view - returns ( - uint256 - ); - - function latestRound() - external - view - returns ( - uint256 - ); - - function getAnswer( - uint256 roundId - ) - external - view - returns ( - int256 - ); - - function getTimestamp( - uint256 roundId - ) - external - view - returns ( - uint256 - ); - - event AnswerUpdated( - int256 indexed current, - uint256 indexed roundId, - uint256 updatedAt - ); - - event NewRound( - uint256 indexed roundId, - address indexed startedBy, - uint256 startedAt - ); -} diff --git a/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol b/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol deleted file mode 100644 index 6b4975edf47..00000000000 --- a/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import "./AggregatorInterface.sol"; -import "./AggregatorV3Interface.sol"; - -interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface -{ -} diff --git a/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol b/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol deleted file mode 100644 index a1af9924ca4..00000000000 --- a/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -interface AggregatorV3Interface { - - function decimals() - external - view - returns ( - uint8 - ); - - function description() - external - view - returns ( - string memory - ); - - function version() - external - view - returns ( - uint256 - ); - - function getRoundData( - uint80 _roundId - ) - external - view - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - - function latestRoundData() - external - view - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - -} diff --git a/contracts/src/v0.6/interfaces/AggregatorValidatorInterface.sol b/contracts/src/v0.6/interfaces/AggregatorValidatorInterface.sol deleted file mode 100644 index 50c3226f6d8..00000000000 --- a/contracts/src/v0.6/interfaces/AggregatorValidatorInterface.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -interface AggregatorValidatorInterface { - function validate( - uint256 previousRoundId, - int256 previousAnswer, - uint256 currentRoundId, - int256 currentAnswer - ) external returns (bool); -} diff --git a/contracts/src/v0.6/interfaces/BlockHashStoreInterface.sol b/contracts/src/v0.6/interfaces/BlockHashStoreInterface.sol deleted file mode 100644 index 18927e64eed..00000000000 --- a/contracts/src/v0.6/interfaces/BlockHashStoreInterface.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.6.6; - -interface BlockHashStoreInterface { - function getBlockhash(uint256 number) external view returns (bytes32); -} diff --git a/contracts/src/v0.6/interfaces/ChainlinkRequestInterface.sol b/contracts/src/v0.6/interfaces/ChainlinkRequestInterface.sol deleted file mode 100644 index bcbd2511901..00000000000 --- a/contracts/src/v0.6/interfaces/ChainlinkRequestInterface.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -interface ChainlinkRequestInterface { - function oracleRequest( - address sender, - uint256 requestPrice, - bytes32 serviceAgreementID, - address callbackAddress, - bytes4 callbackFunctionId, - uint256 nonce, - uint256 dataVersion, - bytes calldata data - ) external; - - function cancelOracleRequest( - bytes32 requestId, - uint256 payment, - bytes4 callbackFunctionId, - uint256 expiration - ) external; -} diff --git a/contracts/src/v0.6/interfaces/ENSInterface.sol b/contracts/src/v0.6/interfaces/ENSInterface.sol deleted file mode 100644 index 158242cd0d5..00000000000 --- a/contracts/src/v0.6/interfaces/ENSInterface.sol +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -interface ENSInterface { - - // Logged when the owner of a node assigns a new owner to a subnode. - event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner); - - // Logged when the owner of a node transfers ownership to a new account. - event Transfer(bytes32 indexed node, address owner); - - // Logged when the resolver for a node changes. - event NewResolver(bytes32 indexed node, address resolver); - - // Logged when the TTL of a node changes - event NewTTL(bytes32 indexed node, uint64 ttl); - - - function setSubnodeOwner(bytes32 node, bytes32 label, address _owner) external; - function setResolver(bytes32 node, address _resolver) external; - function setOwner(bytes32 node, address _owner) external; - function setTTL(bytes32 node, uint64 _ttl) external; - function owner(bytes32 node) external view returns (address); - function resolver(bytes32 node) external view returns (address); - function ttl(bytes32 node) external view returns (uint64); - -} diff --git a/contracts/src/v0.6/interfaces/FeedRegistryInterface.sol b/contracts/src/v0.6/interfaces/FeedRegistryInterface.sol deleted file mode 100644 index 0eb2d1d6bd8..00000000000 --- a/contracts/src/v0.6/interfaces/FeedRegistryInterface.sol +++ /dev/null @@ -1,298 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; -pragma experimental ABIEncoderV2; - -import "./AggregatorV2V3Interface.sol"; - -interface FeedRegistryInterface { - struct Phase { - uint16 phaseId; - uint80 startingAggregatorRoundId; - uint80 endingAggregatorRoundId; - } - - event FeedProposed( - address indexed asset, - address indexed denomination, - address indexed proposedAggregator, - address currentAggregator, - address sender - ); - event FeedConfirmed( - address indexed asset, - address indexed denomination, - address indexed latestAggregator, - address previousAggregator, - uint16 nextPhaseId, - address sender - ); - - // V3 AggregatorV3Interface - - function decimals( - address base, - address quote - ) - external - view - returns ( - uint8 - ); - - function description( - address base, - address quote - ) - external - view - returns ( - string memory - ); - - function version( - address base, - address quote - ) - external - view - returns ( - uint256 - ); - - function latestRoundData( - address base, - address quote - ) - external - view - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - - function getRoundData( - address base, - address quote, - uint80 _roundId - ) - external - view - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - - // V2 AggregatorInterface - - function latestAnswer( - address base, - address quote - ) - external - view - returns ( - int256 answer - ); - - function latestTimestamp( - address base, - address quote - ) - external - view - returns ( - uint256 timestamp - ); - - function latestRound( - address base, - address quote - ) - external - view - returns ( - uint256 roundId - ); - - function getAnswer( - address base, - address quote, - uint256 roundId - ) - external - view - returns ( - int256 answer - ); - - function getTimestamp( - address base, - address quote, - uint256 roundId - ) - external - view - returns ( - uint256 timestamp - ); - - // Registry getters - - function getFeed( - address base, - address quote - ) - external - view - returns ( - AggregatorV2V3Interface aggregator - ); - - function getPhaseFeed( - address base, - address quote, - uint16 phaseId - ) - external - view - returns ( - AggregatorV2V3Interface aggregator - ); - - function isFeedEnabled( - address aggregator - ) - external - view - returns ( - bool - ); - - function getPhase( - address base, - address quote, - uint16 phaseId - ) - external - view - returns ( - Phase memory phase - ); - - // Round helpers - - function getRoundFeed( - address base, - address quote, - uint80 roundId - ) - external - view - returns ( - AggregatorV2V3Interface aggregator - ); - - function getPhaseRange( - address base, - address quote, - uint16 phaseId - ) - external - view - returns ( - uint80 startingRoundId, - uint80 endingRoundId - ); - - function getPreviousRoundId( - address base, - address quote, - uint80 roundId - ) external - view - returns ( - uint80 previousRoundId - ); - - function getNextRoundId( - address base, - address quote, - uint80 roundId - ) external - view - returns ( - uint80 nextRoundId - ); - - // Feed management - - function proposeFeed( - address base, - address quote, - address aggregator - ) external; - - function confirmFeed( - address base, - address quote, - address aggregator - ) external; - - // Proposed aggregator - - function getProposedFeed( - address base, - address quote - ) - external - view - returns ( - AggregatorV2V3Interface proposedAggregator - ); - - function proposedGetRoundData( - address base, - address quote, - uint80 roundId - ) - external - view - returns ( - uint80 id, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - - function proposedLatestRoundData( - address base, - address quote - ) - external - view - returns ( - uint80 id, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - - // Phases - function getCurrentPhaseId( - address base, - address quote - ) - external - view - returns ( - uint16 currentPhaseId - ); -} diff --git a/contracts/src/v0.6/interfaces/FlagsInterface.sol b/contracts/src/v0.6/interfaces/FlagsInterface.sol deleted file mode 100644 index ad39cae3a62..00000000000 --- a/contracts/src/v0.6/interfaces/FlagsInterface.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -interface FlagsInterface { - function getFlag(address) external view returns (bool); - function getFlags(address[] calldata) external view returns (bool[] memory); - function raiseFlag(address) external; - function raiseFlags(address[] calldata) external; - function lowerFlags(address[] calldata) external; - function setRaisingAccessController(address) external; -} diff --git a/contracts/src/v0.6/interfaces/KeeperCompatibleInterface.sol b/contracts/src/v0.6/interfaces/KeeperCompatibleInterface.sol deleted file mode 100644 index f092fc9ef40..00000000000 --- a/contracts/src/v0.6/interfaces/KeeperCompatibleInterface.sol +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -interface KeeperCompatibleInterface { - - /** - * @notice method that is simulated by the keepers to see if any work actually - * needs to be performed. This method does does not actually need to be - * executable, and since it is only ever simulated it can consume lots of gas. - * @dev To ensure that it is never called, you may want to add the - * cannotExecute modifier from KeeperBase to your implementation of this - * method. - * @param checkData specified in the upkeep registration so it is always the - * same for a registered upkeep. This can easily be broken down into specific - * arguments using `abi.decode`, so multiple upkeeps can be registered on the - * same contract and easily differentiated by the contract. - * @return upkeepNeeded boolean to indicate whether the keeper should call - * performUpkeep or not. - * @return performData bytes that the keeper should call performUpkeep with, if - * upkeep is needed. If you would like to encode data to decode later, try - * `abi.encode`. - */ - function checkUpkeep( - bytes calldata checkData - ) - external - returns ( - bool upkeepNeeded, - bytes memory performData - ); - - /** - * @notice method that is actually executed by the keepers, via the registry. - * The data returned by the checkUpkeep simulation will be passed into - * this method to actually be executed. - * @dev The input to this method should not be trusted, and the caller of the - * method should not even be restricted to any single registry. Anyone should - * be able call it, and the input should be validated, there is no guarantee - * that the data passed in is the performData returned from checkUpkeep. This - * could happen due to malicious keepers, racing keepers, or simply a state - * change while the performUpkeep transaction is waiting for confirmation. - * Always validate the data passed in. - * @param performData is the data which was passed back from the checkData - * simulation. If it is encoded, it can easily be decoded into other types by - * calling `abi.decode`. This data should not be trusted, and should be - * validated against the contract's current state. - */ - function performUpkeep( - bytes calldata performData - ) external; -} diff --git a/contracts/src/v0.6/interfaces/LinkTokenInterface.sol b/contracts/src/v0.6/interfaces/LinkTokenInterface.sol deleted file mode 100644 index eeb944411f7..00000000000 --- a/contracts/src/v0.6/interfaces/LinkTokenInterface.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -interface LinkTokenInterface { - function allowance(address owner, address spender) external view returns (uint256 remaining); - function approve(address spender, uint256 value) external returns (bool success); - function balanceOf(address owner) external view returns (uint256 balance); - function decimals() external view returns (uint8 decimalPlaces); - function decreaseApproval(address spender, uint256 addedValue) external returns (bool success); - function increaseApproval(address spender, uint256 subtractedValue) external; - function name() external view returns (string memory tokenName); - function symbol() external view returns (string memory tokenSymbol); - function totalSupply() external view returns (uint256 totalTokensIssued); - function transfer(address to, uint256 value) external returns (bool success); - function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool success); - function transferFrom(address from, address to, uint256 value) external returns (bool success); -} diff --git a/contracts/src/v0.6/interfaces/OracleInterface.sol b/contracts/src/v0.6/interfaces/OracleInterface.sol deleted file mode 100644 index 96b49f0341d..00000000000 --- a/contracts/src/v0.6/interfaces/OracleInterface.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -interface OracleInterface { - function fulfillOracleRequest( - bytes32 requestId, - uint256 payment, - address callbackAddress, - bytes4 callbackFunctionId, - uint256 expiration, - bytes32 data - ) external returns (bool); - function getAuthorizationStatus(address node) external view returns (bool); - function setFulfillmentPermission(address node, bool allowed) external; - function withdraw(address recipient, uint256 amount) external; - function withdrawable() external view returns (uint256); -} diff --git a/contracts/src/v0.6/interfaces/PointerInterface.sol b/contracts/src/v0.6/interfaces/PointerInterface.sol deleted file mode 100644 index e1cac19dfea..00000000000 --- a/contracts/src/v0.6/interfaces/PointerInterface.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -interface PointerInterface { - function getAddress() external view returns (address); -} diff --git a/contracts/src/v0.6/interfaces/WithdrawalInterface.sol b/contracts/src/v0.6/interfaces/WithdrawalInterface.sol deleted file mode 100644 index e83d3273fe8..00000000000 --- a/contracts/src/v0.6/interfaces/WithdrawalInterface.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -interface WithdrawalInterface { - /** - * @notice transfer LINK held by the contract belonging to msg.sender to - * another address - * @param recipient is the address to send the LINK to - * @param amount is the amount of LINK to send - */ - function withdraw(address recipient, uint256 amount) external; - - /** - * @notice query the available amount of LINK to withdraw by msg.sender - */ - function withdrawable() external view returns (uint256); -} diff --git a/contracts/src/v0.6/tests/AggregatorValidatorMock.sol b/contracts/src/v0.6/tests/AggregatorValidatorMock.sol deleted file mode 100644 index 7af4717c688..00000000000 --- a/contracts/src/v0.6/tests/AggregatorValidatorMock.sol +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.6.6; - -import "../interfaces/AggregatorValidatorInterface.sol"; - -contract AggregatorValidatorMock is AggregatorValidatorInterface { - uint256 public previousRoundId; - int256 public previousAnswer; - uint256 public currentRoundId; - int256 public currentAnswer; - - event Validated( - uint256 _previousRoundId, - int256 indexed _previousAnswer, - uint256 _currentRoundId, - int256 indexed _currentAnswer - ); - - function validate( - uint256 _previousRoundId, - int256 _previousAnswer, - uint256 _currentRoundId, - int256 _currentAnswer - ) - external - override - returns (bool) - { - emit Validated( - _previousRoundId, - _previousAnswer, - _currentRoundId, - _currentAnswer - ); - return true; - } - -} diff --git a/contracts/src/v0.6/tests/BasicConsumer.sol b/contracts/src/v0.6/tests/BasicConsumer.sol deleted file mode 100644 index f657fb0bdc5..00000000000 --- a/contracts/src/v0.6/tests/BasicConsumer.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import "./Consumer.sol"; - -contract BasicConsumer is Consumer { - - constructor(address _link, address _oracle, bytes32 _specId) public { - setChainlinkToken(_link); - setChainlinkOracle(_oracle); - specId = _specId; - } - -} diff --git a/contracts/src/v0.6/tests/BlockhashStoreTestHelper.sol b/contracts/src/v0.6/tests/BlockhashStoreTestHelper.sol deleted file mode 100644 index 895962547da..00000000000 --- a/contracts/src/v0.6/tests/BlockhashStoreTestHelper.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.6.6; - -import "../BlockhashStore.sol"; - -contract BlockhashStoreTestHelper is BlockhashStore { - function godmodeSetHash(uint256 n, bytes32 h) public { - s_blockhashes[n] = h; - } -} diff --git a/contracts/src/v0.6/tests/ChainlinkClientTestHelper.sol b/contracts/src/v0.6/tests/ChainlinkClientTestHelper.sol deleted file mode 100644 index 2a390dc56c0..00000000000 --- a/contracts/src/v0.6/tests/ChainlinkClientTestHelper.sol +++ /dev/null @@ -1,120 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import "../ChainlinkClient.sol"; -import "../vendor/SafeMathChainlink.sol"; - -contract ChainlinkClientTestHelper is ChainlinkClient { - using SafeMathChainlink for uint256; - - constructor( - address _link, - address _oracle - ) public { - setChainlinkToken(_link); - setChainlinkOracle(_oracle); - } - - event Request( - bytes32 id, - address callbackAddress, - bytes4 callbackfunctionSelector, - bytes data - ); - event LinkAmount( - uint256 amount - ); - - function publicNewRequest( - bytes32 _id, - address _address, - bytes memory _fulfillmentSignature - ) - public - { - Chainlink.Request memory req = buildChainlinkRequest( - _id, _address, bytes4(keccak256(_fulfillmentSignature))); - emit Request( - req.id, - req.callbackAddress, - req.callbackFunctionId, - req.buf.buf - ); - } - - function publicRequest( - bytes32 _id, - address _address, - bytes memory _fulfillmentSignature, - uint256 _wei - ) - public - { - Chainlink.Request memory req = buildChainlinkRequest( - _id, _address, bytes4(keccak256(_fulfillmentSignature))); - sendChainlinkRequest(req, _wei); - } - - function publicRequestRunTo( - address _oracle, - bytes32 _id, - address _address, - bytes memory _fulfillmentSignature, - uint256 _wei - ) - public - { - Chainlink.Request memory run = buildChainlinkRequest(_id, _address, bytes4(keccak256(_fulfillmentSignature))); - sendChainlinkRequestTo(_oracle, run, _wei); - } - - function publicCancelRequest( - bytes32 _requestId, - uint256 _payment, - bytes4 _callbackFunctionId, - uint256 _expiration - ) public { - cancelChainlinkRequest(_requestId, _payment, _callbackFunctionId, _expiration); - } - - function publicChainlinkToken() public view returns (address) { - return chainlinkTokenAddress(); - } - - function publicFulfillChainlinkRequest(bytes32 _requestId, bytes32) public { - fulfillRequest(_requestId, bytes32(0)); - } - - function fulfillRequest(bytes32 _requestId, bytes32) - public - { - validateChainlinkCallback(_requestId); - } - - function publicLINK( - uint256 _amount - ) - public - { - emit LinkAmount(LINK.mul(_amount)); - } - - function publicOracleAddress() - public - view - returns ( - address - ) - { - return chainlinkOracleAddress(); - } - - function publicAddExternalRequest( - address _oracle, - bytes32 _requestId - ) - public - { - addChainlinkExternalRequest(_oracle, _requestId); - } -} diff --git a/contracts/src/v0.6/tests/ChainlinkTestHelper.sol b/contracts/src/v0.6/tests/ChainlinkTestHelper.sol deleted file mode 100644 index 09b46a97657..00000000000 --- a/contracts/src/v0.6/tests/ChainlinkTestHelper.sol +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import "../Chainlink.sol"; -import "../vendor/CBORChainlink.sol"; -import "../vendor/BufferChainlink.sol"; - -contract ChainlinkTestHelper { - using Chainlink for Chainlink.Request; - using CBORChainlink for BufferChainlink.buffer; - - Chainlink.Request private req; - - event RequestData(bytes payload); - - function closeEvent() public { - emit RequestData(req.buf.buf); - } - - function setBuffer(bytes memory data) public { - Chainlink.Request memory r2 = req; - r2.setBuffer(data); - req = r2; - } - - function add(string memory _key, string memory _value) public { - Chainlink.Request memory r2 = req; - r2.add(_key, _value); - req = r2; - } - - function addBytes(string memory _key, bytes memory _value) public { - Chainlink.Request memory r2 = req; - r2.addBytes(_key, _value); - req = r2; - } - - function addInt(string memory _key, int256 _value) public { - Chainlink.Request memory r2 = req; - r2.addInt(_key, _value); - req = r2; - } - - function addUint(string memory _key, uint256 _value) public { - Chainlink.Request memory r2 = req; - r2.addUint(_key, _value); - req = r2; - } - - // Temporarily have method receive bytes32[] memory until experimental - // string[] memory can be invoked from truffle tests. - function addStringArray(string memory _key, bytes32[] memory _values) public { - string[] memory strings = new string[](_values.length); - for (uint256 i = 0; i < _values.length; i++) { - strings[i] = bytes32ToString(_values[i]); - } - Chainlink.Request memory r2 = req; - r2.addStringArray(_key, strings); - req = r2; - } - - function bytes32ToString(bytes32 x) private pure returns (string memory) { - bytes memory bytesString = new bytes(32); - uint charCount = 0; - for (uint j = 0; j < 32; j++) { - byte char = byte(bytes32(uint(x) * 2 ** (8 * j))); - if (char != 0) { - bytesString[charCount] = char; - charCount++; - } - } - bytes memory bytesStringTrimmed = new bytes(charCount); - for (uint j = 0; j < charCount; j++) { - bytesStringTrimmed[j] = bytesString[j]; - } - return string(bytesStringTrimmed); - } -} diff --git a/contracts/src/v0.6/tests/CheckedMathTestHelper.sol b/contracts/src/v0.6/tests/CheckedMathTestHelper.sol deleted file mode 100644 index 1306c53d8e4..00000000000 --- a/contracts/src/v0.6/tests/CheckedMathTestHelper.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import "../CheckedMath.sol"; - -contract CheckedMathTestHelper { - using CheckedMath for int256; - - function add(int256 a, int256 b) - external - pure - returns (int256 result, bool ok) - { - return a.add(b); - } - - function sub(int256 a, int256 b) - external - pure - returns (int256 result, bool ok) - { - return a.sub(b); - } - - function mul(int256 a, int256 b) - external - pure - returns (int256 result, bool ok) - { - return a.mul(b); - } - - function div(int256 a, int256 b) - external - pure - returns (int256 result, bool ok) - { - return a.div(b); - } - -} diff --git a/contracts/src/v0.6/tests/ConcreteSignedSafeMath.sol b/contracts/src/v0.6/tests/ConcreteSignedSafeMath.sol deleted file mode 100644 index 14be54685b5..00000000000 --- a/contracts/src/v0.6/tests/ConcreteSignedSafeMath.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import "../SignedSafeMath.sol"; - -contract ConcreteSignedSafeMath { - function testAdd(int256 _a, int256 _b) - external - pure - returns (int256) - { - return SignedSafeMath.add(_a, _b); - } - - function testAvg(int256 _a, int256 _b) - external - pure - returns (int256) - { - return SignedSafeMath.avg(_a, _b); - } -} diff --git a/contracts/src/v0.6/tests/EmptyOracle.sol b/contracts/src/v0.6/tests/EmptyOracle.sol deleted file mode 100644 index f076d129926..00000000000 --- a/contracts/src/v0.6/tests/EmptyOracle.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import "../interfaces/ChainlinkRequestInterface.sol"; -import "../interfaces/OracleInterface.sol"; - -/* solhint-disable no-empty-blocks */ - -contract EmptyOracle is ChainlinkRequestInterface, OracleInterface { - - function cancelOracleRequest(bytes32, uint256, bytes4, uint256) external override {} - function fulfillOracleRequest(bytes32, uint256, address, bytes4, uint256, bytes32) external override returns (bool) {} - function getAuthorizationStatus(address) external override view returns (bool) { return false; } - function onTokenTransfer(address, uint256, bytes calldata) external pure {} - function oracleRequest(address, uint256, bytes32, address, bytes4, uint256, uint256, bytes calldata) external override {} - function setFulfillmentPermission(address, bool) external override {} - function withdraw(address, uint256) external override {} - function withdrawable() external override view returns (uint256) {} - -} diff --git a/contracts/src/v0.6/tests/FlagsTestHelper.sol b/contracts/src/v0.6/tests/FlagsTestHelper.sol deleted file mode 100644 index 0ed37b6e965..00000000000 --- a/contracts/src/v0.6/tests/FlagsTestHelper.sol +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import "../Flags.sol"; - -contract FlagsTestHelper { - Flags public flags; - - constructor( - address flagsContract - ) - public - { - flags = Flags(flagsContract); - } - - function getFlag( - address subject - ) - external - view - returns(bool) - { - return flags.getFlag(subject); - } - - function getFlags( - address[] calldata subjects - ) - external - view - returns(bool[] memory) - { - return flags.getFlags(subjects); - } - -} diff --git a/contracts/src/v0.6/tests/FluxAggregatorTestHelper.sol b/contracts/src/v0.6/tests/FluxAggregatorTestHelper.sol deleted file mode 100644 index 24af37f4992..00000000000 --- a/contracts/src/v0.6/tests/FluxAggregatorTestHelper.sol +++ /dev/null @@ -1,71 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import "../FluxAggregator.sol"; - -contract FluxAggregatorTestHelper { - - uint80 public requestedRoundId; - - function readOracleRoundState(address _aggregator, address _oracle) - external - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - FluxAggregator(_aggregator).oracleRoundState(_oracle, 0); - } - - function readGetRoundData(address _aggregator, uint80 _roundID) - external - { - FluxAggregator(_aggregator).getRoundData(_roundID); - } - - function readLatestRoundData(address _aggregator) - external - { - FluxAggregator(_aggregator).latestRoundData(); - } - - function readLatestAnswer(address _aggregator) - external - { - FluxAggregator(_aggregator).latestAnswer(); - } - - function readLatestTimestamp(address _aggregator) - external - { - FluxAggregator(_aggregator).latestTimestamp(); - } - - function readLatestRound(address _aggregator) - external - { - FluxAggregator(_aggregator).latestRound(); - } - - function requestNewRound(address _aggregator) - external - { - requestedRoundId = FluxAggregator(_aggregator).requestNewRound(); - } - - function readGetAnswer(address _aggregator, uint256 _roundID) - external - { - FluxAggregator(_aggregator).getAnswer(_roundID); - } - - function readGetTimestamp(address _aggregator, uint256 _roundID) - external - { - FluxAggregator(_aggregator).getTimestamp(_roundID); - } - -} diff --git a/contracts/src/v0.6/tests/GasGuzzler.sol b/contracts/src/v0.6/tests/GasGuzzler.sol deleted file mode 100644 index 5b30f1bef52..00000000000 --- a/contracts/src/v0.6/tests/GasGuzzler.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.6.6; - -contract GasGuzzler { - fallback() external payable { - while (true) { - } - } -} - diff --git a/contracts/src/v0.6/tests/GasGuzzlingConsumer.sol b/contracts/src/v0.6/tests/GasGuzzlingConsumer.sol deleted file mode 100644 index 8122f45dbab..00000000000 --- a/contracts/src/v0.6/tests/GasGuzzlingConsumer.sol +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import "./Consumer.sol"; - -contract GasGuzzlingConsumer is Consumer{ - - constructor(address _link, address _oracle, bytes32 _specId) public { - setChainlinkToken(_link); - setChainlinkOracle(_oracle); - specId = _specId; - } - - function gassyRequestEthereumPrice(uint256 _payment) public { - Chainlink.Request memory req = buildChainlinkRequest(specId, address(this), this.gassyFulfill.selector); - req.add("get", "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD,EUR,JPY"); - string[] memory path = new string[](1); - path[0] = "USD"; - req.addStringArray("path", path); - sendChainlinkRequest(req, _payment); - } - - function gassyFulfill(bytes32 _requestId, bytes32 _price) - public - recordChainlinkFulfillment(_requestId) - { - while(true){ - } - } - - function gassyMultiWordRequest(uint256 _payment) public { - Chainlink.Request memory req = buildChainlinkRequest(specId, address(this), this.gassyMultiWordFulfill.selector); - req.add("get", "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD,EUR,JPY"); - string[] memory path = new string[](1); - path[0] = "USD"; - req.addStringArray("path", path); - sendChainlinkRequest(req, _payment); - } - - function gassyMultiWordFulfill(bytes32 _requestId, bytes memory _price) - public - recordChainlinkFulfillment(_requestId) - { - while(true){ - } - } -} \ No newline at end of file diff --git a/contracts/src/v0.6/tests/KeeperCompatibleTestHelper.sol b/contracts/src/v0.6/tests/KeeperCompatibleTestHelper.sol deleted file mode 100644 index 5c760bfaeff..00000000000 --- a/contracts/src/v0.6/tests/KeeperCompatibleTestHelper.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import "../KeeperCompatible.sol"; - -contract KeeperCompatibleTestHelper is KeeperCompatible { - function checkUpkeep(bytes calldata) external override returns (bool, bytes memory) {} - - function performUpkeep(bytes calldata) external override {} - - function verifyCannotExecute() public view cannotExecute {} -} diff --git a/contracts/src/v0.6/tests/MedianTestHelper.sol b/contracts/src/v0.6/tests/MedianTestHelper.sol deleted file mode 100644 index 5386790f02f..00000000000 --- a/contracts/src/v0.6/tests/MedianTestHelper.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import "../Median.sol"; - -contract MedianTestHelper { - function publicGet(int256[] memory list) - public - pure - returns (int256) - { - return Median.calculate(list); - } - - function publicQuickselectTwo(int256[] memory list, uint256 k1, uint256 k2) - public - pure - returns (int256, int256) - { - return Median.quickselectTwo(list, 0, list.length - 1, k1, k2); - } -} diff --git a/contracts/src/v0.6/tests/MockETHLINKAggregator.sol b/contracts/src/v0.6/tests/MockETHLINKAggregator.sol deleted file mode 100644 index 70cd9a76bfd..00000000000 --- a/contracts/src/v0.6/tests/MockETHLINKAggregator.sol +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import "../interfaces/AggregatorV3Interface.sol"; - -contract MockETHLINKAggregator is AggregatorV3Interface { - int256 public answer; - - constructor(int256 _answer) public { - answer = _answer; - } - - function decimals() external view override returns (uint8) { - return 18; - } - - function description() external view override returns (string memory) { - return "MockETHLINKAggregator"; - } - - function version() external view override returns (uint256) { - return 1; - } - - function getRoundData(uint80 _roundId) - external - view - override - returns ( - uint80 roundId, - int256 ans, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - return (1, answer, block.timestamp, block.timestamp, 1); - } - - function latestRoundData() - external - view - override - returns ( - uint80 roundId, - int256 ans, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - return (1, answer, block.timestamp, block.timestamp, 1); - } -} diff --git a/contracts/src/v0.6/tests/MockGASAggregator.sol b/contracts/src/v0.6/tests/MockGASAggregator.sol deleted file mode 100644 index 271e79e1e21..00000000000 --- a/contracts/src/v0.6/tests/MockGASAggregator.sol +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import "../interfaces/AggregatorV3Interface.sol"; - -contract MockGASAggregator is AggregatorV3Interface { - int256 public answer; - constructor (int256 _answer) public { - answer = _answer; - } - function decimals() external override view returns (uint8) { - return 18; - } - function description() external override view returns (string memory) { - return "MockGASAggregator"; - } - function version() external override view returns (uint256) { - return 1; - } - function getRoundData(uint80 _roundId) external override view returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) { - return (1, answer, block.timestamp, block.timestamp, 1); - } - function latestRoundData() external override view returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) { - return (1, answer, block.timestamp, block.timestamp, 1); - } -} \ No newline at end of file diff --git a/contracts/src/v0.6/tests/MockOracle.sol b/contracts/src/v0.6/tests/MockOracle.sol deleted file mode 100644 index 7c86d29dc28..00000000000 --- a/contracts/src/v0.6/tests/MockOracle.sol +++ /dev/null @@ -1,204 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import "../LinkTokenReceiver.sol"; -import "../interfaces/ChainlinkRequestInterface.sol"; -import "../interfaces/LinkTokenInterface.sol"; -import "../vendor/SafeMathChainlink.sol"; - -/** - * @title The Chainlink Mock Oracle contract - * @notice Chainlink smart contract developers can use this to test their contracts - */ -contract MockOracle is ChainlinkRequestInterface, LinkTokenReceiver { - using SafeMathChainlink for uint256; - - uint256 constant public EXPIRY_TIME = 5 minutes; - uint256 constant private MINIMUM_CONSUMER_GAS_LIMIT = 400000; - - struct Request { - address callbackAddr; - bytes4 callbackFunctionId; - } - - LinkTokenInterface internal LinkToken; - mapping(bytes32 => Request) private commitments; - - event OracleRequest( - bytes32 indexed specId, - address requester, - bytes32 requestId, - uint256 payment, - address callbackAddr, - bytes4 callbackFunctionId, - uint256 cancelExpiration, - uint256 dataVersion, - bytes data - ); - - event CancelOracleRequest( - bytes32 indexed requestId - ); - - /** - * @notice Deploy with the address of the LINK token - * @dev Sets the LinkToken address for the imported LinkTokenInterface - * @param _link The address of the LINK token - */ - constructor( - address _link - ) - public - { - LinkToken = LinkTokenInterface(_link); // external but already deployed and unalterable - } - - /** - * @notice Creates the Chainlink request - * @dev Stores the hash of the params as the on-chain commitment for the request. - * Emits OracleRequest event for the Chainlink node to detect. - * @param _sender The sender of the request - * @param _payment The amount of payment given (specified in wei) - * @param _specId The Job Specification ID - * @param _callbackAddress The callback address for the response - * @param _callbackFunctionId The callback function ID for the response - * @param _nonce The nonce sent by the requester - * @param _dataVersion The specified data version - * @param _data The CBOR payload of the request - */ - function oracleRequest( - address _sender, - uint256 _payment, - bytes32 _specId, - address _callbackAddress, - bytes4 _callbackFunctionId, - uint256 _nonce, - uint256 _dataVersion, - bytes calldata _data - ) - external - override - onlyLINK() - checkCallbackAddress(_callbackAddress) - { - bytes32 requestId = keccak256(abi.encodePacked(_sender, _nonce)); - require(commitments[requestId].callbackAddr == address(0), "Must use a unique ID"); - // solhint-disable-next-line not-rely-on-time - uint256 expiration = now.add(EXPIRY_TIME); - - commitments[requestId] = Request( - _callbackAddress, - _callbackFunctionId - ); - - emit OracleRequest( - _specId, - _sender, - requestId, - _payment, - _callbackAddress, - _callbackFunctionId, - expiration, - _dataVersion, - _data); - } - - /** - * @notice Called by the Chainlink node to fulfill requests - * @dev Given params must hash back to the commitment stored from `oracleRequest`. - * Will call the callback address' callback function without bubbling up error - * checking in a `require` so that the node can get paid. - * @param _requestId The fulfillment request ID that must match the requester's - * @param _data The data to return to the consuming contract - * @return Status if the external call was successful - */ - function fulfillOracleRequest( - bytes32 _requestId, - bytes32 _data - ) - external - isValidRequest(_requestId) - returns ( - bool - ) - { - Request memory req = commitments[_requestId]; - delete commitments[_requestId]; - require(gasleft() >= MINIMUM_CONSUMER_GAS_LIMIT, "Must provide consumer enough gas"); - // All updates to the oracle's fulfillment should come before calling the - // callback(addr+functionId) as it is untrusted. - // See: https://solidity.readthedocs.io/en/develop/security-considerations.html#use-the-checks-effects-interactions-pattern - (bool success, ) = req.callbackAddr.call(abi.encodeWithSelector(req.callbackFunctionId, _requestId, _data)); // solhint-disable-line avoid-low-level-calls - return success; - } - - /** - * @notice Allows requesters to cancel requests sent to this oracle contract. Will transfer the LINK - * sent for the request back to the requester's address. - * @dev Given params must hash to a commitment stored on the contract in order for the request to be valid - * Emits CancelOracleRequest event. - * @param _requestId The request ID - * @param _payment The amount of payment given (specified in wei) - * @param _expiration The time of the expiration for the request - */ - function cancelOracleRequest( - bytes32 _requestId, - uint256 _payment, - bytes4, - uint256 _expiration - ) - external - override - { - require(commitments[_requestId].callbackAddr != address(0), "Must use a unique ID"); - // solhint-disable-next-line not-rely-on-time - require(_expiration <= now, "Request is not expired"); - - delete commitments[_requestId]; - emit CancelOracleRequest(_requestId); - - assert(LinkToken.transfer(msg.sender, _payment)); - } - - /** - * @notice Returns the address of the LINK token - * @dev This is the public implementation for chainlinkTokenAddress, which is - * an internal method of the ChainlinkClient contract - */ - function getChainlinkToken() - public - view - override - returns ( - address - ) - { - return address(LinkToken); - } - - // MODIFIERS - - /** - * @dev Reverts if request ID does not exist - * @param _requestId The given request ID to check in stored `commitments` - */ - modifier isValidRequest( - bytes32 _requestId - ) { - require(commitments[_requestId].callbackAddr != address(0), "Must have a valid requestId"); - _; - } - - - /** - * @dev Reverts if the callback address is the LINK token - * @param _to The callback address - */ - modifier checkCallbackAddress( - address _to - ) { - require(_to != address(LinkToken), "Cannot callback to LINK"); - _; - } - -} diff --git a/contracts/src/v0.6/tests/MockV3Aggregator.sol b/contracts/src/v0.6/tests/MockV3Aggregator.sol deleted file mode 100644 index b382281ea7c..00000000000 --- a/contracts/src/v0.6/tests/MockV3Aggregator.sol +++ /dev/null @@ -1,109 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import "../interfaces/AggregatorV2V3Interface.sol"; - -/** - * @title MockV3Aggregator - * @notice Based on the FluxAggregator contract - * @notice Use this contract when you need to test - * other contract's ability to read data from an - * aggregator contract, but how the aggregator got - * its answer is unimportant - */ -contract MockV3Aggregator is AggregatorV2V3Interface { - uint256 constant public override version = 0; - - uint8 public override decimals; - int256 public override latestAnswer; - uint256 public override latestTimestamp; - uint256 public override latestRound; - - mapping(uint256 => int256) public override getAnswer; - mapping(uint256 => uint256) public override getTimestamp; - mapping(uint256 => uint256) private getStartedAt; - - constructor( - uint8 _decimals, - int256 _initialAnswer - ) public { - decimals = _decimals; - updateAnswer(_initialAnswer); - } - - function updateAnswer( - int256 _answer - ) public { - latestAnswer = _answer; - latestTimestamp = block.timestamp; - latestRound++; - getAnswer[latestRound] = _answer; - getTimestamp[latestRound] = block.timestamp; - getStartedAt[latestRound] = block.timestamp; - } - - function updateRoundData( - uint80 _roundId, - int256 _answer, - uint256 _timestamp, - uint256 _startedAt - ) public { - latestRound = _roundId; - latestAnswer = _answer; - latestTimestamp = _timestamp; - getAnswer[latestRound] = _answer; - getTimestamp[latestRound] = _timestamp; - getStartedAt[latestRound] = _startedAt; - } - - function getRoundData(uint80 _roundId) - external - view - override - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - return ( - _roundId, - getAnswer[_roundId], - getStartedAt[_roundId], - getTimestamp[_roundId], - _roundId - ); - } - - function latestRoundData() - external - view - override - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - return ( - uint80(latestRound), - getAnswer[latestRound], - getStartedAt[latestRound], - getTimestamp[latestRound], - uint80(latestRound) - ); - } - - function description() - external - view - override - returns (string memory) - { - return "v0.6/tests/MockV3Aggregator.sol"; - } -} \ No newline at end of file diff --git a/contracts/src/v0.6/tests/MultiWordConsumer.sol b/contracts/src/v0.6/tests/MultiWordConsumer.sol deleted file mode 100644 index a2ff5d4080e..00000000000 --- a/contracts/src/v0.6/tests/MultiWordConsumer.sol +++ /dev/null @@ -1,88 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import "../ChainlinkClient.sol"; - -contract MultiWordConsumer is ChainlinkClient{ - bytes32 internal specId; - bytes public currentPrice; - - bytes32 public first; - bytes32 public second; - - event RequestFulfilled( - bytes32 indexed requestId, // User-defined ID - bytes indexed price - ); - - event RequestMultipleFulfilled( - bytes32 indexed requestId, - bytes32 indexed first, - bytes32 indexed second - ); - - constructor(address _link, address _oracle, bytes32 _specId) public { - setChainlinkToken(_link); - setChainlinkOracle(_oracle); - specId = _specId; - } - - function requestEthereumPrice(string memory _currency, uint256 _payment) public { - requestEthereumPriceByCallback(_currency, _payment, address(this)); - } - - function requestEthereumPriceByCallback(string memory _currency, uint256 _payment, address _callback) public { - Chainlink.Request memory req = buildChainlinkRequest(specId, _callback, this.fulfillBytes.selector); - req.add("get", "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD,EUR,JPY"); - string[] memory path = new string[](1); - path[0] = _currency; - req.addStringArray("path", path); - sendChainlinkRequest(req, _payment); - } - - function requestMultipleParameters(string memory _currency, uint256 _payment) public { - Chainlink.Request memory req = buildChainlinkRequest(specId, address(this), this.fulfillMultipleParameters.selector); - req.add("get", "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD,EUR,JPY"); - string[] memory path = new string[](1); - path[0] = _currency; - req.addStringArray("path", path); - sendChainlinkRequest(req, _payment); - } - - function cancelRequest( - address _oracle, - bytes32 _requestId, - uint256 _payment, - bytes4 _callbackFunctionId, - uint256 _expiration - ) public { - ChainlinkRequestInterface requested = ChainlinkRequestInterface(_oracle); - requested.cancelOracleRequest(_requestId, _payment, _callbackFunctionId, _expiration); - } - - function withdrawLink() public { - LinkTokenInterface _link = LinkTokenInterface(chainlinkTokenAddress()); - require(_link.transfer(msg.sender, _link.balanceOf(address(this))), "Unable to transfer"); - } - - function addExternalRequest(address _oracle, bytes32 _requestId) external { - addChainlinkExternalRequest(_oracle, _requestId); - } - - function fulfillMultipleParameters(bytes32 _requestId, bytes32 _first, bytes32 _second) - public - recordChainlinkFulfillment(_requestId) - { - emit RequestMultipleFulfilled(_requestId, _first, _second); - first = _first; - second = _second; - } - - function fulfillBytes(bytes32 _requestId, bytes memory _price) - public - recordChainlinkFulfillment(_requestId) - { - emit RequestFulfilled(_requestId, _price); - currentPrice = _price; - } -} \ No newline at end of file diff --git a/contracts/src/v0.6/tests/Reverter.sol b/contracts/src/v0.6/tests/Reverter.sol deleted file mode 100644 index a262fbe5592..00000000000 --- a/contracts/src/v0.6/tests/Reverter.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.6.6; - -contract Reverter { - - fallback() external payable { - require(false, "Raised by Reverter.sol"); - } - -} diff --git a/contracts/src/v0.6/tests/TestAPIConsumer.sol b/contracts/src/v0.6/tests/TestAPIConsumer.sol deleted file mode 100644 index e16e6916206..00000000000 --- a/contracts/src/v0.6/tests/TestAPIConsumer.sol +++ /dev/null @@ -1,123 +0,0 @@ -/** This example code is designed to quickly deploy an example contract using Remix. - * If you have never used Remix, try our example walkthrough: https://docs.chain.link/docs/example-walkthrough - * You will need testnet ETH and LINK. - * - Kovan ETH faucet: https://faucet.kovan.network/ - * - Kovan LINK faucet: https://kovan.chain.link/ - */ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -import "../interfaces/LinkTokenInterface.sol"; -import "../ChainlinkClient.sol"; -import "../vendor/Ownable.sol"; - -/** - * @title TestAPIConsumer is an example contract which requests data from - * the Chainlink network - * @dev This contract is designed to work on multiple networks, including - * local test networks - */ -contract TestAPIConsumer is ChainlinkClient, Ownable { - uint256 public currentRoundID = 0; - uint256 public data; - bytes4 public selector; - - event PerfMetricsEvent(uint256 roundID, bytes32 requestId, uint256 timestamp); - - - /** - * @notice Deploy the contract with a specified address for the LINK - * and Oracle contract addresses - * @dev Sets the storage for the specified addresses - * @param _link The address of the LINK token contract - */ - constructor(address _link) public { - if (_link == address(0)) { - setPublicChainlinkToken(); - } else { - setChainlinkToken(_link); - } - } - - /** - * @notice Returns the address of the LINK token - * @dev This is the public implementation for chainlinkTokenAddress, which is - * an internal method of the ChainlinkClient contract - */ - function getChainlinkToken() public view returns (address) { - return chainlinkTokenAddress(); - } - - /** - * @notice Creates a request to the specified Oracle contract address - * @dev This function ignores the stored Oracle contract address and - * will instead send the request to the address specified - * @param _oracle The Oracle contract address to send the request to - * @param _jobId The bytes32 JobID to be executed - * @param _url The URL to fetch data from - * @param _path The dot-delimited path to parse of the response - * @param _times The number to multiply the result by - */ - function createRequestTo( - address _oracle, - bytes32 _jobId, - uint256 _payment, - string memory _url, - string memory _path, - int256 _times - ) - public - onlyOwner - returns (bytes32 requestId) - { - selector = this.fulfill.selector; - Chainlink.Request memory req = buildChainlinkRequest(_jobId, address(this), this.fulfill.selector); - req.add("get", _url); - req.add("path", _path); - req.addInt("times", _times); - requestId = sendChainlinkRequestTo(_oracle, req, _payment); - } - - /** - * @notice The fulfill method from requests created by this contract - * @dev The recordChainlinkFulfillment protects this function from being called - * by anyone other than the oracle address that the request was sent to - * @param _requestId The ID that was generated for the request - * @param _data The answer provided by the oracle - */ - function fulfill(bytes32 _requestId, uint256 _data) - public - { - data = _data; - currentRoundID += 1; - emit PerfMetricsEvent(currentRoundID, _requestId, block.timestamp); - } - - /** - * @notice Allows the owner to withdraw any LINK balance on the contract - */ - function withdrawLink() public onlyOwner { - LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress()); - require(link.transfer(msg.sender, link.balanceOf(address(this))), "Unable to transfer"); - } - - /** - * @notice Call this method if no response is received within 5 minutes - * @param _requestId The ID that was generated for the request to cancel - * @param _payment The payment specified for the request to cancel - * @param _callbackFunctionId The bytes4 callback function ID specified for - * the request to cancel - * @param _expiration The expiration generated for the request to cancel - */ - function cancelRequest( - bytes32 _requestId, - uint256 _payment, - bytes4 _callbackFunctionId, - uint256 _expiration - ) - public - onlyOwner - { - cancelChainlinkRequest(_requestId, _payment, _callbackFunctionId, _expiration); - } -} diff --git a/contracts/src/v0.6/tests/VRFConsumer.sol b/contracts/src/v0.6/tests/VRFConsumer.sol deleted file mode 100644 index ff0a09fb8c9..00000000000 --- a/contracts/src/v0.6/tests/VRFConsumer.sol +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.6.6; - -import "../interfaces/LinkTokenInterface.sol"; -import "../VRFCoordinator.sol"; -import "../VRFConsumerBase.sol"; - -contract VRFConsumer is VRFConsumerBase { - - uint256 public currentRoundID = 0; - uint256 public randomnessOutput; - bytes32 public requestId; - - constructor(address _vrfCoordinator, address _link) public - // solhint-disable-next-line no-empty-blocks - VRFConsumerBase(_vrfCoordinator, _link) { /* empty */ } - - function fulfillRandomness(bytes32 _requestId, uint256 _randomness) - internal override - { - randomnessOutput = _randomness; - requestId = _requestId; - currentRoundID += 1; - } - - function testRequestRandomness(bytes32 _keyHash, uint256 _fee) - external returns (bytes32 requestId) - { - return requestRandomness(_keyHash, _fee); - } -} diff --git a/contracts/src/v0.6/tests/VRFCoordinatorMock.sol b/contracts/src/v0.6/tests/VRFCoordinatorMock.sol deleted file mode 100644 index dd8b8063bf1..00000000000 --- a/contracts/src/v0.6/tests/VRFCoordinatorMock.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.6.6; - -import "../interfaces/LinkTokenInterface.sol"; -import "../VRFConsumerBase.sol"; - -contract VRFCoordinatorMock { - - LinkTokenInterface public LINK; - - event RandomnessRequest(address indexed sender, bytes32 indexed keyHash, uint256 indexed seed); - - constructor(address linkAddress) public { - LINK = LinkTokenInterface(linkAddress); - } - - function onTokenTransfer(address sender, uint256 fee, bytes memory _data) - public - onlyLINK - { - (bytes32 keyHash, uint256 seed) = abi.decode(_data, (bytes32, uint256)); - emit RandomnessRequest(sender, keyHash, seed); - } - - function callBackWithRandomness( - bytes32 requestId, - uint256 randomness, - address consumerContract - ) public { - VRFConsumerBase v; - bytes memory resp = abi.encodeWithSelector(v.rawFulfillRandomness.selector, requestId, randomness); - uint256 b = 206000; - require(gasleft() >= b, "not enough gas for consumer"); - (bool success,) = consumerContract.call(resp); - } - - modifier onlyLINK() { - require(msg.sender == address(LINK), "Must use LINK token"); - _; - } -} \ No newline at end of file diff --git a/contracts/src/v0.6/tests/VRFRequestIDBaseTestHelper.sol b/contracts/src/v0.6/tests/VRFRequestIDBaseTestHelper.sol deleted file mode 100644 index f1b81f210ed..00000000000 --- a/contracts/src/v0.6/tests/VRFRequestIDBaseTestHelper.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.6.6; - -import "../VRFRequestIDBase.sol"; - -contract VRFRequestIDBaseTestHelper is VRFRequestIDBase { - - function makeVRFInputSeed_(bytes32 _keyHash, uint256 _userSeed, - address _requester, uint256 _nonce) - public pure returns (uint256) { - return makeVRFInputSeed(_keyHash, _userSeed, _requester, _nonce); - } - - function makeRequestId_( - bytes32 _keyHash, uint256 _vRFInputSeed) public pure returns (bytes32) { - return makeRequestId(_keyHash, _vRFInputSeed); - } -} diff --git a/contracts/src/v0.6/tests/VRFTestHelper.sol b/contracts/src/v0.6/tests/VRFTestHelper.sol deleted file mode 100644 index d79e71dce1b..00000000000 --- a/contracts/src/v0.6/tests/VRFTestHelper.sol +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.6.6; - -import "../VRF.sol"; - -/** *********************************************************************** - @notice Testing harness for VRF.sol, exposing its internal methods. Not to - @notice be used for production. -*/ -contract VRFTestHelper is VRF { - function bigModExp_(uint256 base, uint256 exponent) public view returns (uint256) { - return super.bigModExp(base, exponent); - } - function squareRoot_(uint256 x) public view returns (uint256) { - return super.squareRoot(x); - } - function ySquared_(uint256 x) public pure returns (uint256) { - return super.ySquared(x); - } - function fieldHash_(bytes memory b) public pure returns (uint256) { - return super.fieldHash(b); - } - function hashToCurve_(uint256[2] memory pk, uint256 x) public view returns(uint256[2] memory) { - return super.hashToCurve(pk, x); - } - function ecmulVerify_(uint256[2] memory x, uint256 scalar, uint256[2] memory q) public pure returns (bool) { - return super.ecmulVerify(x, scalar, q); - } - function projectiveECAdd_(uint256 px, uint256 py, uint256 qx, uint256 qy) public pure returns(uint256, uint256, uint256) { - return super.projectiveECAdd(px, py, qx, qy); - } - function affineECAdd_(uint256[2] memory p1, uint256[2] memory p2, uint256 invZ) public pure returns (uint256[2] memory) { - return super.affineECAdd(p1, p2, invZ); - } - function verifyLinearCombinationWithGenerator_(uint256 c, uint256[2] memory p, uint256 s, address lcWitness) public pure returns (bool) { - return super.verifyLinearCombinationWithGenerator(c, p, s, lcWitness); - } - function linearCombination_(uint256 c, uint256[2] memory p1, uint256[2] memory cp1Witness, uint256 s, uint256[2] memory p2, uint256[2] memory sp2Witness, uint256 zInv) public pure returns (uint256[2] memory) { - return super.linearCombination(c, p1, cp1Witness, s, p2, sp2Witness, zInv); - } - function scalarFromCurvePoints_(uint256[2] memory hash, uint256[2] memory pk, uint256[2] memory gamma, address uWitness, uint256[2] memory v) public pure returns (uint256) { - return super.scalarFromCurvePoints(hash, pk, gamma, uWitness, v); - } - function verifyVRFProof_( - uint256[2] memory pk, uint256[2] memory gamma, uint256 c, uint256 s, - uint256 seed, address uWitness, uint256[2] memory cGammaWitness, - uint256[2] memory sHashWitness, uint256 zInv) - public view { - super.verifyVRFProof(pk, gamma, c, s, seed, uWitness, cGammaWitness, sHashWitness, zInv); - } - function randomValueFromVRFProof_(bytes memory proof) - public view returns (uint256 output) { - return super.randomValueFromVRFProof(proof); - } -} diff --git a/contracts/src/v0.6/vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol b/contracts/src/v0.6/vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol deleted file mode 100644 index fb48f360814..00000000000 --- a/contracts/src/v0.6/vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2021-2022, Offchain Labs, Inc. -// For license information, see https://github.com/nitro/blob/master/LICENSE -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity >=0.4.21 <0.9.0; - -/** - * @title System level functionality - * @notice For use by contracts to interact with core L2-specific functionality. - * Precompiled contract that exists in every Arbitrum chain at address(100), 0x0000000000000000000000000000000000000064. - */ -interface ArbSys { - /** - * @notice Get Arbitrum block number (distinct from L1 block number; Arbitrum genesis block has block number 0) - * @return block number as int - */ - function arbBlockNumber() external view returns (uint256); - - /** - * @notice Get Arbitrum block hash (reverts unless currentBlockNum-256 <= arbBlockNum < currentBlockNum) - * @return block hash - */ - function arbBlockHash(uint256 arbBlockNum) external view returns (bytes32); - - /** - * @notice Gets the rollup's unique chain identifier - * @return Chain identifier as int - */ - function arbChainID() external view returns (uint256); - - /** - * @notice Get internal version number identifying an ArbOS build - * @return version number as int - */ - function arbOSVersion() external view returns (uint256); - - /** - * @notice Returns 0 since Nitro has no concept of storage gas - * @return uint 0 - */ - function getStorageGasAvailable() external view returns (uint256); - - /** - * @notice (deprecated) check if current call is top level (meaning it was triggered by an EoA or a L1 contract) - * @dev this call has been deprecated and may be removed in a future release - * @return true if current execution frame is not a call by another L2 contract - */ - function isTopLevelCall() external view returns (bool); - - /** - * @notice map L1 sender contract address to its L2 alias - * @param sender sender address - * @param unused argument no longer used - * @return aliased sender address - */ - function mapL1SenderContractAddressToL2Alias(address sender, address unused) - external - pure - returns (address); - - /** - * @notice check if the caller (of this caller of this) is an aliased L1 contract address - * @return true iff the caller's address is an alias for an L1 contract address - */ - function wasMyCallersAddressAliased() external view returns (bool); - - /** - * @notice return the address of the caller (of this caller of this), without applying L1 contract address aliasing - * @return address of the caller's caller, without applying L1 contract address aliasing - */ - function myCallersAddressWithoutAliasing() external view returns (address); - - /** - * @notice Send given amount of Eth to dest from sender. - * This is a convenience function, which is equivalent to calling sendTxToL1 with empty data. - * @param destination recipient address on L1 - * @return unique identifier for this L2-to-L1 transaction. - */ - function withdrawEth(address destination) - external - payable - returns (uint256); - - /** - * @notice Send a transaction to L1 - * @dev it is not possible to execute on the L1 any L2-to-L1 transaction which contains data - * to a contract address without any code (as enforced by the Bridge contract). - * @param destination recipient address on L1 - * @param data (optional) calldata for L1 contract call - * @return a unique identifier for this L2-to-L1 transaction. - */ - function sendTxToL1(address destination, bytes calldata data) - external - payable - returns (uint256); - - /** - * @notice Get send Merkle tree state - * @return size number of sends in the history - * @return root root hash of the send history - * @return partials hashes of partial subtrees in the send history tree - */ - function sendMerkleTreeState() - external - view - returns ( - uint256 size, - bytes32 root, - bytes32[] memory partials - ); - - /** - * @notice creates a send txn from L2 to L1 - * @param position = (level << 192) + leaf = (0 << 192) + leaf = leaf - */ - event L2ToL1Tx( - address caller, - address indexed destination, - uint256 indexed hash, - uint256 indexed position, - uint256 arbBlockNum, - uint256 ethBlockNum, - uint256 timestamp, - uint256 callvalue, - bytes data - ); - - /// @dev DEPRECATED in favour of the new L2ToL1Tx event above after the nitro upgrade - event L2ToL1Transaction( - address caller, - address indexed destination, - uint256 indexed uniqueId, - uint256 indexed batchNumber, - uint256 indexInBatch, - uint256 arbBlockNum, - uint256 ethBlockNum, - uint256 timestamp, - uint256 callvalue, - bytes data - ); - - /** - * @notice logs a merkle branch for proof synthesis - * @param reserved an index meant only to align the 4th index with L2ToL1Transaction's 4th event - * @param hash the merkle hash - * @param position = (level << 192) + leaf - */ - event SendMerkleUpdate( - uint256 indexed reserved, - bytes32 indexed hash, - uint256 indexed position - ); -} diff --git a/contracts/src/v0.6/vendor/BufferChainlink.sol b/contracts/src/v0.6/vendor/BufferChainlink.sol deleted file mode 100644 index 2ef5342b6f0..00000000000 --- a/contracts/src/v0.6/vendor/BufferChainlink.sol +++ /dev/null @@ -1,302 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -/** -* @dev A library for working with mutable byte buffers in Solidity. -* -* Byte buffers are mutable and expandable, and provide a variety of primitives -* for writing to them. At any time you can fetch a bytes object containing the -* current contents of the buffer. The bytes object should not be stored between -* operations, as it may change due to resizing of the buffer. -*/ -library BufferChainlink { - /** - * @dev Represents a mutable buffer. Buffers have a current value (buf) and - * a capacity. The capacity may be longer than the current value, in - * which case it can be extended without the need to allocate more memory. - */ - struct buffer { - bytes buf; - uint capacity; - } - - /** - * @dev Initializes a buffer with an initial capacity. - * @param buf The buffer to initialize. - * @param capacity The number of bytes of space to allocate the buffer. - * @return The buffer, for chaining. - */ - function init(buffer memory buf, uint capacity) internal pure returns(buffer memory) { - if (capacity % 32 != 0) { - capacity += 32 - (capacity % 32); - } - // Allocate space for the buffer data - buf.capacity = capacity; - assembly { - let ptr := mload(0x40) - mstore(buf, ptr) - mstore(ptr, 0) - mstore(0x40, add(32, add(ptr, capacity))) - } - return buf; - } - - /** - * @dev Initializes a new buffer from an existing bytes object. - * Changes to the buffer may mutate the original value. - * @param b The bytes object to initialize the buffer with. - * @return A new buffer. - */ - function fromBytes(bytes memory b) internal pure returns(buffer memory) { - buffer memory buf; - buf.buf = b; - buf.capacity = b.length; - return buf; - } - - function resize(buffer memory buf, uint capacity) private pure { - bytes memory oldbuf = buf.buf; - init(buf, capacity); - append(buf, oldbuf); - } - - function max(uint a, uint b) private pure returns(uint) { - if (a > b) { - return a; - } - return b; - } - - /** - * @dev Sets buffer length to 0. - * @param buf The buffer to truncate. - * @return The original buffer, for chaining.. - */ - function truncate(buffer memory buf) internal pure returns (buffer memory) { - assembly { - let bufptr := mload(buf) - mstore(bufptr, 0) - } - return buf; - } - - /** - * @dev Writes a byte string to a buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param off The start offset to write to. - * @param data The data to append. - * @param len The number of bytes to copy. - * @return The original buffer, for chaining. - */ - function write(buffer memory buf, uint off, bytes memory data, uint len) internal pure returns(buffer memory) { - require(len <= data.length); - - if (off + len > buf.capacity) { - resize(buf, max(buf.capacity, len + off) * 2); - } - - uint dest; - uint src; - assembly { - // Memory address of the buffer data - let bufptr := mload(buf) - // Length of existing buffer data - let buflen := mload(bufptr) - // Start address = buffer address + offset + sizeof(buffer length) - dest := add(add(bufptr, 32), off) - // Update buffer length if we're extending it - if gt(add(len, off), buflen) { - mstore(bufptr, add(len, off)) - } - src := add(data, 32) - } - - // Copy word-length chunks while possible - for (; len >= 32; len -= 32) { - assembly { - mstore(dest, mload(src)) - } - dest += 32; - src += 32; - } - - // Copy remaining bytes - uint mask = 256 ** (32 - len) - 1; - assembly { - let srcpart := and(mload(src), not(mask)) - let destpart := and(mload(dest), mask) - mstore(dest, or(destpart, srcpart)) - } - - return buf; - } - - /** - * @dev Appends a byte string to a buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @param len The number of bytes to copy. - * @return The original buffer, for chaining. - */ - function append(buffer memory buf, bytes memory data, uint len) internal pure returns (buffer memory) { - return write(buf, buf.buf.length, data, len); - } - - /** - * @dev Appends a byte string to a buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer, for chaining. - */ - function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) { - return write(buf, buf.buf.length, data, data.length); - } - - /** - * @dev Writes a byte to the buffer. Resizes if doing so would exceed the - * capacity of the buffer. - * @param buf The buffer to append to. - * @param off The offset to write the byte at. - * @param data The data to append. - * @return The original buffer, for chaining. - */ - function writeUint8(buffer memory buf, uint off, uint8 data) internal pure returns(buffer memory) { - if (off >= buf.capacity) { - resize(buf, buf.capacity * 2); - } - - assembly { - // Memory address of the buffer data - let bufptr := mload(buf) - // Length of existing buffer data - let buflen := mload(bufptr) - // Address = buffer address + sizeof(buffer length) + off - let dest := add(add(bufptr, off), 32) - mstore8(dest, data) - // Update buffer length if we extended it - if eq(off, buflen) { - mstore(bufptr, add(buflen, 1)) - } - } - return buf; - } - - /** - * @dev Appends a byte to the buffer. Resizes if doing so would exceed the - * capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer, for chaining. - */ - function appendUint8(buffer memory buf, uint8 data) internal pure returns(buffer memory) { - return writeUint8(buf, buf.buf.length, data); - } - - /** - * @dev Writes up to 32 bytes to the buffer. Resizes if doing so would - * exceed the capacity of the buffer. - * @param buf The buffer to append to. - * @param off The offset to write at. - * @param data The data to append. - * @param len The number of bytes to write (left-aligned). - * @return The original buffer, for chaining. - */ - function write(buffer memory buf, uint off, bytes32 data, uint len) private pure returns(buffer memory) { - if (len + off > buf.capacity) { - resize(buf, (len + off) * 2); - } - - uint mask = 256 ** len - 1; - // Right-align data - data = data >> (8 * (32 - len)); - assembly { - // Memory address of the buffer data - let bufptr := mload(buf) - // Address = buffer address + sizeof(buffer length) + off + len - let dest := add(add(bufptr, off), len) - mstore(dest, or(and(mload(dest), not(mask)), data)) - // Update buffer length if we extended it - if gt(add(off, len), mload(bufptr)) { - mstore(bufptr, add(off, len)) - } - } - return buf; - } - - /** - * @dev Writes a bytes20 to the buffer. Resizes if doing so would exceed the - * capacity of the buffer. - * @param buf The buffer to append to. - * @param off The offset to write at. - * @param data The data to append. - * @return The original buffer, for chaining. - */ - function writeBytes20(buffer memory buf, uint off, bytes20 data) internal pure returns (buffer memory) { - return write(buf, off, bytes32(data), 20); - } - - /** - * @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer, for chhaining. - */ - function appendBytes20(buffer memory buf, bytes20 data) internal pure returns (buffer memory) { - return write(buf, buf.buf.length, bytes32(data), 20); - } - - /** - * @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer, for chaining. - */ - function appendBytes32(buffer memory buf, bytes32 data) internal pure returns (buffer memory) { - return write(buf, buf.buf.length, data, 32); - } - - /** - * @dev Writes an integer to the buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param off The offset to write at. - * @param data The data to append. - * @param len The number of bytes to write (right-aligned). - * @return The original buffer, for chaining. - */ - function writeInt(buffer memory buf, uint off, uint data, uint len) private pure returns(buffer memory) { - if (len + off > buf.capacity) { - resize(buf, (len + off) * 2); - } - - uint mask = 256 ** len - 1; - assembly { - // Memory address of the buffer data - let bufptr := mload(buf) - // Address = buffer address + off + sizeof(buffer length) + len - let dest := add(add(bufptr, off), len) - mstore(dest, or(and(mload(dest), not(mask)), data)) - // Update buffer length if we extended it - if gt(add(off, len), mload(bufptr)) { - mstore(bufptr, add(off, len)) - } - } - return buf; - } - - /** - * @dev Appends a byte to the end of the buffer. Resizes if doing so would - * exceed the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer. - */ - function appendInt(buffer memory buf, uint data, uint len) internal pure returns(buffer memory) { - return writeInt(buf, buf.buf.length, data, len); - } -} diff --git a/contracts/src/v0.6/vendor/CBORChainlink.sol b/contracts/src/v0.6/vendor/CBORChainlink.sol deleted file mode 100644 index 90a1b1bd6d6..00000000000 --- a/contracts/src/v0.6/vendor/CBORChainlink.sol +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >= 0.4.19; - -import { BufferChainlink } from "./BufferChainlink.sol"; - -library CBORChainlink { - using BufferChainlink for BufferChainlink.buffer; - - uint8 private constant MAJOR_TYPE_INT = 0; - uint8 private constant MAJOR_TYPE_NEGATIVE_INT = 1; - uint8 private constant MAJOR_TYPE_BYTES = 2; - uint8 private constant MAJOR_TYPE_STRING = 3; - uint8 private constant MAJOR_TYPE_ARRAY = 4; - uint8 private constant MAJOR_TYPE_MAP = 5; - uint8 private constant MAJOR_TYPE_TAG = 6; - uint8 private constant MAJOR_TYPE_CONTENT_FREE = 7; - - uint8 private constant TAG_TYPE_BIGNUM = 2; - uint8 private constant TAG_TYPE_NEGATIVE_BIGNUM = 3; - - function encodeFixedNumeric(BufferChainlink.buffer memory buf, uint8 major, uint64 value) private pure { - if(value <= 23) { - buf.appendUint8(uint8((major << 5) | value)); - } else if(value <= 0xFF) { - buf.appendUint8(uint8((major << 5) | 24)); - buf.appendInt(value, 1); - } else if(value <= 0xFFFF) { - buf.appendUint8(uint8((major << 5) | 25)); - buf.appendInt(value, 2); - } else if(value <= 0xFFFFFFFF) { - buf.appendUint8(uint8((major << 5) | 26)); - buf.appendInt(value, 4); - } else { - buf.appendUint8(uint8((major << 5) | 27)); - buf.appendInt(value, 8); - } - } - - function encodeIndefiniteLengthType(BufferChainlink.buffer memory buf, uint8 major) private pure { - buf.appendUint8(uint8((major << 5) | 31)); - } - - function encodeUInt(BufferChainlink.buffer memory buf, uint value) internal pure { - if(value > 0xFFFFFFFFFFFFFFFF) { - encodeBigNum(buf, value); - } else { - encodeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(value)); - } - } - - function encodeInt(BufferChainlink.buffer memory buf, int value) internal pure { - if(value < -0x10000000000000000) { - encodeSignedBigNum(buf, value); - } else if(value > 0xFFFFFFFFFFFFFFFF) { - encodeBigNum(buf, uint(value)); - } else if(value >= 0) { - encodeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(value)); - } else { - encodeFixedNumeric(buf, MAJOR_TYPE_NEGATIVE_INT, uint64(-1 - value)); - } - } - - function encodeBytes(BufferChainlink.buffer memory buf, bytes memory value) internal pure { - encodeFixedNumeric(buf, MAJOR_TYPE_BYTES, uint64(value.length)); - buf.append(value); - } - - function encodeBigNum(BufferChainlink.buffer memory buf, uint value) internal pure { - buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_BIGNUM)); - encodeBytes(buf, abi.encode(value)); - } - - function encodeSignedBigNum(BufferChainlink.buffer memory buf, int input) internal pure { - buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_NEGATIVE_BIGNUM)); - encodeBytes(buf, abi.encode(uint(-1 - input))); - } - - function encodeString(BufferChainlink.buffer memory buf, string memory value) internal pure { - encodeFixedNumeric(buf, MAJOR_TYPE_STRING, uint64(bytes(value).length)); - buf.append(bytes(value)); - } - - function startArray(BufferChainlink.buffer memory buf) internal pure { - encodeIndefiniteLengthType(buf, MAJOR_TYPE_ARRAY); - } - - function startMap(BufferChainlink.buffer memory buf) internal pure { - encodeIndefiniteLengthType(buf, MAJOR_TYPE_MAP); - } - - function endSequence(BufferChainlink.buffer memory buf) internal pure { - encodeIndefiniteLengthType(buf, MAJOR_TYPE_CONTENT_FREE); - } -} diff --git a/contracts/src/v0.6/vendor/ENSResolver.sol b/contracts/src/v0.6/vendor/ENSResolver.sol deleted file mode 100644 index a2aff795186..00000000000 --- a/contracts/src/v0.6/vendor/ENSResolver.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -abstract contract ENSResolver { - function addr(bytes32 node) public view virtual returns (address); -} diff --git a/contracts/src/v0.6/vendor/Ownable.sol b/contracts/src/v0.6/vendor/Ownable.sol deleted file mode 100644 index f0299db3ec8..00000000000 --- a/contracts/src/v0.6/vendor/Ownable.sol +++ /dev/null @@ -1,66 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -/** - * @dev Contract module which provides a basic access control mechanism, where - * there is an account (an owner) that can be granted exclusive access to - * specific functions. - * - * This module is used through inheritance. It will make available the modifier - * `onlyOwner`, which can be aplied to your functions to restrict their use to - * the owner. - * - * This contract has been modified to remove the revokeOwnership function - */ -contract Ownable { - address private _owner; - - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); - - /** - * @dev Initializes the contract setting the deployer as the initial owner. - */ - constructor () internal { - _owner = msg.sender; - emit OwnershipTransferred(address(0), _owner); - } - - /** - * @dev Returns the address of the current owner. - */ - function owner() public view returns (address) { - return _owner; - } - - /** - * @dev Throws if called by any account other than the owner. - */ - modifier onlyOwner() { - require(isOwner(), "Ownable: caller is not the owner"); - _; - } - - /** - * @dev Returns true if the caller is the current owner. - */ - function isOwner() public view returns (bool) { - return msg.sender == _owner; - } - - /** - * @dev Transfers ownership of the contract to a new account (`newOwner`). - * Can only be called by the current owner. - */ - function transferOwnership(address newOwner) public onlyOwner { - _transferOwnership(newOwner); - } - - /** - * @dev Transfers ownership of the contract to a new account (`newOwner`). - */ - function _transferOwnership(address newOwner) internal { - require(newOwner != address(0), "Ownable: new owner is the zero address"); - emit OwnershipTransferred(_owner, newOwner); - _owner = newOwner; - } -} diff --git a/contracts/src/v0.6/vendor/SafeMathChainlink.sol b/contracts/src/v0.6/vendor/SafeMathChainlink.sol deleted file mode 100644 index 39d73a5e85c..00000000000 --- a/contracts/src/v0.6/vendor/SafeMathChainlink.sol +++ /dev/null @@ -1,108 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMathChainlink { - /** - * @dev Returns the addition of two unsigned integers, reverting on - * overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on - * overflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot overflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - require(b <= a, "SafeMath: subtraction overflow"); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on - * overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. Reverts on - * division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, "SafeMath: division by zero"); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - require(b != 0, "SafeMath: modulo by zero"); - return a % b; - } -} diff --git a/contracts/src/v0.7/AuthorizedForwarder.sol b/contracts/src/v0.7/AuthorizedForwarder.sol deleted file mode 100644 index 30cfb2c1ed7..00000000000 --- a/contracts/src/v0.7/AuthorizedForwarder.sol +++ /dev/null @@ -1,89 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "./interfaces/OperatorInterface.sol"; -import "./ConfirmedOwnerWithProposal.sol"; -import "./AuthorizedReceiver.sol"; -import "./vendor/Address.sol"; - -contract AuthorizedForwarder is ConfirmedOwnerWithProposal, AuthorizedReceiver { - using Address for address; - - address public immutable getChainlinkToken; - - event OwnershipTransferRequestedWithMessage(address indexed from, address indexed to, bytes message); - - constructor( - address link, - address owner, - address recipient, - bytes memory message - ) ConfirmedOwnerWithProposal(owner, recipient) { - require(link != address(0)); - getChainlinkToken = link; - if (recipient != address(0)) { - emit OwnershipTransferRequestedWithMessage(owner, recipient, message); - } - } - - /** - * @notice The type and version of this contract - * @return Type and version string - */ - function typeAndVersion() external pure virtual returns (string memory) { - return "AuthorizedForwarder 1.0.0"; - } - - /** - * @notice Forward a call to another contract - * @dev Only callable by an authorized sender - * @param to address - * @param data to forward - */ - function forward(address to, bytes calldata data) external validateAuthorizedSender { - require(to != getChainlinkToken, "Cannot forward to Link token"); - _forward(to, data); - } - - /** - * @notice Forward a call to another contract - * @dev Only callable by the owner - * @param to address - * @param data to forward - */ - function ownerForward(address to, bytes calldata data) external onlyOwner { - _forward(to, data); - } - - /** - * @notice Transfer ownership with instructions for recipient - * @param to address proposed recipient of ownership - * @param message instructions for recipient upon accepting ownership - */ - function transferOwnershipWithMessage(address to, bytes calldata message) external { - transferOwnership(to); - emit OwnershipTransferRequestedWithMessage(msg.sender, to, message); - } - - /** - * @notice concrete implementation of AuthorizedReceiver - * @return bool of whether sender is authorized - */ - function _canSetAuthorizedSenders() internal view override returns (bool) { - return owner() == msg.sender; - } - - /** - * @notice common forwarding functionality and validation - */ - function _forward(address to, bytes calldata data) private { - require(to.isContract(), "Must forward to a contract"); - (bool success, bytes memory result) = to.call(data); - if (!success) { - if (result.length == 0) revert("Forwarded call reverted without reason"); - assembly { - revert(add(32, result), mload(result)) - } - } - } -} diff --git a/contracts/src/v0.7/AuthorizedReceiver.sol b/contracts/src/v0.7/AuthorizedReceiver.sol deleted file mode 100644 index daa2792f5a4..00000000000 --- a/contracts/src/v0.7/AuthorizedReceiver.sol +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "./interfaces/AuthorizedReceiverInterface.sol"; - -abstract contract AuthorizedReceiver is AuthorizedReceiverInterface { - mapping(address => bool) private s_authorizedSenders; - address[] private s_authorizedSenderList; - - event AuthorizedSendersChanged(address[] senders, address changedBy); - - /** - * @notice Sets the fulfillment permission for a given node. Use `true` to allow, `false` to disallow. - * @param senders The addresses of the authorized Chainlink node - */ - function setAuthorizedSenders(address[] calldata senders) external override validateAuthorizedSenderSetter { - require(senders.length > 0, "Must have at least 1 sender"); - // Set previous authorized senders to false - uint256 authorizedSendersLength = s_authorizedSenderList.length; - for (uint256 i = 0; i < authorizedSendersLength; i++) { - s_authorizedSenders[s_authorizedSenderList[i]] = false; - } - // Set new to true - for (uint256 i = 0; i < senders.length; i++) { - require(s_authorizedSenders[senders[i]] == false, "Must not have duplicate senders"); - s_authorizedSenders[senders[i]] = true; - } - // Replace list - s_authorizedSenderList = senders; - emit AuthorizedSendersChanged(senders, msg.sender); - } - - /** - * @notice Retrieve a list of authorized senders - * @return array of addresses - */ - function getAuthorizedSenders() external view override returns (address[] memory) { - return s_authorizedSenderList; - } - - /** - * @notice Use this to check if a node is authorized for fulfilling requests - * @param sender The address of the Chainlink node - * @return The authorization status of the node - */ - function isAuthorizedSender(address sender) public view override returns (bool) { - return s_authorizedSenders[sender]; - } - - /** - * @notice customizable guard of who can update the authorized sender list - * @return bool whether sender can update authorized sender list - */ - function _canSetAuthorizedSenders() internal virtual returns (bool); - - /** - * @notice validates the sender is an authorized sender - */ - function _validateIsAuthorizedSender() internal view { - require(isAuthorizedSender(msg.sender), "Not authorized sender"); - } - - /** - * @notice prevents non-authorized addresses from calling this method - */ - modifier validateAuthorizedSender() { - _validateIsAuthorizedSender(); - _; - } - - /** - * @notice prevents non-authorized addresses from calling this method - */ - modifier validateAuthorizedSenderSetter() { - require(_canSetAuthorizedSenders(), "Cannot set authorized senders"); - _; - } -} diff --git a/contracts/src/v0.7/Chainlink.sol b/contracts/src/v0.7/Chainlink.sol deleted file mode 100644 index e08d87ceabf..00000000000 --- a/contracts/src/v0.7/Chainlink.sol +++ /dev/null @@ -1,135 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import {CBORChainlink} from "./vendor/CBORChainlink.sol"; -import {BufferChainlink} from "./vendor/BufferChainlink.sol"; - -/** - * @title Library for common Chainlink functions - * @dev Uses imported CBOR library for encoding to buffer - */ -library Chainlink { - uint256 internal constant defaultBufferSize = 256; // solhint-disable-line const-name-snakecase - - using CBORChainlink for BufferChainlink.buffer; - - struct Request { - bytes32 id; - address callbackAddress; - bytes4 callbackFunctionId; - uint256 nonce; - BufferChainlink.buffer buf; - } - - /** - * @notice Initializes a Chainlink request - * @dev Sets the ID, callback address, and callback function signature on the request - * @param self The uninitialized request - * @param jobId The Job Specification ID - * @param callbackAddr The callback address - * @param callbackFunc The callback function signature - * @return The initialized request - */ - function initialize( - Request memory self, - bytes32 jobId, - address callbackAddr, - bytes4 callbackFunc - ) internal pure returns (Chainlink.Request memory) { - BufferChainlink.init(self.buf, defaultBufferSize); - self.id = jobId; - self.callbackAddress = callbackAddr; - self.callbackFunctionId = callbackFunc; - return self; - } - - /** - * @notice Sets the data for the buffer without encoding CBOR on-chain - * @dev CBOR can be closed with curly-brackets {} or they can be left off - * @param self The initialized request - * @param data The CBOR data - */ - function setBuffer(Request memory self, bytes memory data) internal pure { - BufferChainlink.init(self.buf, data.length); - BufferChainlink.append(self.buf, data); - } - - /** - * @notice Adds a string value to the request with a given key name - * @param self The initialized request - * @param key The name of the key - * @param value The string value to add - */ - function add( - Request memory self, - string memory key, - string memory value - ) internal pure { - self.buf.encodeString(key); - self.buf.encodeString(value); - } - - /** - * @notice Adds a bytes value to the request with a given key name - * @param self The initialized request - * @param key The name of the key - * @param value The bytes value to add - */ - function addBytes( - Request memory self, - string memory key, - bytes memory value - ) internal pure { - self.buf.encodeString(key); - self.buf.encodeBytes(value); - } - - /** - * @notice Adds a int256 value to the request with a given key name - * @param self The initialized request - * @param key The name of the key - * @param value The int256 value to add - */ - function addInt( - Request memory self, - string memory key, - int256 value - ) internal pure { - self.buf.encodeString(key); - self.buf.encodeInt(value); - } - - /** - * @notice Adds a uint256 value to the request with a given key name - * @param self The initialized request - * @param key The name of the key - * @param value The uint256 value to add - */ - function addUint( - Request memory self, - string memory key, - uint256 value - ) internal pure { - self.buf.encodeString(key); - self.buf.encodeUInt(value); - } - - /** - * @notice Adds an array of strings to the request with a given key name - * @param self The initialized request - * @param key The name of the key - * @param values The array of string values to add - */ - function addStringArray( - Request memory self, - string memory key, - string[] memory values - ) internal pure { - self.buf.encodeString(key); - self.buf.startArray(); - for (uint256 i = 0; i < values.length; i++) { - self.buf.encodeString(values[i]); - } - self.buf.endSequence(); - } -} diff --git a/contracts/src/v0.7/ChainlinkClient.sol b/contracts/src/v0.7/ChainlinkClient.sol deleted file mode 100644 index 48cc048bb67..00000000000 --- a/contracts/src/v0.7/ChainlinkClient.sol +++ /dev/null @@ -1,315 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "./Chainlink.sol"; -import "./interfaces/ENSInterface.sol"; -import "./interfaces/LinkTokenInterface.sol"; -import "./interfaces/ChainlinkRequestInterface.sol"; -import "./interfaces/OperatorInterface.sol"; -import "./interfaces/PointerInterface.sol"; -import {ENSResolver as ENSResolver_Chainlink} from "./vendor/ENSResolver.sol"; - -/** - * @title The ChainlinkClient contract - * @notice Contract writers can inherit this contract in order to create requests for the - * Chainlink network - */ -abstract contract ChainlinkClient { - using Chainlink for Chainlink.Request; - - uint256 internal constant LINK_DIVISIBILITY = 10**18; - uint256 private constant AMOUNT_OVERRIDE = 0; - address private constant SENDER_OVERRIDE = address(0); - uint256 private constant ORACLE_ARGS_VERSION = 1; - uint256 private constant OPERATOR_ARGS_VERSION = 2; - bytes32 private constant ENS_TOKEN_SUBNAME = keccak256("link"); - bytes32 private constant ENS_ORACLE_SUBNAME = keccak256("oracle"); - address private constant LINK_TOKEN_POINTER = 0xC89bD4E1632D3A43CB03AAAd5262cbe4038Bc571; - - ENSInterface private s_ens; - bytes32 private s_ensNode; - LinkTokenInterface private s_link; - OperatorInterface private s_oracle; - uint256 private s_requestCount = 1; - mapping(bytes32 => address) private s_pendingRequests; - - event ChainlinkRequested(bytes32 indexed id); - event ChainlinkFulfilled(bytes32 indexed id); - event ChainlinkCancelled(bytes32 indexed id); - - /** - * @notice Creates a request that can hold additional parameters - * @param specId The Job Specification ID that the request will be created for - * @param callbackAddr address to operate the callback on - * @param callbackFunctionSignature function signature to use for the callback - * @return A Chainlink Request struct in memory - */ - function buildChainlinkRequest( - bytes32 specId, - address callbackAddr, - bytes4 callbackFunctionSignature - ) internal pure returns (Chainlink.Request memory) { - Chainlink.Request memory req; - return req.initialize(specId, callbackAddr, callbackFunctionSignature); - } - - /** - * @notice Creates a request that can hold additional parameters - * @param specId The Job Specification ID that the request will be created for - * @param callbackFunctionSignature function signature to use for the callback - * @return A Chainlink Request struct in memory - */ - function buildOperatorRequest(bytes32 specId, bytes4 callbackFunctionSignature) - internal - view - returns (Chainlink.Request memory) - { - Chainlink.Request memory req; - return req.initialize(specId, address(this), callbackFunctionSignature); - } - - /** - * @notice Creates a Chainlink request to the stored oracle address - * @dev Calls `chainlinkRequestTo` with the stored oracle address - * @param req The initialized Chainlink Request - * @param payment The amount of LINK to send for the request - * @return requestId The request ID - */ - function sendChainlinkRequest(Chainlink.Request memory req, uint256 payment) internal returns (bytes32) { - return sendChainlinkRequestTo(address(s_oracle), req, payment); - } - - /** - * @notice Creates a Chainlink request to the specified oracle address - * @dev Generates and stores a request ID, increments the local nonce, and uses `transferAndCall` to - * send LINK which creates a request on the target oracle contract. - * Emits ChainlinkRequested event. - * @param oracleAddress The address of the oracle for the request - * @param req The initialized Chainlink Request - * @param payment The amount of LINK to send for the request - * @return requestId The request ID - */ - function sendChainlinkRequestTo( - address oracleAddress, - Chainlink.Request memory req, - uint256 payment - ) internal returns (bytes32 requestId) { - uint256 nonce = s_requestCount; - s_requestCount = nonce + 1; - bytes memory encodedRequest = abi.encodeWithSelector( - ChainlinkRequestInterface.oracleRequest.selector, - SENDER_OVERRIDE, // Sender value - overridden by onTokenTransfer by the requesting contract's address - AMOUNT_OVERRIDE, // Amount value - overridden by onTokenTransfer by the actual amount of LINK sent - req.id, - address(this), - req.callbackFunctionId, - nonce, - ORACLE_ARGS_VERSION, - req.buf.buf - ); - return _rawRequest(oracleAddress, nonce, payment, encodedRequest); - } - - /** - * @notice Creates a Chainlink request to the stored oracle address - * @dev This function supports multi-word response - * @dev Calls `sendOperatorRequestTo` with the stored oracle address - * @param req The initialized Chainlink Request - * @param payment The amount of LINK to send for the request - * @return requestId The request ID - */ - function sendOperatorRequest(Chainlink.Request memory req, uint256 payment) internal returns (bytes32) { - return sendOperatorRequestTo(address(s_oracle), req, payment); - } - - /** - * @notice Creates a Chainlink request to the specified oracle address - * @dev This function supports multi-word response - * @dev Generates and stores a request ID, increments the local nonce, and uses `transferAndCall` to - * send LINK which creates a request on the target oracle contract. - * Emits ChainlinkRequested event. - * @param oracleAddress The address of the oracle for the request - * @param req The initialized Chainlink Request - * @param payment The amount of LINK to send for the request - * @return requestId The request ID - */ - function sendOperatorRequestTo( - address oracleAddress, - Chainlink.Request memory req, - uint256 payment - ) internal returns (bytes32 requestId) { - uint256 nonce = s_requestCount; - s_requestCount = nonce + 1; - bytes memory encodedRequest = abi.encodeWithSelector( - OperatorInterface.operatorRequest.selector, - SENDER_OVERRIDE, // Sender value - overridden by onTokenTransfer by the requesting contract's address - AMOUNT_OVERRIDE, // Amount value - overridden by onTokenTransfer by the actual amount of LINK sent - req.id, - req.callbackFunctionId, - nonce, - OPERATOR_ARGS_VERSION, - req.buf.buf - ); - return _rawRequest(oracleAddress, nonce, payment, encodedRequest); - } - - /** - * @notice Make a request to an oracle - * @param oracleAddress The address of the oracle for the request - * @param nonce used to generate the request ID - * @param payment The amount of LINK to send for the request - * @param encodedRequest data encoded for request type specific format - * @return requestId The request ID - */ - function _rawRequest( - address oracleAddress, - uint256 nonce, - uint256 payment, - bytes memory encodedRequest - ) private returns (bytes32 requestId) { - requestId = keccak256(abi.encodePacked(this, nonce)); - s_pendingRequests[requestId] = oracleAddress; - emit ChainlinkRequested(requestId); - require(s_link.transferAndCall(oracleAddress, payment, encodedRequest), "unable to transferAndCall to oracle"); - } - - /** - * @notice Allows a request to be cancelled if it has not been fulfilled - * @dev Requires keeping track of the expiration value emitted from the oracle contract. - * Deletes the request from the `pendingRequests` mapping. - * Emits ChainlinkCancelled event. - * @param requestId The request ID - * @param payment The amount of LINK sent for the request - * @param callbackFunc The callback function specified for the request - * @param expiration The time of the expiration for the request - */ - function cancelChainlinkRequest( - bytes32 requestId, - uint256 payment, - bytes4 callbackFunc, - uint256 expiration - ) internal { - OperatorInterface requested = OperatorInterface(s_pendingRequests[requestId]); - delete s_pendingRequests[requestId]; - emit ChainlinkCancelled(requestId); - requested.cancelOracleRequest(requestId, payment, callbackFunc, expiration); - } - - /** - * @notice the next request count to be used in generating a nonce - * @dev starts at 1 in order to ensure consistent gas cost - * @return returns the next request count to be used in a nonce - */ - function getNextRequestCount() internal view returns (uint256) { - return s_requestCount; - } - - /** - * @notice Sets the stored oracle address - * @param oracleAddress The address of the oracle contract - */ - function setChainlinkOracle(address oracleAddress) internal { - s_oracle = OperatorInterface(oracleAddress); - } - - /** - * @notice Sets the LINK token address - * @param linkAddress The address of the LINK token contract - */ - function setChainlinkToken(address linkAddress) internal { - s_link = LinkTokenInterface(linkAddress); - } - - /** - * @notice Sets the Chainlink token address for the public - * network as given by the Pointer contract - */ - function setPublicChainlinkToken() internal { - setChainlinkToken(PointerInterface(LINK_TOKEN_POINTER).getAddress()); - } - - /** - * @notice Retrieves the stored address of the LINK token - * @return The address of the LINK token - */ - function chainlinkTokenAddress() internal view returns (address) { - return address(s_link); - } - - /** - * @notice Retrieves the stored address of the oracle contract - * @return The address of the oracle contract - */ - function chainlinkOracleAddress() internal view returns (address) { - return address(s_oracle); - } - - /** - * @notice Allows for a request which was created on another contract to be fulfilled - * on this contract - * @param oracleAddress The address of the oracle contract that will fulfill the request - * @param requestId The request ID used for the response - */ - function addChainlinkExternalRequest(address oracleAddress, bytes32 requestId) internal notPendingRequest(requestId) { - s_pendingRequests[requestId] = oracleAddress; - } - - /** - * @notice Sets the stored oracle and LINK token contracts with the addresses resolved by ENS - * @dev Accounts for subnodes having different resolvers - * @param ensAddress The address of the ENS contract - * @param node The ENS node hash - */ - function useChainlinkWithENS(address ensAddress, bytes32 node) internal { - s_ens = ENSInterface(ensAddress); - s_ensNode = node; - bytes32 linkSubnode = keccak256(abi.encodePacked(s_ensNode, ENS_TOKEN_SUBNAME)); - ENSResolver_Chainlink resolver = ENSResolver_Chainlink(s_ens.resolver(linkSubnode)); - setChainlinkToken(resolver.addr(linkSubnode)); - updateChainlinkOracleWithENS(); - } - - /** - * @notice Sets the stored oracle contract with the address resolved by ENS - * @dev This may be called on its own as long as `useChainlinkWithENS` has been called previously - */ - function updateChainlinkOracleWithENS() internal { - bytes32 oracleSubnode = keccak256(abi.encodePacked(s_ensNode, ENS_ORACLE_SUBNAME)); - ENSResolver_Chainlink resolver = ENSResolver_Chainlink(s_ens.resolver(oracleSubnode)); - setChainlinkOracle(resolver.addr(oracleSubnode)); - } - - /** - * @notice Ensures that the fulfillment is valid for this contract - * @dev Use if the contract developer prefers methods instead of modifiers for validation - * @param requestId The request ID for fulfillment - */ - function validateChainlinkCallback(bytes32 requestId) - internal - recordChainlinkFulfillment(requestId) - // solhint-disable-next-line no-empty-blocks - { - - } - - /** - * @dev Reverts if the sender is not the oracle of the request. - * Emits ChainlinkFulfilled event. - * @param requestId The request ID for fulfillment - */ - modifier recordChainlinkFulfillment(bytes32 requestId) { - require(msg.sender == s_pendingRequests[requestId], "Source must be the oracle of the request"); - delete s_pendingRequests[requestId]; - emit ChainlinkFulfilled(requestId); - _; - } - - /** - * @dev Reverts if the request is already pending - * @param requestId The request ID for fulfillment - */ - modifier notPendingRequest(bytes32 requestId) { - require(s_pendingRequests[requestId] == address(0), "Request is already pending"); - _; - } -} diff --git a/contracts/src/v0.7/ConfirmedOwner.sol b/contracts/src/v0.7/ConfirmedOwner.sol deleted file mode 100644 index a411ba8ee58..00000000000 --- a/contracts/src/v0.7/ConfirmedOwner.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "./ConfirmedOwnerWithProposal.sol"; - -/** - * @title The ConfirmedOwner contract - * @notice A contract with helpers for basic contract ownership. - */ -contract ConfirmedOwner is ConfirmedOwnerWithProposal { - constructor(address newOwner) ConfirmedOwnerWithProposal(newOwner, address(0)) {} -} diff --git a/contracts/src/v0.7/ConfirmedOwnerWithProposal.sol b/contracts/src/v0.7/ConfirmedOwnerWithProposal.sol deleted file mode 100644 index b95c1711db7..00000000000 --- a/contracts/src/v0.7/ConfirmedOwnerWithProposal.sol +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "./interfaces/OwnableInterface.sol"; - -/** - * @title The ConfirmedOwner contract - * @notice A contract with helpers for basic contract ownership. - */ -contract ConfirmedOwnerWithProposal is OwnableInterface { - address private s_owner; - address private s_pendingOwner; - - event OwnershipTransferRequested(address indexed from, address indexed to); - event OwnershipTransferred(address indexed from, address indexed to); - - constructor(address newOwner, address pendingOwner) { - require(newOwner != address(0), "Cannot set owner to zero"); - - s_owner = newOwner; - if (pendingOwner != address(0)) { - _transferOwnership(pendingOwner); - } - } - - /** - * @notice Allows an owner to begin transferring ownership to a new address, - * pending. - */ - function transferOwnership(address to) public override onlyOwner { - _transferOwnership(to); - } - - /** - * @notice Allows an ownership transfer to be completed by the recipient. - */ - function acceptOwnership() external override { - require(msg.sender == s_pendingOwner, "Must be proposed owner"); - - address oldOwner = s_owner; - s_owner = msg.sender; - s_pendingOwner = address(0); - - emit OwnershipTransferred(oldOwner, msg.sender); - } - - /** - * @notice Get the current owner - */ - function owner() public view override returns (address) { - return s_owner; - } - - /** - * @notice validate, transfer ownership, and emit relevant events - */ - function _transferOwnership(address to) private { - require(to != msg.sender, "Cannot transfer to self"); - - s_pendingOwner = to; - - emit OwnershipTransferRequested(s_owner, to); - } - - /** - * @notice validate access - */ - function _validateOwnership() internal view { - require(msg.sender == s_owner, "Only callable by owner"); - } - - /** - * @notice Reverts if called by anyone other than the contract owner. - */ - modifier onlyOwner() { - _validateOwnership(); - _; - } -} diff --git a/contracts/src/v0.7/Denominations.sol b/contracts/src/v0.7/Denominations.sol deleted file mode 100644 index 54556db8e8f..00000000000 --- a/contracts/src/v0.7/Denominations.sol +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -library Denominations { - address public constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; - address public constant BTC = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB; - - // Fiat currencies follow https://en.wikipedia.org/wiki/ISO_4217 - address public constant USD = address(840); - address public constant GBP = address(826); - address public constant EUR = address(978); - address public constant JPY = address(392); - address public constant KRW = address(410); - address public constant CNY = address(156); - address public constant AUD = address(36); - address public constant CAD = address(124); - address public constant CHF = address(756); - address public constant ARS = address(32); - address public constant PHP = address(608); - address public constant NZD = address(554); - address public constant SGD = address(702); - address public constant NGN = address(566); - address public constant ZAR = address(710); - address public constant RUB = address(643); - address public constant INR = address(356); - address public constant BRL = address(986); -} diff --git a/contracts/src/v0.7/KeeperBase.sol b/contracts/src/v0.7/KeeperBase.sol deleted file mode 100644 index 6af11a8eab9..00000000000 --- a/contracts/src/v0.7/KeeperBase.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -contract KeeperBase { - /** - * @notice method that allows it to be simulated via eth_call by checking that - * the sender is the zero address. - */ - function preventExecution() internal view { - require(tx.origin == address(0), "only for simulated backend"); - } - - /** - * @notice modifier that allows it to be simulated via eth_call by checking - * that the sender is the zero address. - */ - modifier cannotExecute() { - preventExecution(); - _; - } -} diff --git a/contracts/src/v0.7/KeeperCompatible.sol b/contracts/src/v0.7/KeeperCompatible.sol deleted file mode 100644 index 9780eb64f7a..00000000000 --- a/contracts/src/v0.7/KeeperCompatible.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "./KeeperBase.sol"; -import "./interfaces/KeeperCompatibleInterface.sol"; - -abstract contract KeeperCompatible is KeeperBase, KeeperCompatibleInterface {} diff --git a/contracts/src/v0.7/KeeperRegistry1_1.sol b/contracts/src/v0.7/KeeperRegistry1_1.sol deleted file mode 100644 index d61ada83e01..00000000000 --- a/contracts/src/v0.7/KeeperRegistry1_1.sol +++ /dev/null @@ -1,834 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "./interfaces/AggregatorV3Interface.sol"; -import "./interfaces/LinkTokenInterface.sol"; -import "./interfaces/KeeperCompatibleInterface.sol"; -import "./interfaces/KeeperRegistryInterface.sol"; -import "./interfaces/TypeAndVersionInterface.sol"; -import "./vendor/SafeMathChainlink.sol"; -import "./vendor/Address.sol"; -import "./vendor/Pausable.sol"; -import "./vendor/ReentrancyGuard.sol"; -import "./vendor/SignedSafeMath.sol"; -import "./vendor/SafeMath96.sol"; -import "./KeeperBase.sol"; -import "./ConfirmedOwner.sol"; - -/** - * @notice Registry for adding work for Chainlink Keepers to perform on client - * contracts. Clients must support the Upkeep interface. - */ -contract KeeperRegistry1_1 is - TypeAndVersionInterface, - ConfirmedOwner, - KeeperBase, - ReentrancyGuard, - Pausable, - KeeperRegistryExecutableInterface -{ - using Address for address; - using SafeMathChainlink for uint256; - using SafeMath96 for uint96; - using SignedSafeMath for int256; - - address private constant ZERO_ADDRESS = address(0); - address private constant IGNORE_ADDRESS = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF; - bytes4 private constant CHECK_SELECTOR = KeeperCompatibleInterface.checkUpkeep.selector; - bytes4 private constant PERFORM_SELECTOR = KeeperCompatibleInterface.performUpkeep.selector; - uint256 private constant CALL_GAS_MAX = 5_000_000; - uint256 private constant CALL_GAS_MIN = 2_300; - uint256 private constant CANCELATION_DELAY = 50; - uint256 private constant CUSHION = 5_000; - uint256 private constant REGISTRY_GAS_OVERHEAD = 80_000; - uint256 private constant PPB_BASE = 1_000_000_000; - uint64 private constant UINT64_MAX = 2**64 - 1; - uint96 private constant LINK_TOTAL_SUPPLY = 1e27; - - uint256 private s_upkeepCount; - uint256[] private s_canceledUpkeepList; - address[] private s_keeperList; - mapping(uint256 => Upkeep) private s_upkeep; - mapping(address => KeeperInfo) private s_keeperInfo; - mapping(address => address) private s_proposedPayee; - mapping(uint256 => bytes) private s_checkData; - Config private s_config; - uint256 private s_fallbackGasPrice; // not in config object for gas savings - uint256 private s_fallbackLinkPrice; // not in config object for gas savings - uint256 private s_expectedLinkBalance; - - LinkTokenInterface public immutable LINK; - AggregatorV3Interface public immutable LINK_ETH_FEED; - AggregatorV3Interface public immutable FAST_GAS_FEED; - - address private s_registrar; - - /** - * @notice versions: - * - KeeperRegistry 1.1.0: added flatFeeMicroLink - * - KeeperRegistry 1.0.0: initial release - */ - string public constant override typeAndVersion = "KeeperRegistry 1.1.0"; - - struct Upkeep { - address target; - uint32 executeGas; - uint96 balance; - address admin; - uint64 maxValidBlocknumber; - address lastKeeper; - } - - struct KeeperInfo { - address payee; - uint96 balance; - bool active; - } - - struct Config { - uint32 paymentPremiumPPB; - uint32 flatFeeMicroLink; // min 0.000001 LINK, max 4294 LINK - uint24 blockCountPerTurn; - uint32 checkGasLimit; - uint24 stalenessSeconds; - uint16 gasCeilingMultiplier; - } - - struct PerformParams { - address from; - uint256 id; - bytes performData; - uint256 maxLinkPayment; - uint256 gasLimit; - uint256 adjustedGasWei; - uint256 linkEth; - } - - event UpkeepRegistered(uint256 indexed id, uint32 executeGas, address admin); - event UpkeepPerformed( - uint256 indexed id, - bool indexed success, - address indexed from, - uint96 payment, - bytes performData - ); - event UpkeepCanceled(uint256 indexed id, uint64 indexed atBlockHeight); - event FundsAdded(uint256 indexed id, address indexed from, uint96 amount); - event FundsWithdrawn(uint256 indexed id, uint256 amount, address to); - event ConfigSet( - uint32 paymentPremiumPPB, - uint24 blockCountPerTurn, - uint32 checkGasLimit, - uint24 stalenessSeconds, - uint16 gasCeilingMultiplier, - uint256 fallbackGasPrice, - uint256 fallbackLinkPrice - ); - event FlatFeeSet(uint32 flatFeeMicroLink); - event KeepersUpdated(address[] keepers, address[] payees); - event PaymentWithdrawn(address indexed keeper, uint256 indexed amount, address indexed to, address payee); - event PayeeshipTransferRequested(address indexed keeper, address indexed from, address indexed to); - event PayeeshipTransferred(address indexed keeper, address indexed from, address indexed to); - event RegistrarChanged(address indexed from, address indexed to); - - /** - * @param link address of the LINK Token - * @param linkEthFeed address of the LINK/ETH price feed - * @param fastGasFeed address of the Fast Gas price feed - * @param paymentPremiumPPB payment premium rate oracles receive on top of - * being reimbursed for gas, measured in parts per billion - * @param flatFeeMicroLink flat fee paid to oracles for performing upkeeps, - * priced in MicroLink; can be used in conjunction with or independently of - * paymentPremiumPPB - * @param blockCountPerTurn number of blocks each oracle has during their turn to - * perform upkeep before it will be the next keeper's turn to submit - * @param checkGasLimit gas limit when checking for upkeep - * @param stalenessSeconds number of seconds that is allowed for feed data to - * be stale before switching to the fallback pricing - * @param gasCeilingMultiplier multiplier to apply to the fast gas feed price - * when calculating the payment ceiling for keepers - * @param fallbackGasPrice gas price used if the gas price feed is stale - * @param fallbackLinkPrice LINK price used if the LINK price feed is stale - */ - constructor( - address link, - address linkEthFeed, - address fastGasFeed, - uint32 paymentPremiumPPB, - uint32 flatFeeMicroLink, - uint24 blockCountPerTurn, - uint32 checkGasLimit, - uint24 stalenessSeconds, - uint16 gasCeilingMultiplier, - uint256 fallbackGasPrice, - uint256 fallbackLinkPrice - ) ConfirmedOwner(msg.sender) { - LINK = LinkTokenInterface(link); - LINK_ETH_FEED = AggregatorV3Interface(linkEthFeed); - FAST_GAS_FEED = AggregatorV3Interface(fastGasFeed); - - setConfig( - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - fallbackGasPrice, - fallbackLinkPrice - ); - } - - // ACTIONS - - /** - * @notice adds a new upkeep - * @param target address to perform upkeep on - * @param gasLimit amount of gas to provide the target contract when - * performing upkeep - * @param admin address to cancel upkeep and withdraw remaining funds - * @param checkData data passed to the contract when checking for upkeep - */ - function registerUpkeep( - address target, - uint32 gasLimit, - address admin, - bytes calldata checkData - ) external override onlyOwnerOrRegistrar returns (uint256 id) { - require(target.isContract(), "target is not a contract"); - require(gasLimit >= CALL_GAS_MIN, "min gas is 2300"); - require(gasLimit <= CALL_GAS_MAX, "max gas is 5000000"); - - id = s_upkeepCount; - s_upkeep[id] = Upkeep({ - target: target, - executeGas: gasLimit, - balance: 0, - admin: admin, - maxValidBlocknumber: UINT64_MAX, - lastKeeper: address(0) - }); - s_checkData[id] = checkData; - s_upkeepCount++; - - emit UpkeepRegistered(id, gasLimit, admin); - - return id; - } - - /** - * @notice simulated by keepers via eth_call to see if the upkeep needs to be - * performed. If upkeep is needed, the call then simulates performUpkeep - * to make sure it succeeds. Finally, it returns the success status along with - * payment information and the perform data payload. - * @param id identifier of the upkeep to check - * @param from the address to simulate performing the upkeep from - */ - function checkUpkeep(uint256 id, address from) - external - override - whenNotPaused - cannotExecute - returns ( - bytes memory performData, - uint256 maxLinkPayment, - uint256 gasLimit, - uint256 adjustedGasWei, - uint256 linkEth - ) - { - Upkeep memory upkeep = s_upkeep[id]; - - bytes memory callData = abi.encodeWithSelector(CHECK_SELECTOR, s_checkData[id]); - (bool success, bytes memory result) = upkeep.target.call{gas: s_config.checkGasLimit}(callData); - - if (!success) { - string memory upkeepRevertReason = getRevertMsg(result); - string memory reason = string(abi.encodePacked("call to check target failed: ", upkeepRevertReason)); - revert(reason); - } - - (success, performData) = abi.decode(result, (bool, bytes)); - require(success, "upkeep not needed"); - - PerformParams memory params = generatePerformParams(from, id, performData, false); - prePerformUpkeep(upkeep, params.from, params.maxLinkPayment); - - return (performData, params.maxLinkPayment, params.gasLimit, params.adjustedGasWei, params.linkEth); - } - - /** - * @notice executes the upkeep with the perform data returned from - * checkUpkeep, validates the keeper's permissions, and pays the keeper. - * @param id identifier of the upkeep to execute the data with. - * @param performData calldata parameter to be passed to the target upkeep. - */ - function performUpkeep(uint256 id, bytes calldata performData) external override returns (bool success) { - return performUpkeepWithParams(generatePerformParams(msg.sender, id, performData, true)); - } - - /** - * @notice prevent an upkeep from being performed in the future - * @param id upkeep to be canceled - */ - function cancelUpkeep(uint256 id) external override { - uint64 maxValid = s_upkeep[id].maxValidBlocknumber; - bool notCanceled = maxValid == UINT64_MAX; - bool isOwner = msg.sender == owner(); - require(notCanceled || (isOwner && maxValid > block.number), "too late to cancel upkeep"); - require(isOwner || msg.sender == s_upkeep[id].admin, "only owner or admin"); - - uint256 height = block.number; - if (!isOwner) { - height = height.add(CANCELATION_DELAY); - } - s_upkeep[id].maxValidBlocknumber = uint64(height); - if (notCanceled) { - s_canceledUpkeepList.push(id); - } - - emit UpkeepCanceled(id, uint64(height)); - } - - /** - * @notice adds LINK funding for an upkeep by transferring from the sender's - * LINK balance - * @param id upkeep to fund - * @param amount number of LINK to transfer - */ - function addFunds(uint256 id, uint96 amount) external override { - require(s_upkeep[id].maxValidBlocknumber == UINT64_MAX, "upkeep must be active"); - s_upkeep[id].balance = s_upkeep[id].balance.add(amount); - s_expectedLinkBalance = s_expectedLinkBalance.add(amount); - LINK.transferFrom(msg.sender, address(this), amount); - emit FundsAdded(id, msg.sender, amount); - } - - /** - * @notice uses LINK's transferAndCall to LINK and add funding to an upkeep - * @dev safe to cast uint256 to uint96 as total LINK supply is under UINT96MAX - * @param sender the account which transferred the funds - * @param amount number of LINK transfer - */ - function onTokenTransfer( - address sender, - uint256 amount, - bytes calldata data - ) external { - require(msg.sender == address(LINK), "only callable through LINK"); - require(data.length == 32, "data must be 32 bytes"); - uint256 id = abi.decode(data, (uint256)); - require(s_upkeep[id].maxValidBlocknumber == UINT64_MAX, "upkeep must be active"); - - s_upkeep[id].balance = s_upkeep[id].balance.add(uint96(amount)); - s_expectedLinkBalance = s_expectedLinkBalance.add(amount); - - emit FundsAdded(id, sender, uint96(amount)); - } - - /** - * @notice removes funding from a canceled upkeep - * @param id upkeep to withdraw funds from - * @param to destination address for sending remaining funds - */ - function withdrawFunds(uint256 id, address to) external validateRecipient(to) { - require(s_upkeep[id].admin == msg.sender, "only callable by admin"); - require(s_upkeep[id].maxValidBlocknumber <= block.number, "upkeep must be canceled"); - - uint256 amount = s_upkeep[id].balance; - s_upkeep[id].balance = 0; - s_expectedLinkBalance = s_expectedLinkBalance.sub(amount); - emit FundsWithdrawn(id, amount, to); - - LINK.transfer(to, amount); - } - - /** - * @notice recovers LINK funds improperly transferred to the registry - * @dev In principle this function’s execution cost could exceed block - * gas limit. However, in our anticipated deployment, the number of upkeeps and - * keepers will be low enough to avoid this problem. - */ - function recoverFunds() external onlyOwner { - uint256 total = LINK.balanceOf(address(this)); - LINK.transfer(msg.sender, total.sub(s_expectedLinkBalance)); - } - - /** - * @notice withdraws a keeper's payment, callable only by the keeper's payee - * @param from keeper address - * @param to address to send the payment to - */ - function withdrawPayment(address from, address to) external validateRecipient(to) { - KeeperInfo memory keeper = s_keeperInfo[from]; - require(keeper.payee == msg.sender, "only callable by payee"); - - s_keeperInfo[from].balance = 0; - s_expectedLinkBalance = s_expectedLinkBalance.sub(keeper.balance); - emit PaymentWithdrawn(from, keeper.balance, to, msg.sender); - - LINK.transfer(to, keeper.balance); - } - - /** - * @notice proposes the safe transfer of a keeper's payee to another address - * @param keeper address of the keeper to transfer payee role - * @param proposed address to nominate for next payeeship - */ - function transferPayeeship(address keeper, address proposed) external { - require(s_keeperInfo[keeper].payee == msg.sender, "only callable by payee"); - require(proposed != msg.sender, "cannot transfer to self"); - - if (s_proposedPayee[keeper] != proposed) { - s_proposedPayee[keeper] = proposed; - emit PayeeshipTransferRequested(keeper, msg.sender, proposed); - } - } - - /** - * @notice accepts the safe transfer of payee role for a keeper - * @param keeper address to accept the payee role for - */ - function acceptPayeeship(address keeper) external { - require(s_proposedPayee[keeper] == msg.sender, "only callable by proposed payee"); - address past = s_keeperInfo[keeper].payee; - s_keeperInfo[keeper].payee = msg.sender; - s_proposedPayee[keeper] = ZERO_ADDRESS; - - emit PayeeshipTransferred(keeper, past, msg.sender); - } - - /** - * @notice signals to keepers that they should not perform upkeeps until the - * contract has been unpaused - */ - function pause() external onlyOwner { - _pause(); - } - - /** - * @notice signals to keepers that they can perform upkeeps once again after - * having been paused - */ - function unpause() external onlyOwner { - _unpause(); - } - - // SETTERS - - /** - * @notice updates the configuration of the registry - * @param paymentPremiumPPB payment premium rate oracles receive on top of - * being reimbursed for gas, measured in parts per billion - * @param flatFeeMicroLink flat fee paid to oracles for performing upkeeps - * @param blockCountPerTurn number of blocks an oracle should wait before - * checking for upkeep - * @param checkGasLimit gas limit when checking for upkeep - * @param stalenessSeconds number of seconds that is allowed for feed data to - * be stale before switching to the fallback pricing - * @param fallbackGasPrice gas price used if the gas price feed is stale - * @param fallbackLinkPrice LINK price used if the LINK price feed is stale - */ - function setConfig( - uint32 paymentPremiumPPB, - uint32 flatFeeMicroLink, - uint24 blockCountPerTurn, - uint32 checkGasLimit, - uint24 stalenessSeconds, - uint16 gasCeilingMultiplier, - uint256 fallbackGasPrice, - uint256 fallbackLinkPrice - ) public onlyOwner { - s_config = Config({ - paymentPremiumPPB: paymentPremiumPPB, - flatFeeMicroLink: flatFeeMicroLink, - blockCountPerTurn: blockCountPerTurn, - checkGasLimit: checkGasLimit, - stalenessSeconds: stalenessSeconds, - gasCeilingMultiplier: gasCeilingMultiplier - }); - s_fallbackGasPrice = fallbackGasPrice; - s_fallbackLinkPrice = fallbackLinkPrice; - - emit ConfigSet( - paymentPremiumPPB, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - fallbackGasPrice, - fallbackLinkPrice - ); - emit FlatFeeSet(flatFeeMicroLink); - } - - /** - * @notice update the list of keepers allowed to perform upkeep - * @param keepers list of addresses allowed to perform upkeep - * @param payees addresses corresponding to keepers who are allowed to - * move payments which have been accrued - */ - function setKeepers(address[] calldata keepers, address[] calldata payees) external onlyOwner { - require(keepers.length == payees.length, "address lists not the same length"); - require(keepers.length >= 2, "not enough keepers"); - for (uint256 i = 0; i < s_keeperList.length; i++) { - address keeper = s_keeperList[i]; - s_keeperInfo[keeper].active = false; - } - for (uint256 i = 0; i < keepers.length; i++) { - address keeper = keepers[i]; - KeeperInfo storage s_keeper = s_keeperInfo[keeper]; - address oldPayee = s_keeper.payee; - address newPayee = payees[i]; - require(newPayee != address(0), "cannot set payee to the zero address"); - require(oldPayee == ZERO_ADDRESS || oldPayee == newPayee || newPayee == IGNORE_ADDRESS, "cannot change payee"); - require(!s_keeper.active, "cannot add keeper twice"); - s_keeper.active = true; - if (newPayee != IGNORE_ADDRESS) { - s_keeper.payee = newPayee; - } - } - s_keeperList = keepers; - emit KeepersUpdated(keepers, payees); - } - - /** - * @notice update registrar - * @param registrar new registrar - */ - function setRegistrar(address registrar) external onlyOwnerOrRegistrar { - address previous = s_registrar; - require(registrar != previous, "Same registrar"); - s_registrar = registrar; - emit RegistrarChanged(previous, registrar); - } - - // GETTERS - - /** - * @notice read all of the details about an upkeep - */ - function getUpkeep(uint256 id) - external - view - override - returns ( - address target, - uint32 executeGas, - bytes memory checkData, - uint96 balance, - address lastKeeper, - address admin, - uint64 maxValidBlocknumber - ) - { - Upkeep memory reg = s_upkeep[id]; - return ( - reg.target, - reg.executeGas, - s_checkData[id], - reg.balance, - reg.lastKeeper, - reg.admin, - reg.maxValidBlocknumber - ); - } - - /** - * @notice read the total number of upkeep's registered - */ - function getUpkeepCount() external view override returns (uint256) { - return s_upkeepCount; - } - - /** - * @notice read the current list canceled upkeep IDs - */ - function getCanceledUpkeepList() external view override returns (uint256[] memory) { - return s_canceledUpkeepList; - } - - /** - * @notice read the current list of addresses allowed to perform upkeep - */ - function getKeeperList() external view override returns (address[] memory) { - return s_keeperList; - } - - /** - * @notice read the current registrar - */ - function getRegistrar() external view returns (address) { - return s_registrar; - } - - /** - * @notice read the current info about any keeper address - */ - function getKeeperInfo(address query) - external - view - override - returns ( - address payee, - bool active, - uint96 balance - ) - { - KeeperInfo memory keeper = s_keeperInfo[query]; - return (keeper.payee, keeper.active, keeper.balance); - } - - /** - * @notice read the current configuration of the registry - */ - function getConfig() - external - view - override - returns ( - uint32 paymentPremiumPPB, - uint24 blockCountPerTurn, - uint32 checkGasLimit, - uint24 stalenessSeconds, - uint16 gasCeilingMultiplier, - uint256 fallbackGasPrice, - uint256 fallbackLinkPrice - ) - { - Config memory config = s_config; - return ( - config.paymentPremiumPPB, - config.blockCountPerTurn, - config.checkGasLimit, - config.stalenessSeconds, - config.gasCeilingMultiplier, - s_fallbackGasPrice, - s_fallbackLinkPrice - ); - } - - /** - * @notice getFlatFee gets the flat rate fee charged to customers when performing upkeep, - * in units of of micro LINK - */ - function getFlatFee() external view returns (uint32) { - return s_config.flatFeeMicroLink; - } - - /** - * @notice calculates the minimum balance required for an upkeep to remain eligible - */ - function getMinBalanceForUpkeep(uint256 id) external view returns (uint96 minBalance) { - return getMaxPaymentForGas(s_upkeep[id].executeGas); - } - - /** - * @notice calculates the maximum payment for a given gas limit - */ - function getMaxPaymentForGas(uint256 gasLimit) public view returns (uint96 maxPayment) { - (uint256 gasWei, uint256 linkEth) = getFeedData(); - uint256 adjustedGasWei = adjustGasPrice(gasWei, false); - return calculatePaymentAmount(gasLimit, adjustedGasWei, linkEth); - } - - // PRIVATE - - /** - * @dev retrieves feed data for fast gas/eth and link/eth prices. if the feed - * data is stale it uses the configured fallback price. Once a price is picked - * for gas it takes the min of gas price in the transaction or the fast gas - * price in order to reduce costs for the upkeep clients. - */ - function getFeedData() private view returns (uint256 gasWei, uint256 linkEth) { - uint32 stalenessSeconds = s_config.stalenessSeconds; - bool staleFallback = stalenessSeconds > 0; - uint256 timestamp; - int256 feedValue; - (, feedValue, , timestamp, ) = FAST_GAS_FEED.latestRoundData(); - if ((staleFallback && stalenessSeconds < block.timestamp - timestamp) || feedValue <= 0) { - gasWei = s_fallbackGasPrice; - } else { - gasWei = uint256(feedValue); - } - (, feedValue, , timestamp, ) = LINK_ETH_FEED.latestRoundData(); - if ((staleFallback && stalenessSeconds < block.timestamp - timestamp) || feedValue <= 0) { - linkEth = s_fallbackLinkPrice; - } else { - linkEth = uint256(feedValue); - } - return (gasWei, linkEth); - } - - /** - * @dev calculates LINK paid for gas spent plus a configure premium percentage - */ - function calculatePaymentAmount( - uint256 gasLimit, - uint256 gasWei, - uint256 linkEth - ) private view returns (uint96 payment) { - Config memory config = s_config; - uint256 weiForGas = gasWei.mul(gasLimit.add(REGISTRY_GAS_OVERHEAD)); - uint256 premium = PPB_BASE.add(config.paymentPremiumPPB); - uint256 total = weiForGas.mul(1e9).mul(premium).div(linkEth).add(uint256(config.flatFeeMicroLink).mul(1e12)); - require(total <= LINK_TOTAL_SUPPLY, "payment greater than all LINK"); - return uint96(total); // LINK_TOTAL_SUPPLY < UINT96_MAX - } - - /** - * @dev calls target address with exactly gasAmount gas and data as calldata - * or reverts if at least gasAmount gas is not available - */ - function callWithExactGas( - uint256 gasAmount, - address target, - bytes memory data - ) private returns (bool success) { - assembly { - let g := gas() - // Compute g -= CUSHION and check for underflow - if lt(g, CUSHION) { - revert(0, 0) - } - g := sub(g, CUSHION) - // if g - g//64 <= gasAmount, revert - // (we subtract g//64 because of EIP-150) - if iszero(gt(sub(g, div(g, 64)), gasAmount)) { - revert(0, 0) - } - // solidity calls check that a contract actually exists at the destination, so we do the same - if iszero(extcodesize(target)) { - revert(0, 0) - } - // call and return whether we succeeded. ignore return data - success := call(gasAmount, target, 0, add(data, 0x20), mload(data), 0, 0) - } - return success; - } - - /** - * @dev calls the Upkeep target with the performData param passed in by the - * keeper and the exact gas required by the Upkeep - */ - function performUpkeepWithParams(PerformParams memory params) - private - nonReentrant - validUpkeep(params.id) - returns (bool success) - { - Upkeep memory upkeep = s_upkeep[params.id]; - prePerformUpkeep(upkeep, params.from, params.maxLinkPayment); - - uint256 gasUsed = gasleft(); - bytes memory callData = abi.encodeWithSelector(PERFORM_SELECTOR, params.performData); - success = callWithExactGas(params.gasLimit, upkeep.target, callData); - gasUsed = gasUsed - gasleft(); - - uint96 payment = calculatePaymentAmount(gasUsed, params.adjustedGasWei, params.linkEth); - - uint96 newUpkeepBalance = s_upkeep[params.id].balance.sub(payment); - s_upkeep[params.id].balance = newUpkeepBalance; - s_upkeep[params.id].lastKeeper = params.from; - - uint96 newKeeperBalance = s_keeperInfo[params.from].balance.add(payment); - s_keeperInfo[params.from].balance = newKeeperBalance; - - emit UpkeepPerformed(params.id, success, params.from, payment, params.performData); - return success; - } - - /** - * @dev ensures a upkeep is valid - */ - function validateUpkeep(uint256 id) private view { - require(s_upkeep[id].maxValidBlocknumber > block.number, "invalid upkeep id"); - } - - /** - * @dev ensures all required checks are passed before an upkeep is performed - */ - function prePerformUpkeep( - Upkeep memory upkeep, - address from, - uint256 maxLinkPayment - ) private view { - require(s_keeperInfo[from].active, "only active keepers"); - require(upkeep.balance >= maxLinkPayment, "insufficient funds"); - require(upkeep.lastKeeper != from, "keepers must take turns"); - } - - /** - * @dev adjusts the gas price to min(ceiling, tx.gasprice) or just uses the ceiling if tx.gasprice is disabled - */ - function adjustGasPrice(uint256 gasWei, bool useTxGasPrice) private view returns (uint256 adjustedPrice) { - adjustedPrice = gasWei.mul(s_config.gasCeilingMultiplier); - if (useTxGasPrice && tx.gasprice < adjustedPrice) { - adjustedPrice = tx.gasprice; - } - } - - /** - * @dev generates a PerformParams struct for use in performUpkeepWithParams() - */ - function generatePerformParams( - address from, - uint256 id, - bytes memory performData, - bool useTxGasPrice - ) private view returns (PerformParams memory) { - uint256 gasLimit = s_upkeep[id].executeGas; - (uint256 gasWei, uint256 linkEth) = getFeedData(); - uint256 adjustedGasWei = adjustGasPrice(gasWei, useTxGasPrice); - uint96 maxLinkPayment = calculatePaymentAmount(gasLimit, adjustedGasWei, linkEth); - - return - PerformParams({ - from: from, - id: id, - performData: performData, - maxLinkPayment: maxLinkPayment, - gasLimit: gasLimit, - adjustedGasWei: adjustedGasWei, - linkEth: linkEth - }); - } - - /** - * @dev extracts a revert reason from a call result payload - */ - function getRevertMsg(bytes memory _payload) private pure returns (string memory) { - if (_payload.length < 68) return "transaction reverted silently"; - assembly { - _payload := add(_payload, 0x04) - } - return abi.decode(_payload, (string)); - } - - // MODIFIERS - - /** - * @dev ensures a upkeep is valid - */ - modifier validUpkeep(uint256 id) { - validateUpkeep(id); - _; - } - - /** - * @dev ensures that burns don't accidentally happen by sending to the zero - * address - */ - modifier validateRecipient(address to) { - require(to != address(0), "cannot send to zero address"); - _; - } - - /** - * @dev Reverts if called by anyone other than the contract owner or registrar. - */ - modifier onlyOwnerOrRegistrar() { - require(msg.sender == owner() || msg.sender == s_registrar, "Only callable by owner or registrar"); - _; - } -} diff --git a/contracts/src/v0.7/KeeperRegistry1_1Mock.sol b/contracts/src/v0.7/KeeperRegistry1_1Mock.sol deleted file mode 100644 index 3acbfb5e7af..00000000000 --- a/contracts/src/v0.7/KeeperRegistry1_1Mock.sol +++ /dev/null @@ -1,351 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -contract KeeperRegistry1_1Mock { - event ConfigSet( - uint32 paymentPremiumPPB, - uint24 blockCountPerTurn, - uint32 checkGasLimit, - uint24 stalenessSeconds, - uint16 gasCeilingMultiplier, - uint256 fallbackGasPrice, - uint256 fallbackLinkPrice - ); - event FlatFeeSet(uint32 flatFeeMicroLink); - event FundsAdded(uint256 indexed id, address indexed from, uint96 amount); - event FundsWithdrawn(uint256 indexed id, uint256 amount, address to); - event KeepersUpdated(address[] keepers, address[] payees); - event OwnershipTransferRequested(address indexed from, address indexed to); - event OwnershipTransferred(address indexed from, address indexed to); - event Paused(address account); - event PayeeshipTransferRequested(address indexed keeper, address indexed from, address indexed to); - event PayeeshipTransferred(address indexed keeper, address indexed from, address indexed to); - event PaymentWithdrawn(address indexed keeper, uint256 indexed amount, address indexed to, address payee); - event RegistrarChanged(address indexed from, address indexed to); - event Unpaused(address account); - event UpkeepCanceled(uint256 indexed id, uint64 indexed atBlockHeight); - event UpkeepPerformed( - uint256 indexed id, - bool indexed success, - address indexed from, - uint96 payment, - bytes performData - ); - event UpkeepRegistered(uint256 indexed id, uint32 executeGas, address admin); - - function emitConfigSet( - uint32 paymentPremiumPPB, - uint24 blockCountPerTurn, - uint32 checkGasLimit, - uint24 stalenessSeconds, - uint16 gasCeilingMultiplier, - uint256 fallbackGasPrice, - uint256 fallbackLinkPrice - ) public { - emit ConfigSet( - paymentPremiumPPB, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - fallbackGasPrice, - fallbackLinkPrice - ); - } - - function emitFlatFeeSet(uint32 flatFeeMicroLink) public { - emit FlatFeeSet(flatFeeMicroLink); - } - - function emitFundsAdded(uint256 id, address from, uint96 amount) public { - emit FundsAdded(id, from, amount); - } - - function emitFundsWithdrawn(uint256 id, uint256 amount, address to) public { - emit FundsWithdrawn(id, amount, to); - } - - function emitKeepersUpdated(address[] memory keepers, address[] memory payees) public { - emit KeepersUpdated(keepers, payees); - } - - function emitOwnershipTransferRequested(address from, address to) public { - emit OwnershipTransferRequested(from, to); - } - - function emitOwnershipTransferred(address from, address to) public { - emit OwnershipTransferred(from, to); - } - - function emitPaused(address account) public { - emit Paused(account); - } - - function emitPayeeshipTransferRequested(address keeper, address from, address to) public { - emit PayeeshipTransferRequested(keeper, from, to); - } - - function emitPayeeshipTransferred(address keeper, address from, address to) public { - emit PayeeshipTransferred(keeper, from, to); - } - - function emitPaymentWithdrawn(address keeper, uint256 amount, address to, address payee) public { - emit PaymentWithdrawn(keeper, amount, to, payee); - } - - function emitRegistrarChanged(address from, address to) public { - emit RegistrarChanged(from, to); - } - - function emitUnpaused(address account) public { - emit Unpaused(account); - } - - function emitUpkeepCanceled(uint256 id, uint64 atBlockHeight) public { - emit UpkeepCanceled(id, atBlockHeight); - } - - function emitUpkeepPerformed( - uint256 id, - bool success, - address from, - uint96 payment, - bytes memory performData - ) public { - emit UpkeepPerformed(id, success, from, payment, performData); - } - - function emitUpkeepRegistered(uint256 id, uint32 executeGas, address admin) public { - emit UpkeepRegistered(id, executeGas, admin); - } - - uint256 private s_upkeepCount; - - // Function to set the current number of registered upkeeps - function setUpkeepCount(uint256 _upkeepCount) external { - s_upkeepCount = _upkeepCount; - } - - // Function to get the current number of registered upkeeps - function getUpkeepCount() external view returns (uint256) { - return s_upkeepCount; - } - - uint256[] private s_canceledUpkeepList; - - // Function to set the current number of canceled upkeeps - function setCanceledUpkeepList(uint256[] memory _canceledUpkeepList) external { - s_canceledUpkeepList = _canceledUpkeepList; - } - - // Function to set the current number of canceled upkeeps - function getCanceledUpkeepList() external view returns (uint256[] memory) { - return s_canceledUpkeepList; - } - - address[] private s_keeperList; - - // Function to set the keeper list for testing purposes - function setKeeperList(address[] memory _keepers) external { - s_keeperList = _keepers; - } - - // Function to get the keeper list - function getKeeperList() external view returns (address[] memory) { - return s_keeperList; - } - - struct Config { - uint32 paymentPremiumPPB; - uint32 flatFeeMicroLink; // min 0.000001 LINK, max 4294 LINK - uint24 blockCountPerTurn; - uint32 checkGasLimit; - uint24 stalenessSeconds; - uint16 gasCeilingMultiplier; - } - - Config private s_config; - uint256 private s_fallbackGasPrice; - uint256 private s_fallbackLinkPrice; - - // Function to set the configuration for testing purposes - function setConfig( - uint32 _paymentPremiumPPB, - uint32 _flatFeeMicroLink, - uint24 _blockCountPerTurn, - uint32 _checkGasLimit, - uint24 _stalenessSeconds, - uint16 _gasCeilingMultiplier, - uint256 _fallbackGasPrice, - uint256 _fallbackLinkPrice - ) external { - s_config.paymentPremiumPPB = _paymentPremiumPPB; - s_config.flatFeeMicroLink = _flatFeeMicroLink; - s_config.blockCountPerTurn = _blockCountPerTurn; - s_config.checkGasLimit = _checkGasLimit; - s_config.stalenessSeconds = _stalenessSeconds; - s_config.gasCeilingMultiplier = _gasCeilingMultiplier; - s_fallbackGasPrice = _fallbackGasPrice; - s_fallbackLinkPrice = _fallbackLinkPrice; - } - - // Function to get the configuration - function getConfig() - external - view - returns ( - uint32 paymentPremiumPPB, - uint24 blockCountPerTurn, - uint32 checkGasLimit, - uint24 stalenessSeconds, - uint16 gasCeilingMultiplier, - uint256 fallbackGasPrice, - uint256 fallbackLinkPrice - ) - { - return ( - s_config.paymentPremiumPPB, - s_config.blockCountPerTurn, - s_config.checkGasLimit, - s_config.stalenessSeconds, - s_config.gasCeilingMultiplier, - s_fallbackGasPrice, - s_fallbackLinkPrice - ); - } - - struct Upkeep { - address target; - uint32 executeGas; - uint96 balance; - address admin; - uint64 maxValidBlocknumber; - address lastKeeper; - } - - mapping(uint256 => Upkeep) private s_upkeep; - mapping(uint256 => bytes) private s_checkData; - - // Function to set the upkeep and checkData for testing purposes - function setUpkeep( - uint256 id, - address _target, - uint32 _executeGas, - uint96 _balance, - address _admin, - uint64 _maxValidBlocknumber, - address _lastKeeper, - bytes memory _checkData - ) external { - Upkeep memory upkeep = Upkeep({ - target: _target, - executeGas: _executeGas, - balance: _balance, - admin: _admin, - maxValidBlocknumber: _maxValidBlocknumber, - lastKeeper: _lastKeeper - }); - - s_upkeep[id] = upkeep; - s_checkData[id] = _checkData; - } - - // Function to get the upkeep and checkData - function getUpkeep( - uint256 id - ) - external - view - returns ( - address target, - uint32 executeGas, - bytes memory checkData, - uint96 balance, - address lastKeeper, - address admin, - uint64 maxValidBlocknumber - ) - { - Upkeep memory reg = s_upkeep[id]; - return ( - reg.target, - reg.executeGas, - s_checkData[id], - reg.balance, - reg.lastKeeper, - reg.admin, - reg.maxValidBlocknumber - ); - } - - mapping(uint256 => uint96) private s_minBalances; - - // Function to set the minimum balance for a specific upkeep id - function setMinBalance(uint256 id, uint96 minBalance) external { - s_minBalances[id] = minBalance; - } - - // Function to get the minimum balance for a specific upkeep id - function getMinBalanceForUpkeep(uint256 id) external view returns (uint96) { - return s_minBalances[id]; - } - - struct UpkeepData { - bytes performData; - uint256 maxLinkPayment; - uint256 gasLimit; - uint256 adjustedGasWei; - uint256 linkEth; - } - - mapping(uint256 => UpkeepData) private s_upkeepData; - - // Function to set mock data for the checkUpkeep function - function setCheckUpkeepData( - uint256 id, - bytes memory performData, - uint256 maxLinkPayment, - uint256 gasLimit, - uint256 adjustedGasWei, - uint256 linkEth - ) external { - s_upkeepData[id] = UpkeepData({ - performData: performData, - maxLinkPayment: maxLinkPayment, - gasLimit: gasLimit, - adjustedGasWei: adjustedGasWei, - linkEth: linkEth - }); - } - - // Mock checkUpkeep function - function checkUpkeep( - uint256 id, - address from - ) - external - view - returns ( - bytes memory performData, - uint256 maxLinkPayment, - uint256 gasLimit, - uint256 adjustedGasWei, - uint256 linkEth - ) - { - UpkeepData storage data = s_upkeepData[id]; - return (data.performData, data.maxLinkPayment, data.gasLimit, data.adjustedGasWei, data.linkEth); - } - - mapping(uint256 => bool) private s_upkeepSuccess; - - // Function to set mock return data for the performUpkeep function - function setPerformUpkeepSuccess(uint256 id, bool success) external { - s_upkeepSuccess[id] = success; - } - - // Mock performUpkeep function - function performUpkeep(uint256 id, bytes calldata performData) external returns (bool success) { - return s_upkeepSuccess[id]; - } -} diff --git a/contracts/src/v0.7/LinkTokenReceiver.sol b/contracts/src/v0.7/LinkTokenReceiver.sol deleted file mode 100644 index d98cc25d843..00000000000 --- a/contracts/src/v0.7/LinkTokenReceiver.sol +++ /dev/null @@ -1,57 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -abstract contract LinkTokenReceiver { - /** - * @notice Called when LINK is sent to the contract via `transferAndCall` - * @dev The data payload's first 2 words will be overwritten by the `sender` and `amount` - * values to ensure correctness. Calls oracleRequest. - * @param sender Address of the sender - * @param amount Amount of LINK sent (specified in wei) - * @param data Payload of the transaction - */ - function onTokenTransfer( - address sender, - uint256 amount, - bytes memory data - ) public validateFromLINK permittedFunctionsForLINK(data) { - assembly { - // solhint-disable-next-line avoid-low-level-calls - mstore(add(data, 36), sender) // ensure correct sender is passed - // solhint-disable-next-line avoid-low-level-calls - mstore(add(data, 68), amount) // ensure correct amount is passed - } - // solhint-disable-next-line avoid-low-level-calls - (bool success, ) = address(this).delegatecall(data); // calls oracleRequest - require(success, "Unable to create request"); - } - - function getChainlinkToken() public view virtual returns (address); - - /** - * @notice Validate the function called on token transfer - */ - function _validateTokenTransferAction(bytes4 funcSelector, bytes memory data) internal virtual; - - /** - * @dev Reverts if not sent from the LINK token - */ - modifier validateFromLINK() { - require(msg.sender == getChainlinkToken(), "Must use LINK token"); - _; - } - - /** - * @dev Reverts if the given data does not begin with the `oracleRequest` function selector - * @param data The data payload of the request - */ - modifier permittedFunctionsForLINK(bytes memory data) { - bytes4 funcSelector; - assembly { - // solhint-disable-next-line avoid-low-level-calls - funcSelector := mload(add(data, 32)) - } - _validateTokenTransferAction(funcSelector, data); - _; - } -} diff --git a/contracts/src/v0.7/Operator.sol b/contracts/src/v0.7/Operator.sol deleted file mode 100644 index b61680d2ed0..00000000000 --- a/contracts/src/v0.7/Operator.sol +++ /dev/null @@ -1,580 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "./AuthorizedReceiver.sol"; -import "./LinkTokenReceiver.sol"; -import "./ConfirmedOwner.sol"; -import "./interfaces/LinkTokenInterface.sol"; -import "./interfaces/OperatorInterface.sol"; -import "./interfaces/OwnableInterface.sol"; -import "./interfaces/WithdrawalInterface.sol"; -import "./vendor/Address.sol"; -import "./vendor/SafeMathChainlink.sol"; - -/** - * @title The Chainlink Operator contract - * @notice Node operators can deploy this contract to fulfill requests sent to them - */ -contract Operator is AuthorizedReceiver, ConfirmedOwner, LinkTokenReceiver, OperatorInterface, WithdrawalInterface { - using Address for address; - using SafeMathChainlink for uint256; - - struct Commitment { - bytes31 paramsHash; - uint8 dataVersion; - } - - uint256 public constant getExpiryTime = 5 minutes; - uint256 private constant MAXIMUM_DATA_VERSION = 256; - uint256 private constant MINIMUM_CONSUMER_GAS_LIMIT = 400000; - uint256 private constant SELECTOR_LENGTH = 4; - uint256 private constant EXPECTED_REQUEST_WORDS = 2; - uint256 private constant MINIMUM_REQUEST_LENGTH = SELECTOR_LENGTH + (32 * EXPECTED_REQUEST_WORDS); - // We initialize fields to 1 instead of 0 so that the first invocation - // does not cost more gas. - uint256 private constant ONE_FOR_CONSISTENT_GAS_COST = 1; - // oracleRequest is intended for version 1, enabling single word responses - bytes4 private constant ORACLE_REQUEST_SELECTOR = this.oracleRequest.selector; - // operatorRequest is intended for version 2, enabling multi-word responses - bytes4 private constant OPERATOR_REQUEST_SELECTOR = this.operatorRequest.selector; - - LinkTokenInterface internal immutable linkToken; - mapping(bytes32 => Commitment) private s_commitments; - mapping(address => bool) private s_owned; - // Tokens sent for requests that have not been fulfilled yet - uint256 private s_tokensInEscrow = ONE_FOR_CONSISTENT_GAS_COST; - - event OracleRequest( - bytes32 indexed specId, - address requester, - bytes32 requestId, - uint256 payment, - address callbackAddr, - bytes4 callbackFunctionId, - uint256 cancelExpiration, - uint256 dataVersion, - bytes data - ); - - event CancelOracleRequest(bytes32 indexed requestId); - - event OracleResponse(bytes32 indexed requestId); - - event OwnableContractAccepted(address indexed acceptedContract); - - event TargetsUpdatedAuthorizedSenders(address[] targets, address[] senders, address changedBy); - - /** - * @notice Deploy with the address of the LINK token - * @dev Sets the LinkToken address for the imported LinkTokenInterface - * @param link The address of the LINK token - * @param owner The address of the owner - */ - constructor(address link, address owner) ConfirmedOwner(owner) { - linkToken = LinkTokenInterface(link); // external but already deployed and unalterable - } - - /** - * @notice The type and version of this contract - * @return Type and version string - */ - function typeAndVersion() external pure virtual returns (string memory) { - return "Operator 1.0.0"; - } - - /** - * @notice Creates the Chainlink request. This is a backwards compatible API - * with the Oracle.sol contract, but the behavior changes because - * callbackAddress is assumed to be the same as the request sender. - * @param callbackAddress The consumer of the request - * @param payment The amount of payment given (specified in wei) - * @param specId The Job Specification ID - * @param callbackAddress The address the oracle data will be sent to - * @param callbackFunctionId The callback function ID for the response - * @param nonce The nonce sent by the requester - * @param dataVersion The specified data version - * @param data The extra request parameters - */ - function oracleRequest( - address sender, - uint256 payment, - bytes32 specId, - address callbackAddress, - bytes4 callbackFunctionId, - uint256 nonce, - uint256 dataVersion, - bytes calldata data - ) external override validateFromLINK { - (bytes32 requestId, uint256 expiration) = _verifyAndProcessOracleRequest( - sender, - payment, - callbackAddress, - callbackFunctionId, - nonce, - dataVersion - ); - emit OracleRequest(specId, sender, requestId, payment, sender, callbackFunctionId, expiration, dataVersion, data); - } - - /** - * @notice Creates the Chainlink request - * @dev Stores the hash of the params as the on-chain commitment for the request. - * Emits OracleRequest event for the Chainlink node to detect. - * @param sender The sender of the request - * @param payment The amount of payment given (specified in wei) - * @param specId The Job Specification ID - * @param callbackFunctionId The callback function ID for the response - * @param nonce The nonce sent by the requester - * @param dataVersion The specified data version - * @param data The extra request parameters - */ - function operatorRequest( - address sender, - uint256 payment, - bytes32 specId, - bytes4 callbackFunctionId, - uint256 nonce, - uint256 dataVersion, - bytes calldata data - ) external override validateFromLINK { - (bytes32 requestId, uint256 expiration) = _verifyAndProcessOracleRequest( - sender, - payment, - sender, - callbackFunctionId, - nonce, - dataVersion - ); - emit OracleRequest(specId, sender, requestId, payment, sender, callbackFunctionId, expiration, dataVersion, data); - } - - /** - * @notice Called by the Chainlink node to fulfill requests - * @dev Given params must hash back to the commitment stored from `oracleRequest`. - * Will call the callback address' callback function without bubbling up error - * checking in a `require` so that the node can get paid. - * @param requestId The fulfillment request ID that must match the requester's - * @param payment The payment amount that will be released for the oracle (specified in wei) - * @param callbackAddress The callback address to call for fulfillment - * @param callbackFunctionId The callback function ID to use for fulfillment - * @param expiration The expiration that the node should respond by before the requester can cancel - * @param data The data to return to the consuming contract - * @return Status if the external call was successful - */ - function fulfillOracleRequest( - bytes32 requestId, - uint256 payment, - address callbackAddress, - bytes4 callbackFunctionId, - uint256 expiration, - bytes32 data - ) - external - override - validateAuthorizedSender - validateRequestId(requestId) - validateCallbackAddress(callbackAddress) - returns (bool) - { - _verifyOracleRequestAndProcessPayment(requestId, payment, callbackAddress, callbackFunctionId, expiration, 1); - emit OracleResponse(requestId); - require(gasleft() >= MINIMUM_CONSUMER_GAS_LIMIT, "Must provide consumer enough gas"); - // All updates to the oracle's fulfillment should come before calling the - // callback(addr+functionId) as it is untrusted. - // See: https://solidity.readthedocs.io/en/develop/security-considerations.html#use-the-checks-effects-interactions-pattern - (bool success, ) = callbackAddress.call(abi.encodeWithSelector(callbackFunctionId, requestId, data)); // solhint-disable-line avoid-low-level-calls - return success; - } - - /** - * @notice Called by the Chainlink node to fulfill requests with multi-word support - * @dev Given params must hash back to the commitment stored from `oracleRequest`. - * Will call the callback address' callback function without bubbling up error - * checking in a `require` so that the node can get paid. - * @param requestId The fulfillment request ID that must match the requester's - * @param payment The payment amount that will be released for the oracle (specified in wei) - * @param callbackAddress The callback address to call for fulfillment - * @param callbackFunctionId The callback function ID to use for fulfillment - * @param expiration The expiration that the node should respond by before the requester can cancel - * @param data The data to return to the consuming contract - * @return Status if the external call was successful - */ - function fulfillOracleRequest2( - bytes32 requestId, - uint256 payment, - address callbackAddress, - bytes4 callbackFunctionId, - uint256 expiration, - bytes calldata data - ) - external - override - validateAuthorizedSender - validateRequestId(requestId) - validateCallbackAddress(callbackAddress) - validateMultiWordResponseId(requestId, data) - returns (bool) - { - _verifyOracleRequestAndProcessPayment(requestId, payment, callbackAddress, callbackFunctionId, expiration, 2); - emit OracleResponse(requestId); - require(gasleft() >= MINIMUM_CONSUMER_GAS_LIMIT, "Must provide consumer enough gas"); - // All updates to the oracle's fulfillment should come before calling the - // callback(addr+functionId) as it is untrusted. - // See: https://solidity.readthedocs.io/en/develop/security-considerations.html#use-the-checks-effects-interactions-pattern - (bool success, ) = callbackAddress.call(abi.encodePacked(callbackFunctionId, data)); // solhint-disable-line avoid-low-level-calls - return success; - } - - /** - * @notice Transfer the ownership of ownable contracts. This is primarily - * intended for Authorized Forwarders but could possibly be extended to work - * with future contracts. - * @param ownable list of addresses to transfer - * @param newOwner address to transfer ownership to - */ - function transferOwnableContracts(address[] calldata ownable, address newOwner) external onlyOwner { - for (uint256 i = 0; i < ownable.length; i++) { - s_owned[ownable[i]] = false; - OwnableInterface(ownable[i]).transferOwnership(newOwner); - } - } - - /** - * @notice Accept the ownership of an ownable contract. This is primarily - * intended for Authorized Forwarders but could possibly be extended to work - * with future contracts. - * @dev Must be the pending owner on the contract - * @param ownable list of addresses of Ownable contracts to accept - */ - function acceptOwnableContracts(address[] calldata ownable) public validateAuthorizedSenderSetter { - for (uint256 i = 0; i < ownable.length; i++) { - s_owned[ownable[i]] = true; - emit OwnableContractAccepted(ownable[i]); - OwnableInterface(ownable[i]).acceptOwnership(); - } - } - - /** - * @notice Sets the fulfillment permission for - * @param targets The addresses to set permissions on - * @param senders The addresses that are allowed to send updates - */ - function setAuthorizedSendersOn(address[] calldata targets, address[] calldata senders) - public - validateAuthorizedSenderSetter - { - TargetsUpdatedAuthorizedSenders(targets, senders, msg.sender); - - for (uint256 i = 0; i < targets.length; i++) { - AuthorizedReceiverInterface(targets[i]).setAuthorizedSenders(senders); - } - } - - /** - * @notice Accepts ownership of ownable contracts and then immediately sets - * the authorized sender list on each of the newly owned contracts. This is - * primarily intended for Authorized Forwarders but could possibly be - * extended to work with future contracts. - * @param targets The addresses to set permissions on - * @param senders The addresses that are allowed to send updates - */ - function acceptAuthorizedReceivers(address[] calldata targets, address[] calldata senders) - external - validateAuthorizedSenderSetter - { - acceptOwnableContracts(targets); - setAuthorizedSendersOn(targets, senders); - } - - /** - * @notice Allows the node operator to withdraw earned LINK to a given address - * @dev The owner of the contract can be another wallet and does not have to be a Chainlink node - * @param recipient The address to send the LINK token to - * @param amount The amount to send (specified in wei) - */ - function withdraw(address recipient, uint256 amount) - external - override(OracleInterface, WithdrawalInterface) - onlyOwner - validateAvailableFunds(amount) - { - assert(linkToken.transfer(recipient, amount)); - } - - /** - * @notice Displays the amount of LINK that is available for the node operator to withdraw - * @dev We use `ONE_FOR_CONSISTENT_GAS_COST` in place of 0 in storage - * @return The amount of withdrawable LINK on the contract - */ - function withdrawable() external view override(OracleInterface, WithdrawalInterface) returns (uint256) { - return _fundsAvailable(); - } - - /** - * @notice Forward a call to another contract - * @dev Only callable by the owner - * @param to address - * @param data to forward - */ - function ownerForward(address to, bytes calldata data) external onlyOwner validateNotToLINK(to) { - require(to.isContract(), "Must forward to a contract"); - (bool status, ) = to.call(data); - require(status, "Forwarded call failed"); - } - - /** - * @notice Interact with other LinkTokenReceiver contracts by calling transferAndCall - * @param to The address to transfer to. - * @param value The amount to be transferred. - * @param data The extra data to be passed to the receiving contract. - * @return success bool - */ - function ownerTransferAndCall( - address to, - uint256 value, - bytes calldata data - ) external override onlyOwner validateAvailableFunds(value) returns (bool success) { - return linkToken.transferAndCall(to, value, data); - } - - /** - * @notice Distribute funds to multiple addresses using ETH send - * to this payable function. - * @dev Array length must be equal, ETH sent must equal the sum of amounts. - * A malicious receiver could cause the distribution to revert, in which case - * it is expected that the address is removed from the list. - * @param receivers list of addresses - * @param amounts list of amounts - */ - function distributeFunds(address payable[] calldata receivers, uint256[] calldata amounts) external payable { - require(receivers.length > 0 && receivers.length == amounts.length, "Invalid array length(s)"); - uint256 valueRemaining = msg.value; - for (uint256 i = 0; i < receivers.length; i++) { - uint256 sendAmount = amounts[i]; - valueRemaining = valueRemaining.sub(sendAmount); - receivers[i].transfer(sendAmount); - } - require(valueRemaining == 0, "Too much ETH sent"); - } - - /** - * @notice Allows recipient to cancel requests sent to this oracle contract. - * Will transfer the LINK sent for the request back to the recipient address. - * @dev Given params must hash to a commitment stored on the contract in order - * for the request to be valid. Emits CancelOracleRequest event. - * @param requestId The request ID - * @param payment The amount of payment given (specified in wei) - * @param callbackFunc The requester's specified callback function selector - * @param expiration The time of the expiration for the request - */ - function cancelOracleRequest( - bytes32 requestId, - uint256 payment, - bytes4 callbackFunc, - uint256 expiration - ) external override { - bytes31 paramsHash = _buildParamsHash(payment, msg.sender, callbackFunc, expiration); - require(s_commitments[requestId].paramsHash == paramsHash, "Params do not match request ID"); - // solhint-disable-next-line not-rely-on-time - require(expiration <= block.timestamp, "Request is not expired"); - - delete s_commitments[requestId]; - emit CancelOracleRequest(requestId); - - linkToken.transfer(msg.sender, payment); - } - - /** - * @notice Allows requester to cancel requests sent to this oracle contract. - * Will transfer the LINK sent for the request back to the recipient address. - * @dev Given params must hash to a commitment stored on the contract in order - * for the request to be valid. Emits CancelOracleRequest event. - * @param nonce The nonce used to generate the request ID - * @param payment The amount of payment given (specified in wei) - * @param callbackFunc The requester's specified callback function selector - * @param expiration The time of the expiration for the request - */ - function cancelOracleRequestByRequester( - uint256 nonce, - uint256 payment, - bytes4 callbackFunc, - uint256 expiration - ) external { - bytes32 requestId = keccak256(abi.encodePacked(msg.sender, nonce)); - bytes31 paramsHash = _buildParamsHash(payment, msg.sender, callbackFunc, expiration); - require(s_commitments[requestId].paramsHash == paramsHash, "Params do not match request ID"); - // solhint-disable-next-line not-rely-on-time - require(expiration <= block.timestamp, "Request is not expired"); - - delete s_commitments[requestId]; - emit CancelOracleRequest(requestId); - - linkToken.transfer(msg.sender, payment); - } - - /** - * @notice Returns the address of the LINK token - * @dev This is the public implementation for chainlinkTokenAddress, which is - * an internal method of the ChainlinkClient contract - */ - function getChainlinkToken() public view override returns (address) { - return address(linkToken); - } - - /** - * @notice Require that the token transfer action is valid - * @dev OPERATOR_REQUEST_SELECTOR = multiword, ORACLE_REQUEST_SELECTOR = singleword - */ - function _validateTokenTransferAction(bytes4 funcSelector, bytes memory data) internal pure override { - require(data.length >= MINIMUM_REQUEST_LENGTH, "Invalid request length"); - require( - funcSelector == OPERATOR_REQUEST_SELECTOR || funcSelector == ORACLE_REQUEST_SELECTOR, - "Must use whitelisted functions" - ); - } - - /** - * @notice Verify the Oracle Request and record necessary information - * @param sender The sender of the request - * @param payment The amount of payment given (specified in wei) - * @param callbackAddress The callback address for the response - * @param callbackFunctionId The callback function ID for the response - * @param nonce The nonce sent by the requester - */ - function _verifyAndProcessOracleRequest( - address sender, - uint256 payment, - address callbackAddress, - bytes4 callbackFunctionId, - uint256 nonce, - uint256 dataVersion - ) private validateNotToLINK(callbackAddress) returns (bytes32 requestId, uint256 expiration) { - requestId = keccak256(abi.encodePacked(sender, nonce)); - require(s_commitments[requestId].paramsHash == 0, "Must use a unique ID"); - // solhint-disable-next-line not-rely-on-time - expiration = block.timestamp.add(getExpiryTime); - bytes31 paramsHash = _buildParamsHash(payment, callbackAddress, callbackFunctionId, expiration); - s_commitments[requestId] = Commitment(paramsHash, _safeCastToUint8(dataVersion)); - s_tokensInEscrow = s_tokensInEscrow.add(payment); - return (requestId, expiration); - } - - /** - * @notice Verify the Oracle request and unlock escrowed payment - * @param requestId The fulfillment request ID that must match the requester's - * @param payment The payment amount that will be released for the oracle (specified in wei) - * @param callbackAddress The callback address to call for fulfillment - * @param callbackFunctionId The callback function ID to use for fulfillment - * @param expiration The expiration that the node should respond by before the requester can cancel - */ - function _verifyOracleRequestAndProcessPayment( - bytes32 requestId, - uint256 payment, - address callbackAddress, - bytes4 callbackFunctionId, - uint256 expiration, - uint256 dataVersion - ) internal { - bytes31 paramsHash = _buildParamsHash(payment, callbackAddress, callbackFunctionId, expiration); - require(s_commitments[requestId].paramsHash == paramsHash, "Params do not match request ID"); - require(s_commitments[requestId].dataVersion <= _safeCastToUint8(dataVersion), "Data versions must match"); - s_tokensInEscrow = s_tokensInEscrow.sub(payment); - delete s_commitments[requestId]; - } - - /** - * @notice Build the bytes31 hash from the payment, callback and expiration. - * @param payment The payment amount that will be released for the oracle (specified in wei) - * @param callbackAddress The callback address to call for fulfillment - * @param callbackFunctionId The callback function ID to use for fulfillment - * @param expiration The expiration that the node should respond by before the requester can cancel - * @return hash bytes31 - */ - function _buildParamsHash( - uint256 payment, - address callbackAddress, - bytes4 callbackFunctionId, - uint256 expiration - ) internal pure returns (bytes31) { - return bytes31(keccak256(abi.encodePacked(payment, callbackAddress, callbackFunctionId, expiration))); - } - - /** - * @notice Safely cast uint256 to uint8 - * @param number uint256 - * @return uint8 number - */ - function _safeCastToUint8(uint256 number) internal pure returns (uint8) { - require(number < MAXIMUM_DATA_VERSION, "number too big to cast"); - return uint8(number); - } - - /** - * @notice Returns the LINK available in this contract, not locked in escrow - * @return uint256 LINK tokens available - */ - function _fundsAvailable() private view returns (uint256) { - uint256 inEscrow = s_tokensInEscrow.sub(ONE_FOR_CONSISTENT_GAS_COST); - return linkToken.balanceOf(address(this)).sub(inEscrow); - } - - /** - * @notice concrete implementation of AuthorizedReceiver - * @return bool of whether sender is authorized - */ - function _canSetAuthorizedSenders() internal view override returns (bool) { - return isAuthorizedSender(msg.sender) || owner() == msg.sender; - } - - // MODIFIERS - - /** - * @dev Reverts if the first 32 bytes of the bytes array is not equal to requestId - * @param requestId bytes32 - * @param data bytes - */ - modifier validateMultiWordResponseId(bytes32 requestId, bytes calldata data) { - require(data.length >= 32, "Response must be > 32 bytes"); - bytes32 firstDataWord; - assembly { - firstDataWord := calldataload(data.offset) - } - require(requestId == firstDataWord, "First word must be requestId"); - _; - } - - /** - * @dev Reverts if amount requested is greater than withdrawable balance - * @param amount The given amount to compare to `s_withdrawableTokens` - */ - modifier validateAvailableFunds(uint256 amount) { - require(_fundsAvailable() >= amount, "Amount requested is greater than withdrawable balance"); - _; - } - - /** - * @dev Reverts if request ID does not exist - * @param requestId The given request ID to check in stored `commitments` - */ - modifier validateRequestId(bytes32 requestId) { - require(s_commitments[requestId].paramsHash != 0, "Must have a valid requestId"); - _; - } - - /** - * @dev Reverts if the callback address is the LINK token - * @param to The callback address - */ - modifier validateNotToLINK(address to) { - require(to != address(linkToken), "Cannot call to LINK"); - _; - } - - /** - * @dev Reverts if the target address is owned by the operator - */ - modifier validateCallbackAddress(address callbackAddress) { - require(!s_owned[callbackAddress], "Cannot call owned contract"); - _; - } -} diff --git a/contracts/src/v0.7/OperatorFactory.sol b/contracts/src/v0.7/OperatorFactory.sol deleted file mode 100644 index b137ab4b3bd..00000000000 --- a/contracts/src/v0.7/OperatorFactory.sol +++ /dev/null @@ -1,93 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "./Operator.sol"; -import "./AuthorizedForwarder.sol"; - -/** - * @title Operator Factory - * @notice Creates Operator contracts for node operators - */ -contract OperatorFactory { - address public immutable getChainlinkToken; - mapping(address => bool) private s_created; - - event OperatorCreated(address indexed operator, address indexed owner, address indexed sender); - event AuthorizedForwarderCreated(address indexed forwarder, address indexed owner, address indexed sender); - - /** - * @param linkAddress address - */ - constructor(address linkAddress) { - getChainlinkToken = linkAddress; - } - - /** - * @notice The type and version of this contract - * @return Type and version string - */ - function typeAndVersion() external pure virtual returns (string memory) { - return "OperatorFactory 1.0.0"; - } - - /** - * @notice creates a new Operator contract with the msg.sender as owner - */ - function deployNewOperator() external returns (address) { - Operator operator = new Operator(getChainlinkToken, msg.sender); - - s_created[address(operator)] = true; - emit OperatorCreated(address(operator), msg.sender, msg.sender); - - return address(operator); - } - - /** - * @notice creates a new Operator contract with the msg.sender as owner and a - * new Operator Forwarder with the Operator as the owner - */ - function deployNewOperatorAndForwarder() external returns (address, address) { - Operator operator = new Operator(getChainlinkToken, msg.sender); - s_created[address(operator)] = true; - emit OperatorCreated(address(operator), msg.sender, msg.sender); - - bytes memory tmp = new bytes(0); - AuthorizedForwarder forwarder = new AuthorizedForwarder(getChainlinkToken, address(this), address(operator), tmp); - s_created[address(forwarder)] = true; - emit AuthorizedForwarderCreated(address(forwarder), address(this), msg.sender); - - return (address(operator), address(forwarder)); - } - - /** - * @notice creates a new Forwarder contract with the msg.sender as owner - */ - function deployNewForwarder() external returns (address) { - bytes memory tmp = new bytes(0); - AuthorizedForwarder forwarder = new AuthorizedForwarder(getChainlinkToken, msg.sender, address(0), tmp); - - s_created[address(forwarder)] = true; - emit AuthorizedForwarderCreated(address(forwarder), msg.sender, msg.sender); - - return address(forwarder); - } - - /** - * @notice creates a new Forwarder contract with the msg.sender as owner - */ - function deployNewForwarderAndTransferOwnership(address to, bytes calldata message) external returns (address) { - AuthorizedForwarder forwarder = new AuthorizedForwarder(getChainlinkToken, msg.sender, to, message); - - s_created[address(forwarder)] = true; - emit AuthorizedForwarderCreated(address(forwarder), msg.sender, msg.sender); - - return address(forwarder); - } - - /** - * @notice indicates whether this factory deployed an address - */ - function created(address query) external view returns (bool) { - return s_created[query]; - } -} diff --git a/contracts/src/v0.7/UpkeepRegistrationRequests.sol b/contracts/src/v0.7/UpkeepRegistrationRequests.sol deleted file mode 100644 index 9c0fe6efc81..00000000000 --- a/contracts/src/v0.7/UpkeepRegistrationRequests.sol +++ /dev/null @@ -1,334 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "./interfaces/LinkTokenInterface.sol"; -import "./interfaces/KeeperRegistryInterface.sol"; -import "./interfaces/TypeAndVersionInterface.sol"; -import "./vendor/SafeMath96.sol"; -import "./ConfirmedOwner.sol"; - -/** - * @notice Contract to accept requests for upkeep registrations - * @dev There are 2 registration workflows in this contract - * Flow 1. auto approve OFF / manual registration - UI calls `register` function on this contract, this contract owner at a later time then manually - * calls `approve` to register upkeep and emit events to inform UI and others interested. - * Flow 2. auto approve ON / real time registration - UI calls `register` function as before, which calls the `registerUpkeep` function directly on - * keeper registry and then emits approved event to finish the flow automatically without manual intervention. - * The idea is to have same interface(functions,events) for UI or anyone using this contract irrespective of auto approve being enabled or not. - * they can just listen to `RegistrationRequested` & `RegistrationApproved` events and know the status on registrations. - */ -contract UpkeepRegistrationRequests is TypeAndVersionInterface, ConfirmedOwner { - using SafeMath96 for uint96; - - bytes4 private constant REGISTER_REQUEST_SELECTOR = this.register.selector; - - uint256 private s_minLINKJuels; - mapping(bytes32 => PendingRequest) private s_pendingRequests; - - LinkTokenInterface public immutable LINK; - - /** - * @notice versions: - * - UpkeepRegistration 1.0.0: initial release - */ - string public constant override typeAndVersion = "UpkeepRegistrationRequests 1.0.0"; - - struct AutoApprovedConfig { - bool enabled; - uint16 allowedPerWindow; - uint32 windowSizeInBlocks; - uint64 windowStart; - uint16 approvedInCurrentWindow; - } - - struct PendingRequest { - address admin; - uint96 balance; - } - - AutoApprovedConfig private s_config; - KeeperRegistryBaseInterface private s_keeperRegistry; - - event RegistrationRequested( - bytes32 indexed hash, - string name, - bytes encryptedEmail, - address indexed upkeepContract, - uint32 gasLimit, - address adminAddress, - bytes checkData, - uint96 amount, - uint8 indexed source - ); - - event RegistrationApproved(bytes32 indexed hash, string displayName, uint256 indexed upkeepId); - - event RegistrationRejected(bytes32 indexed hash); - - event ConfigChanged( - bool enabled, - uint32 windowSizeInBlocks, - uint16 allowedPerWindow, - address keeperRegistry, - uint256 minLINKJuels - ); - - constructor(address LINKAddress, uint256 minimumLINKJuels) ConfirmedOwner(msg.sender) { - LINK = LinkTokenInterface(LINKAddress); - s_minLINKJuels = minimumLINKJuels; - } - - //EXTERNAL - - /** - * @notice register can only be called through transferAndCall on LINK contract - * @param name string of the upkeep to be registered - * @param encryptedEmail email address of upkeep contact - * @param upkeepContract address to perform upkeep on - * @param gasLimit amount of gas to provide the target contract when performing upkeep - * @param adminAddress address to cancel upkeep and withdraw remaining funds - * @param checkData data passed to the contract when checking for upkeep - * @param amount quantity of LINK upkeep is funded with (specified in Juels) - * @param source application sending this request - */ - function register( - string memory name, - bytes calldata encryptedEmail, - address upkeepContract, - uint32 gasLimit, - address adminAddress, - bytes calldata checkData, - uint96 amount, - uint8 source - ) external onlyLINK { - require(adminAddress != address(0), "invalid admin address"); - bytes32 hash = keccak256(abi.encode(upkeepContract, gasLimit, adminAddress, checkData)); - - emit RegistrationRequested( - hash, - name, - encryptedEmail, - upkeepContract, - gasLimit, - adminAddress, - checkData, - amount, - source - ); - - AutoApprovedConfig memory config = s_config; - if (config.enabled && _underApprovalLimit(config)) { - _incrementApprovedCount(config); - - _approve(name, upkeepContract, gasLimit, adminAddress, checkData, amount, hash); - } else { - uint96 newBalance = s_pendingRequests[hash].balance.add(amount); - s_pendingRequests[hash] = PendingRequest({admin: adminAddress, balance: newBalance}); - } - } - - /** - * @dev register upkeep on KeeperRegistry contract and emit RegistrationApproved event - */ - function approve( - string memory name, - address upkeepContract, - uint32 gasLimit, - address adminAddress, - bytes calldata checkData, - bytes32 hash - ) external onlyOwner { - PendingRequest memory request = s_pendingRequests[hash]; - require(request.admin != address(0), "request not found"); - bytes32 expectedHash = keccak256(abi.encode(upkeepContract, gasLimit, adminAddress, checkData)); - require(hash == expectedHash, "hash and payload do not match"); - delete s_pendingRequests[hash]; - _approve(name, upkeepContract, gasLimit, adminAddress, checkData, request.balance, hash); - } - - /** - * @notice cancel will remove a registration request and return the refunds to the msg.sender - * @param hash the request hash - */ - function cancel(bytes32 hash) external { - PendingRequest memory request = s_pendingRequests[hash]; - require(msg.sender == request.admin || msg.sender == owner(), "only admin / owner can cancel"); - require(request.admin != address(0), "request not found"); - delete s_pendingRequests[hash]; - require(LINK.transfer(msg.sender, request.balance), "LINK token transfer failed"); - emit RegistrationRejected(hash); - } - - /** - * @notice owner calls this function to set if registration requests should be sent directly to the Keeper Registry - * @param enabled setting for auto-approve registrations - * @param windowSizeInBlocks window size defined in number of blocks - * @param allowedPerWindow number of registrations that can be auto approved in above window - * @param keeperRegistry new keeper registry address - */ - function setRegistrationConfig( - bool enabled, - uint32 windowSizeInBlocks, - uint16 allowedPerWindow, - address keeperRegistry, - uint256 minLINKJuels - ) external onlyOwner { - s_config = AutoApprovedConfig({ - enabled: enabled, - allowedPerWindow: allowedPerWindow, - windowSizeInBlocks: windowSizeInBlocks, - windowStart: 0, - approvedInCurrentWindow: 0 - }); - s_minLINKJuels = minLINKJuels; - s_keeperRegistry = KeeperRegistryBaseInterface(keeperRegistry); - - emit ConfigChanged(enabled, windowSizeInBlocks, allowedPerWindow, keeperRegistry, minLINKJuels); - } - - /** - * @notice read the current registration configuration - */ - function getRegistrationConfig() - external - view - returns ( - bool enabled, - uint32 windowSizeInBlocks, - uint16 allowedPerWindow, - address keeperRegistry, - uint256 minLINKJuels, - uint64 windowStart, - uint16 approvedInCurrentWindow - ) - { - AutoApprovedConfig memory config = s_config; - return ( - config.enabled, - config.windowSizeInBlocks, - config.allowedPerWindow, - address(s_keeperRegistry), - s_minLINKJuels, - config.windowStart, - config.approvedInCurrentWindow - ); - } - - /** - * @notice gets the admin address and the current balance of a registration request - */ - function getPendingRequest(bytes32 hash) external view returns (address, uint96) { - PendingRequest memory request = s_pendingRequests[hash]; - return (request.admin, request.balance); - } - - /** - * @notice Called when LINK is sent to the contract via `transferAndCall` - * @param amount Amount of LINK sent (specified in Juels) - * @param data Payload of the transaction - */ - function onTokenTransfer( - address, /* sender */ - uint256 amount, - bytes calldata data - ) external onlyLINK permittedFunctionsForLINK(data) isActualAmount(amount, data) { - require(amount >= s_minLINKJuels, "Insufficient payment"); - (bool success, ) = address(this).delegatecall(data); - // calls register - require(success, "Unable to create request"); - } - - //PRIVATE - - /** - * @dev reset auto approve window if passed end of current window - */ - function _resetWindowIfRequired(AutoApprovedConfig memory config) private { - uint64 blocksPassed = uint64(block.number - config.windowStart); - if (blocksPassed >= config.windowSizeInBlocks) { - config.windowStart = uint64(block.number); - config.approvedInCurrentWindow = 0; - s_config = config; - } - } - - /** - * @dev register upkeep on KeeperRegistry contract and emit RegistrationApproved event - */ - function _approve( - string memory name, - address upkeepContract, - uint32 gasLimit, - address adminAddress, - bytes calldata checkData, - uint96 amount, - bytes32 hash - ) private { - KeeperRegistryBaseInterface keeperRegistry = s_keeperRegistry; - - // register upkeep - uint256 upkeepId = keeperRegistry.registerUpkeep(upkeepContract, gasLimit, adminAddress, checkData); - // fund upkeep - bool success = LINK.transferAndCall(address(keeperRegistry), amount, abi.encode(upkeepId)); - require(success, "failed to fund upkeep"); - - emit RegistrationApproved(hash, name, upkeepId); - } - - /** - * @dev determine approval limits and check if in range - */ - function _underApprovalLimit(AutoApprovedConfig memory config) private returns (bool) { - _resetWindowIfRequired(config); - if (config.approvedInCurrentWindow < config.allowedPerWindow) { - return true; - } - return false; - } - - /** - * @dev record new latest approved count - */ - function _incrementApprovedCount(AutoApprovedConfig memory config) private { - config.approvedInCurrentWindow++; - s_config = config; - } - - //MODIFIERS - - /** - * @dev Reverts if not sent from the LINK token - */ - modifier onlyLINK() { - require(msg.sender == address(LINK), "Must use LINK token"); - _; - } - - /** - * @dev Reverts if the given data does not begin with the `register` function selector - * @param _data The data payload of the request - */ - modifier permittedFunctionsForLINK(bytes memory _data) { - bytes4 funcSelector; - assembly { - // solhint-disable-next-line avoid-low-level-calls - funcSelector := mload(add(_data, 32)) - } - require(funcSelector == REGISTER_REQUEST_SELECTOR, "Must use whitelisted functions"); - _; - } - - /** - * @dev Reverts if the actual amount passed does not match the expected amount - * @param expected amount that should match the actual amount - * @param data bytes - */ - modifier isActualAmount(uint256 expected, bytes memory data) { - uint256 actual; - assembly { - actual := mload(add(data, 228)) - } - require(expected == actual, "Amount mismatch"); - _; - } -} diff --git a/contracts/src/v0.7/VRFConsumerBase.sol b/contracts/src/v0.7/VRFConsumerBase.sol deleted file mode 100644 index 9956c2a0b09..00000000000 --- a/contracts/src/v0.7/VRFConsumerBase.sol +++ /dev/null @@ -1,199 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "./vendor/SafeMathChainlink.sol"; - -import "./interfaces/LinkTokenInterface.sol"; - -import "./VRFRequestIDBase.sol"; - -/** **************************************************************************** - * @notice Interface for contracts using VRF randomness - * ***************************************************************************** - * @dev PURPOSE - * - * @dev Reggie the Random Oracle (not his real job) wants to provide randomness - * @dev to Vera the verifier in such a way that Vera can be sure he's not - * @dev making his output up to suit himself. Reggie provides Vera a public key - * @dev to which he knows the secret key. Each time Vera provides a seed to - * @dev Reggie, he gives back a value which is computed completely - * @dev deterministically from the seed and the secret key. - * - * @dev Reggie provides a proof by which Vera can verify that the output was - * @dev correctly computed once Reggie tells it to her, but without that proof, - * @dev the output is indistinguishable to her from a uniform random sample - * @dev from the output space. - * - * @dev The purpose of this contract is to make it easy for unrelated contracts - * @dev to talk to Vera the verifier about the work Reggie is doing, to provide - * @dev simple access to a verifiable source of randomness. - * ***************************************************************************** - * @dev USAGE - * - * @dev Calling contracts must inherit from VRFConsumerBase, and can - * @dev initialize VRFConsumerBase's attributes in their constructor as - * @dev shown: - * - * @dev contract VRFConsumer { - * @dev constructor(, address _vrfCoordinator, address _link) - * @dev VRFConsumerBase(_vrfCoordinator, _link) public { - * @dev - * @dev } - * @dev } - * - * @dev The oracle will have given you an ID for the VRF keypair they have - * @dev committed to (let's call it keyHash), and have told you the minimum LINK - * @dev price for VRF service. Make sure your contract has sufficient LINK, and - * @dev call requestRandomness(keyHash, fee, seed), where seed is the input you - * @dev want to generate randomness from. - * - * @dev Once the VRFCoordinator has received and validated the oracle's response - * @dev to your request, it will call your contract's fulfillRandomness method. - * - * @dev The randomness argument to fulfillRandomness is the actual random value - * @dev generated from your seed. - * - * @dev The requestId argument is generated from the keyHash and the seed by - * @dev makeRequestId(keyHash, seed). If your contract could have concurrent - * @dev requests open, you can use the requestId to track which seed is - * @dev associated with which randomness. See VRFRequestIDBase.sol for more - * @dev details. (See "SECURITY CONSIDERATIONS" for principles to keep in mind, - * @dev if your contract could have multiple requests in flight simultaneously.) - * - * @dev Colliding `requestId`s are cryptographically impossible as long as seeds - * @dev differ. (Which is critical to making unpredictable randomness! See the - * @dev next section.) - * - * ***************************************************************************** - * @dev SECURITY CONSIDERATIONS - * - * @dev A method with the ability to call your fulfillRandomness method directly - * @dev could spoof a VRF response with any random value, so it's critical that - * @dev it cannot be directly called by anything other than this base contract - * @dev (specifically, by the VRFConsumerBase.rawFulfillRandomness method). - * - * @dev For your users to trust that your contract's random behavior is free - * @dev from malicious interference, it's best if you can write it so that all - * @dev behaviors implied by a VRF response are executed *during* your - * @dev fulfillRandomness method. If your contract must store the response (or - * @dev anything derived from it) and use it later, you must ensure that any - * @dev user-significant behavior which depends on that stored value cannot be - * @dev manipulated by a subsequent VRF request. - * - * @dev Similarly, both miners and the VRF oracle itself have some influence - * @dev over the order in which VRF responses appear on the blockchain, so if - * @dev your contract could have multiple VRF requests in flight simultaneously, - * @dev you must ensure that the order in which the VRF responses arrive cannot - * @dev be used to manipulate your contract's user-significant behavior. - * - * @dev Since the ultimate input to the VRF is mixed with the block hash of the - * @dev block in which the request is made, user-provided seeds have no impact - * @dev on its economic security properties. They are only included for API - * @dev compatability with previous versions of this contract. - * - * @dev Since the block hash of the block which contains the requestRandomness - * @dev call is mixed into the input to the VRF *last*, a sufficiently powerful - * @dev miner could, in principle, fork the blockchain to evict the block - * @dev containing the request, forcing the request to be included in a - * @dev different block with a different hash, and therefore a different input - * @dev to the VRF. However, such an attack would incur a substantial economic - * @dev cost. This cost scales with the number of blocks the VRF oracle waits - * @dev until it calls responds to a request. - */ -abstract contract VRFConsumerBase is VRFRequestIDBase { - using SafeMathChainlink for uint256; - - /** - * @notice fulfillRandomness handles the VRF response. Your contract must - * @notice implement it. See "SECURITY CONSIDERATIONS" above for important - * @notice principles to keep in mind when implementing your fulfillRandomness - * @notice method. - * - * @dev VRFConsumerBase expects its subcontracts to have a method with this - * @dev signature, and will call it once it has verified the proof - * @dev associated with the randomness. (It is triggered via a call to - * @dev rawFulfillRandomness, below.) - * - * @param requestId The Id initially returned by requestRandomness - * @param randomness the VRF output - */ - function fulfillRandomness(bytes32 requestId, uint256 randomness) internal virtual; - - /** - * @dev In order to keep backwards compatibility we have kept the user - * seed field around. We remove the use of it because given that the blockhash - * enters later, it overrides whatever randomness the used seed provides. - * Given that it adds no security, and can easily lead to misunderstandings, - * we have removed it from usage and can now provide a simpler API. - */ - uint256 private constant USER_SEED_PLACEHOLDER = 0; - - /** - * @notice requestRandomness initiates a request for VRF output given _seed - * - * @dev The fulfillRandomness method receives the output, once it's provided - * @dev by the Oracle, and verified by the vrfCoordinator. - * - * @dev The _keyHash must already be registered with the VRFCoordinator, and - * @dev the _fee must exceed the fee specified during registration of the - * @dev _keyHash. - * - * @dev The _seed parameter is vestigial, and is kept only for API - * @dev compatibility with older versions. It can't *hurt* to mix in some of - * @dev your own randomness, here, but it's not necessary because the VRF - * @dev oracle will mix the hash of the block containing your request into the - * @dev VRF seed it ultimately uses. - * - * @param _keyHash ID of public key against which randomness is generated - * @param _fee The amount of LINK to send with the request - * - * @return requestId unique ID for this request - * - * @dev The returned requestId can be used to distinguish responses to - * @dev concurrent requests. It is passed as the first argument to - * @dev fulfillRandomness. - */ - function requestRandomness(bytes32 _keyHash, uint256 _fee) internal returns (bytes32 requestId) { - LINK.transferAndCall(vrfCoordinator, _fee, abi.encode(_keyHash, USER_SEED_PLACEHOLDER)); - // This is the seed passed to VRFCoordinator. The oracle will mix this with - // the hash of the block containing this request to obtain the seed/input - // which is finally passed to the VRF cryptographic machinery. - uint256 vRFSeed = makeVRFInputSeed(_keyHash, USER_SEED_PLACEHOLDER, address(this), nonces[_keyHash]); - // nonces[_keyHash] must stay in sync with - // VRFCoordinator.nonces[_keyHash][this], which was incremented by the above - // successful LINK.transferAndCall (in VRFCoordinator.randomnessRequest). - // This provides protection against the user repeating their input seed, - // which would result in a predictable/duplicate output, if multiple such - // requests appeared in the same block. - nonces[_keyHash] = nonces[_keyHash].add(1); - return makeRequestId(_keyHash, vRFSeed); - } - - LinkTokenInterface internal immutable LINK; - address private immutable vrfCoordinator; - - // Nonces for each VRF key from which randomness has been requested. - // - // Must stay in sync with VRFCoordinator[_keyHash][this] - mapping(bytes32 => uint256) /* keyHash */ /* nonce */ - private nonces; - - /** - * @param _vrfCoordinator address of VRFCoordinator contract - * @param _link address of LINK token contract - * - * @dev https://docs.chain.link/docs/link-token-contracts - */ - constructor(address _vrfCoordinator, address _link) { - vrfCoordinator = _vrfCoordinator; - LINK = LinkTokenInterface(_link); - } - - // rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF - // proof. rawFulfillRandomness then calls fulfillRandomness, after validating - // the origin of the call - function rawFulfillRandomness(bytes32 requestId, uint256 randomness) external { - require(msg.sender == vrfCoordinator, "Only VRFCoordinator can fulfill"); - fulfillRandomness(requestId, randomness); - } -} diff --git a/contracts/src/v0.7/VRFRequestIDBase.sol b/contracts/src/v0.7/VRFRequestIDBase.sol deleted file mode 100644 index 87bb6fe20ef..00000000000 --- a/contracts/src/v0.7/VRFRequestIDBase.sol +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -contract VRFRequestIDBase { - /** - * @notice returns the seed which is actually input to the VRF coordinator - * - * @dev To prevent repetition of VRF output due to repetition of the - * @dev user-supplied seed, that seed is combined in a hash with the - * @dev user-specific nonce, and the address of the consuming contract. The - * @dev risk of repetition is mostly mitigated by inclusion of a blockhash in - * @dev the final seed, but the nonce does protect against repetition in - * @dev requests which are included in a single block. - * - * @param _userSeed VRF seed input provided by user - * @param _requester Address of the requesting contract - * @param _nonce User-specific nonce at the time of the request - */ - function makeVRFInputSeed( - bytes32 _keyHash, - uint256 _userSeed, - address _requester, - uint256 _nonce - ) internal pure returns (uint256) { - return uint256(keccak256(abi.encode(_keyHash, _userSeed, _requester, _nonce))); - } - - /** - * @notice Returns the id for this request - * @param _keyHash The serviceAgreement ID to be used for this request - * @param _vRFInputSeed The seed to be passed directly to the VRF - * @return The id for this request - * - * @dev Note that _vRFInputSeed is not the seed passed by the consuming - * @dev contract, but the one generated by makeVRFInputSeed - */ - function makeRequestId(bytes32 _keyHash, uint256 _vRFInputSeed) internal pure returns (bytes32) { - return keccak256(abi.encodePacked(_keyHash, _vRFInputSeed)); - } -} diff --git a/contracts/src/v0.7/dev/AggregatorProxy.sol b/contracts/src/v0.7/dev/AggregatorProxy.sol deleted file mode 100644 index 9f68faa19b3..00000000000 --- a/contracts/src/v0.7/dev/AggregatorProxy.sol +++ /dev/null @@ -1,386 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "../ConfirmedOwner.sol"; -import "../interfaces/AggregatorProxyInterface.sol"; - -/** - * @title A trusted proxy for updating where current answers are read from - * @notice This contract provides a consistent address for the - * CurrentAnswerInterface but delegates where it reads from to the owner, who is - * trusted to update it. - */ -contract AggregatorProxy is AggregatorProxyInterface, ConfirmedOwner { - struct Phase { - uint16 id; - AggregatorProxyInterface aggregator; - } - AggregatorProxyInterface private s_proposedAggregator; - mapping(uint16 => AggregatorProxyInterface) private s_phaseAggregators; - Phase private s_currentPhase; - - uint256 private constant PHASE_OFFSET = 64; - uint256 private constant PHASE_SIZE = 16; - uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; - - event AggregatorProposed(address indexed current, address indexed proposed); - event AggregatorConfirmed(address indexed previous, address indexed latest); - - constructor(address aggregatorAddress) ConfirmedOwner(msg.sender) { - setAggregator(aggregatorAddress); - } - - /** - * @notice Reads the current answer from aggregator delegated to. - * - * @dev #[deprecated] Use latestRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended latestRoundData - * instead which includes better verification information. - */ - function latestAnswer() public view virtual override returns (int256 answer) { - return s_currentPhase.aggregator.latestAnswer(); - } - - /** - * @notice Reads the last updated height from aggregator delegated to. - * - * @dev #[deprecated] Use latestRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended latestRoundData - * instead which includes better verification information. - */ - function latestTimestamp() public view virtual override returns (uint256 updatedAt) { - return s_currentPhase.aggregator.latestTimestamp(); - } - - /** - * @notice get past rounds answers - * @param roundId the answer number to retrieve the answer for - * - * @dev #[deprecated] Use getRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended getRoundData - * instead which includes better verification information. - */ - function getAnswer(uint256 roundId) public view virtual override returns (int256 answer) { - if (roundId > MAX_ID) return 0; - - (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(roundId); - AggregatorProxyInterface aggregator = s_phaseAggregators[phaseId]; - if (address(aggregator) == address(0)) return 0; - - return aggregator.getAnswer(aggregatorRoundId); - } - - /** - * @notice get block timestamp when an answer was last updated - * @param roundId the answer number to retrieve the updated timestamp for - * - * @dev #[deprecated] Use getRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended getRoundData - * instead which includes better verification information. - */ - function getTimestamp(uint256 roundId) public view virtual override returns (uint256 updatedAt) { - if (roundId > MAX_ID) return 0; - - (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(roundId); - AggregatorProxyInterface aggregator = s_phaseAggregators[phaseId]; - if (address(aggregator) == address(0)) return 0; - - return aggregator.getTimestamp(aggregatorRoundId); - } - - /** - * @notice get the latest completed round where the answer was updated. This - * ID includes the proxy's phase, to make sure round IDs increase even when - * switching to a newly deployed aggregator. - * - * @dev #[deprecated] Use latestRoundData instead. This does not error if no - * answer has been reached, it will simply return 0. Either wait to point to - * an already answered Aggregator or use the recommended latestRoundData - * instead which includes better verification information. - */ - function latestRound() public view virtual override returns (uint256 roundId) { - Phase memory phase = s_currentPhase; // cache storage reads - return addPhase(phase.id, uint64(phase.aggregator.latestRound())); - } - - /** - * @notice get data about a round. Consumers are encouraged to check - * that they're receiving fresh data by inspecting the updatedAt and - * answeredInRound return values. - * Note that different underlying implementations of AggregatorV3Interface - * have slightly different semantics for some of the return values. Consumers - * should determine what implementations they expect to receive - * data from and validate that they can properly handle return data from all - * of them. - * @param roundId the requested round ID as presented through the proxy, this - * is made up of the aggregator's round ID with the phase ID encoded in the - * two highest order bytes - * @return id is the round ID from the aggregator for which the data was - * retrieved combined with an phase to ensure that round IDs get larger as - * time moves forward. - * @return answer is the answer for the given round - * @return startedAt is the timestamp when the round was started. - * (Only some AggregatorV3Interface implementations return meaningful values) - * @return updatedAt is the timestamp when the round last was updated (i.e. - * answer was last computed) - * @return answeredInRound is the round ID of the round in which the answer - * was computed. - * (Only some AggregatorV3Interface implementations return meaningful values) - * @dev Note that answer and updatedAt may change between queries. - */ - function getRoundData(uint80 roundId) - public - view - virtual - override - returns ( - uint80 id, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(roundId); - - (id, answer, startedAt, updatedAt, answeredInRound) = s_phaseAggregators[phaseId].getRoundData(aggregatorRoundId); - - return addPhaseIds(id, answer, startedAt, updatedAt, answeredInRound, phaseId); - } - - /** - * @notice get data about the latest round. Consumers are encouraged to check - * that they're receiving fresh data by inspecting the updatedAt and - * answeredInRound return values. - * Note that different underlying implementations of AggregatorV3Interface - * have slightly different semantics for some of the return values. Consumers - * should determine what implementations they expect to receive - * data from and validate that they can properly handle return data from all - * of them. - * @return id is the round ID from the aggregator for which the data was - * retrieved combined with an phase to ensure that round IDs get larger as - * time moves forward. - * @return answer is the answer for the given round - * @return startedAt is the timestamp when the round was started. - * (Only some AggregatorV3Interface implementations return meaningful values) - * @return updatedAt is the timestamp when the round last was updated (i.e. - * answer was last computed) - * @return answeredInRound is the round ID of the round in which the answer - * was computed. - * (Only some AggregatorV3Interface implementations return meaningful values) - * @dev Note that answer and updatedAt may change between queries. - */ - function latestRoundData() - public - view - virtual - override - returns ( - uint80 id, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - Phase memory current = s_currentPhase; // cache storage reads - - (id, answer, startedAt, updatedAt, answeredInRound) = current.aggregator.latestRoundData(); - - return addPhaseIds(id, answer, startedAt, updatedAt, answeredInRound, current.id); - } - - /** - * @notice Used if an aggregator contract has been proposed. - * @param roundId the round ID to retrieve the round data for - * @return id is the round ID for which data was retrieved - * @return answer is the answer for the given round - * @return startedAt is the timestamp when the round was started. - * (Only some AggregatorV3Interface implementations return meaningful values) - * @return updatedAt is the timestamp when the round last was updated (i.e. - * answer was last computed) - * @return answeredInRound is the round ID of the round in which the answer - * was computed. - */ - function proposedGetRoundData(uint80 roundId) - external - view - virtual - override - hasProposal - returns ( - uint80 id, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - return s_proposedAggregator.getRoundData(roundId); - } - - /** - * @notice Used if an aggregator contract has been proposed. - * @return id is the round ID for which data was retrieved - * @return answer is the answer for the given round - * @return startedAt is the timestamp when the round was started. - * (Only some AggregatorV3Interface implementations return meaningful values) - * @return updatedAt is the timestamp when the round last was updated (i.e. - * answer was last computed) - * @return answeredInRound is the round ID of the round in which the answer - * was computed. - */ - function proposedLatestRoundData() - external - view - virtual - override - hasProposal - returns ( - uint80 id, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - return s_proposedAggregator.latestRoundData(); - } - - /** - * @notice returns the current phase's aggregator address. - */ - function aggregator() external view override returns (address) { - return address(s_currentPhase.aggregator); - } - - /** - * @notice returns the current phase's ID. - */ - function phaseId() external view override returns (uint16) { - return s_currentPhase.id; - } - - /** - * @notice represents the number of decimals the aggregator responses represent. - */ - function decimals() external view override returns (uint8) { - return s_currentPhase.aggregator.decimals(); - } - - /** - * @notice the version number representing the type of aggregator the proxy - * points to. - */ - function version() external view override returns (uint256) { - return s_currentPhase.aggregator.version(); - } - - /** - * @notice returns the description of the aggregator the proxy points to. - */ - function description() external view override returns (string memory) { - return s_currentPhase.aggregator.description(); - } - - /** - * @notice returns the current proposed aggregator - */ - function proposedAggregator() external view override returns (address) { - return address(s_proposedAggregator); - } - - /** - * @notice return a phase aggregator using the phaseId - * - * @param phaseId uint16 - */ - function phaseAggregators(uint16 phaseId) external view override returns (address) { - return address(s_phaseAggregators[phaseId]); - } - - /** - * @notice Allows the owner to propose a new address for the aggregator - * @param aggregatorAddress The new address for the aggregator contract - */ - function proposeAggregator(address aggregatorAddress) external onlyOwner { - s_proposedAggregator = AggregatorProxyInterface(aggregatorAddress); - emit AggregatorProposed(address(s_currentPhase.aggregator), aggregatorAddress); - } - - /** - * @notice Allows the owner to confirm and change the address - * to the proposed aggregator - * @dev Reverts if the given address doesn't match what was previously - * proposed - * @param aggregatorAddress The new address for the aggregator contract - */ - function confirmAggregator(address aggregatorAddress) external onlyOwner { - require(aggregatorAddress == address(s_proposedAggregator), "Invalid proposed aggregator"); - address previousAggregator = address(s_currentPhase.aggregator); - delete s_proposedAggregator; - setAggregator(aggregatorAddress); - emit AggregatorConfirmed(previousAggregator, aggregatorAddress); - } - - /* - * Internal - */ - - function setAggregator(address aggregatorAddress) internal { - uint16 id = s_currentPhase.id + 1; - s_currentPhase = Phase(id, AggregatorProxyInterface(aggregatorAddress)); - s_phaseAggregators[id] = AggregatorProxyInterface(aggregatorAddress); - } - - function addPhase(uint16 phase, uint64 originalId) internal pure returns (uint80) { - return uint80((uint256(phase) << PHASE_OFFSET) | originalId); - } - - function parseIds(uint256 roundId) internal pure returns (uint16, uint64) { - uint16 phaseId = uint16(roundId >> PHASE_OFFSET); - uint64 aggregatorRoundId = uint64(roundId); - - return (phaseId, aggregatorRoundId); - } - - function addPhaseIds( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound, - uint16 phaseId - ) - internal - pure - returns ( - uint80, - int256, - uint256, - uint256, - uint80 - ) - { - return ( - addPhase(phaseId, uint64(roundId)), - answer, - startedAt, - updatedAt, - addPhase(phaseId, uint64(answeredInRound)) - ); - } - - /* - * Modifiers - */ - - modifier hasProposal() { - require(address(s_proposedAggregator) != address(0), "No proposed aggregator present"); - _; - } -} diff --git a/contracts/src/v0.7/dev/CompoundPriceFlaggingValidator.sol b/contracts/src/v0.7/dev/CompoundPriceFlaggingValidator.sol deleted file mode 100644 index 37a15fc9cd6..00000000000 --- a/contracts/src/v0.7/dev/CompoundPriceFlaggingValidator.sol +++ /dev/null @@ -1,334 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "../ConfirmedOwner.sol"; -import "../vendor/SafeMathChainlink.sol"; -import "../interfaces/FlagsInterface.sol"; -import "../interfaces/AggregatorV3Interface.sol"; -import "../interfaces/UniswapAnchoredView.sol"; -import "../interfaces/KeeperCompatibleInterface.sol"; - -/** - * @notice This validator compares the price of Chainlink aggregators against - * their equivalent Compound Open Oracle feeds. For each aggregator, a Compound - * feed is configured with its symbol, number of decimals, and deviation threshold. - * An aggregator address is flagged when its corresponding Compound feed price deviates - * by more than the configured threshold from the aggregator price. - */ -contract CompoundPriceFlaggingValidator is ConfirmedOwner, KeeperCompatibleInterface { - using SafeMathChainlink for uint256; - - struct CompoundFeedDetails { - // Used to call the Compound Open Oracle - string symbol; - // Used to convert price to match aggregator decimals - uint8 decimals; - // The numerator used to determine the threshold percentage - // as parts per billion. - // 1,000,000,000 = 100% - // 500,000,000 = 50% - // 100,000,000 = 10% - // 50,000,000 = 5% - // 10,000,000 = 1% - // 2,000,000 = 0.2% - // etc - uint32 deviationThresholdNumerator; - } - - uint256 private constant BILLION = 1_000_000_000; - - FlagsInterface private s_flags; - UniswapAnchoredView private s_compOpenOracle; - mapping(address => CompoundFeedDetails) private s_feedDetails; - - event CompoundOpenOracleAddressUpdated(address indexed from, address indexed to); - event FlagsAddressUpdated(address indexed from, address indexed to); - event FeedDetailsSet(address indexed aggregator, string symbol, uint8 decimals, uint32 deviationThresholdNumerator); - - /** - * @notice Create a new CompoundPriceFlaggingValidator - * @dev Use this contract to compare Chainlink aggregator prices - * against the Compound Open Oracle prices - * @param flagsAddress Address of the flag contract - * @param compoundOracleAddress Address of the Compound Open Oracle UniswapAnchoredView contract - */ - constructor(address flagsAddress, address compoundOracleAddress) ConfirmedOwner(msg.sender) { - setFlagsAddress(flagsAddress); - setCompoundOpenOracleAddress(compoundOracleAddress); - } - - /** - * @notice Set the address of the Compound Open Oracle UniswapAnchoredView contract - * @param oracleAddress Compound Open Oracle UniswapAnchoredView address - */ - function setCompoundOpenOracleAddress(address oracleAddress) public onlyOwner { - address previous = address(s_compOpenOracle); - if (previous != oracleAddress) { - s_compOpenOracle = UniswapAnchoredView(oracleAddress); - emit CompoundOpenOracleAddressUpdated(previous, oracleAddress); - } - } - - /** - * @notice Updates the flagging contract address for raising flags - * @param flagsAddress sets the address of the flags contract - */ - function setFlagsAddress(address flagsAddress) public onlyOwner { - address previous = address(s_flags); - if (previous != flagsAddress) { - s_flags = FlagsInterface(flagsAddress); - emit FlagsAddressUpdated(previous, flagsAddress); - } - } - - /** - * @notice Set the threshold details for comparing a Chainlink aggregator - * to a Compound Open Oracle feed. - * @param aggregator The Chainlink aggregator address - * @param compoundSymbol The symbol used by Compound for this feed - * @param compoundDecimals The number of decimals in the Compound feed - * @param compoundDeviationThresholdNumerator The threshold numerator use to determine - * the percentage with which the difference in prices must reside within. Parts per billion. - * For example: - * If prices are valid within a 5% threshold, assuming x is the compoundDeviationThresholdNumerator: - * x / 1,000,000,000 = 0.05 - * x = 50,000,000 - */ - function setFeedDetails( - address aggregator, - string calldata compoundSymbol, - uint8 compoundDecimals, - uint32 compoundDeviationThresholdNumerator - ) public onlyOwner { - require( - compoundDeviationThresholdNumerator > 0 && compoundDeviationThresholdNumerator <= BILLION, - "Invalid threshold numerator" - ); - require(_compoundPriceOf(compoundSymbol) != 0, "Invalid Compound price"); - string memory currentSymbol = s_feedDetails[aggregator].symbol; - // If symbol is not set, use the new one - if (bytes(currentSymbol).length == 0) { - s_feedDetails[aggregator] = CompoundFeedDetails({ - symbol: compoundSymbol, - decimals: compoundDecimals, - deviationThresholdNumerator: compoundDeviationThresholdNumerator - }); - emit FeedDetailsSet(aggregator, compoundSymbol, compoundDecimals, compoundDeviationThresholdNumerator); - } - // If the symbol is already set, don't change it - else { - s_feedDetails[aggregator] = CompoundFeedDetails({ - symbol: currentSymbol, - decimals: compoundDecimals, - deviationThresholdNumerator: compoundDeviationThresholdNumerator - }); - emit FeedDetailsSet(aggregator, currentSymbol, compoundDecimals, compoundDeviationThresholdNumerator); - } - } - - /** - * @notice Check the price deviation of an array of aggregators - * @dev If any of the aggregators provided have an equivalent Compound Oracle feed - * that with a price outside of the configured deviation, this function will return them. - * @param aggregators address[] memory - * @return address[] invalid feeds - */ - function check(address[] memory aggregators) public view returns (address[] memory) { - address[] memory invalidAggregators = new address[](aggregators.length); - uint256 invalidCount = 0; - for (uint256 i = 0; i < aggregators.length; i++) { - address aggregator = aggregators[i]; - if (_isInvalid(aggregator)) { - invalidAggregators[invalidCount] = aggregator; - invalidCount++; - } - } - - if (aggregators.length != invalidCount) { - assembly { - mstore(invalidAggregators, invalidCount) - } - } - return invalidAggregators; - } - - /** - * @notice Check and raise flags for any aggregator that has an equivalent Compound - * Open Oracle feed with a price deviation exceeding the configured setting. - * @dev This contract must have write permissions on the Flags contract - * @param aggregators address[] memory - * @return address[] memory invalid aggregators - */ - function update(address[] memory aggregators) public returns (address[] memory) { - address[] memory invalidAggregators = check(aggregators); - s_flags.raiseFlags(invalidAggregators); - return invalidAggregators; - } - - /** - * @notice Check the price deviation of an array of aggregators - * @dev If any of the aggregators provided have an equivalent Compound Oracle feed - * that with a price outside of the configured deviation, this function will return them. - * @param data bytes encoded address array - * @return needsUpkeep bool indicating whether upkeep needs to be performed - * @return invalid aggregators - bytes encoded address array of invalid aggregator addresses - */ - function checkUpkeep(bytes calldata data) external view override returns (bool, bytes memory) { - address[] memory invalidAggregators = check(abi.decode(data, (address[]))); - bool needsUpkeep = (invalidAggregators.length > 0); - return (needsUpkeep, abi.encode(invalidAggregators)); - } - - /** - * @notice Check and raise flags for any aggregator that has an equivalent Compound - * Open Oracle feed with a price deviation exceeding the configured setting. - * @dev This contract must have write permissions on the Flags contract - * @param data bytes encoded address array - */ - function performUpkeep(bytes calldata data) external override { - update(abi.decode(data, (address[]))); - } - - /** - * @notice Get the threshold of an aggregator - * @param aggregator address - * @return string Compound Oracle Symbol - * @return uint8 Compound Oracle Decimals - * @return uint32 Deviation Threshold Numerator - */ - function getFeedDetails(address aggregator) - public - view - returns ( - string memory, - uint8, - uint32 - ) - { - CompoundFeedDetails memory compDetails = s_feedDetails[aggregator]; - return (compDetails.symbol, compDetails.decimals, compDetails.deviationThresholdNumerator); - } - - /** - * @notice Get the flags address - * @return address - */ - function flags() external view returns (address) { - return address(s_flags); - } - - /** - * @notice Get the Compound Open Oracle address - * @return address - */ - function compoundOpenOracle() external view returns (address) { - return address(s_compOpenOracle); - } - - /** - * @notice Return the Compound oracle price of an asset using its symbol - * @param symbol string - * @return price uint256 - */ - function _compoundPriceOf(string memory symbol) private view returns (uint256) { - return s_compOpenOracle.price(symbol); - } - - // VALIDATION FUNCTIONS - - /** - * @notice Check if an aggregator has an equivalent Compound Oracle feed - * that's price is deviated more than the threshold. - * @param aggregator address of the Chainlink aggregator - * @return invalid bool. True if the deviation exceeds threshold. - */ - function _isInvalid(address aggregator) private view returns (bool invalid) { - CompoundFeedDetails memory compDetails = s_feedDetails[aggregator]; - if (compDetails.deviationThresholdNumerator == 0) { - return false; - } - // Get both oracle price details - uint256 compPrice = _compoundPriceOf(compDetails.symbol); - (uint256 aggregatorPrice, uint8 aggregatorDecimals) = _aggregatorValues(aggregator); - - // Adjust the prices so the number of decimals in each align - (aggregatorPrice, compPrice) = _adjustPriceDecimals( - aggregatorPrice, - aggregatorDecimals, - compPrice, - compDetails.decimals - ); - - // Check whether the prices deviate beyond the threshold. - return _deviatesBeyondThreshold(aggregatorPrice, compPrice, compDetails.deviationThresholdNumerator); - } - - /** - * @notice Retrieve the price and the decimals from an Aggregator - * @param aggregator address - * @return price uint256 - * @return decimals uint8 - */ - function _aggregatorValues(address aggregator) private view returns (uint256 price, uint8 decimals) { - AggregatorV3Interface priceFeed = AggregatorV3Interface(aggregator); - (, int256 signedPrice, , , ) = priceFeed.latestRoundData(); - price = uint256(signedPrice); - decimals = priceFeed.decimals(); - } - - /** - * @notice Adjust the price values of the Aggregator and Compound feeds so that - * their decimal places align. This enables deviation to be calculated. - * @param aggregatorPrice uint256 - * @param aggregatorDecimals uint8 - decimal places included in the aggregator price - * @param compoundPrice uint256 - * @param compoundDecimals uint8 - decimal places included in the compound price - * @return adjustedAggregatorPrice uint256 - * @return adjustedCompoundPrice uint256 - */ - function _adjustPriceDecimals( - uint256 aggregatorPrice, - uint8 aggregatorDecimals, - uint256 compoundPrice, - uint8 compoundDecimals - ) private pure returns (uint256 adjustedAggregatorPrice, uint256 adjustedCompoundPrice) { - if (aggregatorDecimals > compoundDecimals) { - uint8 diff = aggregatorDecimals - compoundDecimals; - uint256 multiplier = 10**uint256(diff); - compoundPrice = compoundPrice * multiplier; - } else if (aggregatorDecimals < compoundDecimals) { - uint8 diff = compoundDecimals - aggregatorDecimals; - uint256 multiplier = 10**uint256(diff); - aggregatorPrice = aggregatorPrice * multiplier; - } - adjustedAggregatorPrice = aggregatorPrice; - adjustedCompoundPrice = compoundPrice; - } - - /** - * @notice Check whether the compound price deviates from the aggregator price - * beyond the given threshold - * @dev Prices must be adjusted to match decimals prior to calling this function - * @param aggregatorPrice uint256 - * @param compPrice uint256 - * @param deviationThresholdNumerator uint32 - * @return beyondThreshold boolean. Returns true if deviation is beyond threshold. - */ - function _deviatesBeyondThreshold( - uint256 aggregatorPrice, - uint256 compPrice, - uint32 deviationThresholdNumerator - ) private pure returns (bool beyondThreshold) { - // Deviation amount threshold from the aggregator price - uint256 deviationAmountThreshold = aggregatorPrice.mul(deviationThresholdNumerator).div(BILLION); - - // Calculate deviation - uint256 deviation; - if (aggregatorPrice > compPrice) { - deviation = aggregatorPrice.sub(compPrice); - } else if (aggregatorPrice < compPrice) { - deviation = compPrice.sub(aggregatorPrice); - } - beyondThreshold = (deviation >= deviationAmountThreshold); - } -} diff --git a/contracts/src/v0.7/dev/StalenessFlaggingValidator.sol b/contracts/src/v0.7/dev/StalenessFlaggingValidator.sol deleted file mode 100644 index 070ff473e04..00000000000 --- a/contracts/src/v0.7/dev/StalenessFlaggingValidator.sol +++ /dev/null @@ -1,159 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "../ConfirmedOwner.sol"; -import "../vendor/SafeMathChainlink.sol"; -import "../interfaces/FlagsInterface.sol"; -import "../interfaces/AggregatorV3Interface.sol"; -import "../interfaces/KeeperCompatibleInterface.sol"; - -contract StalenessFlaggingValidator is ConfirmedOwner, KeeperCompatibleInterface { - using SafeMathChainlink for uint256; - - FlagsInterface private s_flags; - mapping(address => uint256) private s_thresholdSeconds; - - event FlagsAddressUpdated(address indexed previous, address indexed current); - event FlaggingThresholdUpdated(address indexed aggregator, uint256 indexed previous, uint256 indexed current); - - /** - * @notice Create a new StalenessFlaggingValidator - * @param flagsAddress Address of the flag contract - * @dev Ensure that this contract has sufficient write permissions - * on the flag contract - */ - constructor(address flagsAddress) ConfirmedOwner(msg.sender) { - setFlagsAddress(flagsAddress); - } - - /** - * @notice Updates the flagging contract address for raising flags - * @param flagsAddress sets the address of the flags contract - */ - function setFlagsAddress(address flagsAddress) public onlyOwner { - address previous = address(s_flags); - if (previous != flagsAddress) { - s_flags = FlagsInterface(flagsAddress); - emit FlagsAddressUpdated(previous, flagsAddress); - } - } - - /** - * @notice Set the threshold limits for each aggregator - * @dev parameters must be same length - * @param aggregators address[] memory - * @param flaggingThresholds uint256[] memory - */ - function setThresholds(address[] memory aggregators, uint256[] memory flaggingThresholds) public onlyOwner { - require(aggregators.length == flaggingThresholds.length, "Different sized arrays"); - for (uint256 i = 0; i < aggregators.length; i++) { - address aggregator = aggregators[i]; - uint256 previousThreshold = s_thresholdSeconds[aggregator]; - uint256 newThreshold = flaggingThresholds[i]; - if (previousThreshold != newThreshold) { - s_thresholdSeconds[aggregator] = newThreshold; - emit FlaggingThresholdUpdated(aggregator, previousThreshold, newThreshold); - } - } - } - - /** - * @notice Check for staleness in an array of aggregators - * @dev If any of the aggregators are stale, this function will return true, - * otherwise false - * @param aggregators address[] memory - * @return address[] memory stale aggregators - */ - function check(address[] memory aggregators) public view returns (address[] memory) { - uint256 currentTimestamp = block.timestamp; - address[] memory staleAggregators = new address[](aggregators.length); - uint256 staleCount = 0; - for (uint256 i = 0; i < aggregators.length; i++) { - address aggregator = aggregators[i]; - if (isStale(aggregator, currentTimestamp)) { - staleAggregators[staleCount] = aggregator; - staleCount++; - } - } - - if (aggregators.length != staleCount) { - assembly { - mstore(staleAggregators, staleCount) - } - } - return staleAggregators; - } - - /** - * @notice Check for staleness in an array of aggregators, raise a flag - * on the flags contract for each aggregator that is stale - * @dev This contract must have write permissions on the flags contract - * @param aggregators address[] memory - * @return address[] memory stale aggregators - */ - function update(address[] memory aggregators) public returns (address[] memory) { - address[] memory staleAggregators = check(aggregators); - s_flags.raiseFlags(staleAggregators); - return staleAggregators; - } - - /** - * @notice Check for staleness in an array of aggregators - * @dev Overriding KeeperInterface - * @param data bytes encoded address array - * @return needsUpkeep bool indicating whether upkeep needs to be performed - * @return staleAggregators bytes encoded address array of stale aggregator addresses - */ - function checkUpkeep(bytes calldata data) external view override returns (bool, bytes memory) { - address[] memory staleAggregators = check(abi.decode(data, (address[]))); - bool needsUpkeep = (staleAggregators.length > 0); - return (needsUpkeep, abi.encode(staleAggregators)); - } - - /** - * @notice Check for staleness in an array of aggregators, raise a flag - * on the flags contract for each aggregator that is stale - * @dev Overriding KeeperInterface - * @param data bytes encoded address array - */ - function performUpkeep(bytes calldata data) external override { - update(abi.decode(data, (address[]))); - } - - /** - * @notice Get the threshold of an aggregator - * @param aggregator address - * @return uint256 - */ - function threshold(address aggregator) external view returns (uint256) { - return s_thresholdSeconds[aggregator]; - } - - /** - * @notice Get the flags address - * @return address - */ - function flags() external view returns (address) { - return address(s_flags); - } - - /** - * @notice Check if an aggregator is stale. - * @dev Staleness is where an aggregator's `updatedAt` field is older - * than the threshold set for it in this contract - * @param aggregator address - * @param currentTimestamp uint256 - * @return stale bool - */ - function isStale(address aggregator, uint256 currentTimestamp) private view returns (bool stale) { - if (s_thresholdSeconds[aggregator] == 0) { - return false; - } - (, , , uint256 updatedAt, ) = AggregatorV3Interface(aggregator).latestRoundData(); - uint256 diff = currentTimestamp.sub(updatedAt); - if (diff > s_thresholdSeconds[aggregator]) { - return true; - } - return false; - } -} diff --git a/contracts/src/v0.7/interfaces/AggregatorInterface.sol b/contracts/src/v0.7/interfaces/AggregatorInterface.sol deleted file mode 100644 index 8eddc4a7011..00000000000 --- a/contracts/src/v0.7/interfaces/AggregatorInterface.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -interface AggregatorInterface { - function latestAnswer() external view returns (int256); - - function latestTimestamp() external view returns (uint256); - - function latestRound() external view returns (uint256); - - function getAnswer(uint256 roundId) external view returns (int256); - - function getTimestamp(uint256 roundId) external view returns (uint256); - - event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt); - - event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt); -} diff --git a/contracts/src/v0.7/interfaces/AggregatorProxyInterface.sol b/contracts/src/v0.7/interfaces/AggregatorProxyInterface.sol deleted file mode 100644 index a56f5eb2aa5..00000000000 --- a/contracts/src/v0.7/interfaces/AggregatorProxyInterface.sol +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "./AggregatorV2V3Interface.sol"; - -interface AggregatorProxyInterface is AggregatorV2V3Interface { - function phaseAggregators(uint16 phaseId) external view returns (address); - - function phaseId() external view returns (uint16); - - function proposedAggregator() external view returns (address); - - function proposedGetRoundData(uint80 roundId) - external - view - returns ( - uint80 id, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - - function proposedLatestRoundData() - external - view - returns ( - uint80 id, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - - function aggregator() external view returns (address); -} diff --git a/contracts/src/v0.7/interfaces/AggregatorV2V3Interface.sol b/contracts/src/v0.7/interfaces/AggregatorV2V3Interface.sol deleted file mode 100644 index a03536879f7..00000000000 --- a/contracts/src/v0.7/interfaces/AggregatorV2V3Interface.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "./AggregatorInterface.sol"; -import "./AggregatorV3Interface.sol"; - -interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface {} diff --git a/contracts/src/v0.7/interfaces/AggregatorV3Interface.sol b/contracts/src/v0.7/interfaces/AggregatorV3Interface.sol deleted file mode 100644 index 06b7b1a6eb3..00000000000 --- a/contracts/src/v0.7/interfaces/AggregatorV3Interface.sol +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -interface AggregatorV3Interface { - function decimals() external view returns (uint8); - - function description() external view returns (string memory); - - function version() external view returns (uint256); - - // getRoundData and latestRoundData should both raise "No data present" - // if they do not have data to report, instead of returning unset values - // which could be misinterpreted as actual reported values. - function getRoundData(uint80 _roundId) - external - view - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - - function latestRoundData() - external - view - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); -} diff --git a/contracts/src/v0.7/interfaces/AuthorizedReceiverInterface.sol b/contracts/src/v0.7/interfaces/AuthorizedReceiverInterface.sol deleted file mode 100644 index aec2c033328..00000000000 --- a/contracts/src/v0.7/interfaces/AuthorizedReceiverInterface.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -interface AuthorizedReceiverInterface { - function isAuthorizedSender(address sender) external view returns (bool); - - function getAuthorizedSenders() external returns (address[] memory); - - function setAuthorizedSenders(address[] calldata senders) external; -} diff --git a/contracts/src/v0.7/interfaces/ChainlinkRequestInterface.sol b/contracts/src/v0.7/interfaces/ChainlinkRequestInterface.sol deleted file mode 100644 index 77d2b6e0f36..00000000000 --- a/contracts/src/v0.7/interfaces/ChainlinkRequestInterface.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -interface ChainlinkRequestInterface { - function oracleRequest( - address sender, - uint256 requestPrice, - bytes32 serviceAgreementID, - address callbackAddress, - bytes4 callbackFunctionId, - uint256 nonce, - uint256 dataVersion, - bytes calldata data - ) external; - - function cancelOracleRequest( - bytes32 requestId, - uint256 payment, - bytes4 callbackFunctionId, - uint256 expiration - ) external; -} diff --git a/contracts/src/v0.7/interfaces/ENSInterface.sol b/contracts/src/v0.7/interfaces/ENSInterface.sol deleted file mode 100644 index 84fd654d630..00000000000 --- a/contracts/src/v0.7/interfaces/ENSInterface.sol +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -interface ENSInterface { - // Logged when the owner of a node assigns a new owner to a subnode. - event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner); - - // Logged when the owner of a node transfers ownership to a new account. - event Transfer(bytes32 indexed node, address owner); - - // Logged when the resolver for a node changes. - event NewResolver(bytes32 indexed node, address resolver); - - // Logged when the TTL of a node changes - event NewTTL(bytes32 indexed node, uint64 ttl); - - function setSubnodeOwner( - bytes32 node, - bytes32 label, - address owner - ) external; - - function setResolver(bytes32 node, address resolver) external; - - function setOwner(bytes32 node, address owner) external; - - function setTTL(bytes32 node, uint64 ttl) external; - - function owner(bytes32 node) external view returns (address); - - function resolver(bytes32 node) external view returns (address); - - function ttl(bytes32 node) external view returns (uint64); -} diff --git a/contracts/src/v0.7/interfaces/FeedRegistryInterface.sol b/contracts/src/v0.7/interfaces/FeedRegistryInterface.sol deleted file mode 100644 index 43f5fd7b194..00000000000 --- a/contracts/src/v0.7/interfaces/FeedRegistryInterface.sol +++ /dev/null @@ -1,177 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; -pragma abicoder v2; - -import "./AggregatorV2V3Interface.sol"; - -interface FeedRegistryInterface { - struct Phase { - uint16 phaseId; - uint80 startingAggregatorRoundId; - uint80 endingAggregatorRoundId; - } - - event FeedProposed( - address indexed asset, - address indexed denomination, - address indexed proposedAggregator, - address currentAggregator, - address sender - ); - event FeedConfirmed( - address indexed asset, - address indexed denomination, - address indexed latestAggregator, - address previousAggregator, - uint16 nextPhaseId, - address sender - ); - - // V3 AggregatorV3Interface - - function decimals(address base, address quote) external view returns (uint8); - - function description(address base, address quote) external view returns (string memory); - - function version(address base, address quote) external view returns (uint256); - - function latestRoundData(address base, address quote) - external - view - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - - function getRoundData( - address base, - address quote, - uint80 _roundId - ) - external - view - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - - // V2 AggregatorInterface - - function latestAnswer(address base, address quote) external view returns (int256 answer); - - function latestTimestamp(address base, address quote) external view returns (uint256 timestamp); - - function latestRound(address base, address quote) external view returns (uint256 roundId); - - function getAnswer( - address base, - address quote, - uint256 roundId - ) external view returns (int256 answer); - - function getTimestamp( - address base, - address quote, - uint256 roundId - ) external view returns (uint256 timestamp); - - // Registry getters - - function getFeed(address base, address quote) external view returns (AggregatorV2V3Interface aggregator); - - function getPhaseFeed( - address base, - address quote, - uint16 phaseId - ) external view returns (AggregatorV2V3Interface aggregator); - - function isFeedEnabled(address aggregator) external view returns (bool); - - function getPhase( - address base, - address quote, - uint16 phaseId - ) external view returns (Phase memory phase); - - // Round helpers - - function getRoundFeed( - address base, - address quote, - uint80 roundId - ) external view returns (AggregatorV2V3Interface aggregator); - - function getPhaseRange( - address base, - address quote, - uint16 phaseId - ) external view returns (uint80 startingRoundId, uint80 endingRoundId); - - function getPreviousRoundId( - address base, - address quote, - uint80 roundId - ) external view returns (uint80 previousRoundId); - - function getNextRoundId( - address base, - address quote, - uint80 roundId - ) external view returns (uint80 nextRoundId); - - // Feed management - - function proposeFeed( - address base, - address quote, - address aggregator - ) external; - - function confirmFeed( - address base, - address quote, - address aggregator - ) external; - - // Proposed aggregator - - function getProposedFeed(address base, address quote) - external - view - returns (AggregatorV2V3Interface proposedAggregator); - - function proposedGetRoundData( - address base, - address quote, - uint80 roundId - ) - external - view - returns ( - uint80 id, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - - function proposedLatestRoundData(address base, address quote) - external - view - returns ( - uint80 id, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ); - - // Phases - function getCurrentPhaseId(address base, address quote) external view returns (uint16 currentPhaseId); -} diff --git a/contracts/src/v0.7/interfaces/FlagsInterface.sol b/contracts/src/v0.7/interfaces/FlagsInterface.sol deleted file mode 100644 index 157d1ed46de..00000000000 --- a/contracts/src/v0.7/interfaces/FlagsInterface.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -interface FlagsInterface { - function getFlag(address) external view returns (bool); - - function getFlags(address[] calldata) external view returns (bool[] memory); - - function raiseFlag(address) external; - - function raiseFlags(address[] calldata) external; - - function lowerFlags(address[] calldata) external; - - function setRaisingAccessController(address) external; -} diff --git a/contracts/src/v0.7/interfaces/KeeperCompatibleInterface.sol b/contracts/src/v0.7/interfaces/KeeperCompatibleInterface.sol deleted file mode 100644 index c14de02c25c..00000000000 --- a/contracts/src/v0.7/interfaces/KeeperCompatibleInterface.sol +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.7.0; - -interface KeeperCompatibleInterface { - /** - * @notice method that is simulated by the keepers to see if any work actually - * needs to be performed. This method does does not actually need to be - * executable, and since it is only ever simulated it can consume lots of gas. - * @dev To ensure that it is never called, you may want to add the - * cannotExecute modifier from KeeperBase to your implementation of this - * method. - * @param checkData specified in the upkeep registration so it is always the - * same for a registered upkeep. This can easily be broken down into specific - * arguments using `abi.decode`, so multiple upkeeps can be registered on the - * same contract and easily differentiated by the contract. - * @return upkeepNeeded boolean to indicate whether the keeper should call - * performUpkeep or not. - * @return performData bytes that the keeper should call performUpkeep with, if - * upkeep is needed. If you would like to encode data to decode later, try - * `abi.encode`. - */ - function checkUpkeep(bytes calldata checkData) external returns (bool upkeepNeeded, bytes memory performData); - - /** - * @notice method that is actually executed by the keepers, via the registry. - * The data returned by the checkUpkeep simulation will be passed into - * this method to actually be executed. - * @dev The input to this method should not be trusted, and the caller of the - * method should not even be restricted to any single registry. Anyone should - * be able call it, and the input should be validated, there is no guarantee - * that the data passed in is the performData returned from checkUpkeep. This - * could happen due to malicious keepers, racing keepers, or simply a state - * change while the performUpkeep transaction is waiting for confirmation. - * Always validate the data passed in. - * @param performData is the data which was passed back from the checkData - * simulation. If it is encoded, it can easily be decoded into other types by - * calling `abi.decode`. This data should not be trusted, and should be - * validated against the contract's current state. - */ - function performUpkeep(bytes calldata performData) external; -} diff --git a/contracts/src/v0.7/interfaces/KeeperRegistryInterface.sol b/contracts/src/v0.7/interfaces/KeeperRegistryInterface.sol deleted file mode 100644 index df5ea92860a..00000000000 --- a/contracts/src/v0.7/interfaces/KeeperRegistryInterface.sol +++ /dev/null @@ -1,89 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.7.0; - -interface KeeperRegistryBaseInterface { - function registerUpkeep( - address target, - uint32 gasLimit, - address admin, - bytes calldata checkData - ) external returns (uint256 id); - - function performUpkeep(uint256 id, bytes calldata performData) external returns (bool success); - - function cancelUpkeep(uint256 id) external; - - function addFunds(uint256 id, uint96 amount) external; - - function getUpkeep(uint256 id) - external - view - returns ( - address target, - uint32 executeGas, - bytes memory checkData, - uint96 balance, - address lastKeeper, - address admin, - uint64 maxValidBlocknumber - ); - - function getUpkeepCount() external view returns (uint256); - - function getCanceledUpkeepList() external view returns (uint256[] memory); - - function getKeeperList() external view returns (address[] memory); - - function getKeeperInfo(address query) - external - view - returns ( - address payee, - bool active, - uint96 balance - ); - - function getConfig() - external - view - returns ( - uint32 paymentPremiumPPB, - uint24 checkFrequencyBlocks, - uint32 checkGasLimit, - uint24 stalenessSeconds, - uint16 gasCeilingMultiplier, - uint256 fallbackGasPrice, - uint256 fallbackLinkPrice - ); -} - -/** - * @dev The view methods are not actually marked as view in the implementation - * but we want them to be easily queried off-chain. Solidity will not compile - * if we actually inherit from this interface, so we document it here. - */ -interface KeeperRegistryInterface is KeeperRegistryBaseInterface { - function checkUpkeep(uint256 upkeepId, address from) - external - view - returns ( - bytes memory performData, - uint256 maxLinkPayment, - uint256 gasLimit, - int256 gasWei, - int256 linkEth - ); -} - -interface KeeperRegistryExecutableInterface is KeeperRegistryBaseInterface { - function checkUpkeep(uint256 upkeepId, address from) - external - returns ( - bytes memory performData, - uint256 maxLinkPayment, - uint256 gasLimit, - uint256 adjustedGasWei, - uint256 linkEth - ); -} diff --git a/contracts/src/v0.7/interfaces/LinkTokenInterface.sol b/contracts/src/v0.7/interfaces/LinkTokenInterface.sol deleted file mode 100644 index d9b59c7a9d2..00000000000 --- a/contracts/src/v0.7/interfaces/LinkTokenInterface.sol +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -interface LinkTokenInterface { - function allowance(address owner, address spender) external view returns (uint256 remaining); - - function approve(address spender, uint256 value) external returns (bool success); - - function balanceOf(address owner) external view returns (uint256 balance); - - function decimals() external view returns (uint8 decimalPlaces); - - function decreaseApproval(address spender, uint256 addedValue) external returns (bool success); - - function increaseApproval(address spender, uint256 subtractedValue) external; - - function name() external view returns (string memory tokenName); - - function symbol() external view returns (string memory tokenSymbol); - - function totalSupply() external view returns (uint256 totalTokensIssued); - - function transfer(address to, uint256 value) external returns (bool success); - - function transferAndCall( - address to, - uint256 value, - bytes calldata data - ) external returns (bool success); - - function transferFrom( - address from, - address to, - uint256 value - ) external returns (bool success); -} diff --git a/contracts/src/v0.7/interfaces/OperatorInterface.sol b/contracts/src/v0.7/interfaces/OperatorInterface.sol deleted file mode 100644 index 2a76a8b2056..00000000000 --- a/contracts/src/v0.7/interfaces/OperatorInterface.sol +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "./ChainlinkRequestInterface.sol"; -import "./OracleInterface.sol"; - -interface OperatorInterface is ChainlinkRequestInterface, OracleInterface { - function operatorRequest( - address sender, - uint256 payment, - bytes32 specId, - bytes4 callbackFunctionId, - uint256 nonce, - uint256 dataVersion, - bytes calldata data - ) external; - - function fulfillOracleRequest2( - bytes32 requestId, - uint256 payment, - address callbackAddress, - bytes4 callbackFunctionId, - uint256 expiration, - bytes calldata data - ) external returns (bool); - - function ownerTransferAndCall( - address to, - uint256 value, - bytes calldata data - ) external returns (bool success); -} diff --git a/contracts/src/v0.7/interfaces/OracleInterface.sol b/contracts/src/v0.7/interfaces/OracleInterface.sol deleted file mode 100644 index bf54fc0506f..00000000000 --- a/contracts/src/v0.7/interfaces/OracleInterface.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -interface OracleInterface { - function fulfillOracleRequest( - bytes32 requestId, - uint256 payment, - address callbackAddress, - bytes4 callbackFunctionId, - uint256 expiration, - bytes32 data - ) external returns (bool); - - function withdraw(address recipient, uint256 amount) external; - - function withdrawable() external view returns (uint256); -} diff --git a/contracts/src/v0.7/interfaces/OwnableInterface.sol b/contracts/src/v0.7/interfaces/OwnableInterface.sol deleted file mode 100644 index 94900657baa..00000000000 --- a/contracts/src/v0.7/interfaces/OwnableInterface.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -interface OwnableInterface { - function owner() external returns (address); - - function transferOwnership(address recipient) external; - - function acceptOwnership() external; -} diff --git a/contracts/src/v0.7/interfaces/PointerInterface.sol b/contracts/src/v0.7/interfaces/PointerInterface.sol deleted file mode 100644 index ee3d8ae9ced..00000000000 --- a/contracts/src/v0.7/interfaces/PointerInterface.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -interface PointerInterface { - function getAddress() external view returns (address); -} diff --git a/contracts/src/v0.7/interfaces/TypeAndVersionInterface.sol b/contracts/src/v0.7/interfaces/TypeAndVersionInterface.sol deleted file mode 100644 index 6adff620259..00000000000 --- a/contracts/src/v0.7/interfaces/TypeAndVersionInterface.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -abstract contract TypeAndVersionInterface { - function typeAndVersion() external pure virtual returns (string memory); -} diff --git a/contracts/src/v0.7/interfaces/UniswapAnchoredView.sol b/contracts/src/v0.7/interfaces/UniswapAnchoredView.sol deleted file mode 100644 index f750cc29084..00000000000 --- a/contracts/src/v0.7/interfaces/UniswapAnchoredView.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -// Compound Finance's oracle interface -interface UniswapAnchoredView { - function price(string memory symbol) external view returns (uint256); -} diff --git a/contracts/src/v0.7/interfaces/WithdrawalInterface.sol b/contracts/src/v0.7/interfaces/WithdrawalInterface.sol deleted file mode 100644 index 8049850a796..00000000000 --- a/contracts/src/v0.7/interfaces/WithdrawalInterface.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -interface WithdrawalInterface { - /** - * @notice transfer LINK held by the contract belonging to msg.sender to - * another address - * @param recipient is the address to send the LINK to - * @param amount is the amount of LINK to send - */ - function withdraw(address recipient, uint256 amount) external; - - /** - * @notice query the available amount of LINK to withdraw by msg.sender - */ - function withdrawable() external view returns (uint256); -} diff --git a/contracts/src/v0.7/tests/ChainlinkClientTestHelper.sol b/contracts/src/v0.7/tests/ChainlinkClientTestHelper.sol deleted file mode 100644 index 5d9afb21075..00000000000 --- a/contracts/src/v0.7/tests/ChainlinkClientTestHelper.sol +++ /dev/null @@ -1,100 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "../ChainlinkClient.sol"; -import "../vendor/SafeMathChainlink.sol"; - -contract ChainlinkClientTestHelper is ChainlinkClient { - using SafeMathChainlink for uint256; - - constructor(address _link, address _oracle) { - setChainlinkToken(_link); - setChainlinkOracle(_oracle); - } - - event Request(bytes32 id, address callbackAddress, bytes4 callbackfunctionSelector, bytes data); - event LinkAmount(uint256 amount); - - function publicNewRequest( - bytes32 _id, - address _address, - bytes memory _fulfillmentSignature - ) public { - Chainlink.Request memory req = buildChainlinkRequest(_id, _address, bytes4(keccak256(_fulfillmentSignature))); - emit Request(req.id, req.callbackAddress, req.callbackFunctionId, req.buf.buf); - } - - function publicRequest( - bytes32 _id, - address _address, - bytes memory _fulfillmentSignature, - uint256 _wei - ) public { - Chainlink.Request memory req = buildChainlinkRequest(_id, _address, bytes4(keccak256(_fulfillmentSignature))); - sendChainlinkRequest(req, _wei); - } - - function publicRequestRunTo( - address _oracle, - bytes32 _id, - address _address, - bytes memory _fulfillmentSignature, - uint256 _wei - ) public { - Chainlink.Request memory run = buildChainlinkRequest(_id, _address, bytes4(keccak256(_fulfillmentSignature))); - sendChainlinkRequestTo(_oracle, run, _wei); - } - - function publicRequestOracleData( - bytes32 _id, - bytes memory _fulfillmentSignature, - uint256 _wei - ) public { - Chainlink.Request memory req = buildOperatorRequest(_id, bytes4(keccak256(_fulfillmentSignature))); - sendOperatorRequest(req, _wei); - } - - function publicRequestOracleDataFrom( - address _oracle, - bytes32 _id, - address _address, - bytes memory _fulfillmentSignature, - uint256 _wei - ) public { - Chainlink.Request memory run = buildOperatorRequest(_id, bytes4(keccak256(_fulfillmentSignature))); - sendOperatorRequestTo(_oracle, run, _wei); - } - - function publicCancelRequest( - bytes32 _requestId, - uint256 _payment, - bytes4 _callbackFunctionId, - uint256 _expiration - ) public { - cancelChainlinkRequest(_requestId, _payment, _callbackFunctionId, _expiration); - } - - function publicChainlinkToken() public view returns (address) { - return chainlinkTokenAddress(); - } - - function publicFulfillChainlinkRequest(bytes32 _requestId, bytes32) public { - fulfillRequest(_requestId, bytes32(0)); - } - - function fulfillRequest(bytes32 _requestId, bytes32) public { - validateChainlinkCallback(_requestId); - } - - function publicLINK(uint256 _amount) public { - emit LinkAmount(LINK_DIVISIBILITY.mul(_amount)); - } - - function publicOracleAddress() public view returns (address) { - return chainlinkOracleAddress(); - } - - function publicAddExternalRequest(address _oracle, bytes32 _requestId) public { - addChainlinkExternalRequest(_oracle, _requestId); - } -} diff --git a/contracts/src/v0.7/tests/ChainlinkTestHelper.sol b/contracts/src/v0.7/tests/ChainlinkTestHelper.sol deleted file mode 100644 index 6a27e1e60ee..00000000000 --- a/contracts/src/v0.7/tests/ChainlinkTestHelper.sol +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "../Chainlink.sol"; -import "../vendor/CBORChainlink.sol"; -import "../vendor/BufferChainlink.sol"; - -contract ChainlinkTestHelper { - using Chainlink for Chainlink.Request; - using CBORChainlink for BufferChainlink.buffer; - - Chainlink.Request private req; - - event RequestData(bytes payload); - - function closeEvent() public { - emit RequestData(req.buf.buf); - } - - function setBuffer(bytes memory data) public { - Chainlink.Request memory r2 = req; - r2.setBuffer(data); - req = r2; - } - - function add(string memory _key, string memory _value) public { - Chainlink.Request memory r2 = req; - r2.add(_key, _value); - req = r2; - } - - function addBytes(string memory _key, bytes memory _value) public { - Chainlink.Request memory r2 = req; - r2.addBytes(_key, _value); - req = r2; - } - - function addInt(string memory _key, int256 _value) public { - Chainlink.Request memory r2 = req; - r2.addInt(_key, _value); - req = r2; - } - - function addUint(string memory _key, uint256 _value) public { - Chainlink.Request memory r2 = req; - r2.addUint(_key, _value); - req = r2; - } - - // Temporarily have method receive bytes32[] memory until experimental - // string[] memory can be invoked from truffle tests. - function addStringArray(string memory _key, bytes32[] memory _values) public { - string[] memory strings = new string[](_values.length); - for (uint256 i = 0; i < _values.length; i++) { - strings[i] = bytes32ToString(_values[i]); - } - Chainlink.Request memory r2 = req; - r2.addStringArray(_key, strings); - req = r2; - } - - function bytes32ToString(bytes32 x) private pure returns (string memory) { - bytes memory bytesString = new bytes(32); - uint256 charCount = 0; - for (uint256 j = 0; j < 32; j++) { - bytes1 char = bytes1(bytes32(uint256(x) * 2**(8 * j))); - if (char != 0) { - bytesString[charCount] = char; - charCount++; - } - } - bytes memory bytesStringTrimmed = new bytes(charCount); - for (uint256 j = 0; j < charCount; j++) { - bytesStringTrimmed[j] = bytesString[j]; - } - return string(bytesStringTrimmed); - } -} diff --git a/contracts/src/v0.7/tests/Consumer.sol b/contracts/src/v0.7/tests/Consumer.sol deleted file mode 100644 index 99934df1cd2..00000000000 --- a/contracts/src/v0.7/tests/Consumer.sol +++ /dev/null @@ -1,85 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "../ChainlinkClient.sol"; - -contract Consumer is ChainlinkClient { - using Chainlink for Chainlink.Request; - - bytes32 internal specId; - bytes32 public currentPrice; - uint256 public currentPriceInt; - - event RequestFulfilled( - bytes32 indexed requestId, // User-defined ID - bytes32 indexed price - ); - - constructor( - address _link, - address _oracle, - bytes32 _specId - ) public { - setChainlinkToken(_link); - setChainlinkOracle(_oracle); - specId = _specId; - } - - function setSpecID(bytes32 _specId) public { - specId = _specId; - } - - function requestEthereumPrice(string memory _currency, uint256 _payment) public { - Chainlink.Request memory req = buildOperatorRequest(specId, this.fulfill.selector); - req.add("get", "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD,EUR,JPY"); - string[] memory path = new string[](1); - path[0] = _currency; - req.addStringArray("path", path); - // version 2 - sendChainlinkRequest(req, _payment); - } - - function requestMultipleParametersWithCustomURLs( - string memory _urlUSD, - string memory _pathUSD, - uint256 _payment - ) public { - Chainlink.Request memory req = buildOperatorRequest(specId, this.fulfillParametersWithCustomURLs.selector); - req.add("urlUSD", _urlUSD); - req.add("pathUSD", _pathUSD); - sendChainlinkRequest(req, _payment); - } - - function cancelRequest( - address _oracle, - bytes32 _requestId, - uint256 _payment, - bytes4 _callbackFunctionId, - uint256 _expiration - ) public { - ChainlinkRequestInterface requested = ChainlinkRequestInterface(_oracle); - requested.cancelOracleRequest(_requestId, _payment, _callbackFunctionId, _expiration); - } - - function withdrawLink() public { - LinkTokenInterface _link = LinkTokenInterface(chainlinkTokenAddress()); - require(_link.transfer(msg.sender, _link.balanceOf(address(this))), "Unable to transfer"); - } - - function addExternalRequest(address _oracle, bytes32 _requestId) external { - addChainlinkExternalRequest(_oracle, _requestId); - } - - function fulfill(bytes32 _requestId, bytes32 _price) public recordChainlinkFulfillment(_requestId) { - emit RequestFulfilled(_requestId, _price); - currentPrice = _price; - } - - function fulfillParametersWithCustomURLs(bytes32 _requestId, uint256 _price) - public - recordChainlinkFulfillment(_requestId) - { - emit RequestFulfilled(_requestId, bytes32(_price)); - currentPriceInt = _price; - } -} diff --git a/contracts/src/v0.7/tests/KeeperCompatibleTestHelper.sol b/contracts/src/v0.7/tests/KeeperCompatibleTestHelper.sol deleted file mode 100644 index 0cf86848766..00000000000 --- a/contracts/src/v0.7/tests/KeeperCompatibleTestHelper.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "../KeeperCompatible.sol"; - -contract KeeperCompatibleTestHelper is KeeperCompatible { - function checkUpkeep(bytes calldata) external override returns (bool, bytes memory) {} - - function performUpkeep(bytes calldata) external override {} - - function verifyCannotExecute() public view cannotExecute {} -} diff --git a/contracts/src/v0.7/tests/MockCompoundOracle.sol b/contracts/src/v0.7/tests/MockCompoundOracle.sol deleted file mode 100644 index 0b9ff5774ec..00000000000 --- a/contracts/src/v0.7/tests/MockCompoundOracle.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "../interfaces/UniswapAnchoredView.sol"; - -contract MockCompoundOracle is UniswapAnchoredView { - struct OracleDetails { - uint256 price; - uint256 decimals; - } - - mapping(string => OracleDetails) s_oracleDetails; - - function price(string memory symbol) external view override returns (uint256) { - return s_oracleDetails[symbol].price; - } - - function setPrice( - string memory symbol, - uint256 newPrice, - uint256 newDecimals - ) public { - OracleDetails memory details = s_oracleDetails[symbol]; - details.price = newPrice; - details.decimals = newDecimals; - s_oracleDetails[symbol] = details; - } -} diff --git a/contracts/src/v0.7/tests/MockV2Aggregator.sol b/contracts/src/v0.7/tests/MockV2Aggregator.sol deleted file mode 100644 index 2aeb8406ac1..00000000000 --- a/contracts/src/v0.7/tests/MockV2Aggregator.sol +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "../interfaces/AggregatorInterface.sol"; - -/** - * @title MockV2Aggregator - * @notice Based on the HistoricAggregator contract - * @notice Use this contract when you need to test - * other contract's ability to read data from an - * aggregator contract, but how the aggregator got - * its answer is unimportant - */ -contract MockV2Aggregator is AggregatorInterface { - int256 public override latestAnswer; - uint256 public override latestTimestamp; - uint256 public override latestRound; - - mapping(uint256 => int256) public override getAnswer; - mapping(uint256 => uint256) public override getTimestamp; - mapping(uint256 => uint256) private getStartedAt; - - constructor(int256 _initialAnswer) public { - updateAnswer(_initialAnswer); - } - - function updateAnswer(int256 _answer) public { - latestAnswer = _answer; - latestTimestamp = block.timestamp; - latestRound++; - getAnswer[latestRound] = _answer; - getTimestamp[latestRound] = block.timestamp; - } - - function updateRoundData( - uint256 _roundId, - int256 _answer, - uint256 _timestamp, - uint256 _startedAt - ) public { - latestRound = _roundId; - latestAnswer = _answer; - latestTimestamp = _timestamp; - getAnswer[latestRound] = _answer; - getTimestamp[latestRound] = _timestamp; - getStartedAt[latestRound] = _startedAt; - } -} diff --git a/contracts/src/v0.7/tests/MockV3Aggregator.sol b/contracts/src/v0.7/tests/MockV3Aggregator.sol deleted file mode 100644 index d14a67d915a..00000000000 --- a/contracts/src/v0.7/tests/MockV3Aggregator.sol +++ /dev/null @@ -1,93 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "../interfaces/AggregatorV2V3Interface.sol"; - -/** - * @title MockV3Aggregator - * @notice Based on the FluxAggregator contract - * @notice Use this contract when you need to test - * other contract's ability to read data from an - * aggregator contract, but how the aggregator got - * its answer is unimportant - */ -contract MockV3Aggregator is AggregatorV2V3Interface { - uint256 public constant override version = 0; - - uint8 public override decimals; - int256 public override latestAnswer; - uint256 public override latestTimestamp; - uint256 public override latestRound; - - mapping(uint256 => int256) public override getAnswer; - mapping(uint256 => uint256) public override getTimestamp; - mapping(uint256 => uint256) private getStartedAt; - - constructor(uint8 _decimals, int256 _initialAnswer) { - decimals = _decimals; - updateAnswer(_initialAnswer); - } - - function updateAnswer(int256 _answer) public { - latestAnswer = _answer; - latestTimestamp = block.timestamp; - latestRound++; - getAnswer[latestRound] = _answer; - getTimestamp[latestRound] = block.timestamp; - getStartedAt[latestRound] = block.timestamp; - } - - function updateRoundData( - uint80 _roundId, - int256 _answer, - uint256 _timestamp, - uint256 _startedAt - ) public { - latestRound = _roundId; - latestAnswer = _answer; - latestTimestamp = _timestamp; - getAnswer[latestRound] = _answer; - getTimestamp[latestRound] = _timestamp; - getStartedAt[latestRound] = _startedAt; - } - - function getRoundData(uint80 _roundId) - external - view - override - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - return (_roundId, getAnswer[_roundId], getStartedAt[_roundId], getTimestamp[_roundId], _roundId); - } - - function latestRoundData() - external - view - override - returns ( - uint80 roundId, - int256 answer, - uint256 startedAt, - uint256 updatedAt, - uint80 answeredInRound - ) - { - return ( - uint80(latestRound), - getAnswer[latestRound], - getStartedAt[latestRound], - getTimestamp[latestRound], - uint80(latestRound) - ); - } - - function description() external pure override returns (string memory) { - return "v0.6/tests/MockV3Aggregator.sol"; - } -} diff --git a/contracts/src/v0.7/tests/UpkeepCounter.sol b/contracts/src/v0.7/tests/UpkeepCounter.sol deleted file mode 100644 index 3c42b58255f..00000000000 --- a/contracts/src/v0.7/tests/UpkeepCounter.sol +++ /dev/null @@ -1,57 +0,0 @@ -pragma solidity ^0.7.6; - -contract UpkeepCounter { - event PerformingUpkeep( - address indexed from, - uint256 initialBlock, - uint256 lastBlock, - uint256 previousBlock, - uint256 counter - ); - - uint256 public testRange; - uint256 public interval; - uint256 public lastBlock; - uint256 public previousPerformBlock; - uint256 public initialBlock; - uint256 public counter; - - constructor(uint256 _testRange, uint256 _interval) { - testRange = _testRange; - interval = _interval; - previousPerformBlock = 0; - lastBlock = block.number; - initialBlock = 0; - counter = 0; - } - - function checkUpkeep(bytes calldata data) external view returns (bool, bytes memory) { - return (eligible(), data); - } - - function performUpkeep(bytes calldata performData) external { - if (initialBlock == 0) { - initialBlock = block.number; - } - lastBlock = block.number; - counter = counter + 1; - performData; - emit PerformingUpkeep(tx.origin, initialBlock, lastBlock, previousPerformBlock, counter); - previousPerformBlock = lastBlock; - } - - function eligible() public view returns (bool) { - if (initialBlock == 0) { - return true; - } - - return (block.number - initialBlock) < testRange && (block.number - lastBlock) >= interval; - } - - function setSpread(uint256 _testRange, uint256 _interval) external { - testRange = _testRange; - interval = _interval; - initialBlock = 0; - counter = 0; - } -} diff --git a/contracts/src/v0.7/tests/UpkeepPerformCounterRestrictive.sol b/contracts/src/v0.7/tests/UpkeepPerformCounterRestrictive.sol deleted file mode 100644 index 35e28584a09..00000000000 --- a/contracts/src/v0.7/tests/UpkeepPerformCounterRestrictive.sol +++ /dev/null @@ -1,85 +0,0 @@ -pragma solidity 0.7.6; - -contract UpkeepPerformCounterRestrictive { - event PerformingUpkeep(bool eligible, address from, uint256 initialCall, uint256 nextEligible, uint256 blockNumber); - - uint256 public initialCall = 0; - uint256 public nextEligible = 0; - uint256 public testRange; - uint256 public averageEligibilityCadence; - uint256 public checkGasToBurn; - uint256 public performGasToBurn; - mapping(bytes32 => bool) public dummyMap; // used to force storage lookup - - uint256 private count = 0; - - constructor(uint256 _testRange, uint256 _averageEligibilityCadence) { - testRange = _testRange; - averageEligibilityCadence = _averageEligibilityCadence; - } - - function checkUpkeep(bytes calldata data) external view returns (bool, bytes memory) { - uint256 startGas = gasleft(); - uint256 blockNum = block.number - 1; - bool dummy; - // burn gas - while (startGas - gasleft() < checkGasToBurn) { - dummy = dummy && dummyMap[blockhash(blockNum)]; // arbitrary storage reads - blockNum--; - } - return (eligible(), abi.encode(dummy)); - } - - function performUpkeep(bytes calldata) external { - uint256 startGas = gasleft(); - bool eligible = eligible(); - uint256 blockNum = block.number; - emit PerformingUpkeep(eligible, tx.origin, initialCall, nextEligible, blockNum); - require(eligible); - if (initialCall == 0) { - initialCall = blockNum; - } - nextEligible = (blockNum + (rand() % (averageEligibilityCadence * 2))) + 1; - count++; - // burn gas - blockNum--; - while (startGas - gasleft() < performGasToBurn) { - dummyMap[blockhash(blockNum)] = false; // arbitrary storage writes - blockNum--; - } - } - - function setCheckGasToBurn(uint256 value) public { - checkGasToBurn = value; - } - - function setPerformGasToBurn(uint256 value) public { - performGasToBurn = value; - } - - function getCountPerforms() public view returns (uint256) { - return count; - } - - function eligible() internal view returns (bool) { - return initialCall == 0 || (block.number - initialCall < testRange && block.number > nextEligible); - } - - function checkEligible() public view returns (bool) { - return eligible(); - } - - function reset() external { - initialCall = 0; - count = 0; - } - - function setSpread(uint256 _newTestRange, uint256 _newAverageEligibilityCadence) external { - testRange = _newTestRange; - averageEligibilityCadence = _newAverageEligibilityCadence; - } - - function rand() private view returns (uint256) { - return uint256(keccak256(abi.encode(blockhash(block.number - 1), address(this)))); - } -} diff --git a/contracts/src/v0.7/tests/UpkeepReverter.sol b/contracts/src/v0.7/tests/UpkeepReverter.sol deleted file mode 100644 index c39cbf7db4e..00000000000 --- a/contracts/src/v0.7/tests/UpkeepReverter.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "../KeeperCompatible.sol"; - -contract UpkeepReverter is KeeperCompatible { - function checkUpkeep(bytes calldata data) - public - view - override - cannotExecute - returns (bool callable, bytes calldata executedata) - { - require(false, "!working"); - return (true, data); - } - - function performUpkeep(bytes calldata) external pure override { - require(false, "!working"); - } -} diff --git a/contracts/src/v0.7/tests/VRFCoordinatorMock.sol b/contracts/src/v0.7/tests/VRFCoordinatorMock.sol deleted file mode 100644 index a46c9a748fc..00000000000 --- a/contracts/src/v0.7/tests/VRFCoordinatorMock.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -import "../interfaces/LinkTokenInterface.sol"; -import "../VRFConsumerBase.sol"; - -contract VRFCoordinatorMock { - LinkTokenInterface public LINK; - - event RandomnessRequest(address indexed sender, bytes32 indexed keyHash, uint256 indexed seed); - - constructor(address linkAddress) public { - LINK = LinkTokenInterface(linkAddress); - } - - function onTokenTransfer( - address sender, - uint256 fee, - bytes memory _data - ) public onlyLINK { - (bytes32 keyHash, uint256 seed) = abi.decode(_data, (bytes32, uint256)); - emit RandomnessRequest(sender, keyHash, seed); - } - - function callBackWithRandomness( - bytes32 requestId, - uint256 randomness, - address consumerContract - ) public { - VRFConsumerBase v; - bytes memory resp = abi.encodeWithSelector(v.rawFulfillRandomness.selector, requestId, randomness); - uint256 b = 206000; - require(gasleft() >= b, "not enough gas for consumer"); - (bool success, ) = consumerContract.call(resp); - } - - modifier onlyLINK() { - require(msg.sender == address(LINK), "Must use LINK token"); - _; - } -} diff --git a/contracts/src/v0.7/vendor/Address.sol b/contracts/src/v0.7/vendor/Address.sol deleted file mode 100644 index eec7c36dcd7..00000000000 --- a/contracts/src/v0.7/vendor/Address.sol +++ /dev/null @@ -1,217 +0,0 @@ -// SPDX-License-Identifier: MIT -// From https://github.com/OpenZeppelin/openzeppelin-contracts v3.4.0(fa64a1ced0b70ab89073d5d0b6e01b0778f7e7d6) - -pragma solidity >=0.6.2 <0.8.0; - -/** - * @dev Collection of functions related to the address type - */ -library Address { - /** - * @dev Returns true if `account` is a contract. - * - * [IMPORTANT] - * ==== - * It is unsafe to assume that an address for which this function returns - * false is an externally-owned account (EOA) and not a contract. - * - * Among others, `isContract` will return false for the following - * types of addresses: - * - * - an externally-owned account - * - a contract in construction - * - an address where a contract will be created - * - an address where a contract lived, but was destroyed - * ==== - */ - function isContract(address account) internal view returns (bool) { - // This method relies on extcodesize, which returns 0 for contracts in - // construction, since the code is only stored at the end of the - // constructor execution. - - uint256 size; - // solhint-disable-next-line no-inline-assembly - assembly { - size := extcodesize(account) - } - return size > 0; - } - - /** - * @dev Replacement for Solidity's `transfer`: sends `amount` wei to - * `recipient`, forwarding all available gas and reverting on errors. - * - * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost - * of certain opcodes, possibly making contracts go over the 2300 gas limit - * imposed by `transfer`, making them unable to receive funds via - * `transfer`. {sendValue} removes this limitation. - * - * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. - * - * IMPORTANT: because control is transferred to `recipient`, care must be - * taken to not create reentrancy vulnerabilities. Consider using - * {ReentrancyGuard} or the - * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. - */ - function sendValue(address payable recipient, uint256 amount) internal { - require(address(this).balance >= amount, "Address: insufficient balance"); - - // solhint-disable-next-line avoid-low-level-calls, avoid-call-value - (bool success, ) = recipient.call{value: amount}(""); - require(success, "Address: unable to send value, recipient may have reverted"); - } - - /** - * @dev Performs a Solidity function call using a low level `call`. A - * plain`call` is an unsafe replacement for a function call: use this - * function instead. - * - * If `target` reverts with a revert reason, it is bubbled up by this - * function (like regular Solidity function calls). - * - * Returns the raw returned data. To convert to the expected return value, - * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. - * - * Requirements: - * - * - `target` must be a contract. - * - calling `target` with `data` must not revert. - * - * _Available since v3.1._ - */ - function functionCall(address target, bytes memory data) internal returns (bytes memory) { - return functionCall(target, data, "Address: low-level call failed"); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with - * `errorMessage` as a fallback revert reason when `target` reverts. - * - * _Available since v3.1._ - */ - function functionCall( - address target, - bytes memory data, - string memory errorMessage - ) internal returns (bytes memory) { - return functionCallWithValue(target, data, 0, errorMessage); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], - * but also transferring `value` wei to `target`. - * - * Requirements: - * - * - the calling contract must have an ETH balance of at least `value`. - * - the called Solidity function must be `payable`. - * - * _Available since v3.1._ - */ - function functionCallWithValue( - address target, - bytes memory data, - uint256 value - ) internal returns (bytes memory) { - return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); - } - - /** - * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but - * with `errorMessage` as a fallback revert reason when `target` reverts. - * - * _Available since v3.1._ - */ - function functionCallWithValue( - address target, - bytes memory data, - uint256 value, - string memory errorMessage - ) internal returns (bytes memory) { - require(address(this).balance >= value, "Address: insufficient balance for call"); - require(isContract(target), "Address: call to non-contract"); - - // solhint-disable-next-line avoid-low-level-calls - (bool success, bytes memory returndata) = target.call{value: value}(data); - return _verifyCallResult(success, returndata, errorMessage); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], - * but performing a static call. - * - * _Available since v3.3._ - */ - function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { - return functionStaticCall(target, data, "Address: low-level static call failed"); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], - * but performing a static call. - * - * _Available since v3.3._ - */ - function functionStaticCall( - address target, - bytes memory data, - string memory errorMessage - ) internal view returns (bytes memory) { - require(isContract(target), "Address: static call to non-contract"); - - // solhint-disable-next-line avoid-low-level-calls - (bool success, bytes memory returndata) = target.staticcall(data); - return _verifyCallResult(success, returndata, errorMessage); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], - * but performing a delegate call. - * - * _Available since v3.4._ - */ - function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { - return functionDelegateCall(target, data, "Address: low-level delegate call failed"); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], - * but performing a delegate call. - * - * _Available since v3.4._ - */ - function functionDelegateCall( - address target, - bytes memory data, - string memory errorMessage - ) internal returns (bytes memory) { - require(isContract(target), "Address: delegate call to non-contract"); - - // solhint-disable-next-line avoid-low-level-calls - (bool success, bytes memory returndata) = target.delegatecall(data); - return _verifyCallResult(success, returndata, errorMessage); - } - - function _verifyCallResult( - bool success, - bytes memory returndata, - string memory errorMessage - ) private pure returns (bytes memory) { - if (success) { - return returndata; - } else { - // Look for revert reason and bubble it up if present - if (returndata.length > 0) { - // The easiest way to bubble the revert reason is using memory via assembly - - // solhint-disable-next-line no-inline-assembly - assembly { - let returndata_size := mload(returndata) - revert(add(32, returndata), returndata_size) - } - } else { - revert(errorMessage); - } - } - } -} diff --git a/contracts/src/v0.7/vendor/BufferChainlink.sol b/contracts/src/v0.7/vendor/BufferChainlink.sol deleted file mode 100644 index 7d2056921d9..00000000000 --- a/contracts/src/v0.7/vendor/BufferChainlink.sol +++ /dev/null @@ -1,333 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -/** - * @dev A library for working with mutable byte buffers in Solidity. - * - * Byte buffers are mutable and expandable, and provide a variety of primitives - * for writing to them. At any time you can fetch a bytes object containing the - * current contents of the buffer. The bytes object should not be stored between - * operations, as it may change due to resizing of the buffer. - */ -library BufferChainlink { - /** - * @dev Represents a mutable buffer. Buffers have a current value (buf) and - * a capacity. The capacity may be longer than the current value, in - * which case it can be extended without the need to allocate more memory. - */ - struct buffer { - bytes buf; - uint256 capacity; - } - - /** - * @dev Initializes a buffer with an initial capacity. - * @param buf The buffer to initialize. - * @param capacity The number of bytes of space to allocate the buffer. - * @return The buffer, for chaining. - */ - function init(buffer memory buf, uint256 capacity) internal pure returns (buffer memory) { - if (capacity % 32 != 0) { - capacity += 32 - (capacity % 32); - } - // Allocate space for the buffer data - buf.capacity = capacity; - assembly { - let ptr := mload(0x40) - mstore(buf, ptr) - mstore(ptr, 0) - mstore(0x40, add(32, add(ptr, capacity))) - } - return buf; - } - - /** - * @dev Initializes a new buffer from an existing bytes object. - * Changes to the buffer may mutate the original value. - * @param b The bytes object to initialize the buffer with. - * @return A new buffer. - */ - function fromBytes(bytes memory b) internal pure returns (buffer memory) { - buffer memory buf; - buf.buf = b; - buf.capacity = b.length; - return buf; - } - - function resize(buffer memory buf, uint256 capacity) private pure { - bytes memory oldbuf = buf.buf; - init(buf, capacity); - append(buf, oldbuf); - } - - function max(uint256 a, uint256 b) private pure returns (uint256) { - if (a > b) { - return a; - } - return b; - } - - /** - * @dev Sets buffer length to 0. - * @param buf The buffer to truncate. - * @return The original buffer, for chaining.. - */ - function truncate(buffer memory buf) internal pure returns (buffer memory) { - assembly { - let bufptr := mload(buf) - mstore(bufptr, 0) - } - return buf; - } - - /** - * @dev Writes a byte string to a buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param off The start offset to write to. - * @param data The data to append. - * @param len The number of bytes to copy. - * @return The original buffer, for chaining. - */ - function write( - buffer memory buf, - uint256 off, - bytes memory data, - uint256 len - ) internal pure returns (buffer memory) { - require(len <= data.length); - - if (off + len > buf.capacity) { - resize(buf, max(buf.capacity, len + off) * 2); - } - - uint256 dest; - uint256 src; - assembly { - // Memory address of the buffer data - let bufptr := mload(buf) - // Length of existing buffer data - let buflen := mload(bufptr) - // Start address = buffer address + offset + sizeof(buffer length) - dest := add(add(bufptr, 32), off) - // Update buffer length if we're extending it - if gt(add(len, off), buflen) { - mstore(bufptr, add(len, off)) - } - src := add(data, 32) - } - - // Copy word-length chunks while possible - for (; len >= 32; len -= 32) { - assembly { - mstore(dest, mload(src)) - } - dest += 32; - src += 32; - } - - // Copy remaining bytes - uint256 mask = 256**(32 - len) - 1; - assembly { - let srcpart := and(mload(src), not(mask)) - let destpart := and(mload(dest), mask) - mstore(dest, or(destpart, srcpart)) - } - - return buf; - } - - /** - * @dev Appends a byte string to a buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @param len The number of bytes to copy. - * @return The original buffer, for chaining. - */ - function append( - buffer memory buf, - bytes memory data, - uint256 len - ) internal pure returns (buffer memory) { - return write(buf, buf.buf.length, data, len); - } - - /** - * @dev Appends a byte string to a buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer, for chaining. - */ - function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) { - return write(buf, buf.buf.length, data, data.length); - } - - /** - * @dev Writes a byte to the buffer. Resizes if doing so would exceed the - * capacity of the buffer. - * @param buf The buffer to append to. - * @param off The offset to write the byte at. - * @param data The data to append. - * @return The original buffer, for chaining. - */ - function writeUint8( - buffer memory buf, - uint256 off, - uint8 data - ) internal pure returns (buffer memory) { - if (off >= buf.capacity) { - resize(buf, buf.capacity * 2); - } - - assembly { - // Memory address of the buffer data - let bufptr := mload(buf) - // Length of existing buffer data - let buflen := mload(bufptr) - // Address = buffer address + sizeof(buffer length) + off - let dest := add(add(bufptr, off), 32) - mstore8(dest, data) - // Update buffer length if we extended it - if eq(off, buflen) { - mstore(bufptr, add(buflen, 1)) - } - } - return buf; - } - - /** - * @dev Appends a byte to the buffer. Resizes if doing so would exceed the - * capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer, for chaining. - */ - function appendUint8(buffer memory buf, uint8 data) internal pure returns (buffer memory) { - return writeUint8(buf, buf.buf.length, data); - } - - /** - * @dev Writes up to 32 bytes to the buffer. Resizes if doing so would - * exceed the capacity of the buffer. - * @param buf The buffer to append to. - * @param off The offset to write at. - * @param data The data to append. - * @param len The number of bytes to write (left-aligned). - * @return The original buffer, for chaining. - */ - function write( - buffer memory buf, - uint256 off, - bytes32 data, - uint256 len - ) private pure returns (buffer memory) { - if (len + off > buf.capacity) { - resize(buf, (len + off) * 2); - } - - uint256 mask = 256**len - 1; - // Right-align data - data = data >> (8 * (32 - len)); - assembly { - // Memory address of the buffer data - let bufptr := mload(buf) - // Address = buffer address + sizeof(buffer length) + off + len - let dest := add(add(bufptr, off), len) - mstore(dest, or(and(mload(dest), not(mask)), data)) - // Update buffer length if we extended it - if gt(add(off, len), mload(bufptr)) { - mstore(bufptr, add(off, len)) - } - } - return buf; - } - - /** - * @dev Writes a bytes20 to the buffer. Resizes if doing so would exceed the - * capacity of the buffer. - * @param buf The buffer to append to. - * @param off The offset to write at. - * @param data The data to append. - * @return The original buffer, for chaining. - */ - function writeBytes20( - buffer memory buf, - uint256 off, - bytes20 data - ) internal pure returns (buffer memory) { - return write(buf, off, bytes32(data), 20); - } - - /** - * @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer, for chhaining. - */ - function appendBytes20(buffer memory buf, bytes20 data) internal pure returns (buffer memory) { - return write(buf, buf.buf.length, bytes32(data), 20); - } - - /** - * @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer, for chaining. - */ - function appendBytes32(buffer memory buf, bytes32 data) internal pure returns (buffer memory) { - return write(buf, buf.buf.length, data, 32); - } - - /** - * @dev Writes an integer to the buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param off The offset to write at. - * @param data The data to append. - * @param len The number of bytes to write (right-aligned). - * @return The original buffer, for chaining. - */ - function writeInt( - buffer memory buf, - uint256 off, - uint256 data, - uint256 len - ) private pure returns (buffer memory) { - if (len + off > buf.capacity) { - resize(buf, (len + off) * 2); - } - - uint256 mask = 256**len - 1; - assembly { - // Memory address of the buffer data - let bufptr := mload(buf) - // Address = buffer address + off + sizeof(buffer length) + len - let dest := add(add(bufptr, off), len) - mstore(dest, or(and(mload(dest), not(mask)), data)) - // Update buffer length if we extended it - if gt(add(off, len), mload(bufptr)) { - mstore(bufptr, add(off, len)) - } - } - return buf; - } - - /** - * @dev Appends a byte to the end of the buffer. Resizes if doing so would - * exceed the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer. - */ - function appendInt( - buffer memory buf, - uint256 data, - uint256 len - ) internal pure returns (buffer memory) { - return writeInt(buf, buf.buf.length, data, len); - } -} diff --git a/contracts/src/v0.7/vendor/CBORChainlink.sol b/contracts/src/v0.7/vendor/CBORChainlink.sol deleted file mode 100644 index 5ee0cecd203..00000000000 --- a/contracts/src/v0.7/vendor/CBORChainlink.sol +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.4.19; - -import {BufferChainlink} from "./BufferChainlink.sol"; - -library CBORChainlink { - using BufferChainlink for BufferChainlink.buffer; - - uint8 private constant MAJOR_TYPE_INT = 0; - uint8 private constant MAJOR_TYPE_NEGATIVE_INT = 1; - uint8 private constant MAJOR_TYPE_BYTES = 2; - uint8 private constant MAJOR_TYPE_STRING = 3; - uint8 private constant MAJOR_TYPE_ARRAY = 4; - uint8 private constant MAJOR_TYPE_MAP = 5; - uint8 private constant MAJOR_TYPE_TAG = 6; - uint8 private constant MAJOR_TYPE_CONTENT_FREE = 7; - - uint8 private constant TAG_TYPE_BIGNUM = 2; - uint8 private constant TAG_TYPE_NEGATIVE_BIGNUM = 3; - - function encodeFixedNumeric(BufferChainlink.buffer memory buf, uint8 major, uint64 value) private pure { - if(value <= 23) { - buf.appendUint8(uint8((major << 5) | value)); - } else if (value <= 0xFF) { - buf.appendUint8(uint8((major << 5) | 24)); - buf.appendInt(value, 1); - } else if (value <= 0xFFFF) { - buf.appendUint8(uint8((major << 5) | 25)); - buf.appendInt(value, 2); - } else if (value <= 0xFFFFFFFF) { - buf.appendUint8(uint8((major << 5) | 26)); - buf.appendInt(value, 4); - } else { - buf.appendUint8(uint8((major << 5) | 27)); - buf.appendInt(value, 8); - } - } - - function encodeIndefiniteLengthType(BufferChainlink.buffer memory buf, uint8 major) private pure { - buf.appendUint8(uint8((major << 5) | 31)); - } - - function encodeUInt(BufferChainlink.buffer memory buf, uint value) internal pure { - if(value > 0xFFFFFFFFFFFFFFFF) { - encodeBigNum(buf, value); - } else { - encodeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(value)); - } - } - - function encodeInt(BufferChainlink.buffer memory buf, int value) internal pure { - if(value < -0x10000000000000000) { - encodeSignedBigNum(buf, value); - } else if(value > 0xFFFFFFFFFFFFFFFF) { - encodeBigNum(buf, uint(value)); - } else if(value >= 0) { - encodeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(uint256(value))); - } else { - encodeFixedNumeric(buf, MAJOR_TYPE_NEGATIVE_INT, uint64(uint256(-1 - value))); - } - } - - function encodeBytes(BufferChainlink.buffer memory buf, bytes memory value) internal pure { - encodeFixedNumeric(buf, MAJOR_TYPE_BYTES, uint64(value.length)); - buf.append(value); - } - - function encodeBigNum(BufferChainlink.buffer memory buf, uint value) internal pure { - buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_BIGNUM)); - encodeBytes(buf, abi.encode(value)); - } - - function encodeSignedBigNum(BufferChainlink.buffer memory buf, int input) internal pure { - buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_NEGATIVE_BIGNUM)); - encodeBytes(buf, abi.encode(uint256(-1 - input))); - } - - function encodeString(BufferChainlink.buffer memory buf, string memory value) internal pure { - encodeFixedNumeric(buf, MAJOR_TYPE_STRING, uint64(bytes(value).length)); - buf.append(bytes(value)); - } - - function startArray(BufferChainlink.buffer memory buf) internal pure { - encodeIndefiniteLengthType(buf, MAJOR_TYPE_ARRAY); - } - - function startMap(BufferChainlink.buffer memory buf) internal pure { - encodeIndefiniteLengthType(buf, MAJOR_TYPE_MAP); - } - - function endSequence(BufferChainlink.buffer memory buf) internal pure { - encodeIndefiniteLengthType(buf, MAJOR_TYPE_CONTENT_FREE); - } -} diff --git a/contracts/src/v0.7/vendor/Context.sol b/contracts/src/v0.7/vendor/Context.sol deleted file mode 100644 index aa7b856e245..00000000000 --- a/contracts/src/v0.7/vendor/Context.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: MIT -// github.com/OpenZeppelin/openzeppelin-contracts@fa64a1ced0b70ab89073d5d0b6e01b0778f7e7d6 - -pragma solidity ^0.7.0; - -/* - * @dev Provides information about the current execution context, including the - * sender of the transaction and its data. While these are generally available - * via msg.sender and msg.data, they should not be accessed in such a direct - * manner, since when dealing with GSN meta-transactions the account sending and - * paying for execution may not be the actual sender (as far as an application - * is concerned). - * - * This contract is only required for intermediate, library-like contracts. - */ -abstract contract Context { - function _msgSender() internal view virtual returns (address payable) { - return msg.sender; - } - - function _msgData() internal view virtual returns (bytes memory) { - this; - // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 - return msg.data; - } -} diff --git a/contracts/src/v0.7/vendor/ENSResolver.sol b/contracts/src/v0.7/vendor/ENSResolver.sol deleted file mode 100644 index d5cbc6727bf..00000000000 --- a/contracts/src/v0.7/vendor/ENSResolver.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -abstract contract ENSResolver { - function addr(bytes32 node) public view virtual returns (address); -} diff --git a/contracts/src/v0.7/vendor/Pausable.sol b/contracts/src/v0.7/vendor/Pausable.sol deleted file mode 100644 index 63ccdd6ce49..00000000000 --- a/contracts/src/v0.7/vendor/Pausable.sol +++ /dev/null @@ -1,91 +0,0 @@ -// SPDX-License-Identifier: MIT -// github.com/OpenZeppelin/openzeppelin-contracts@fa64a1ced0b70ab89073d5d0b6e01b0778f7e7d6 - -pragma solidity ^0.7.0; - -import "./Context.sol"; - -/** - * @dev Contract module which allows children to implement an emergency stop - * mechanism that can be triggered by an authorized account. - * - * This module is used through inheritance. It will make available the - * modifiers `whenNotPaused` and `whenPaused`, which can be applied to - * the functions of your contract. Note that they will not be pausable by - * simply including this module, only once the modifiers are put in place. - */ -abstract contract Pausable is Context { - /** - * @dev Emitted when the pause is triggered by `account`. - */ - event Paused(address account); - - /** - * @dev Emitted when the pause is lifted by `account`. - */ - event Unpaused(address account); - - bool private _paused; - - /** - * @dev Initializes the contract in unpaused state. - */ - constructor() { - _paused = false; - } - - /** - * @dev Returns true if the contract is paused, and false otherwise. - */ - function paused() public view virtual returns (bool) { - return _paused; - } - - /** - * @dev Modifier to make a function callable only when the contract is not paused. - * - * Requirements: - * - * - The contract must not be paused. - */ - modifier whenNotPaused() { - require(!paused(), "Pausable: paused"); - _; - } - - /** - * @dev Modifier to make a function callable only when the contract is paused. - * - * Requirements: - * - * - The contract must be paused. - */ - modifier whenPaused() { - require(paused(), "Pausable: not paused"); - _; - } - - /** - * @dev Triggers stopped state. - * - * Requirements: - * - * - The contract must not be paused. - */ - function _pause() internal virtual whenNotPaused { - _paused = true; - emit Paused(_msgSender()); - } - - /** - * @dev Returns to normal state. - * - * Requirements: - * - * - The contract must be paused. - */ - function _unpause() internal virtual whenPaused { - _paused = false; - emit Unpaused(_msgSender()); - } -} diff --git a/contracts/src/v0.7/vendor/ReentrancyGuard.sol b/contracts/src/v0.7/vendor/ReentrancyGuard.sol deleted file mode 100644 index aaaee1799c4..00000000000 --- a/contracts/src/v0.7/vendor/ReentrancyGuard.sol +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-License-Identifier: MIT -// github.com/OpenZeppelin/openzeppelin-contracts@fa64a1ced0b70ab89073d5d0b6e01b0778f7e7d6 - -pragma solidity ^0.7.0; - -/** - * @dev Contract module that helps prevent reentrant calls to a function. - * - * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier - * available, which can be applied to functions to make sure there are no nested - * (reentrant) calls to them. - * - * Note that because there is a single `nonReentrant` guard, functions marked as - * `nonReentrant` may not call one another. This can be worked around by making - * those functions `private`, and then adding `external` `nonReentrant` entry - * points to them. - * - * TIP: If you would like to learn more about reentrancy and alternative ways - * to protect against it, check out our blog post - * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. - */ -abstract contract ReentrancyGuard { - // Booleans are more expensive than uint256 or any type that takes up a full - // word because each write operation emits an extra SLOAD to first read the - // slot's contents, replace the bits taken up by the boolean, and then write - // back. This is the compiler's defense against contract upgrades and - // pointer aliasing, and it cannot be disabled. - - // The values being non-zero value makes deployment a bit more expensive, - // but in exchange the refund on every call to nonReentrant will be lower in - // amount. Since refunds are capped to a percentage of the total - // transaction's gas, it is best to keep them low in cases like this one, to - // increase the likelihood of the full refund coming into effect. - uint256 private constant _NOT_ENTERED = 1; - uint256 private constant _ENTERED = 2; - - uint256 private _status; - - constructor() { - _status = _NOT_ENTERED; - } - - /** - * @dev Prevents a contract from calling itself, directly or indirectly. - * Calling a `nonReentrant` function from another `nonReentrant` - * function is not supported. It is possible to prevent this from happening - * by making the `nonReentrant` function external, and make it call a - * `private` function that does the actual work. - */ - modifier nonReentrant() { - // On the first call to nonReentrant, _notEntered will be true - require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); - - // Any calls to nonReentrant after this point will fail - _status = _ENTERED; - - _; - - // By storing the original value once again, a refund is triggered (see - // https://eips.ethereum.org/EIPS/eip-2200) - _status = _NOT_ENTERED; - } -} diff --git a/contracts/src/v0.7/vendor/SafeMath96.sol b/contracts/src/v0.7/vendor/SafeMath96.sol deleted file mode 100644 index b51849950ba..00000000000 --- a/contracts/src/v0.7/vendor/SafeMath96.sol +++ /dev/null @@ -1,112 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.7.0; - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - * - * This library is a version of Open Zeppelin's SafeMath, modified to support - * unsigned 96 bit integers. - */ -library SafeMath96 { - /** - * @dev Returns the addition of two unsigned integers, reverting on - * overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint96 a, uint96 b) internal pure returns (uint96) { - uint96 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on - * overflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot overflow. - */ - function sub(uint96 a, uint96 b) internal pure returns (uint96) { - require(b <= a, "SafeMath: subtraction overflow"); - uint96 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on - * overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint96 a, uint96 b) internal pure returns (uint96) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 - if (a == 0) { - return 0; - } - - uint96 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. Reverts on - * division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint96 a, uint96 b) internal pure returns (uint96) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, "SafeMath: division by zero"); - uint96 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint96 a, uint96 b) internal pure returns (uint96) { - require(b != 0, "SafeMath: modulo by zero"); - return a % b; - } -} diff --git a/contracts/src/v0.7/vendor/SafeMathChainlink.sol b/contracts/src/v0.7/vendor/SafeMathChainlink.sol deleted file mode 100644 index 1a95b1a7fa5..00000000000 --- a/contracts/src/v0.7/vendor/SafeMathChainlink.sol +++ /dev/null @@ -1,108 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; - -/** - * @dev Wrappers over Solidity's arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it's recommended to use it always. - */ -library SafeMathChainlink { - /** - * @dev Returns the addition of two unsigned integers, reverting on - * overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on - * overflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - Subtraction cannot overflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - require(b <= a, "SafeMath: subtraction overflow"); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on - * overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. Reverts on - * division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, "SafeMath: division by zero"); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - require(b != 0, "SafeMath: modulo by zero"); - return a % b; - } -} diff --git a/contracts/src/v0.7/vendor/SignedSafeMath.sol b/contracts/src/v0.7/vendor/SignedSafeMath.sol deleted file mode 100644 index 61658cd803c..00000000000 --- a/contracts/src/v0.7/vendor/SignedSafeMath.sol +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.7.0; - -/** - * @title SignedSafeMath - * @dev Signed math operations with safety checks that revert on error. - */ -library SignedSafeMath { - int256 private constant _INT256_MIN = -2**255; - - /** - * @dev Returns the multiplication of two signed integers, reverting on - * overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - * - Multiplication cannot overflow. - */ - function mul(int256 a, int256 b) internal pure returns (int256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - require(!(a == -1 && b == _INT256_MIN), "SignedSafeMath: multiplication overflow"); - - int256 c = a * b; - require(c / a == b, "SignedSafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the integer division of two signed integers. Reverts on - * division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - * - The divisor cannot be zero. - */ - function div(int256 a, int256 b) internal pure returns (int256) { - require(b != 0, "SignedSafeMath: division by zero"); - require(!(b == -1 && a == _INT256_MIN), "SignedSafeMath: division overflow"); - - int256 c = a / b; - - return c; - } - - /** - * @dev Returns the subtraction of two signed integers, reverting on - * overflow. - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - * - Subtraction cannot overflow. - */ - function sub(int256 a, int256 b) internal pure returns (int256) { - int256 c = a - b; - require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow"); - - return c; - } - - /** - * @dev Returns the addition of two signed integers, reverting on - * overflow. - * - * Counterpart to Solidity's `+` operator. - * - * Requirements: - * - * - Addition cannot overflow. - */ - function add(int256 a, int256 b) internal pure returns (int256) { - int256 c = a + b; - require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow"); - - return c; - } -} diff --git a/contracts/src/v0.8/ChainSpecificUtil.sol b/contracts/src/v0.8/ChainSpecificUtil.sol index 172d8c526f2..e8e52c8e37a 100644 --- a/contracts/src/v0.8/ChainSpecificUtil.sol +++ b/contracts/src/v0.8/ChainSpecificUtil.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.4; +pragma solidity ^0.8.9; import {ArbSys} from "./vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; import {ArbGasInfo} from "./vendor/@arbitrum/nitro-contracts/src/precompiles/ArbGasInfo.sol"; -import {OVM_GasPriceOracle} from "./vendor/@eth-optimism/contracts/v0.8.6/contracts/L2/predeploys/OVM_GasPriceOracle.sol"; +import {OVM_GasPriceOracle} from "./vendor/@eth-optimism/contracts/v0.8.9/contracts/L2/predeploys/OVM_GasPriceOracle.sol"; /// @dev A library that abstracts out opcodes that behave differently across chains. /// @dev The methods below return values that are pertinent to the given chain. diff --git a/contracts/src/v0.8/ChainSpecificUtil_v0_8_6.sol b/contracts/src/v0.8/ChainSpecificUtil_v0_8_6.sol new file mode 100644 index 00000000000..f87c75fe4c6 --- /dev/null +++ b/contracts/src/v0.8/ChainSpecificUtil_v0_8_6.sol @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.6; + +import {ArbSys} from "./vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; +import {ArbGasInfo} from "./vendor/@arbitrum/nitro-contracts/src/precompiles/ArbGasInfo.sol"; +import {OVM_GasPriceOracle} from "./vendor/@eth-optimism/contracts/v0.8.6/contracts/L2/predeploys/OVM_GasPriceOracle.sol"; + +/// @dev A library that abstracts out opcodes that behave differently across chains. +/// @dev The methods below return values that are pertinent to the given chain. +/// @dev For instance, ChainSpecificUtil.getBlockNumber() returns L2 block number in L2 chains +library ChainSpecificUtil { + // ------------ Start Arbitrum Constants ------------ + + /// @dev ARBSYS_ADDR is the address of the ArbSys precompile on Arbitrum. + /// @dev reference: https://github.com/OffchainLabs/nitro/blob/v2.0.14/contracts/src/precompiles/ArbSys.sol#L10 + address private constant ARBSYS_ADDR = address(0x0000000000000000000000000000000000000064); + ArbSys private constant ARBSYS = ArbSys(ARBSYS_ADDR); + + /// @dev ARBGAS_ADDR is the address of the ArbGasInfo precompile on Arbitrum. + /// @dev reference: https://github.com/OffchainLabs/nitro/blob/v2.0.14/contracts/src/precompiles/ArbGasInfo.sol#L10 + address private constant ARBGAS_ADDR = address(0x000000000000000000000000000000000000006C); + ArbGasInfo private constant ARBGAS = ArbGasInfo(ARBGAS_ADDR); + + uint256 private constant ARB_MAINNET_CHAIN_ID = 42161; + uint256 private constant ARB_GOERLI_TESTNET_CHAIN_ID = 421613; + uint256 private constant ARB_SEPOLIA_TESTNET_CHAIN_ID = 421614; + + // ------------ End Arbitrum Constants ------------ + + // ------------ Start Optimism Constants ------------ + /// @dev L1_FEE_DATA_PADDING includes 35 bytes for L1 data padding for Optimism + bytes internal constant L1_FEE_DATA_PADDING = + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + /// @dev OVM_GASPRICEORACLE_ADDR is the address of the OVM_GasPriceOracle precompile on Optimism. + /// @dev reference: https://community.optimism.io/docs/developers/build/transaction-fees/#estimating-the-l1-data-fee + address private constant OVM_GASPRICEORACLE_ADDR = address(0x420000000000000000000000000000000000000F); + OVM_GasPriceOracle private constant OVM_GASPRICEORACLE = OVM_GasPriceOracle(OVM_GASPRICEORACLE_ADDR); + + uint256 private constant OP_MAINNET_CHAIN_ID = 10; + uint256 private constant OP_GOERLI_CHAIN_ID = 420; + uint256 private constant OP_SEPOLIA_CHAIN_ID = 11155420; + + /// @dev Base is a OP stack based rollup and follows the same L1 pricing logic as Optimism. + uint256 private constant BASE_MAINNET_CHAIN_ID = 8453; + uint256 private constant BASE_GOERLI_CHAIN_ID = 84531; + + // ------------ End Optimism Constants ------------ + + /** + * @notice Returns the blockhash for the given blockNumber. + * @notice If the blockNumber is more than 256 blocks in the past, returns the empty string. + * @notice When on a known Arbitrum chain, it uses ArbSys.arbBlockHash to get the blockhash. + * @notice Otherwise, it uses the blockhash opcode. + * @notice Note that the blockhash opcode will return the L2 blockhash on Optimism. + */ + function _getBlockhash(uint64 blockNumber) internal view returns (bytes32) { + uint256 chainid = block.chainid; + if (_isArbitrumChainId(chainid)) { + if ((_getBlockNumber() - blockNumber) > 256 || blockNumber >= _getBlockNumber()) { + return ""; + } + return ARBSYS.arbBlockHash(blockNumber); + } + return blockhash(blockNumber); + } + + /** + * @notice Returns the block number of the current block. + * @notice When on a known Arbitrum chain, it uses ArbSys.arbBlockNumber to get the block number. + * @notice Otherwise, it uses the block.number opcode. + * @notice Note that the block.number opcode will return the L2 block number on Optimism. + */ + function _getBlockNumber() internal view returns (uint256) { + uint256 chainid = block.chainid; + if (_isArbitrumChainId(chainid)) { + return ARBSYS.arbBlockNumber(); + } + return block.number; + } + + /** + * @notice Returns the L1 fees that will be paid for the current transaction, given any calldata + * @notice for the current transaction. + * @notice When on a known Arbitrum chain, it uses ArbGas.getCurrentTxL1GasFees to get the fees. + * @notice On Arbitrum, the provided calldata is not used to calculate the fees. + * @notice On Optimism, the provided calldata is passed to the OVM_GasPriceOracle predeploy + * @notice and getL1Fee is called to get the fees. + */ + function _getCurrentTxL1GasFees(bytes memory txCallData) internal view returns (uint256) { + uint256 chainid = block.chainid; + if (_isArbitrumChainId(chainid)) { + return ARBGAS.getCurrentTxL1GasFees(); + } else if (_isOptimismChainId(chainid)) { + return OVM_GASPRICEORACLE.getL1Fee(bytes.concat(txCallData, L1_FEE_DATA_PADDING)); + } + return 0; + } + + /** + * @notice Returns the gas cost in wei of calldataSizeBytes of calldata being posted + * @notice to L1. + */ + function _getL1CalldataGasCost(uint256 calldataSizeBytes) internal view returns (uint256) { + uint256 chainid = block.chainid; + if (_isArbitrumChainId(chainid)) { + (, uint256 l1PricePerByte, , , , ) = ARBGAS.getPricesInWei(); + // see https://developer.arbitrum.io/devs-how-tos/how-to-estimate-gas#where-do-we-get-all-this-information-from + // for the justification behind the 140 number. + return l1PricePerByte * (calldataSizeBytes + 140); + } else if (_isOptimismChainId(chainid)) { + return _calculateOptimismL1DataFee(calldataSizeBytes); + } + return 0; + } + + /** + * @notice Return true if and only if the provided chain ID is an Arbitrum chain ID. + */ + function _isArbitrumChainId(uint256 chainId) internal pure returns (bool) { + return + chainId == ARB_MAINNET_CHAIN_ID || + chainId == ARB_GOERLI_TESTNET_CHAIN_ID || + chainId == ARB_SEPOLIA_TESTNET_CHAIN_ID; + } + + /** + * @notice Return true if and only if the provided chain ID is an Optimism chain ID. + * @notice Note that optimism chain id's are also OP stack chain id's. + */ + function _isOptimismChainId(uint256 chainId) internal pure returns (bool) { + return + chainId == OP_MAINNET_CHAIN_ID || + chainId == OP_GOERLI_CHAIN_ID || + chainId == OP_SEPOLIA_CHAIN_ID || + chainId == BASE_MAINNET_CHAIN_ID || + chainId == BASE_GOERLI_CHAIN_ID; + } + + function _calculateOptimismL1DataFee(uint256 calldataSizeBytes) internal view returns (uint256) { + // from: https://community.optimism.io/docs/developers/build/transaction-fees/#the-l1-data-fee + // l1_data_fee = l1_gas_price * (tx_data_gas + fixed_overhead) * dynamic_overhead + // tx_data_gas = count_zero_bytes(tx_data) * 4 + count_non_zero_bytes(tx_data) * 16 + // note we conservatively assume all non-zero bytes. + uint256 l1BaseFeeWei = OVM_GASPRICEORACLE.l1BaseFee(); + uint256 numZeroBytes = 0; + uint256 numNonzeroBytes = calldataSizeBytes - numZeroBytes; + uint256 txDataGas = numZeroBytes * 4 + numNonzeroBytes * 16; + uint256 fixedOverhead = OVM_GASPRICEORACLE.overhead(); + + // The scalar is some value like 0.684, but is represented as + // that times 10 ^ number of scalar decimals. + // e.g scalar = 0.684 * 10^6 + // The divisor is used to divide that and have a net result of the true scalar. + uint256 scalar = OVM_GASPRICEORACLE.scalar(); + uint256 scalarDecimals = OVM_GASPRICEORACLE.decimals(); + uint256 divisor = 10 ** scalarDecimals; + + uint256 l1DataFee = (l1BaseFeeWei * (txDataGas + fixedOverhead) * scalar) / divisor; + return l1DataFee; + } +} diff --git a/contracts/src/v0.8/ChainlinkClient.sol b/contracts/src/v0.8/ChainlinkClient.sol index ef7f7943452..1d8640a27b2 100644 --- a/contracts/src/v0.8/ChainlinkClient.sol +++ b/contracts/src/v0.8/ChainlinkClient.sol @@ -14,7 +14,7 @@ import {ENSResolver as ENSResolver_Chainlink} from "./vendor/ENSResolver.sol"; * @notice Contract writers can inherit this contract in order to create requests for the * Chainlink network */ -// solhint-disable custom-errors +// solhint-disable gas-custom-errors abstract contract ChainlinkClient { using Chainlink for Chainlink.Request; diff --git a/contracts/src/v0.8/Flags.sol b/contracts/src/v0.8/Flags.sol index 7cd5a54b0fd..de14583bcb4 100644 --- a/contracts/src/v0.8/Flags.sol +++ b/contracts/src/v0.8/Flags.sol @@ -13,7 +13,7 @@ import {FlagsInterface} from "./interfaces/FlagsInterface.sol"; * to allow addresses to raise flags on themselves, so if you are subscribing to * FlagOn events you should filter for addresses you care about. */ -// solhint-disable custom-errors +// solhint-disable gas-custom-errors contract Flags is FlagsInterface, SimpleReadAccessController { AccessControllerInterface public raisingAccessController; diff --git a/contracts/src/v0.8/ValidatorProxy.sol b/contracts/src/v0.8/ValidatorProxy.sol index 4584bb02559..58e0e28a899 100644 --- a/contracts/src/v0.8/ValidatorProxy.sol +++ b/contracts/src/v0.8/ValidatorProxy.sol @@ -5,7 +5,7 @@ import {ConfirmedOwner} from "./shared/access/ConfirmedOwner.sol"; import {AggregatorValidatorInterface} from "./shared/interfaces/AggregatorValidatorInterface.sol"; import {TypeAndVersionInterface} from "./interfaces/TypeAndVersionInterface.sol"; -// solhint-disable custom-errors +// solhint-disable gas-custom-errors contract ValidatorProxy is AggregatorValidatorInterface, TypeAndVersionInterface, ConfirmedOwner { /// @notice Uses a single storage slot to store the current address struct AggregatorConfiguration { diff --git a/contracts/src/v0.8/automation/Chainable.sol b/contracts/src/v0.8/automation/Chainable.sol index 9ebc8c34025..469ea91aff0 100644 --- a/contracts/src/v0.8/automation/Chainable.sol +++ b/contracts/src/v0.8/automation/Chainable.sol @@ -30,9 +30,8 @@ contract Chainable { * @notice the fallback function routes the call to the next contract in the chain * @dev most of the implementation is copied directly from OZ's Proxy contract */ - // solhint-disable payable-fallback // solhint-disable-next-line no-complex-fallback - fallback() external { + fallback() external payable { // copy to memory for assembly access address next = i_FALLBACK_ADDRESS; // copied directly from OZ's Proxy contract diff --git a/contracts/src/v0.8/automation/HeartbeatRequester.sol b/contracts/src/v0.8/automation/HeartbeatRequester.sol index aa390738001..8ef7fa44422 100644 --- a/contracts/src/v0.8/automation/HeartbeatRequester.sol +++ b/contracts/src/v0.8/automation/HeartbeatRequester.sol @@ -33,7 +33,6 @@ contract HeartbeatRequester is TypeAndVersionInterface, ConfirmedOwner { * - HeartbeatRequester 1.0.0: The requester fetches the latest aggregator address from proxy, and request a new round * using the aggregator address. */ - // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override typeAndVersion = "HeartbeatRequester 1.0.0"; constructor() ConfirmedOwner(msg.sender) {} diff --git a/contracts/src/v0.8/automation/README.md b/contracts/src/v0.8/automation/README.md index 9714ccb921b..717e7411774 100644 --- a/contracts/src/v0.8/automation/README.md +++ b/contracts/src/v0.8/automation/README.md @@ -1,38 +1,41 @@ # Automation Contract Structure -The on-chain component of Chainlink automation is too large to fit into the [size requirements][size-limit-eip] of a single contract. It is also too large to fit into 2 contracts, a solution that works for most large projects. Therefore, we included this explanation of how the pieces fit together and various tradeoffs incurred. +The on-chain component of Chainlink automation is too large to fit into the [size requirements][size-limit-eip] of a single contract. Therefore, we include this explanation of how the pieces fit together and various tradeoffs incurred. ### Glossary -**Master Contract** - also known as the “storage” contract. This is the contract whose state we care about. It is the entry-point into the chain of delegatecalls. (We avoid the term "proxy" because it is commonly associated with upgradability, and this system _is not upgradable_ even though it relies on some of the same mechanics.) +**Root Contract** - also known as the “storage” contract. This is the contract whose state we care about. It is the on-chain entry-point into the system. The root contract uses `delegatecall` to execute code at various logic contracts. (We avoid the term "proxy" because it is commonly associated with upgradability, and this system _is not upgradable_ even though it relies on some of the same mechanics.) -**Logic Contract** - this a contract whose sole purpose is to hold code. We use the code at this address and execute it in the context of the master contract in order to increase our total capacity for on-chain code. +**Logic Contract** - this a contract whose sole purpose is to hold code. We use the code at this address and execute it in the context of the root contract in order to increase our total capacity for on-chain code. ### Overview -We chain multiple logic contracts together using [fallback functions][fallback] and [delegatecall][delegatecall]. If a function definition is not found on one contract, we fall back to the next, always executing the function in the scope of the master contract. The actual implementation of this is based off of [OZ's Proxy contract][oz-proxy]. +We chain multiple logic contracts together using [fallback functions][fallback] and [delegatecall][delegatecall]. If a function definition is not found on one contract, we fallback to the next, always executing the function in the scope of the root contract. The actual implementation of this is based off of [OZ's Proxy contract][oz-proxy]. ### Diagram ```mermaid graph LR - Master -- delegatecall --> la[Logic A] + Root -- delegatecall --> la[Logic A] la -- delegatecall --> lb[Logic B] - lb -. delegatecall .-> lx[Logic X] + lb -. delegatecall .-> lx[Logic Z] ``` ### Special Considerations -- functions on the master contract have the least gas overhead, therefore, our most price-sensitive functions live there -- functions on the master contract have first-class support from tools like etherscan and tenderly - functions that we (or users) call often to debug should live there -- etherscan supports executing logic contract functions that are once removed from the master - therefore we give secondary preference to the first logic contract for user and debugging functions -- functions on logic A through logic X (as of writing) have no support on etherscan and will essentially be "invisible" to everyone but advanced users - we will try to reserve this space for uncommon interactions that are mostly done progamatically +- functions on the root contract have the least gas overhead. Therefore, our most price-sensitive functions live there. We have 3 functions that we consider hot paths. Ideally, these would all live on the root contract to minimize gas overhead. + - `transmit()` - this is the most important code path + - `registerUpkeep()` + - `addFunds()` +- functions on the root contract have first-class support from tools like etherscan and tenderly - functions that we (or users) call often to debug should live there +- etherscan supports executing logic contract functions that are once removed from the root - therefore we give secondary preference to the first logic contract for user and debugging functions +- functions on logic B through logic Z (as of writing) have no support on etherscan and will essentially be "invisible" to everyone but advanced users - we will try to reserve this space for uncommon interactions that are mostly done progamatically - We use Logic A, B, C... to avoid confusion with the version ex `AutomationRegistryLogicA2_1.sol` --> Logic Contract A verion 2.1 - Storage locations for logic contract addresses MUST BE BYTECODE (this is done by marking them as "immutable") otherwise the chaining mechanism will break ### Master Interface -The Master Interface is a deduped combination of all the interfaces from all contracts in the chain. We generate this interface programatically using the script `generate-automation-master-interface.ts`. This process is not a hardened one. Users of this script should take great care to ensure it's efficacy. +The Master Interface is a deduped combination of all the interfaces from all contracts in the chain. We generate this interface programatically using the script `generate-automation-master-interface.ts`. [size-limit-eip]: https://eips.ethereum.org/EIPS/eip-170 [fallback]: https://docs.soliditylang.org/en/v0.8.12/contracts.html#fallback-function diff --git a/contracts/src/v0.8/automation/UpkeepTranscoder.sol b/contracts/src/v0.8/automation/UpkeepTranscoder.sol index 144a96c7e77..03f40d890b8 100644 --- a/contracts/src/v0.8/automation/UpkeepTranscoder.sol +++ b/contracts/src/v0.8/automation/UpkeepTranscoder.sol @@ -17,7 +17,6 @@ contract UpkeepTranscoder is UpkeepTranscoderInterface, TypeAndVersionInterface * @notice versions: * - UpkeepTranscoder 1.0.0: placeholder to allow new formats in the future */ - // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override typeAndVersion = "UpkeepTranscoder 1.0.0"; /** diff --git a/contracts/src/v0.8/automation/dev/MercuryRegistry.sol b/contracts/src/v0.8/automation/dev/MercuryRegistry.sol index e6b6920f5db..247301a7438 100644 --- a/contracts/src/v0.8/automation/dev/MercuryRegistry.sol +++ b/contracts/src/v0.8/automation/dev/MercuryRegistry.sol @@ -1,4 +1,4 @@ -pragma solidity 0.8.6; +pragma solidity 0.8.19; import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; import {AutomationCompatibleInterface} from "../interfaces/AutomationCompatibleInterface.sol"; diff --git a/contracts/src/v0.8/automation/dev/MercuryRegistryBatchUpkeep.sol b/contracts/src/v0.8/automation/dev/MercuryRegistryBatchUpkeep.sol index 518275f34e7..2d3daeae19d 100644 --- a/contracts/src/v0.8/automation/dev/MercuryRegistryBatchUpkeep.sol +++ b/contracts/src/v0.8/automation/dev/MercuryRegistryBatchUpkeep.sol @@ -1,4 +1,4 @@ -pragma solidity 0.8.6; +pragma solidity 0.8.19; import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; import {AutomationCompatibleInterface} from "../interfaces/AutomationCompatibleInterface.sol"; diff --git a/contracts/src/v0.8/automation/dev/interfaces/v2_3/IAutomationRegistryMaster2_3.sol b/contracts/src/v0.8/automation/dev/interfaces/v2_3/IAutomationRegistryMaster2_3.sol index c4d3bb48b26..8570c2130f2 100644 --- a/contracts/src/v0.8/automation/dev/interfaces/v2_3/IAutomationRegistryMaster2_3.sol +++ b/contracts/src/v0.8/automation/dev/interfaces/v2_3/IAutomationRegistryMaster2_3.sol @@ -1,4 +1,4 @@ -// abi-checksum: 0x5f06e4e00f3041d11b2f2109257ecaf84cb540cbd4f7246c30d5dca752b51e53 +// abi-checksum: 0x0dcdf05637762c60acb4616a251bdc40d85ba134ec4b1b1e9f66646ba3132055 // SPDX-License-Identifier: MIT // !! THIS FILE WAS AUTOGENERATED BY abi-to-sol v0.6.6. SEE SOURCE BELOW. !! pragma solidity ^0.8.4; @@ -17,18 +17,20 @@ interface IAutomationRegistryMaster2_3 { error IncorrectNumberOfSigners(); error IndexOutOfRange(); error InsufficientBalance(uint256 available, uint256 requested); + error InsufficientLinkLiquidity(); error InvalidDataLength(); error InvalidFeed(); error InvalidPayee(); error InvalidRecipient(); error InvalidReport(); error InvalidSigner(); + error InvalidToken(); error InvalidTransmitter(); error InvalidTrigger(); error InvalidTriggerType(); - error MaxCheckDataSizeCanOnlyIncrease(); - error MaxPerformDataSizeCanOnlyIncrease(); error MigrationNotPermitted(); + error MustSettleOffchain(); + error MustSettleOnchain(); error NotAContract(); error OnlyActiveSigners(); error OnlyActiveTransmitters(); @@ -45,7 +47,6 @@ interface IAutomationRegistryMaster2_3 { error OnlySimulatedBackend(); error OnlyUnpausedUpkeep(); error ParameterLengthError(); - error PaymentGreaterThanAllLINK(); error ReentrantCall(); error RegistryPaused(); error RepeatedSigner(); @@ -61,6 +62,8 @@ interface IAutomationRegistryMaster2_3 { error ValueNotChanged(); error ZeroAddressNotAllowed(); event AdminPrivilegeConfigSet(address indexed admin, bytes privilegeConfig); + event BillingConfigOverridden(uint256 indexed id, AutomationRegistryBase2_3.BillingOverrides overrides); + event BillingConfigOverrideRemoved(uint256 indexed id); event BillingConfigSet(address indexed token, AutomationRegistryBase2_3.BillingConfig config); event CancelledUpkeepReport(uint256 indexed id, bytes trigger); event ChainSpecificModuleUpdated(address newModule); @@ -76,10 +79,11 @@ interface IAutomationRegistryMaster2_3 { bytes offchainConfig ); event DedupKeyAdded(bytes32 indexed dedupKey); - event FeesWithdrawn(address indexed recipient, address indexed assetAddress, uint256 amount); + event FeesWithdrawn(address indexed assetAddress, address indexed recipient, uint256 amount); event FundsAdded(uint256 indexed id, address indexed from, uint96 amount); event FundsWithdrawn(uint256 indexed id, uint256 amount, address to); event InsufficientFundsUpkeepReport(uint256 indexed id, bytes trigger); + event NOPsSettledOffchain(address[] payees, uint256[] payments); event OwnershipTransferRequested(address indexed from, address indexed to); event OwnershipTransferred(address indexed from, address indexed to); event Paused(address account); @@ -112,8 +116,9 @@ interface IAutomationRegistryMaster2_3 { event UpkeepRegistered(uint256 indexed id, uint32 performGas, address admin); event UpkeepTriggerConfigSet(uint256 indexed id, bytes triggerConfig); event UpkeepUnpaused(uint256 indexed id); - fallback() external; + fallback() external payable; function acceptOwnership() external; + function addFunds(uint256 id, uint96 amount) external payable; function fallbackTo() external view returns (address); function latestConfigDetails() external view returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest); function latestConfigDigestAndEpoch() external view returns (bool scanLogs, bytes32 configDigest, uint32 epoch); @@ -137,10 +142,6 @@ interface IAutomationRegistryMaster2_3 { address[] memory billingTokens, AutomationRegistryBase2_3.BillingConfig[] memory billingConfigs ) external; - function simulatePerformUpkeep( - uint256 id, - bytes memory performData - ) external view returns (bool success, uint256 gasUsed); function transferOwnership(address to) external; function transmit( bytes32[3] memory reportContext, @@ -151,8 +152,21 @@ interface IAutomationRegistryMaster2_3 { ) external; function typeAndVersion() external view returns (string memory); - function addFunds(uint256 id, uint96 amount) external; function cancelUpkeep(uint256 id) external; + function migrateUpkeeps(uint256[] memory ids, address destination) external; + function receiveUpkeeps(bytes memory encodedUpkeeps) external; + function registerUpkeep( + address target, + uint32 gasLimit, + address admin, + uint8 triggerType, + address billingToken, + bytes memory checkData, + bytes memory triggerConfig, + bytes memory offchainConfig + ) external returns (uint256 id); + + function acceptUpkeepAdmin(uint256 id) external; function checkCallback( uint256 id, bytes[] memory values, @@ -191,125 +205,159 @@ interface IAutomationRegistryMaster2_3 { uint256 id, bytes memory payload ) external returns (bool upkeepNeeded, bytes memory performData, uint8 upkeepFailureReason, uint256 gasUsed); - function migrateUpkeeps(uint256[] memory ids, address destination) external; - function receiveUpkeeps(bytes memory encodedUpkeeps) external; - function registerUpkeep( - address target, - uint32 gasLimit, - address admin, - uint8 triggerType, - bytes memory checkData, - bytes memory triggerConfig, - bytes memory offchainConfig - ) external returns (uint256 id); - function registerUpkeep( - address target, - uint32 gasLimit, - address admin, - bytes memory checkData, - bytes memory offchainConfig - ) external returns (uint256 id); + function pauseUpkeep(uint256 id) external; + function removeBillingOverrides(uint256 id) external; + function setBillingOverrides(uint256 id, AutomationRegistryBase2_3.BillingOverrides memory billingOverrides) external; + function setUpkeepCheckData(uint256 id, bytes memory newCheckData) external; + function setUpkeepGasLimit(uint256 id, uint32 gasLimit) external; + function setUpkeepOffchainConfig(uint256 id, bytes memory config) external; function setUpkeepTriggerConfig(uint256 id, bytes memory triggerConfig) external; + function simulatePerformUpkeep( + uint256 id, + bytes memory performData + ) external view returns (bool success, uint256 gasUsed); + function transferUpkeepAdmin(uint256 id, address proposed) external; + function unpauseUpkeep(uint256 id) external; + function withdrawERC20Fees(address asset, address to, uint256 amount) external; + function withdrawFunds(uint256 id, address to) external; + function withdrawLink(address to, uint256 amount) external; function acceptPayeeship(address transmitter) external; - function acceptUpkeepAdmin(uint256 id) external; + function disableOffchainPayments() external; function getActiveUpkeepIDs(uint256 startIndex, uint256 maxCount) external view returns (uint256[] memory); function getAdminPrivilegeConfig(address admin) external view returns (bytes memory); function getAllowedReadOnlyAddress() external view returns (address); function getAutomationForwarderLogic() external view returns (address); function getBalance(uint256 id) external view returns (uint96 balance); + function getBillingToken(uint256 upkeepID) external view returns (address); function getBillingTokenConfig(address token) external view returns (AutomationRegistryBase2_3.BillingConfig memory); function getBillingTokens() external view returns (address[] memory); function getCancellationDelay() external pure returns (uint256); function getChainModule() external view returns (address chainModule); function getConditionalGasOverhead() external pure returns (uint256); + function getConfig() external view returns (AutomationRegistryBase2_3.OnchainConfig memory); function getFallbackNativePrice() external view returns (uint256); function getFastGasFeedAddress() external view returns (address); function getForwarder(uint256 upkeepID) external view returns (address); + function getHotVars() external view returns (AutomationRegistryBase2_3.HotVars memory); function getLinkAddress() external view returns (address); function getLinkUSDFeedAddress() external view returns (address); function getLogGasOverhead() external pure returns (uint256); - function getMaxPaymentForGas(uint8 triggerType, uint32 gasLimit) external view returns (uint96 maxPayment); + function getMaxPaymentForGas( + uint256 id, + uint8 triggerType, + uint32 gasLimit, + address billingToken + ) external view returns (uint96 maxPayment); function getMinBalance(uint256 id) external view returns (uint96); function getMinBalanceForUpkeep(uint256 id) external view returns (uint96 minBalance); function getNativeUSDFeedAddress() external view returns (address); + function getNumUpkeeps() external view returns (uint256); + function getPayoutMode() external view returns (uint8); function getPeerRegistryMigrationPermission(address peer) external view returns (uint8); function getPerPerformByteGasOverhead() external pure returns (uint256); function getPerSignerGasOverhead() external pure returns (uint256); function getReorgProtectionEnabled() external view returns (bool reorgProtectionEnabled); + function getReserveAmount(address billingToken) external view returns (uint256); function getSignerInfo(address query) external view returns (bool active, uint8 index); function getState() external view returns ( - AutomationRegistryBase2_3.State memory state, - AutomationRegistryBase2_3.OnchainConfigLegacy memory config, + IAutomationV21PlusCommon.StateLegacy memory state, + IAutomationV21PlusCommon.OnchainConfigLegacy memory config, address[] memory signers, address[] memory transmitters, uint8 f ); + function getStorage() external view returns (AutomationRegistryBase2_3.Storage memory); function getTransmitCalldataFixedBytesOverhead() external pure returns (uint256); function getTransmitCalldataPerSignerBytesOverhead() external pure returns (uint256); function getTransmitterInfo( address query ) external view returns (bool active, uint8 index, uint96 balance, uint96 lastCollected, address payee); function getTriggerType(uint256 upkeepId) external pure returns (uint8); - function getUpkeep(uint256 id) external view returns (AutomationRegistryBase2_3.UpkeepInfo memory upkeepInfo); + function getUpkeep(uint256 id) external view returns (IAutomationV21PlusCommon.UpkeepInfoLegacy memory upkeepInfo); function getUpkeepPrivilegeConfig(uint256 upkeepId) external view returns (bytes memory); function getUpkeepTriggerConfig(uint256 upkeepId) external view returns (bytes memory); + function getWrappedNativeTokenAddress() external view returns (address); function hasDedupKey(bytes32 dedupKey) external view returns (bool); - function linkAvailableForPayment() external view returns (uint256); + function linkAvailableForPayment() external view returns (int256); function pause() external; - function pauseUpkeep(uint256 id) external; function setAdminPrivilegeConfig(address admin, bytes memory newPrivilegeConfig) external; function setPayees(address[] memory payees) external; function setPeerRegistryMigrationPermission(address peer, uint8 permission) external; - function setUpkeepCheckData(uint256 id, bytes memory newCheckData) external; - function setUpkeepGasLimit(uint256 id, uint32 gasLimit) external; - function setUpkeepOffchainConfig(uint256 id, bytes memory config) external; function setUpkeepPrivilegeConfig(uint256 upkeepId, bytes memory newPrivilegeConfig) external; + function settleNOPsOffchain() external; + function supportsBillingToken(address token) external view returns (bool); function transferPayeeship(address transmitter, address proposed) external; - function transferUpkeepAdmin(uint256 id, address proposed) external; function unpause() external; - function unpauseUpkeep(uint256 id) external; - function upkeepTranscoderVersion() external pure returns (uint8); function upkeepVersion() external pure returns (uint8); - function withdrawERC20Fees(address assetAddress, address to, uint256 amount) external; - function withdrawFunds(uint256 id, address to) external; - function withdrawLinkFees(address to, uint256 amount) external; function withdrawPayment(address from, address to) external; } interface AutomationRegistryBase2_3 { + struct BillingOverrides { + uint32 gasFeePPB; + uint24 flatFeeMilliCents; + } + struct BillingConfig { uint32 gasFeePPB; - uint24 flatFeeMicroLink; + uint24 flatFeeMilliCents; address priceFeed; + uint256 fallbackPrice; + uint96 minSpend; } struct OnchainConfig { - uint32 paymentPremiumPPB; - uint32 flatFeeMicroLink; uint32 checkGasLimit; - uint24 stalenessSeconds; - uint16 gasCeilingMultiplier; - uint96 minUpkeepSpend; uint32 maxPerformGas; uint32 maxCheckDataSize; + address transcoder; + bool reorgProtectionEnabled; + uint24 stalenessSeconds; uint32 maxPerformDataSize; uint32 maxRevertDataSize; + address upkeepPrivilegeManager; + uint16 gasCeilingMultiplier; + address financeAdmin; uint256 fallbackGasPrice; uint256 fallbackLinkPrice; uint256 fallbackNativePrice; - address transcoder; address[] registrars; - address upkeepPrivilegeManager; address chainModule; + } + + struct HotVars { + uint96 totalPremium; + uint32 latestEpoch; + uint24 stalenessSeconds; + uint16 gasCeilingMultiplier; + uint8 f; + bool paused; + bool reentrancyGuard; bool reorgProtectionEnabled; + address chainModule; + } + + struct Storage { + address transcoder; + uint32 checkGasLimit; + uint32 maxPerformGas; + uint32 nonce; + address upkeepPrivilegeManager; + uint32 configCount; + uint32 latestConfigBlockNumber; + uint32 maxCheckDataSize; address financeAdmin; + uint32 maxPerformDataSize; + uint32 maxRevertDataSize; } +} - struct State { +interface IAutomationV21PlusCommon { + struct StateLegacy { uint32 nonce; uint96 ownerLinkBalance; uint256 expectedLinkBalance; @@ -340,7 +388,7 @@ interface AutomationRegistryBase2_3 { address upkeepPrivilegeManager; } - struct UpkeepInfo { + struct UpkeepInfoLegacy { address target; uint32 performGas; bytes checkData; @@ -356,5 +404,5 @@ interface AutomationRegistryBase2_3 { // THIS FILE WAS AUTOGENERATED FROM THE FOLLOWING ABI JSON: /* -[{"inputs":[{"internalType":"contract AutomationRegistryLogicB2_3","name":"logicA","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ArrayHasNoEntries","type":"error"},{"inputs":[],"name":"CannotCancel","type":"error"},{"inputs":[],"name":"CheckDataExceedsLimit","type":"error"},{"inputs":[],"name":"ConfigDigestMismatch","type":"error"},{"inputs":[],"name":"DuplicateEntry","type":"error"},{"inputs":[],"name":"DuplicateSigners","type":"error"},{"inputs":[],"name":"GasLimitCanOnlyIncrease","type":"error"},{"inputs":[],"name":"GasLimitOutsideRange","type":"error"},{"inputs":[],"name":"IncorrectNumberOfFaultyOracles","type":"error"},{"inputs":[],"name":"IncorrectNumberOfSignatures","type":"error"},{"inputs":[],"name":"IncorrectNumberOfSigners","type":"error"},{"inputs":[],"name":"IndexOutOfRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"available","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidDataLength","type":"error"},{"inputs":[],"name":"InvalidFeed","type":"error"},{"inputs":[],"name":"InvalidPayee","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidReport","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"InvalidTransmitter","type":"error"},{"inputs":[],"name":"InvalidTrigger","type":"error"},{"inputs":[],"name":"InvalidTriggerType","type":"error"},{"inputs":[],"name":"MaxCheckDataSizeCanOnlyIncrease","type":"error"},{"inputs":[],"name":"MaxPerformDataSizeCanOnlyIncrease","type":"error"},{"inputs":[],"name":"MigrationNotPermitted","type":"error"},{"inputs":[],"name":"NotAContract","type":"error"},{"inputs":[],"name":"OnlyActiveSigners","type":"error"},{"inputs":[],"name":"OnlyActiveTransmitters","type":"error"},{"inputs":[],"name":"OnlyCallableByAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByLINKToken","type":"error"},{"inputs":[],"name":"OnlyCallableByOwnerOrAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByOwnerOrRegistrar","type":"error"},{"inputs":[],"name":"OnlyCallableByPayee","type":"error"},{"inputs":[],"name":"OnlyCallableByProposedAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByProposedPayee","type":"error"},{"inputs":[],"name":"OnlyCallableByUpkeepPrivilegeManager","type":"error"},{"inputs":[],"name":"OnlyFinanceAdmin","type":"error"},{"inputs":[],"name":"OnlyPausedUpkeep","type":"error"},{"inputs":[],"name":"OnlySimulatedBackend","type":"error"},{"inputs":[],"name":"OnlyUnpausedUpkeep","type":"error"},{"inputs":[],"name":"ParameterLengthError","type":"error"},{"inputs":[],"name":"PaymentGreaterThanAllLINK","type":"error"},{"inputs":[],"name":"ReentrantCall","type":"error"},{"inputs":[],"name":"RegistryPaused","type":"error"},{"inputs":[],"name":"RepeatedSigner","type":"error"},{"inputs":[],"name":"RepeatedTransmitter","type":"error"},{"inputs":[{"internalType":"bytes","name":"reason","type":"bytes"}],"name":"TargetCheckReverted","type":"error"},{"inputs":[],"name":"TooManyOracles","type":"error"},{"inputs":[],"name":"TranscoderNotSet","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"UpkeepAlreadyExists","type":"error"},{"inputs":[],"name":"UpkeepCancelled","type":"error"},{"inputs":[],"name":"UpkeepNotCanceled","type":"error"},{"inputs":[],"name":"UpkeepNotNeeded","type":"error"},{"inputs":[],"name":"ValueNotChanged","type":"error"},{"inputs":[],"name":"ZeroAddressNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"bytes","name":"privilegeConfig","type":"bytes"}],"name":"AdminPrivilegeConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IERC20","name":"token","type":"address"},{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMicroLink","type":"uint24"},{"internalType":"address","name":"priceFeed","type":"address"}],"indexed":false,"internalType":"struct AutomationRegistryBase2_3.BillingConfig","name":"config","type":"tuple"}],"name":"BillingConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"CancelledUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newModule","type":"address"}],"name":"ChainSpecificModuleUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"previousConfigBlockNumber","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"configCount","type":"uint64"},{"indexed":false,"internalType":"address[]","name":"signers","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"transmitters","type":"address[]"},{"indexed":false,"internalType":"uint8","name":"f","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"onchainConfig","type":"bytes"},{"indexed":false,"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"indexed":false,"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"ConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"dedupKey","type":"bytes32"}],"name":"DedupKeyAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"address","name":"assetAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint96","name":"amount","type":"uint96"}],"name":"FundsAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"FundsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"InsufficientFundsUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"transmitters","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"payees","type":"address[]"}],"name":"PayeesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"PayeeshipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"PayeeshipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"payee","type":"address"}],"name":"PaymentWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"ReorgedUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"StaleUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"epoch","type":"uint32"}],"name":"Transmitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"UpkeepAdminTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"UpkeepAdminTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"uint64","name":"atBlockHeight","type":"uint64"}],"name":"UpkeepCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"newCheckData","type":"bytes"}],"name":"UpkeepCheckDataSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint96","name":"gasLimit","type":"uint96"}],"name":"UpkeepGasLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"remainingBalance","type":"uint256"},{"indexed":false,"internalType":"address","name":"destination","type":"address"}],"name":"UpkeepMigrated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"UpkeepOffchainConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"UpkeepPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"uint96","name":"totalPayment","type":"uint96"},{"indexed":false,"internalType":"uint256","name":"gasUsed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasOverhead","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"UpkeepPerformed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"privilegeConfig","type":"bytes"}],"name":"UpkeepPrivilegeConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startingBalance","type":"uint256"},{"indexed":false,"internalType":"address","name":"importedFrom","type":"address"}],"name":"UpkeepReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"performGas","type":"uint32"},{"indexed":false,"internalType":"address","name":"admin","type":"address"}],"name":"UpkeepRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"triggerConfig","type":"bytes"}],"name":"UpkeepTriggerConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"UpkeepUnpaused","type":"event"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fallbackTo","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestConfigDetails","outputs":[{"internalType":"uint32","name":"configCount","type":"uint32"},{"internalType":"uint32","name":"blockNumber","type":"uint32"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestConfigDigestAndEpoch","outputs":[{"internalType":"bool","name":"scanLogs","type":"bool"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"internalType":"uint32","name":"epoch","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onTokenTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"},{"internalType":"bytes","name":"onchainConfigBytes","type":"bytes"},{"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"},{"components":[{"internalType":"uint32","name":"paymentPremiumPPB","type":"uint32"},{"internalType":"uint32","name":"flatFeeMicroLink","type":"uint32"},{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"uint96","name":"minUpkeepSpend","type":"uint96"},{"internalType":"uint32","name":"maxPerformGas","type":"uint32"},{"internalType":"uint32","name":"maxCheckDataSize","type":"uint32"},{"internalType":"uint32","name":"maxPerformDataSize","type":"uint32"},{"internalType":"uint32","name":"maxRevertDataSize","type":"uint32"},{"internalType":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackNativePrice","type":"uint256"},{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"address[]","name":"registrars","type":"address[]"},{"internalType":"address","name":"upkeepPrivilegeManager","type":"address"},{"internalType":"contract IChainModule","name":"chainModule","type":"address"},{"internalType":"bool","name":"reorgProtectionEnabled","type":"bool"},{"internalType":"address","name":"financeAdmin","type":"address"}],"internalType":"struct AutomationRegistryBase2_3.OnchainConfig","name":"onchainConfig","type":"tuple"},{"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"},{"internalType":"contract IERC20[]","name":"billingTokens","type":"address[]"},{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMicroLink","type":"uint24"},{"internalType":"address","name":"priceFeed","type":"address"}],"internalType":"struct AutomationRegistryBase2_3.BillingConfig[]","name":"billingConfigs","type":"tuple[]"}],"name":"setConfigTypeSafe","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"performData","type":"bytes"}],"name":"simulatePerformUpkeep","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[3]","name":"reportContext","type":"bytes32[3]"},{"internalType":"bytes","name":"rawReport","type":"bytes"},{"internalType":"bytes32[]","name":"rs","type":"bytes32[]"},{"internalType":"bytes32[]","name":"ss","type":"bytes32[]"},{"internalType":"bytes32","name":"rawVs","type":"bytes32"}],"name":"transmit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"typeAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract AutomationRegistryLogicB2_3","name":"logicB","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint96","name":"amount","type":"uint96"}],"name":"addFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"cancelUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes[]","name":"values","type":"bytes[]"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"checkCallback","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum AutomationRegistryBase2_3.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"triggerData","type":"bytes"}],"name":"checkUpkeep","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum AutomationRegistryBase2_3.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"fastGasWei","type":"uint256"},{"internalType":"uint256","name":"linkUSD","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"checkUpkeep","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum AutomationRegistryBase2_3.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"fastGasWei","type":"uint256"},{"internalType":"uint256","name":"linkUSD","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"executeCallback","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum AutomationRegistryBase2_3.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"address","name":"destination","type":"address"}],"name":"migrateUpkeeps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedUpkeeps","type":"bytes"}],"name":"receiveUpkeeps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint32","name":"gasLimit","type":"uint32"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"enum AutomationRegistryBase2_3.Trigger","name":"triggerType","type":"uint8"},{"internalType":"bytes","name":"checkData","type":"bytes"},{"internalType":"bytes","name":"triggerConfig","type":"bytes"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"registerUpkeep","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint32","name":"gasLimit","type":"uint32"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"bytes","name":"checkData","type":"bytes"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"registerUpkeep","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"triggerConfig","type":"bytes"}],"name":"setUpkeepTriggerConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"link","type":"address"},{"internalType":"address","name":"linkUSDFeed","type":"address"},{"internalType":"address","name":"nativeUSDFeed","type":"address"},{"internalType":"address","name":"fastGasFeed","type":"address"},{"internalType":"address","name":"automationForwarderLogic","type":"address"},{"internalType":"address","name":"allowedReadOnlyAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"transmitter","type":"address"}],"name":"acceptPayeeship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"acceptUpkeepAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"maxCount","type":"uint256"}],"name":"getActiveUpkeepIDs","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"getAdminPrivilegeConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllowedReadOnlyAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAutomationForwarderLogic","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getBalance","outputs":[{"internalType":"uint96","name":"balance","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"getBillingTokenConfig","outputs":[{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMicroLink","type":"uint24"},{"internalType":"address","name":"priceFeed","type":"address"}],"internalType":"struct AutomationRegistryBase2_3.BillingConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBillingTokens","outputs":[{"internalType":"contract IERC20[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCancellationDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getChainModule","outputs":[{"internalType":"contract IChainModule","name":"chainModule","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getConditionalGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getFallbackNativePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFastGasFeedAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepID","type":"uint256"}],"name":"getForwarder","outputs":[{"internalType":"contract IAutomationForwarder","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLinkAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLinkUSDFeedAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLogGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"enum AutomationRegistryBase2_3.Trigger","name":"triggerType","type":"uint8"},{"internalType":"uint32","name":"gasLimit","type":"uint32"}],"name":"getMaxPaymentForGas","outputs":[{"internalType":"uint96","name":"maxPayment","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getMinBalance","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getMinBalanceForUpkeep","outputs":[{"internalType":"uint96","name":"minBalance","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNativeUSDFeedAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"peer","type":"address"}],"name":"getPeerRegistryMigrationPermission","outputs":[{"internalType":"enum AutomationRegistryBase2_3.MigrationPermission","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPerPerformByteGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getPerSignerGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getReorgProtectionEnabled","outputs":[{"internalType":"bool","name":"reorgProtectionEnabled","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"query","type":"address"}],"name":"getSignerInfo","outputs":[{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint8","name":"index","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getState","outputs":[{"components":[{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"uint96","name":"ownerLinkBalance","type":"uint96"},{"internalType":"uint256","name":"expectedLinkBalance","type":"uint256"},{"internalType":"uint96","name":"totalPremium","type":"uint96"},{"internalType":"uint256","name":"numUpkeeps","type":"uint256"},{"internalType":"uint32","name":"configCount","type":"uint32"},{"internalType":"uint32","name":"latestConfigBlockNumber","type":"uint32"},{"internalType":"bytes32","name":"latestConfigDigest","type":"bytes32"},{"internalType":"uint32","name":"latestEpoch","type":"uint32"},{"internalType":"bool","name":"paused","type":"bool"}],"internalType":"struct AutomationRegistryBase2_3.State","name":"state","type":"tuple"},{"components":[{"internalType":"uint32","name":"paymentPremiumPPB","type":"uint32"},{"internalType":"uint32","name":"flatFeeMicroLink","type":"uint32"},{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"uint96","name":"minUpkeepSpend","type":"uint96"},{"internalType":"uint32","name":"maxPerformGas","type":"uint32"},{"internalType":"uint32","name":"maxCheckDataSize","type":"uint32"},{"internalType":"uint32","name":"maxPerformDataSize","type":"uint32"},{"internalType":"uint32","name":"maxRevertDataSize","type":"uint32"},{"internalType":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"},{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"address[]","name":"registrars","type":"address[]"},{"internalType":"address","name":"upkeepPrivilegeManager","type":"address"}],"internalType":"struct AutomationRegistryBase2_3.OnchainConfigLegacy","name":"config","type":"tuple"},{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransmitCalldataFixedBytesOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getTransmitCalldataPerSignerBytesOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"query","type":"address"}],"name":"getTransmitterInfo","outputs":[{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint8","name":"index","type":"uint8"},{"internalType":"uint96","name":"balance","type":"uint96"},{"internalType":"uint96","name":"lastCollected","type":"uint96"},{"internalType":"address","name":"payee","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"}],"name":"getTriggerType","outputs":[{"internalType":"enum AutomationRegistryBase2_3.Trigger","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getUpkeep","outputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint32","name":"performGas","type":"uint32"},{"internalType":"bytes","name":"checkData","type":"bytes"},{"internalType":"uint96","name":"balance","type":"uint96"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"uint64","name":"maxValidBlocknumber","type":"uint64"},{"internalType":"uint32","name":"lastPerformedBlockNumber","type":"uint32"},{"internalType":"uint96","name":"amountSpent","type":"uint96"},{"internalType":"bool","name":"paused","type":"bool"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"internalType":"struct AutomationRegistryBase2_3.UpkeepInfo","name":"upkeepInfo","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"}],"name":"getUpkeepPrivilegeConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"}],"name":"getUpkeepTriggerConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dedupKey","type":"bytes32"}],"name":"hasDedupKey","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"linkAvailableForPayment","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"pauseUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"bytes","name":"newPrivilegeConfig","type":"bytes"}],"name":"setAdminPrivilegeConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"payees","type":"address[]"}],"name":"setPayees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"peer","type":"address"},{"internalType":"enum AutomationRegistryBase2_3.MigrationPermission","name":"permission","type":"uint8"}],"name":"setPeerRegistryMigrationPermission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"newCheckData","type":"bytes"}],"name":"setUpkeepCheckData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint32","name":"gasLimit","type":"uint32"}],"name":"setUpkeepGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"config","type":"bytes"}],"name":"setUpkeepOffchainConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"},{"internalType":"bytes","name":"newPrivilegeConfig","type":"bytes"}],"name":"setUpkeepPrivilegeConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"transmitter","type":"address"},{"internalType":"address","name":"proposed","type":"address"}],"name":"transferPayeeship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"proposed","type":"address"}],"name":"transferUpkeepAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"unpauseUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"upkeepTranscoderVersion","outputs":[{"internalType":"enum UpkeepFormat","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"upkeepVersion","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"assetAddress","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawERC20Fees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawLinkFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawPayment","outputs":[],"stateMutability":"nonpayable","type":"function"}] +[{"inputs":[{"internalType":"contract AutomationRegistryLogicA2_3","name":"logicA","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ArrayHasNoEntries","type":"error"},{"inputs":[],"name":"CannotCancel","type":"error"},{"inputs":[],"name":"CheckDataExceedsLimit","type":"error"},{"inputs":[],"name":"ConfigDigestMismatch","type":"error"},{"inputs":[],"name":"DuplicateEntry","type":"error"},{"inputs":[],"name":"DuplicateSigners","type":"error"},{"inputs":[],"name":"GasLimitCanOnlyIncrease","type":"error"},{"inputs":[],"name":"GasLimitOutsideRange","type":"error"},{"inputs":[],"name":"IncorrectNumberOfFaultyOracles","type":"error"},{"inputs":[],"name":"IncorrectNumberOfSignatures","type":"error"},{"inputs":[],"name":"IncorrectNumberOfSigners","type":"error"},{"inputs":[],"name":"IndexOutOfRange","type":"error"},{"inputs":[{"internalType":"uint256","name":"available","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InsufficientLinkLiquidity","type":"error"},{"inputs":[],"name":"InvalidDataLength","type":"error"},{"inputs":[],"name":"InvalidFeed","type":"error"},{"inputs":[],"name":"InvalidPayee","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidReport","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"InvalidToken","type":"error"},{"inputs":[],"name":"InvalidTransmitter","type":"error"},{"inputs":[],"name":"InvalidTrigger","type":"error"},{"inputs":[],"name":"InvalidTriggerType","type":"error"},{"inputs":[],"name":"MigrationNotPermitted","type":"error"},{"inputs":[],"name":"MustSettleOffchain","type":"error"},{"inputs":[],"name":"MustSettleOnchain","type":"error"},{"inputs":[],"name":"NotAContract","type":"error"},{"inputs":[],"name":"OnlyActiveSigners","type":"error"},{"inputs":[],"name":"OnlyActiveTransmitters","type":"error"},{"inputs":[],"name":"OnlyCallableByAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByLINKToken","type":"error"},{"inputs":[],"name":"OnlyCallableByOwnerOrAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByOwnerOrRegistrar","type":"error"},{"inputs":[],"name":"OnlyCallableByPayee","type":"error"},{"inputs":[],"name":"OnlyCallableByProposedAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByProposedPayee","type":"error"},{"inputs":[],"name":"OnlyCallableByUpkeepPrivilegeManager","type":"error"},{"inputs":[],"name":"OnlyFinanceAdmin","type":"error"},{"inputs":[],"name":"OnlyPausedUpkeep","type":"error"},{"inputs":[],"name":"OnlySimulatedBackend","type":"error"},{"inputs":[],"name":"OnlyUnpausedUpkeep","type":"error"},{"inputs":[],"name":"ParameterLengthError","type":"error"},{"inputs":[],"name":"ReentrantCall","type":"error"},{"inputs":[],"name":"RegistryPaused","type":"error"},{"inputs":[],"name":"RepeatedSigner","type":"error"},{"inputs":[],"name":"RepeatedTransmitter","type":"error"},{"inputs":[{"internalType":"bytes","name":"reason","type":"bytes"}],"name":"TargetCheckReverted","type":"error"},{"inputs":[],"name":"TooManyOracles","type":"error"},{"inputs":[],"name":"TranscoderNotSet","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"UpkeepAlreadyExists","type":"error"},{"inputs":[],"name":"UpkeepCancelled","type":"error"},{"inputs":[],"name":"UpkeepNotCanceled","type":"error"},{"inputs":[],"name":"UpkeepNotNeeded","type":"error"},{"inputs":[],"name":"ValueNotChanged","type":"error"},{"inputs":[],"name":"ZeroAddressNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"bytes","name":"privilegeConfig","type":"bytes"}],"name":"AdminPrivilegeConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"}],"indexed":false,"internalType":"struct AutomationRegistryBase2_3.BillingOverrides","name":"overrides","type":"tuple"}],"name":"BillingConfigOverridden","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"BillingConfigOverrideRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IERC20","name":"token","type":"address"},{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"},{"internalType":"contract AggregatorV3Interface","name":"priceFeed","type":"address"},{"internalType":"uint256","name":"fallbackPrice","type":"uint256"},{"internalType":"uint96","name":"minSpend","type":"uint96"}],"indexed":false,"internalType":"struct AutomationRegistryBase2_3.BillingConfig","name":"config","type":"tuple"}],"name":"BillingConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"CancelledUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newModule","type":"address"}],"name":"ChainSpecificModuleUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"previousConfigBlockNumber","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"configCount","type":"uint64"},{"indexed":false,"internalType":"address[]","name":"signers","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"transmitters","type":"address[]"},{"indexed":false,"internalType":"uint8","name":"f","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"onchainConfig","type":"bytes"},{"indexed":false,"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"indexed":false,"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"ConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"dedupKey","type":"bytes32"}],"name":"DedupKeyAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"assetAddress","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint96","name":"amount","type":"uint96"}],"name":"FundsAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"FundsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"InsufficientFundsUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"payees","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"payments","type":"uint256[]"}],"name":"NOPsSettledOffchain","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"transmitters","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"payees","type":"address[]"}],"name":"PayeesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"PayeeshipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"PayeeshipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"payee","type":"address"}],"name":"PaymentWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"ReorgedUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"StaleUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"epoch","type":"uint32"}],"name":"Transmitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"UpkeepAdminTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"UpkeepAdminTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"uint64","name":"atBlockHeight","type":"uint64"}],"name":"UpkeepCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"newCheckData","type":"bytes"}],"name":"UpkeepCheckDataSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint96","name":"gasLimit","type":"uint96"}],"name":"UpkeepGasLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"remainingBalance","type":"uint256"},{"indexed":false,"internalType":"address","name":"destination","type":"address"}],"name":"UpkeepMigrated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"UpkeepOffchainConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"UpkeepPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"uint96","name":"totalPayment","type":"uint96"},{"indexed":false,"internalType":"uint256","name":"gasUsed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasOverhead","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"UpkeepPerformed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"privilegeConfig","type":"bytes"}],"name":"UpkeepPrivilegeConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startingBalance","type":"uint256"},{"indexed":false,"internalType":"address","name":"importedFrom","type":"address"}],"name":"UpkeepReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"performGas","type":"uint32"},{"indexed":false,"internalType":"address","name":"admin","type":"address"}],"name":"UpkeepRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"triggerConfig","type":"bytes"}],"name":"UpkeepTriggerConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"UpkeepUnpaused","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint96","name":"amount","type":"uint96"}],"name":"addFunds","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"fallbackTo","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestConfigDetails","outputs":[{"internalType":"uint32","name":"configCount","type":"uint32"},{"internalType":"uint32","name":"blockNumber","type":"uint32"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestConfigDigestAndEpoch","outputs":[{"internalType":"bool","name":"scanLogs","type":"bool"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"internalType":"uint32","name":"epoch","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onTokenTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"},{"internalType":"bytes","name":"onchainConfigBytes","type":"bytes"},{"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"},{"components":[{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint32","name":"maxPerformGas","type":"uint32"},{"internalType":"uint32","name":"maxCheckDataSize","type":"uint32"},{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"bool","name":"reorgProtectionEnabled","type":"bool"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint32","name":"maxPerformDataSize","type":"uint32"},{"internalType":"uint32","name":"maxRevertDataSize","type":"uint32"},{"internalType":"address","name":"upkeepPrivilegeManager","type":"address"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"address","name":"financeAdmin","type":"address"},{"internalType":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackNativePrice","type":"uint256"},{"internalType":"address[]","name":"registrars","type":"address[]"},{"internalType":"contract IChainModule","name":"chainModule","type":"address"}],"internalType":"struct AutomationRegistryBase2_3.OnchainConfig","name":"onchainConfig","type":"tuple"},{"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"},{"internalType":"contract IERC20[]","name":"billingTokens","type":"address[]"},{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"},{"internalType":"contract AggregatorV3Interface","name":"priceFeed","type":"address"},{"internalType":"uint256","name":"fallbackPrice","type":"uint256"},{"internalType":"uint96","name":"minSpend","type":"uint96"}],"internalType":"struct AutomationRegistryBase2_3.BillingConfig[]","name":"billingConfigs","type":"tuple[]"}],"name":"setConfigTypeSafe","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[3]","name":"reportContext","type":"bytes32[3]"},{"internalType":"bytes","name":"rawReport","type":"bytes"},{"internalType":"bytes32[]","name":"rs","type":"bytes32[]"},{"internalType":"bytes32[]","name":"ss","type":"bytes32[]"},{"internalType":"bytes32","name":"rawVs","type":"bytes32"}],"name":"transmit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"typeAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract AutomationRegistryLogicB2_3","name":"logicB","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"cancelUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"address","name":"destination","type":"address"}],"name":"migrateUpkeeps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedUpkeeps","type":"bytes"}],"name":"receiveUpkeeps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint32","name":"gasLimit","type":"uint32"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"enum AutomationRegistryBase2_3.Trigger","name":"triggerType","type":"uint8"},{"internalType":"contract IERC20","name":"billingToken","type":"address"},{"internalType":"bytes","name":"checkData","type":"bytes"},{"internalType":"bytes","name":"triggerConfig","type":"bytes"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"registerUpkeep","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract AutomationRegistryLogicC2_3","name":"logicC","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"acceptUpkeepAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes[]","name":"values","type":"bytes[]"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"checkCallback","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum AutomationRegistryBase2_3.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"triggerData","type":"bytes"}],"name":"checkUpkeep","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum AutomationRegistryBase2_3.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"fastGasWei","type":"uint256"},{"internalType":"uint256","name":"linkUSD","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"checkUpkeep","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum AutomationRegistryBase2_3.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"fastGasWei","type":"uint256"},{"internalType":"uint256","name":"linkUSD","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"executeCallback","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum AutomationRegistryBase2_3.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"pauseUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"removeBillingOverrides","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"}],"internalType":"struct AutomationRegistryBase2_3.BillingOverrides","name":"billingOverrides","type":"tuple"}],"name":"setBillingOverrides","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"newCheckData","type":"bytes"}],"name":"setUpkeepCheckData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint32","name":"gasLimit","type":"uint32"}],"name":"setUpkeepGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"config","type":"bytes"}],"name":"setUpkeepOffchainConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"triggerConfig","type":"bytes"}],"name":"setUpkeepTriggerConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"performData","type":"bytes"}],"name":"simulatePerformUpkeep","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"proposed","type":"address"}],"name":"transferUpkeepAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"unpauseUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"asset","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawERC20Fees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawLink","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"link","type":"address"},{"internalType":"address","name":"linkUSDFeed","type":"address"},{"internalType":"address","name":"nativeUSDFeed","type":"address"},{"internalType":"address","name":"fastGasFeed","type":"address"},{"internalType":"address","name":"automationForwarderLogic","type":"address"},{"internalType":"address","name":"allowedReadOnlyAddress","type":"address"},{"internalType":"enum AutomationRegistryBase2_3.PayoutMode","name":"payoutMode","type":"uint8"},{"internalType":"address","name":"wrappedNativeTokenAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"transmitter","type":"address"}],"name":"acceptPayeeship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"disableOffchainPayments","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"maxCount","type":"uint256"}],"name":"getActiveUpkeepIDs","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"getAdminPrivilegeConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllowedReadOnlyAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAutomationForwarderLogic","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getBalance","outputs":[{"internalType":"uint96","name":"balance","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepID","type":"uint256"}],"name":"getBillingToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"getBillingTokenConfig","outputs":[{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"},{"internalType":"contract AggregatorV3Interface","name":"priceFeed","type":"address"},{"internalType":"uint256","name":"fallbackPrice","type":"uint256"},{"internalType":"uint96","name":"minSpend","type":"uint96"}],"internalType":"struct AutomationRegistryBase2_3.BillingConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBillingTokens","outputs":[{"internalType":"contract IERC20[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCancellationDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getChainModule","outputs":[{"internalType":"contract IChainModule","name":"chainModule","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getConditionalGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getConfig","outputs":[{"components":[{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint32","name":"maxPerformGas","type":"uint32"},{"internalType":"uint32","name":"maxCheckDataSize","type":"uint32"},{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"bool","name":"reorgProtectionEnabled","type":"bool"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint32","name":"maxPerformDataSize","type":"uint32"},{"internalType":"uint32","name":"maxRevertDataSize","type":"uint32"},{"internalType":"address","name":"upkeepPrivilegeManager","type":"address"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"address","name":"financeAdmin","type":"address"},{"internalType":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackNativePrice","type":"uint256"},{"internalType":"address[]","name":"registrars","type":"address[]"},{"internalType":"contract IChainModule","name":"chainModule","type":"address"}],"internalType":"struct AutomationRegistryBase2_3.OnchainConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFallbackNativePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFastGasFeedAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepID","type":"uint256"}],"name":"getForwarder","outputs":[{"internalType":"contract IAutomationForwarder","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getHotVars","outputs":[{"components":[{"internalType":"uint96","name":"totalPremium","type":"uint96"},{"internalType":"uint32","name":"latestEpoch","type":"uint32"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"uint8","name":"f","type":"uint8"},{"internalType":"bool","name":"paused","type":"bool"},{"internalType":"bool","name":"reentrancyGuard","type":"bool"},{"internalType":"bool","name":"reorgProtectionEnabled","type":"bool"},{"internalType":"contract IChainModule","name":"chainModule","type":"address"}],"internalType":"struct AutomationRegistryBase2_3.HotVars","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLinkAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLinkUSDFeedAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLogGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"enum AutomationRegistryBase2_3.Trigger","name":"triggerType","type":"uint8"},{"internalType":"uint32","name":"gasLimit","type":"uint32"},{"internalType":"contract IERC20","name":"billingToken","type":"address"}],"name":"getMaxPaymentForGas","outputs":[{"internalType":"uint96","name":"maxPayment","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getMinBalance","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getMinBalanceForUpkeep","outputs":[{"internalType":"uint96","name":"minBalance","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNativeUSDFeedAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNumUpkeeps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPayoutMode","outputs":[{"internalType":"enum AutomationRegistryBase2_3.PayoutMode","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"peer","type":"address"}],"name":"getPeerRegistryMigrationPermission","outputs":[{"internalType":"enum AutomationRegistryBase2_3.MigrationPermission","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPerPerformByteGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getPerSignerGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getReorgProtectionEnabled","outputs":[{"internalType":"bool","name":"reorgProtectionEnabled","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"billingToken","type":"address"}],"name":"getReserveAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"query","type":"address"}],"name":"getSignerInfo","outputs":[{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint8","name":"index","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getState","outputs":[{"components":[{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"uint96","name":"ownerLinkBalance","type":"uint96"},{"internalType":"uint256","name":"expectedLinkBalance","type":"uint256"},{"internalType":"uint96","name":"totalPremium","type":"uint96"},{"internalType":"uint256","name":"numUpkeeps","type":"uint256"},{"internalType":"uint32","name":"configCount","type":"uint32"},{"internalType":"uint32","name":"latestConfigBlockNumber","type":"uint32"},{"internalType":"bytes32","name":"latestConfigDigest","type":"bytes32"},{"internalType":"uint32","name":"latestEpoch","type":"uint32"},{"internalType":"bool","name":"paused","type":"bool"}],"internalType":"struct IAutomationV21PlusCommon.StateLegacy","name":"state","type":"tuple"},{"components":[{"internalType":"uint32","name":"paymentPremiumPPB","type":"uint32"},{"internalType":"uint32","name":"flatFeeMicroLink","type":"uint32"},{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"uint96","name":"minUpkeepSpend","type":"uint96"},{"internalType":"uint32","name":"maxPerformGas","type":"uint32"},{"internalType":"uint32","name":"maxCheckDataSize","type":"uint32"},{"internalType":"uint32","name":"maxPerformDataSize","type":"uint32"},{"internalType":"uint32","name":"maxRevertDataSize","type":"uint32"},{"internalType":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"},{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"address[]","name":"registrars","type":"address[]"},{"internalType":"address","name":"upkeepPrivilegeManager","type":"address"}],"internalType":"struct IAutomationV21PlusCommon.OnchainConfigLegacy","name":"config","type":"tuple"},{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStorage","outputs":[{"components":[{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint32","name":"maxPerformGas","type":"uint32"},{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"address","name":"upkeepPrivilegeManager","type":"address"},{"internalType":"uint32","name":"configCount","type":"uint32"},{"internalType":"uint32","name":"latestConfigBlockNumber","type":"uint32"},{"internalType":"uint32","name":"maxCheckDataSize","type":"uint32"},{"internalType":"address","name":"financeAdmin","type":"address"},{"internalType":"uint32","name":"maxPerformDataSize","type":"uint32"},{"internalType":"uint32","name":"maxRevertDataSize","type":"uint32"}],"internalType":"struct AutomationRegistryBase2_3.Storage","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransmitCalldataFixedBytesOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getTransmitCalldataPerSignerBytesOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"query","type":"address"}],"name":"getTransmitterInfo","outputs":[{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint8","name":"index","type":"uint8"},{"internalType":"uint96","name":"balance","type":"uint96"},{"internalType":"uint96","name":"lastCollected","type":"uint96"},{"internalType":"address","name":"payee","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"}],"name":"getTriggerType","outputs":[{"internalType":"enum AutomationRegistryBase2_3.Trigger","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getUpkeep","outputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint32","name":"performGas","type":"uint32"},{"internalType":"bytes","name":"checkData","type":"bytes"},{"internalType":"uint96","name":"balance","type":"uint96"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"uint64","name":"maxValidBlocknumber","type":"uint64"},{"internalType":"uint32","name":"lastPerformedBlockNumber","type":"uint32"},{"internalType":"uint96","name":"amountSpent","type":"uint96"},{"internalType":"bool","name":"paused","type":"bool"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"internalType":"struct IAutomationV21PlusCommon.UpkeepInfoLegacy","name":"upkeepInfo","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"}],"name":"getUpkeepPrivilegeConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"}],"name":"getUpkeepTriggerConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWrappedNativeTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dedupKey","type":"bytes32"}],"name":"hasDedupKey","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"linkAvailableForPayment","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"bytes","name":"newPrivilegeConfig","type":"bytes"}],"name":"setAdminPrivilegeConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"payees","type":"address[]"}],"name":"setPayees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"peer","type":"address"},{"internalType":"enum AutomationRegistryBase2_3.MigrationPermission","name":"permission","type":"uint8"}],"name":"setPeerRegistryMigrationPermission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"},{"internalType":"bytes","name":"newPrivilegeConfig","type":"bytes"}],"name":"setUpkeepPrivilegeConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"settleNOPsOffchain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"supportsBillingToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"transmitter","type":"address"},{"internalType":"address","name":"proposed","type":"address"}],"name":"transferPayeeship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"upkeepVersion","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawPayment","outputs":[],"stateMutability":"nonpayable","type":"function"}] */ diff --git a/contracts/src/v0.8/automation/dev/interfaces/v2_3/IWrappedNative.sol b/contracts/src/v0.8/automation/dev/interfaces/v2_3/IWrappedNative.sol new file mode 100644 index 00000000000..5b03b2efeb1 --- /dev/null +++ b/contracts/src/v0.8/automation/dev/interfaces/v2_3/IWrappedNative.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IERC20} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; + +interface IWrappedNative is IERC20 { + function deposit() external payable; + + function withdraw(uint256 wad) external; +} diff --git a/contracts/src/v0.8/automation/dev/test/AutomationRegistrar2_3.t.sol b/contracts/src/v0.8/automation/dev/test/AutomationRegistrar2_3.t.sol new file mode 100644 index 00000000000..850d2955a25 --- /dev/null +++ b/contracts/src/v0.8/automation/dev/test/AutomationRegistrar2_3.t.sol @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.19; + +import {BaseTest} from "./BaseTest.t.sol"; +import {IAutomationRegistryMaster2_3} from "../interfaces/v2_3/IAutomationRegistryMaster2_3.sol"; +import {AutomationRegistrar2_3} from "../v2_3/AutomationRegistrar2_3.sol"; +import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {AutomationRegistryBase2_3 as AutoBase} from "../v2_3/AutomationRegistryBase2_3.sol"; +import {IWrappedNative} from "../interfaces/v2_3/IWrappedNative.sol"; + +// forge test --match-path src/v0.8/automation/dev/test/AutomationRegistrar2_3.t.sol + +contract SetUp is BaseTest { + IAutomationRegistryMaster2_3 internal registry; + AutomationRegistrar2_3 internal registrar; + + function setUp() public override { + super.setUp(); + (registry, registrar) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.ON_CHAIN); + vm.stopPrank(); // reset identity at the start of each test + } +} + +contract RegisterUpkeep is SetUp { + function testLink_autoApproveOff_happy() external { + vm.startPrank(UPKEEP_ADMIN); + + uint96 amount = uint96(registrar.getMinimumRegistrationAmount(IERC20(address(linkToken)))); + linkToken.approve(address(registrar), amount); + + registrar.registerUpkeep( + AutomationRegistrar2_3.RegistrationParams({ + upkeepContract: address(TARGET1), + amount: amount, + adminAddress: UPKEEP_ADMIN, + gasLimit: 10_000, + triggerType: 0, + billingToken: IERC20(address(linkToken)), + name: "foobar", + encryptedEmail: "", + checkData: bytes("check data"), + triggerConfig: "", + offchainConfig: "" + }) + ); + + assertEq(linkToken.balanceOf(address(registrar)), amount); + assertEq(registry.getNumUpkeeps(), 0); + } + + function testUSDToken_autoApproveOff_happy() external { + vm.startPrank(UPKEEP_ADMIN); + + uint96 amount = uint96(registrar.getMinimumRegistrationAmount(usdToken)); + usdToken.approve(address(registrar), amount); + + registrar.registerUpkeep( + AutomationRegistrar2_3.RegistrationParams({ + upkeepContract: address(TARGET1), + amount: amount, + adminAddress: UPKEEP_ADMIN, + gasLimit: 10_000, + triggerType: 0, + billingToken: usdToken, + name: "foobar", + encryptedEmail: "", + checkData: bytes("check data"), + triggerConfig: "", + offchainConfig: "" + }) + ); + + assertEq(usdToken.balanceOf(address(registrar)), amount); + assertEq(registry.getNumUpkeeps(), 0); + } + + function testLink_autoApproveOn_happy() external { + registrar.setTriggerConfig(0, AutomationRegistrar2_3.AutoApproveType.ENABLED_ALL, 1000); + + vm.startPrank(UPKEEP_ADMIN); + uint96 amount = uint96(registrar.getMinimumRegistrationAmount(IERC20(address(linkToken)))); + linkToken.approve(address(registrar), amount); + + registrar.registerUpkeep( + AutomationRegistrar2_3.RegistrationParams({ + upkeepContract: address(TARGET1), + amount: amount, + adminAddress: UPKEEP_ADMIN, + gasLimit: 10_000, + triggerType: 0, + billingToken: IERC20(address(linkToken)), + name: "foobar", + encryptedEmail: "", + checkData: bytes("check data"), + triggerConfig: "", + offchainConfig: "" + }) + ); + + assertEq(linkToken.balanceOf(address(registrar)), 0); + assertEq(linkToken.balanceOf(address(registry)), amount); + assertEq(registry.getNumUpkeeps(), 1); + } + + function testUSDToken_autoApproveOn_happy() external { + registrar.setTriggerConfig(0, AutomationRegistrar2_3.AutoApproveType.ENABLED_ALL, 1000); + + vm.startPrank(UPKEEP_ADMIN); + uint96 amount = uint96(registrar.getMinimumRegistrationAmount(usdToken)); + usdToken.approve(address(registrar), amount); + + registrar.registerUpkeep( + AutomationRegistrar2_3.RegistrationParams({ + upkeepContract: address(TARGET1), + amount: amount, + adminAddress: UPKEEP_ADMIN, + gasLimit: 10_000, + triggerType: 0, + billingToken: usdToken, + name: "foobar", + encryptedEmail: "", + checkData: bytes("check data"), + triggerConfig: "", + offchainConfig: "" + }) + ); + + assertEq(usdToken.balanceOf(address(registrar)), 0); + assertEq(usdToken.balanceOf(address(registry)), amount); + assertEq(registry.getNumUpkeeps(), 1); + } + + function testNative_autoApproveOn_happy() external { + registrar.setTriggerConfig(0, AutomationRegistrar2_3.AutoApproveType.ENABLED_ALL, 1000); + + vm.startPrank(UPKEEP_ADMIN); + uint96 amount = uint96(registrar.getMinimumRegistrationAmount(IERC20(address(weth)))); + IWrappedNative(address(weth)).approve(address(registrar), amount); + + registrar.registerUpkeep{value: amount}( + AutomationRegistrar2_3.RegistrationParams({ + upkeepContract: address(TARGET1), + amount: 0, + adminAddress: UPKEEP_ADMIN, + gasLimit: 10_000, + triggerType: 0, + billingToken: IERC20(address(weth)), + name: "foobar", + encryptedEmail: "", + checkData: bytes("check data"), + triggerConfig: "", + offchainConfig: "" + }) + ); + + assertEq(weth.balanceOf(address(registrar)), 0); + assertEq(weth.balanceOf(address(registry)), amount); + assertEq(registry.getNumUpkeeps(), 1); + } + + // when msg.value is 0, it uses the ERC20 payment path + function testNative_autoApproveOff_msgValue0() external { + vm.startPrank(UPKEEP_ADMIN); + + uint96 amount = uint96(registrar.getMinimumRegistrationAmount(IERC20(address(weth)))); + IWrappedNative(address(weth)).approve(address(registrar), amount); + + registrar.registerUpkeep( + AutomationRegistrar2_3.RegistrationParams({ + upkeepContract: address(TARGET1), + amount: amount, + adminAddress: UPKEEP_ADMIN, + gasLimit: 10_000, + triggerType: 0, + billingToken: IERC20(address(weth)), + name: "foobar", + encryptedEmail: "", + checkData: bytes("check data"), + triggerConfig: "", + offchainConfig: "" + }) + ); + + assertEq(weth.balanceOf(address(registrar)), amount); + assertEq(registry.getNumUpkeeps(), 0); + } + + // when msg.value is not 0, it uses the native payment path + function testNative_autoApproveOff_msgValueNot0() external { + vm.startPrank(UPKEEP_ADMIN); + + uint96 amount = uint96(registrar.getMinimumRegistrationAmount(IERC20(address(weth)))); + IWrappedNative(address(weth)).approve(address(registrar), amount); + + registrar.registerUpkeep{value: amount}( + AutomationRegistrar2_3.RegistrationParams({ + upkeepContract: address(TARGET1), + amount: 0, + adminAddress: UPKEEP_ADMIN, + gasLimit: 10_000, + triggerType: 0, + billingToken: IERC20(address(weth)), + name: "foobar", + encryptedEmail: "", + checkData: bytes("check data"), + triggerConfig: "", + offchainConfig: "" + }) + ); + + assertEq(weth.balanceOf(address(registrar)), amount); + assertEq(registry.getNumUpkeeps(), 0); + } +} diff --git a/contracts/src/v0.8/automation/dev/test/AutomationRegistry2_3.t.sol b/contracts/src/v0.8/automation/dev/test/AutomationRegistry2_3.t.sol index 24a4dada36f..1f8fa42f36f 100644 --- a/contracts/src/v0.8/automation/dev/test/AutomationRegistry2_3.t.sol +++ b/contracts/src/v0.8/automation/dev/test/AutomationRegistry2_3.t.sol @@ -1,241 +1,298 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; -import {AutomationForwarderLogic} from "../../AutomationForwarderLogic.sol"; +import {Vm} from "forge-std/Test.sol"; import {BaseTest} from "./BaseTest.t.sol"; -import {AutomationRegistry2_3} from "../v2_3/AutomationRegistry2_3.sol"; -import {AutomationRegistryLogicA2_3} from "../v2_3/AutomationRegistryLogicA2_3.sol"; -import {AutomationRegistryLogicB2_3} from "../v2_3/AutomationRegistryLogicB2_3.sol"; -import {IAutomationRegistryMaster2_3, AutomationRegistryBase2_3} from "../interfaces/v2_3/IAutomationRegistryMaster2_3.sol"; +import {AutomationRegistryBase2_3 as AutoBase} from "../v2_3/AutomationRegistryBase2_3.sol"; +import {AutomationRegistrar2_3 as Registrar} from "../v2_3/AutomationRegistrar2_3.sol"; +import {IAutomationRegistryMaster2_3 as Registry, AutomationRegistryBase2_3} from "../interfaces/v2_3/IAutomationRegistryMaster2_3.sol"; import {ChainModuleBase} from "../../chains/ChainModuleBase.sol"; -import {MockV3Aggregator} from "../../../tests/MockV3Aggregator.sol"; -import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol"; - -contract AutomationRegistry2_3_SetUp is BaseTest { - address internal LINK_USD_FEED; - address internal NATIVE_USD_FEED; - address internal FAST_GAS_FEED; - address internal constant FINANCE_ADMIN_ADDRESS = 0x1111111111111111111111111111111111111114; - address internal constant ZERO_ADDRESS = address(0); - address internal constant UPKEEP_ADMIN = address(uint160(uint256(keccak256("ADMIN")))); - - // Signer private keys used for these test - uint256 internal constant PRIVATE0 = 0x7b2e97fe057e6de99d6872a2ef2abf52c9b4469bc848c2465ac3fcd8d336e81d; - uint256 internal constant PRIVATE1 = 0xab56160806b05ef1796789248e1d7f34a6465c5280899159d645218cd216cee6; - uint256 internal constant PRIVATE2 = 0x6ec7caa8406a49b76736602810e0a2871959fbbb675e23a8590839e4717f1f7f; - uint256 internal constant PRIVATE3 = 0x80f14b11da94ae7f29d9a7713ea13dc838e31960a5c0f2baf45ed458947b730a; - - uint64 internal constant OFFCHAIN_CONFIG_VERSION = 30; // 2 for OCR2 - uint8 internal constant F = 1; - - address[] internal s_valid_signers; - address[] internal s_valid_transmitters; - address[] internal s_registrars; - - IAutomationRegistryMaster2_3 internal registryMaster; - ERC20Mock internal link; // the link token - ERC20Mock internal mockERC20; // the supported ERC20 tokens except link +import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {IWrappedNative} from "../interfaces/v2_3/IWrappedNative.sol"; - function setUp() public override { - LINK_USD_FEED = address(new MockV3Aggregator(8, 2_000_000_000)); // $20 - NATIVE_USD_FEED = address(new MockV3Aggregator(8, 400_000_000_000)); // $4,000 - FAST_GAS_FEED = address(new MockV3Aggregator(0, 1_000_000_000)); // 1 gwei - - link = new ERC20Mock("LINK", "LINK", UPKEEP_ADMIN, 0); - mockERC20 = new ERC20Mock("MOCK_ERC20", "MOCK_ERC20", UPKEEP_ADMIN, 0); +// forge test --match-path src/v0.8/automation/dev/test/AutomationRegistry2_3.t.sol - s_valid_transmitters = new address[](4); - for (uint160 i = 0; i < 4; ++i) { - s_valid_transmitters[i] = address(4 + i); - } +enum Trigger { + CONDITION, + LOG +} - s_valid_signers = new address[](4); - s_valid_signers[0] = vm.addr(PRIVATE0); //0xc110458BE52CaA6bB68E66969C3218A4D9Db0211 - s_valid_signers[1] = vm.addr(PRIVATE1); //0xc110a19c08f1da7F5FfB281dc93630923F8E3719 - s_valid_signers[2] = vm.addr(PRIVATE2); //0xc110fdF6e8fD679C7Cc11602d1cd829211A18e9b - s_valid_signers[3] = vm.addr(PRIVATE3); //0xc11028017c9b445B6bF8aE7da951B5cC28B326C0 +contract SetUp is BaseTest { + Registry internal registry; + AutomationRegistryBase2_3.OnchainConfig internal config; + bytes internal constant offchainConfigBytes = abi.encode(1234, ZERO_ADDRESS); + + uint256 linkUpkeepID; + uint256 usdUpkeepID; + uint256 nativeUpkeepID; + + function setUp() public virtual override { + super.setUp(); + + (registry, ) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.ON_CHAIN); + config = registry.getConfig(); + + vm.startPrank(OWNER); + linkToken.approve(address(registry), type(uint256).max); + usdToken.approve(address(registry), type(uint256).max); + weth.approve(address(registry), type(uint256).max); + vm.startPrank(UPKEEP_ADMIN); + linkToken.approve(address(registry), type(uint256).max); + usdToken.approve(address(registry), type(uint256).max); + weth.approve(address(registry), type(uint256).max); + vm.startPrank(STRANGER); + linkToken.approve(address(registry), type(uint256).max); + usdToken.approve(address(registry), type(uint256).max); + weth.approve(address(registry), type(uint256).max); + vm.stopPrank(); - s_registrars = new address[](1); - s_registrars[0] = 0x3a0eDE26aa188BFE00b9A0C9A431A1a0CA5f7966; + linkUpkeepID = registry.registerUpkeep( + address(TARGET1), + config.maxPerformGas, + UPKEEP_ADMIN, + uint8(Trigger.CONDITION), + address(linkToken), + "", + "", + "" + ); - AutomationForwarderLogic forwarderLogic = new AutomationForwarderLogic(); - AutomationRegistryLogicB2_3 logicB2_3 = new AutomationRegistryLogicB2_3( - address(link), - LINK_USD_FEED, - NATIVE_USD_FEED, - FAST_GAS_FEED, - address(forwarderLogic), - ZERO_ADDRESS + usdUpkeepID = registry.registerUpkeep( + address(TARGET1), + config.maxPerformGas, + UPKEEP_ADMIN, + uint8(Trigger.CONDITION), + address(usdToken), + "", + "", + "" ); - AutomationRegistryLogicA2_3 logicA2_3 = new AutomationRegistryLogicA2_3(logicB2_3); - registryMaster = IAutomationRegistryMaster2_3( - address(new AutomationRegistry2_3(AutomationRegistryLogicB2_3(address(logicA2_3)))) + + nativeUpkeepID = registry.registerUpkeep( + address(TARGET1), + config.maxPerformGas, + UPKEEP_ADMIN, + uint8(Trigger.CONDITION), + address(weth), + "", + "", + "" ); + + vm.startPrank(OWNER); + registry.addFunds(linkUpkeepID, registry.getMinBalanceForUpkeep(linkUpkeepID)); + registry.addFunds(usdUpkeepID, registry.getMinBalanceForUpkeep(usdUpkeepID)); + registry.addFunds(nativeUpkeepID, registry.getMinBalanceForUpkeep(nativeUpkeepID)); + vm.stopPrank(); } } -contract AutomationRegistry2_3_LatestConfigDetails is AutomationRegistry2_3_SetUp { +contract LatestConfigDetails is SetUp { function testGet() public { - (uint32 configCount, uint32 blockNumber, bytes32 configDigest) = registryMaster.latestConfigDetails(); - assertEq(configCount, 0); - assertEq(blockNumber, 0); - assertEq(configDigest, ""); + (uint32 configCount, uint32 blockNumber, bytes32 configDigest) = registry.latestConfigDetails(); + assertEq(configCount, 1); + assertTrue(blockNumber > 0); + assertNotEq(configDigest, ""); } } -contract AutomationRegistry2_3_CheckUpkeep is AutomationRegistry2_3_SetUp { +contract CheckUpkeep is SetUp { function testPreventExecutionOnCheckUpkeep() public { uint256 id = 1; bytes memory triggerData = abi.encodePacked("trigger_data"); // The tx.origin is the DEFAULT_SENDER (0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38) of foundry // Expecting a revert since the tx.origin is not address(0) - vm.expectRevert(abi.encodeWithSelector(IAutomationRegistryMaster2_3.OnlySimulatedBackend.selector)); - registryMaster.checkUpkeep(id, triggerData); + vm.expectRevert(abi.encodeWithSelector(Registry.OnlySimulatedBackend.selector)); + registry.checkUpkeep(id, triggerData); } } -contract AutomationRegistry2_3_Withdraw is AutomationRegistry2_3_SetUp { - address internal aMockAddress = address(0x1111111111111111111111111111111111111113); +contract AddFunds is SetUp { + event FundsAdded(uint256 indexed id, address indexed from, uint96 amount); + + // when msg.value is 0, it uses the ERC20 payment path + function testNative_msgValue0() external { + vm.startPrank(OWNER); + uint256 startRegistryBalance = registry.getBalance(nativeUpkeepID); + uint256 startTokenBalance = registry.getBalance(nativeUpkeepID); + registry.addFunds(nativeUpkeepID, 1); + assertEq(registry.getBalance(nativeUpkeepID), startRegistryBalance + 1); + assertEq(weth.balanceOf(address(registry)), startTokenBalance + 1); + } - function mintLink(address recipient, uint256 amount) public { - vm.prank(UPKEEP_ADMIN); - //mint the link to the recipient - link.mint(recipient, amount); + // when msg.value is not 0, it uses the native payment path + function testNative_msgValueNot0() external { + uint256 startRegistryBalance = registry.getBalance(nativeUpkeepID); + uint256 startTokenBalance = registry.getBalance(nativeUpkeepID); + registry.addFunds{value: 1}(nativeUpkeepID, 1000); // parameter amount should be ignored + assertEq(registry.getBalance(nativeUpkeepID), startRegistryBalance + 1); + assertEq(weth.balanceOf(address(registry)), startTokenBalance + 1); + } + + // it fails when the billing token is not native, but trying to pay with native + function test_RevertsWhen_NativePaymentDoesntMatchBillingToken() external { + vm.expectRevert(abi.encodeWithSelector(Registry.InvalidToken.selector)); + registry.addFunds{value: 1}(linkUpkeepID, 0); + } + + function test_RevertsWhen_UpkeepDoesNotExist() public { + vm.expectRevert(Registry.UpkeepCancelled.selector); + registry.addFunds(randomNumber(), 1); } - function mintERC20(address recipient, uint256 amount) public { + function test_RevertsWhen_UpkeepIsCanceled() public { + registry.cancelUpkeep(linkUpkeepID); + vm.expectRevert(Registry.UpkeepCancelled.selector); + registry.addFunds(linkUpkeepID, 1); + } + + function test_anyoneCanAddFunds() public { + uint256 startAmount = registry.getBalance(linkUpkeepID); vm.prank(UPKEEP_ADMIN); - //mint the ERC20 to the recipient - mockERC20.mint(recipient, amount); + registry.addFunds(linkUpkeepID, 1); + assertEq(registry.getBalance(linkUpkeepID), startAmount + 1); + vm.prank(STRANGER); + registry.addFunds(linkUpkeepID, 1); + assertEq(registry.getBalance(linkUpkeepID), startAmount + 2); } - function setConfigForWithdraw() public { - address module = address(new ChainModuleBase()); - AutomationRegistryBase2_3.OnchainConfig memory cfg = AutomationRegistryBase2_3.OnchainConfig({ - paymentPremiumPPB: 10_000, - flatFeeMicroLink: 40_000, - checkGasLimit: 5_000_000, - stalenessSeconds: 90_000, - gasCeilingMultiplier: 0, - minUpkeepSpend: 0, - maxPerformGas: 10_000_000, - maxCheckDataSize: 5_000, - maxPerformDataSize: 5_000, - maxRevertDataSize: 5_000, - fallbackGasPrice: 20_000_000_000, - fallbackLinkPrice: 2_000_000_000, // $20 - fallbackNativePrice: 400_000_000_000, // $4,000 - transcoder: 0xB1e66855FD67f6e85F0f0fA38cd6fBABdf00923c, - registrars: s_registrars, - upkeepPrivilegeManager: 0xD9c855F08A7e460691F41bBDDe6eC310bc0593D8, - chainModule: module, - reorgProtectionEnabled: true, - financeAdmin: FINANCE_ADMIN_ADDRESS - }); - bytes memory offchainConfigBytes = abi.encode(1234, ZERO_ADDRESS); + function test_movesFundFromCorrectToken() public { + vm.startPrank(UPKEEP_ADMIN); + + uint256 startBalanceLINK = linkToken.balanceOf(address(registry)); + uint256 startBalanceUSDToken = usdToken.balanceOf(address(registry)); + uint256 startLinkUpkeepBalance = registry.getBalance(linkUpkeepID); + uint256 startUSDUpkeepBalance = registry.getBalance(usdUpkeepID); + + registry.addFunds(linkUpkeepID, 1); + assertEq(registry.getBalance(linkUpkeepID), startBalanceLINK + 1); + assertEq(registry.getBalance(usdUpkeepID), startBalanceUSDToken); + assertEq(linkToken.balanceOf(address(registry)), startLinkUpkeepBalance + 1); + assertEq(usdToken.balanceOf(address(registry)), startUSDUpkeepBalance); + + registry.addFunds(usdUpkeepID, 2); + assertEq(registry.getBalance(linkUpkeepID), startBalanceLINK + 1); + assertEq(registry.getBalance(usdUpkeepID), startBalanceUSDToken + 2); + assertEq(linkToken.balanceOf(address(registry)), startLinkUpkeepBalance + 1); + assertEq(usdToken.balanceOf(address(registry)), startUSDUpkeepBalance + 2); + } - registryMaster.setConfigTypeSafe( - s_valid_signers, - s_valid_transmitters, - F, - cfg, - OFFCHAIN_CONFIG_VERSION, - offchainConfigBytes, - new address[](0), - new AutomationRegistryBase2_3.BillingConfig[](0) - ); + function test_emitsAnEvent() public { + vm.startPrank(UPKEEP_ADMIN); + vm.expectEmit(); + emit FundsAdded(linkUpkeepID, address(UPKEEP_ADMIN), 100); + registry.addFunds(linkUpkeepID, 100); } +} + +contract Withdraw is SetUp { + address internal aMockAddress = randomAddress(); function testLinkAvailableForPaymentReturnsLinkBalance() public { + uint256 startBalance = linkToken.balanceOf(address(registry)); + int256 startLinkAvailable = registry.linkAvailableForPayment(); + //simulate a deposit of link to the liquidity pool - mintLink(address(registryMaster), 1e10); + _mintLink(address(registry), 1e10); //check there's a balance - assertGt(link.balanceOf(address(registryMaster)), 0); + assertEq(linkToken.balanceOf(address(registry)), startBalance + 1e10); - //check the link available for payment is the link balance - assertEq(registryMaster.linkAvailableForPayment(), link.balanceOf(address(registryMaster))); + //check the link available has increased by the same amount + assertEq(uint256(registry.linkAvailableForPayment()), uint256(startLinkAvailable) + 1e10); } - function testWithdrawLinkFeesRevertsBecauseOnlyFinanceAdminAllowed() public { - // set config with the finance admin - setConfigForWithdraw(); - - vm.expectRevert(abi.encodeWithSelector(IAutomationRegistryMaster2_3.OnlyFinanceAdmin.selector)); - registryMaster.withdrawLinkFees(aMockAddress, 1); + function testWithdrawLinkRevertsBecauseOnlyFinanceAdminAllowed() public { + vm.expectRevert(abi.encodeWithSelector(Registry.OnlyFinanceAdmin.selector)); + registry.withdrawLink(aMockAddress, 1); } - function testWithdrawLinkFeesRevertsBecauseOfInsufficientBalance() public { - // set config with the finance admin - setConfigForWithdraw(); - - vm.startPrank(FINANCE_ADMIN_ADDRESS); + function testWithdrawLinkRevertsBecauseOfInsufficientBalance() public { + vm.startPrank(FINANCE_ADMIN); // try to withdraw 1 link while there is 0 balance - vm.expectRevert(abi.encodeWithSelector(IAutomationRegistryMaster2_3.InsufficientBalance.selector, 0, 1)); - registryMaster.withdrawLinkFees(aMockAddress, 1); + vm.expectRevert(abi.encodeWithSelector(Registry.InsufficientBalance.selector, 0, 1)); + registry.withdrawLink(aMockAddress, 1); vm.stopPrank(); } - function testWithdrawLinkFeesRevertsBecauseOfInvalidRecipient() public { - // set config with the finance admin - setConfigForWithdraw(); - - vm.startPrank(FINANCE_ADMIN_ADDRESS); + function testWithdrawLinkRevertsBecauseOfInvalidRecipient() public { + vm.startPrank(FINANCE_ADMIN); // try to withdraw 1 link while there is 0 balance - vm.expectRevert(abi.encodeWithSelector(IAutomationRegistryMaster2_3.InvalidRecipient.selector)); - registryMaster.withdrawLinkFees(ZERO_ADDRESS, 1); + vm.expectRevert(abi.encodeWithSelector(Registry.InvalidRecipient.selector)); + registry.withdrawLink(ZERO_ADDRESS, 1); vm.stopPrank(); } - function testWithdrawLinkFeeSuccess() public { - // set config with the finance admin - setConfigForWithdraw(); - + function testWithdrawLinkSuccess() public { //simulate a deposit of link to the liquidity pool - mintLink(address(registryMaster), 1e10); + _mintLink(address(registry), 1e10); + uint256 startBalance = linkToken.balanceOf(address(registry)); - //check there's a balance - assertGt(link.balanceOf(address(registryMaster)), 0); - - vm.startPrank(FINANCE_ADMIN_ADDRESS); + vm.startPrank(FINANCE_ADMIN); // try to withdraw 1 link while there is a ton of link available - registryMaster.withdrawLinkFees(aMockAddress, 1); + registry.withdrawLink(aMockAddress, 1); vm.stopPrank(); - assertEq(link.balanceOf(address(aMockAddress)), 1); - assertEq(link.balanceOf(address(registryMaster)), 1e10 - 1); + assertEq(linkToken.balanceOf(address(aMockAddress)), 1); + assertEq(linkToken.balanceOf(address(registry)), startBalance - 1); } - function testWithdrawERC20FeeSuccess() public { - // set config with the finance admin - setConfigForWithdraw(); + function test_WithdrawERC20Fees_RespectsReserveAmount() public { + assertEq(registry.getBalance(usdUpkeepID), registry.getReserveAmount(address(usdToken))); + vm.startPrank(FINANCE_ADMIN); + vm.expectRevert(abi.encodeWithSelector(Registry.InsufficientBalance.selector, 0, 1)); + registry.withdrawERC20Fees(address(usdToken), FINANCE_ADMIN, 1); + } - // simulate a deposit of ERC20 to the liquidity pool - mintERC20(address(registryMaster), 1e10); + function test_WithdrawERC20Fees_RevertsWhen_AttemptingToWithdrawLINK() public { + _mintLink(address(registry), 1e10); + vm.startPrank(FINANCE_ADMIN); + vm.expectRevert(Registry.InvalidToken.selector); + registry.withdrawERC20Fees(address(linkToken), FINANCE_ADMIN, 1); // should revert + registry.withdrawLink(FINANCE_ADMIN, 1); // but using link withdraw functions succeeds + } - // check there's a balance - assertGt(mockERC20.balanceOf(address(registryMaster)), 0); + function test_WithdrawERC20Fees_RevertsWhen_LinkAvailableForPaymentIsNegative() public { + _transmit(usdUpkeepID, registry); // adds USD token to finance withdrawable, and gives NOPs a LINK balance + require(registry.linkAvailableForPayment() < 0, "linkAvailableForPayment should be negative"); + vm.expectRevert(Registry.InsufficientLinkLiquidity.selector); + vm.prank(FINANCE_ADMIN); + registry.withdrawERC20Fees(address(usdToken), FINANCE_ADMIN, 1); // should revert + _mintLink(address(registry), uint256(registry.linkAvailableForPayment() * -10)); // top up LINK liquidity pool + vm.prank(FINANCE_ADMIN); + registry.withdrawERC20Fees(address(usdToken), FINANCE_ADMIN, 1); // now finance can withdraw + } - vm.startPrank(FINANCE_ADMIN_ADDRESS); + function testWithdrawERC20FeeSuccess() public { + // deposit excess USDToken to the registry (this goes to the "finance withdrawable" pool be default) + uint256 startReserveAmount = registry.getReserveAmount(address(usdToken)); + uint256 startAmount = usdToken.balanceOf(address(registry)); + _mintERC20(address(registry), 1e10); - // try to withdraw 1 link while there is a ton of link available - registryMaster.withdrawERC20Fees(address(mockERC20), aMockAddress, 1); + // depositing shouldn't change reserve amount + assertEq(registry.getReserveAmount(address(usdToken)), startReserveAmount); + + vm.startPrank(FINANCE_ADMIN); + + // try to withdraw 1 USDToken + registry.withdrawERC20Fees(address(usdToken), aMockAddress, 1); vm.stopPrank(); - assertEq(mockERC20.balanceOf(address(aMockAddress)), 1); - assertEq(mockERC20.balanceOf(address(registryMaster)), 1e10 - 1); + assertEq(usdToken.balanceOf(address(aMockAddress)), 1); + assertEq(usdToken.balanceOf(address(registry)), startAmount + 1e10 - 1); + assertEq(registry.getReserveAmount(address(usdToken)), startReserveAmount); } } -contract AutomationRegistry2_3_SetConfig is AutomationRegistry2_3_SetUp { +contract SetConfig is SetUp { event ConfigSet( uint32 previousConfigBlockNumber, bytes32 configDigest, @@ -251,12 +308,9 @@ contract AutomationRegistry2_3_SetConfig is AutomationRegistry2_3_SetUp { address module = address(new ChainModuleBase()); AutomationRegistryBase2_3.OnchainConfig cfg = AutomationRegistryBase2_3.OnchainConfig({ - paymentPremiumPPB: 10_000, - flatFeeMicroLink: 40_000, checkGasLimit: 5_000_000, stalenessSeconds: 90_000, gasCeilingMultiplier: 0, - minUpkeepSpend: 0, maxPerformGas: 10_000_000, maxCheckDataSize: 5_000, maxPerformDataSize: 5_000, @@ -265,16 +319,16 @@ contract AutomationRegistry2_3_SetConfig is AutomationRegistry2_3_SetUp { fallbackLinkPrice: 2_000_000_000, // $20 fallbackNativePrice: 400_000_000_000, // $4,000 transcoder: 0xB1e66855FD67f6e85F0f0fA38cd6fBABdf00923c, - registrars: s_registrars, - upkeepPrivilegeManager: 0xD9c855F08A7e460691F41bBDDe6eC310bc0593D8, + registrars: new address[](0), + upkeepPrivilegeManager: PRIVILEGE_MANAGER, chainModule: module, reorgProtectionEnabled: true, - financeAdmin: FINANCE_ADMIN_ADDRESS + financeAdmin: FINANCE_ADMIN }); function testSetConfigSuccess() public { - (uint32 configCount, , ) = registryMaster.latestConfigDetails(); - assertEq(configCount, 0); + (uint32 configCount, uint32 blockNumber, ) = registry.latestConfigDetails(); + assertEq(configCount, 1); address billingTokenAddress = address(0x1111111111111111111111111111111111111111); address[] memory billingTokens = new address[](1); @@ -283,22 +337,21 @@ contract AutomationRegistry2_3_SetConfig is AutomationRegistry2_3_SetUp { AutomationRegistryBase2_3.BillingConfig[] memory billingConfigs = new AutomationRegistryBase2_3.BillingConfig[](1); billingConfigs[0] = AutomationRegistryBase2_3.BillingConfig({ gasFeePPB: 5_000, - flatFeeMicroLink: 20_000, - priceFeed: 0x2222222222222222222222222222222222222222 + flatFeeMilliCents: 20_000, + priceFeed: 0x2222222222222222222222222222222222222222, + fallbackPrice: 2_000_000_000, // $20 + minSpend: 100_000 }); bytes memory onchainConfigBytes = abi.encode(cfg); bytes memory onchainConfigBytesWithBilling = abi.encode(cfg, billingTokens, billingConfigs); - uint256 a = 1234; - address b = ZERO_ADDRESS; - bytes memory offchainConfigBytes = abi.encode(a, b); bytes32 configDigest = _configDigestFromConfigData( block.chainid, - address(registryMaster), + address(registry), ++configCount, - s_valid_signers, - s_valid_transmitters, + SIGNERS, + TRANSMITTERS, F, onchainConfigBytes, OFFCHAIN_CONFIG_VERSION, @@ -307,44 +360,45 @@ contract AutomationRegistry2_3_SetConfig is AutomationRegistry2_3_SetUp { vm.expectEmit(); emit ConfigSet( - 0, + blockNumber, configDigest, configCount, - s_valid_signers, - s_valid_transmitters, + SIGNERS, + TRANSMITTERS, F, onchainConfigBytes, OFFCHAIN_CONFIG_VERSION, offchainConfigBytes ); - registryMaster.setConfig( - s_valid_signers, - s_valid_transmitters, + registry.setConfig( + SIGNERS, + TRANSMITTERS, F, onchainConfigBytesWithBilling, OFFCHAIN_CONFIG_VERSION, offchainConfigBytes ); - (, , address[] memory signers, address[] memory transmitters, uint8 f) = registryMaster.getState(); + (, , address[] memory signers, address[] memory transmitters, uint8 f) = registry.getState(); - assertEq(signers, s_valid_signers); - assertEq(transmitters, s_valid_transmitters); + assertEq(signers, SIGNERS); + assertEq(transmitters, TRANSMITTERS); assertEq(f, F); - AutomationRegistryBase2_3.BillingConfig memory config = registryMaster.getBillingTokenConfig(billingTokenAddress); + AutomationRegistryBase2_3.BillingConfig memory config = registry.getBillingTokenConfig(billingTokenAddress); assertEq(config.gasFeePPB, 5_000); - assertEq(config.flatFeeMicroLink, 20_000); + assertEq(config.flatFeeMilliCents, 20_000); assertEq(config.priceFeed, 0x2222222222222222222222222222222222222222); + assertEq(config.minSpend, 100_000); - address[] memory tokens = registryMaster.getBillingTokens(); + address[] memory tokens = registry.getBillingTokens(); assertEq(tokens.length, 1); } function testSetConfigMultipleBillingConfigsSuccess() public { - (uint32 configCount, , ) = registryMaster.latestConfigDetails(); - assertEq(configCount, 0); + (uint32 configCount, , ) = registry.latestConfigDetails(); + assertEq(configCount, 1); address billingTokenAddress1 = address(0x1111111111111111111111111111111111111111); address billingTokenAddress2 = address(0x1111111111111111111111111111111111111112); @@ -355,53 +409,57 @@ contract AutomationRegistry2_3_SetConfig is AutomationRegistry2_3_SetUp { AutomationRegistryBase2_3.BillingConfig[] memory billingConfigs = new AutomationRegistryBase2_3.BillingConfig[](2); billingConfigs[0] = AutomationRegistryBase2_3.BillingConfig({ gasFeePPB: 5_001, - flatFeeMicroLink: 20_001, - priceFeed: 0x2222222222222222222222222222222222222221 + flatFeeMilliCents: 20_001, + priceFeed: 0x2222222222222222222222222222222222222221, + fallbackPrice: 100, + minSpend: 100 }); billingConfigs[1] = AutomationRegistryBase2_3.BillingConfig({ gasFeePPB: 5_002, - flatFeeMicroLink: 20_002, - priceFeed: 0x2222222222222222222222222222222222222222 + flatFeeMilliCents: 20_002, + priceFeed: 0x2222222222222222222222222222222222222222, + fallbackPrice: 200, + minSpend: 200 }); bytes memory onchainConfigBytesWithBilling = abi.encode(cfg, billingTokens, billingConfigs); - uint256 a = 1234; - address b = ZERO_ADDRESS; - bytes memory offchainConfigBytes = abi.encode(a, b); - - registryMaster.setConfig( - s_valid_signers, - s_valid_transmitters, + registry.setConfig( + SIGNERS, + TRANSMITTERS, F, onchainConfigBytesWithBilling, OFFCHAIN_CONFIG_VERSION, offchainConfigBytes ); - (, , address[] memory signers, address[] memory transmitters, uint8 f) = registryMaster.getState(); + (, , address[] memory signers, address[] memory transmitters, uint8 f) = registry.getState(); - assertEq(signers, s_valid_signers); - assertEq(transmitters, s_valid_transmitters); + assertEq(signers, SIGNERS); + assertEq(transmitters, TRANSMITTERS); assertEq(f, F); - AutomationRegistryBase2_3.BillingConfig memory config1 = registryMaster.getBillingTokenConfig(billingTokenAddress1); + AutomationRegistryBase2_3.BillingConfig memory config1 = registry.getBillingTokenConfig(billingTokenAddress1); assertEq(config1.gasFeePPB, 5_001); - assertEq(config1.flatFeeMicroLink, 20_001); + assertEq(config1.flatFeeMilliCents, 20_001); assertEq(config1.priceFeed, 0x2222222222222222222222222222222222222221); + assertEq(config1.fallbackPrice, 100); + assertEq(config1.minSpend, 100); - AutomationRegistryBase2_3.BillingConfig memory config2 = registryMaster.getBillingTokenConfig(billingTokenAddress2); + AutomationRegistryBase2_3.BillingConfig memory config2 = registry.getBillingTokenConfig(billingTokenAddress2); assertEq(config2.gasFeePPB, 5_002); - assertEq(config2.flatFeeMicroLink, 20_002); + assertEq(config2.flatFeeMilliCents, 20_002); assertEq(config2.priceFeed, 0x2222222222222222222222222222222222222222); + assertEq(config2.fallbackPrice, 200); + assertEq(config2.minSpend, 200); - address[] memory tokens = registryMaster.getBillingTokens(); + address[] memory tokens = registry.getBillingTokens(); assertEq(tokens.length, 2); } function testSetConfigTwiceAndLastSetOverwrites() public { - (uint32 configCount, , ) = registryMaster.latestConfigDetails(); - assertEq(configCount, 0); + (uint32 configCount, , ) = registry.latestConfigDetails(); + assertEq(configCount, 1); // BillingConfig1 address billingTokenAddress1 = address(0x1111111111111111111111111111111111111111); @@ -411,8 +469,10 @@ contract AutomationRegistry2_3_SetConfig is AutomationRegistry2_3_SetUp { AutomationRegistryBase2_3.BillingConfig[] memory billingConfigs1 = new AutomationRegistryBase2_3.BillingConfig[](1); billingConfigs1[0] = AutomationRegistryBase2_3.BillingConfig({ gasFeePPB: 5_001, - flatFeeMicroLink: 20_001, - priceFeed: 0x2222222222222222222222222222222222222221 + flatFeeMilliCents: 20_001, + priceFeed: 0x2222222222222222222222222222222222222221, + fallbackPrice: 100, + minSpend: 100 }); bytes memory onchainConfigBytesWithBilling1 = abi.encode(cfg, billingTokens1, billingConfigs1); @@ -425,20 +485,18 @@ contract AutomationRegistry2_3_SetConfig is AutomationRegistry2_3_SetUp { AutomationRegistryBase2_3.BillingConfig[] memory billingConfigs2 = new AutomationRegistryBase2_3.BillingConfig[](1); billingConfigs2[0] = AutomationRegistryBase2_3.BillingConfig({ gasFeePPB: 5_002, - flatFeeMicroLink: 20_002, - priceFeed: 0x2222222222222222222222222222222222222222 + flatFeeMilliCents: 20_002, + priceFeed: 0x2222222222222222222222222222222222222222, + fallbackPrice: 200, + minSpend: 200 }); bytes memory onchainConfigBytesWithBilling2 = abi.encode(cfg, billingTokens2, billingConfigs2); - uint256 a = 1234; - address b = ZERO_ADDRESS; - bytes memory offchainConfigBytes = abi.encode(a, b); - // set config once - registryMaster.setConfig( - s_valid_signers, - s_valid_transmitters, + registry.setConfig( + SIGNERS, + TRANSMITTERS, F, onchainConfigBytesWithBilling1, OFFCHAIN_CONFIG_VERSION, @@ -446,33 +504,35 @@ contract AutomationRegistry2_3_SetConfig is AutomationRegistry2_3_SetUp { ); // set config twice - registryMaster.setConfig( - s_valid_signers, - s_valid_transmitters, + registry.setConfig( + SIGNERS, + TRANSMITTERS, F, onchainConfigBytesWithBilling2, OFFCHAIN_CONFIG_VERSION, offchainConfigBytes ); - (, , address[] memory signers, address[] memory transmitters, uint8 f) = registryMaster.getState(); + (, , address[] memory signers, address[] memory transmitters, uint8 f) = registry.getState(); - assertEq(signers, s_valid_signers); - assertEq(transmitters, s_valid_transmitters); + assertEq(signers, SIGNERS); + assertEq(transmitters, TRANSMITTERS); assertEq(f, F); - AutomationRegistryBase2_3.BillingConfig memory config2 = registryMaster.getBillingTokenConfig(billingTokenAddress2); + AutomationRegistryBase2_3.BillingConfig memory config2 = registry.getBillingTokenConfig(billingTokenAddress2); assertEq(config2.gasFeePPB, 5_002); - assertEq(config2.flatFeeMicroLink, 20_002); + assertEq(config2.flatFeeMilliCents, 20_002); assertEq(config2.priceFeed, 0x2222222222222222222222222222222222222222); + assertEq(config2.fallbackPrice, 200); + assertEq(config2.minSpend, 200); - address[] memory tokens = registryMaster.getBillingTokens(); + address[] memory tokens = registry.getBillingTokens(); assertEq(tokens.length, 1); } function testSetConfigDuplicateBillingConfigFailure() public { - (uint32 configCount, , ) = registryMaster.latestConfigDetails(); - assertEq(configCount, 0); + (uint32 configCount, , ) = registry.latestConfigDetails(); + assertEq(configCount, 1); address billingTokenAddress1 = address(0x1111111111111111111111111111111111111111); address billingTokenAddress2 = address(0x1111111111111111111111111111111111111111); @@ -483,26 +543,26 @@ contract AutomationRegistry2_3_SetConfig is AutomationRegistry2_3_SetUp { AutomationRegistryBase2_3.BillingConfig[] memory billingConfigs = new AutomationRegistryBase2_3.BillingConfig[](2); billingConfigs[0] = AutomationRegistryBase2_3.BillingConfig({ gasFeePPB: 5_001, - flatFeeMicroLink: 20_001, - priceFeed: 0x2222222222222222222222222222222222222221 + flatFeeMilliCents: 20_001, + priceFeed: 0x2222222222222222222222222222222222222221, + fallbackPrice: 100, + minSpend: 100 }); billingConfigs[1] = AutomationRegistryBase2_3.BillingConfig({ gasFeePPB: 5_002, - flatFeeMicroLink: 20_002, - priceFeed: 0x2222222222222222222222222222222222222222 + flatFeeMilliCents: 20_002, + priceFeed: 0x2222222222222222222222222222222222222222, + fallbackPrice: 200, + minSpend: 200 }); bytes memory onchainConfigBytesWithBilling = abi.encode(cfg, billingTokens, billingConfigs); - uint256 a = 1234; - address b = ZERO_ADDRESS; - bytes memory offchainConfigBytes = abi.encode(a, b); - // expect revert because of duplicate tokens - vm.expectRevert(abi.encodeWithSelector(IAutomationRegistryMaster2_3.DuplicateEntry.selector)); - registryMaster.setConfig( - s_valid_signers, - s_valid_transmitters, + vm.expectRevert(abi.encodeWithSelector(Registry.DuplicateEntry.selector)); + registry.setConfig( + SIGNERS, + TRANSMITTERS, F, onchainConfigBytesWithBilling, OFFCHAIN_CONFIG_VERSION, @@ -510,6 +570,138 @@ contract AutomationRegistry2_3_SetConfig is AutomationRegistry2_3_SetUp { ); } + function testSetConfigRevertDueToInvalidToken() public { + address[] memory billingTokens = new address[](1); + billingTokens[0] = address(linkToken); + + AutomationRegistryBase2_3.BillingConfig[] memory billingConfigs = new AutomationRegistryBase2_3.BillingConfig[](1); + billingConfigs[0] = AutomationRegistryBase2_3.BillingConfig({ + gasFeePPB: 5_000, + flatFeeMilliCents: 20_000, + priceFeed: 0x2222222222222222222222222222222222222222, + fallbackPrice: 2_000_000_000, // $20 + minSpend: 100_000 + }); + + // deploy registry with OFF_CHAIN payout mode + registry = deployRegistry(AutoBase.PayoutMode.OFF_CHAIN); + + vm.expectRevert(abi.encodeWithSelector(Registry.InvalidToken.selector)); + registry.setConfigTypeSafe( + SIGNERS, + TRANSMITTERS, + F, + cfg, + OFFCHAIN_CONFIG_VERSION, + offchainConfigBytes, + billingTokens, + billingConfigs + ); + } + + function testSetConfigWithNewTransmittersSuccess() public { + registry = deployRegistry(AutoBase.PayoutMode.OFF_CHAIN); + + (uint32 configCount, uint32 blockNumber, ) = registry.latestConfigDetails(); + assertEq(configCount, 0); + + address billingTokenAddress = address(0x1111111111111111111111111111111111111111); + address[] memory billingTokens = new address[](1); + billingTokens[0] = billingTokenAddress; + + AutomationRegistryBase2_3.BillingConfig[] memory billingConfigs = new AutomationRegistryBase2_3.BillingConfig[](1); + billingConfigs[0] = AutomationRegistryBase2_3.BillingConfig({ + gasFeePPB: 5_000, + flatFeeMilliCents: 20_000, + priceFeed: 0x2222222222222222222222222222222222222222, + fallbackPrice: 2_000_000_000, // $20 + minSpend: 100_000 + }); + + bytes memory onchainConfigBytes = abi.encode(cfg); + + bytes32 configDigest = _configDigestFromConfigData( + block.chainid, + address(registry), + ++configCount, + SIGNERS, + TRANSMITTERS, + F, + onchainConfigBytes, + OFFCHAIN_CONFIG_VERSION, + offchainConfigBytes + ); + + vm.expectEmit(); + emit ConfigSet( + blockNumber, + configDigest, + configCount, + SIGNERS, + TRANSMITTERS, + F, + onchainConfigBytes, + OFFCHAIN_CONFIG_VERSION, + offchainConfigBytes + ); + + registry.setConfigTypeSafe( + SIGNERS, + TRANSMITTERS, + F, + cfg, + OFFCHAIN_CONFIG_VERSION, + offchainConfigBytes, + billingTokens, + billingConfigs + ); + + (, , address[] memory signers, address[] memory transmitters, ) = registry.getState(); + assertEq(signers, SIGNERS); + assertEq(transmitters, TRANSMITTERS); + + (configCount, blockNumber, ) = registry.latestConfigDetails(); + configDigest = _configDigestFromConfigData( + block.chainid, + address(registry), + ++configCount, + SIGNERS, + NEW_TRANSMITTERS, + F, + onchainConfigBytes, + OFFCHAIN_CONFIG_VERSION, + offchainConfigBytes + ); + + vm.expectEmit(); + emit ConfigSet( + blockNumber, + configDigest, + configCount, + SIGNERS, + NEW_TRANSMITTERS, + F, + onchainConfigBytes, + OFFCHAIN_CONFIG_VERSION, + offchainConfigBytes + ); + + registry.setConfigTypeSafe( + SIGNERS, + NEW_TRANSMITTERS, + F, + cfg, + OFFCHAIN_CONFIG_VERSION, + offchainConfigBytes, + billingTokens, + billingConfigs + ); + + (, , signers, transmitters, ) = registry.getState(); + assertEq(signers, SIGNERS); + assertEq(transmitters, NEW_TRANSMITTERS); + } + function _configDigestFromConfigData( uint256 chainId, address contractAddress, @@ -541,3 +733,792 @@ contract AutomationRegistry2_3_SetConfig is AutomationRegistry2_3_SetUp { return bytes32((prefix & prefixMask) | (h & ~prefixMask)); } } + +contract NOPsSettlement is SetUp { + event NOPsSettledOffchain(address[] payees, uint256[] payments); + event FundsWithdrawn(uint256 indexed id, uint256 amount, address to); + event PaymentWithdrawn(address indexed transmitter, uint256 indexed amount, address indexed to, address payee); + + function testSettleNOPsOffchainRevertDueToUnauthorizedCaller() public { + (Registry registry, ) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.ON_CHAIN); + + vm.expectRevert(abi.encodeWithSelector(Registry.OnlyFinanceAdmin.selector)); + registry.settleNOPsOffchain(); + } + + function testSettleNOPsOffchainRevertDueToOffchainSettlementDisabled() public { + (Registry registry, ) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.OFF_CHAIN); + + vm.prank(registry.owner()); + registry.disableOffchainPayments(); + + vm.prank(FINANCE_ADMIN); + vm.expectRevert(abi.encodeWithSelector(Registry.MustSettleOnchain.selector)); + registry.settleNOPsOffchain(); + } + + function testSettleNOPsOffchainSuccess() public { + // deploy and configure a registry with OFF_CHAIN payout + (Registry registry, ) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.OFF_CHAIN); + + uint256[] memory payments = new uint256[](TRANSMITTERS.length); + for (uint256 i = 0; i < TRANSMITTERS.length; i++) { + payments[i] = 0; + } + + vm.startPrank(FINANCE_ADMIN); + vm.expectEmit(); + emit NOPsSettledOffchain(PAYEES, payments); + registry.settleNOPsOffchain(); + } + + function testSettleNOPsOffchainSuccessTransmitterBalanceZeroed() public { + // deploy and configure a registry with OFF_CHAIN payout + (Registry registry, ) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.OFF_CHAIN); + + // register an upkeep and add funds + uint256 id = registry.registerUpkeep(address(TARGET1), 1000000, UPKEEP_ADMIN, 0, address(usdToken), "", "", ""); + _mintERC20(UPKEEP_ADMIN, 1e20); + vm.startPrank(UPKEEP_ADMIN); + usdToken.approve(address(registry), 1e20); + registry.addFunds(id, 1e20); + + // manually create a transmit so transmitters earn some rewards + _transmit(id, registry); + + // verify transmitters have positive balances + uint256[] memory payments = new uint256[](TRANSMITTERS.length); + for (uint256 i = 0; i < TRANSMITTERS.length; i++) { + (bool active, uint8 index, uint96 balance, uint96 lastCollected, ) = registry.getTransmitterInfo(TRANSMITTERS[i]); + assertTrue(active); + assertEq(i, index); + assertTrue(balance > 0); + assertEq(0, lastCollected); + + payments[i] = balance; + } + + // verify offchain settlement will emit NOPs' balances + vm.startPrank(FINANCE_ADMIN); + vm.expectEmit(); + emit NOPsSettledOffchain(PAYEES, payments); + registry.settleNOPsOffchain(); + + // verify that transmitters balance has been zeroed out + for (uint256 i = 0; i < TRANSMITTERS.length; i++) { + (bool active, uint8 index, uint96 balance, , ) = registry.getTransmitterInfo(TRANSMITTERS[i]); + assertTrue(active); + assertEq(i, index); + assertEq(0, balance); + } + } + + function testSettleNOPsOffchainForDeactivatedTransmittersSuccess() public { + // deploy and configure a registry with OFF_CHAIN payout + (Registry registry, Registrar registrar) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.OFF_CHAIN); + + // register an upkeep and add funds + uint256 id = registry.registerUpkeep(address(TARGET1), 1000000, UPKEEP_ADMIN, 0, address(usdToken), "", "", ""); + _mintERC20(UPKEEP_ADMIN, 1e20); + vm.startPrank(UPKEEP_ADMIN); + usdToken.approve(address(registry), 1e20); + registry.addFunds(id, 1e20); + + // manually create a transmit so TRANSMITTERS earn some rewards + _transmit(id, registry); + + // TRANSMITTERS have positive balance now + // configure the registry to use NEW_TRANSMITTERS + _configureWithNewTransmitters(registry, registrar); + + _transmit(id, registry); + + // verify all transmitters have positive balances + address[] memory expectedPayees = new address[](6); + uint256[] memory expectedPayments = new uint256[](6); + for (uint256 i = 0; i < NEW_TRANSMITTERS.length; i++) { + (bool active, uint8 index, uint96 balance, uint96 lastCollected, address payee) = registry.getTransmitterInfo( + NEW_TRANSMITTERS[i] + ); + assertTrue(active); + assertEq(i, index); + assertTrue(lastCollected > 0); + expectedPayments[i] = balance; + expectedPayees[i] = payee; + } + for (uint256 i = 2; i < TRANSMITTERS.length; i++) { + (bool active, uint8 index, uint96 balance, uint96 lastCollected, address payee) = registry.getTransmitterInfo( + TRANSMITTERS[i] + ); + assertFalse(active); + assertEq(i, index); + assertTrue(balance > 0); + assertTrue(lastCollected > 0); + expectedPayments[2 + i] = balance; + expectedPayees[2 + i] = payee; + } + + // verify offchain settlement will emit NOPs' balances + vm.startPrank(FINANCE_ADMIN); + + // simply expectEmit won't work here because s_deactivatedTransmitters is an enumerable set so the order of these + // deactivated transmitters is not guaranteed. To handle this, we record logs and decode data field manually. + vm.recordLogs(); + registry.settleNOPsOffchain(); + Vm.Log[] memory entries = vm.getRecordedLogs(); + + assertEq(entries.length, 1); + Vm.Log memory l = entries[0]; + assertEq(l.topics[0], keccak256("NOPsSettledOffchain(address[],uint256[])")); + (address[] memory actualPayees, uint256[] memory actualPayments) = abi.decode(l.data, (address[], uint256[])); + assertEq(actualPayees.length, 6); + assertEq(actualPayments.length, 6); + + // first 4 payees and payments are for NEW_TRANSMITTERS and they are ordered. + for (uint256 i = 0; i < NEW_TRANSMITTERS.length; i++) { + assertEq(actualPayees[i], expectedPayees[i]); + assertEq(actualPayments[i], expectedPayments[i]); + } + + // the last 2 payees and payments for TRANSMITTERS[2] and TRANSMITTERS[3] and they are not ordered + assertTrue( + (actualPayments[5] == expectedPayments[5] && + actualPayees[5] == expectedPayees[5] && + actualPayments[4] == expectedPayments[4] && + actualPayees[4] == expectedPayees[4]) || + (actualPayments[5] == expectedPayments[4] && + actualPayees[5] == expectedPayees[4] && + actualPayments[4] == expectedPayments[5] && + actualPayees[4] == expectedPayees[5]) + ); + + // verify that new transmitters balance has been zeroed out + for (uint256 i = 0; i < NEW_TRANSMITTERS.length; i++) { + (bool active, uint8 index, uint96 balance, , ) = registry.getTransmitterInfo(NEW_TRANSMITTERS[i]); + assertTrue(active); + assertEq(i, index); + assertEq(0, balance); + } + // verify that deactivated transmitters (TRANSMITTERS[2] and TRANSMITTERS[3]) balance has been zeroed out + for (uint256 i = 2; i < TRANSMITTERS.length; i++) { + (bool active, uint8 index, uint96 balance, , ) = registry.getTransmitterInfo(TRANSMITTERS[i]); + assertFalse(active); + assertEq(i, index); + assertEq(0, balance); + } + } + + function testDisableOffchainPaymentsRevertDueToUnauthorizedCaller() public { + (Registry registry, ) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.OFF_CHAIN); + + vm.startPrank(FINANCE_ADMIN); + vm.expectRevert(bytes("Only callable by owner")); + registry.disableOffchainPayments(); + } + + function testDisableOffchainPaymentsSuccess() public { + (Registry registry, ) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.OFF_CHAIN); + + vm.startPrank(registry.owner()); + registry.disableOffchainPayments(); + + assertEq(uint8(AutoBase.PayoutMode.ON_CHAIN), registry.getPayoutMode()); + } + + function testSinglePerformAndNodesCanWithdrawOnchain() public { + // deploy and configure a registry with OFF_CHAIN payout + (Registry registry, ) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.OFF_CHAIN); + + // register an upkeep and add funds + uint256 id = registry.registerUpkeep(address(TARGET1), 1000000, UPKEEP_ADMIN, 0, address(usdToken), "", "", ""); + _mintERC20(UPKEEP_ADMIN, 1e20); + vm.startPrank(UPKEEP_ADMIN); + usdToken.approve(address(registry), 1e20); + registry.addFunds(id, 1e20); + + // manually create a transmit so transmitters earn some rewards + _transmit(id, registry); + + // disable offchain payments + _mintLink(address(registry), 1e19); + vm.prank(registry.owner()); + registry.disableOffchainPayments(); + + // payees should be able to withdraw onchain + for (uint256 i = 0; i < TRANSMITTERS.length; i++) { + (, , uint96 balance, , address payee) = registry.getTransmitterInfo(TRANSMITTERS[i]); + vm.prank(payee); + vm.expectEmit(); + emit PaymentWithdrawn(TRANSMITTERS[i], balance, payee, payee); + registry.withdrawPayment(TRANSMITTERS[i], payee); + } + + // allow upkeep admin to withdraw funds + vm.startPrank(UPKEEP_ADMIN); + registry.cancelUpkeep(id); + vm.roll(100 + block.number); + vm.expectEmit(); + // the upkeep spent less than minimum spending limit so upkeep admin can only withdraw upkeep balance - min spend value + emit FundsWithdrawn(id, 9.9e19, UPKEEP_ADMIN); + registry.withdrawFunds(id, UPKEEP_ADMIN); + } + + function testMultiplePerformsAndNodesCanWithdrawOnchain() public { + // deploy and configure a registry with OFF_CHAIN payout + (Registry registry, ) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.OFF_CHAIN); + + // register an upkeep and add funds + uint256 id = registry.registerUpkeep(address(TARGET1), 1000000, UPKEEP_ADMIN, 0, address(usdToken), "", "", ""); + _mintERC20(UPKEEP_ADMIN, 1e20); + vm.startPrank(UPKEEP_ADMIN); + usdToken.approve(address(registry), 1e20); + registry.addFunds(id, 1e20); + + // manually call transmit so transmitters earn some rewards + for (uint256 i = 0; i < 50; i++) { + vm.roll(100 + block.number); + _transmit(id, registry); + } + + // disable offchain payments + _mintLink(address(registry), 1e19); + vm.prank(registry.owner()); + registry.disableOffchainPayments(); + + // manually call transmit after offchain payment is disabled + for (uint256 i = 0; i < 50; i++) { + vm.roll(100 + block.number); + _transmit(id, registry); + } + + // payees should be able to withdraw onchain + for (uint256 i = 0; i < TRANSMITTERS.length; i++) { + (, , uint96 balance, , address payee) = registry.getTransmitterInfo(TRANSMITTERS[i]); + vm.prank(payee); + vm.expectEmit(); + emit PaymentWithdrawn(TRANSMITTERS[i], balance, payee, payee); + registry.withdrawPayment(TRANSMITTERS[i], payee); + } + + // allow upkeep admin to withdraw funds + vm.startPrank(UPKEEP_ADMIN); + registry.cancelUpkeep(id); + vm.roll(100 + block.number); + uint256 balance = registry.getBalance(id); + vm.expectEmit(); + emit FundsWithdrawn(id, balance, UPKEEP_ADMIN); + registry.withdrawFunds(id, UPKEEP_ADMIN); + } + + function _configureWithNewTransmitters(Registry registry, Registrar registrar) internal { + IERC20[] memory billingTokens = new IERC20[](1); + billingTokens[0] = IERC20(address(usdToken)); + uint256[] memory minRegistrationFees = new uint256[](billingTokens.length); + minRegistrationFees[0] = 100000000000000000000; // 100 USD + address[] memory billingTokenAddresses = new address[](billingTokens.length); + for (uint256 i = 0; i < billingTokens.length; i++) { + billingTokenAddresses[i] = address(billingTokens[i]); + } + AutomationRegistryBase2_3.BillingConfig[] + memory billingTokenConfigs = new AutomationRegistryBase2_3.BillingConfig[](billingTokens.length); + billingTokenConfigs[0] = AutomationRegistryBase2_3.BillingConfig({ + gasFeePPB: 10_000_000, // 15% + flatFeeMilliCents: 2_000, // 2 cents + priceFeed: address(USDTOKEN_USD_FEED), + fallbackPrice: 100_000_000, // $1 + minSpend: 1000000000000000000 // 1 USD + }); + + address[] memory registrars; + registrars = new address[](1); + registrars[0] = address(registrar); + AutomationRegistryBase2_3.OnchainConfig memory cfg = AutomationRegistryBase2_3.OnchainConfig({ + checkGasLimit: 5_000_000, + stalenessSeconds: 90_000, + gasCeilingMultiplier: 2, + maxPerformGas: 10_000_000, + maxCheckDataSize: 5_000, + maxPerformDataSize: 5_000, + maxRevertDataSize: 5_000, + fallbackGasPrice: 20_000_000_000, + fallbackLinkPrice: 2_000_000_000, // $20 + fallbackNativePrice: 400_000_000_000, // $4,000 + transcoder: 0xB1e66855FD67f6e85F0f0fA38cd6fBABdf00923c, + registrars: registrars, + upkeepPrivilegeManager: PRIVILEGE_MANAGER, + chainModule: address(new ChainModuleBase()), + reorgProtectionEnabled: true, + financeAdmin: FINANCE_ADMIN + }); + registry.setConfigTypeSafe( + SIGNERS, + NEW_TRANSMITTERS, + F, + cfg, + OFFCHAIN_CONFIG_VERSION, + "", + billingTokenAddresses, + billingTokenConfigs + ); + registry.setPayees(NEW_PAYEES); + } +} + +contract WithdrawPayment is SetUp { + function testWithdrawPaymentRevertDueToOffchainPayoutMode() public { + registry = deployRegistry(AutoBase.PayoutMode.OFF_CHAIN); + vm.expectRevert(abi.encodeWithSelector(Registry.MustSettleOffchain.selector)); + vm.prank(TRANSMITTERS[0]); + registry.withdrawPayment(TRANSMITTERS[0], TRANSMITTERS[0]); + } +} + +contract RegisterUpkeep is SetUp { + function test_RevertsWhen_Paused() public { + registry.pause(); + vm.expectRevert(Registry.RegistryPaused.selector); + registry.registerUpkeep( + address(TARGET1), + config.maxPerformGas, + UPKEEP_ADMIN, + uint8(Trigger.CONDITION), + address(linkToken), + "", + "", + "" + ); + } + + function test_RevertsWhen_TargetIsNotAContract() public { + vm.expectRevert(Registry.NotAContract.selector); + registry.registerUpkeep( + randomAddress(), + config.maxPerformGas, + UPKEEP_ADMIN, + uint8(Trigger.CONDITION), + address(linkToken), + "", + "", + "" + ); + } + + function test_RevertsWhen_CalledByNonOwner() public { + vm.prank(STRANGER); + vm.expectRevert(Registry.OnlyCallableByOwnerOrRegistrar.selector); + registry.registerUpkeep( + address(TARGET1), + config.maxPerformGas, + UPKEEP_ADMIN, + uint8(Trigger.CONDITION), + address(linkToken), + "", + "", + "" + ); + } + + function test_RevertsWhen_ExecuteGasIsTooLow() public { + vm.expectRevert(Registry.GasLimitOutsideRange.selector); + registry.registerUpkeep( + address(TARGET1), + 2299, // 1 less than min + UPKEEP_ADMIN, + uint8(Trigger.CONDITION), + address(linkToken), + "", + "", + "" + ); + } + + function test_RevertsWhen_ExecuteGasIsTooHigh() public { + vm.expectRevert(Registry.GasLimitOutsideRange.selector); + registry.registerUpkeep( + address(TARGET1), + config.maxPerformGas + 1, + UPKEEP_ADMIN, + uint8(Trigger.CONDITION), + address(linkToken), + "", + "", + "" + ); + } + + function test_RevertsWhen_TheBillingTokenIsNotConfigured() public { + vm.expectRevert(Registry.InvalidToken.selector); + registry.registerUpkeep( + address(TARGET1), + config.maxPerformGas, + UPKEEP_ADMIN, + uint8(Trigger.CONDITION), + randomAddress(), + "", + "", + "" + ); + } + + function test_RevertsWhen_CheckDataIsTooLarge() public { + vm.expectRevert(Registry.CheckDataExceedsLimit.selector); + registry.registerUpkeep( + address(TARGET1), + config.maxPerformGas, + UPKEEP_ADMIN, + uint8(Trigger.CONDITION), + address(linkToken), + randomBytes(config.maxCheckDataSize + 1), + "", + "" + ); + } + + function test_Happy() public { + bytes memory checkData = randomBytes(config.maxCheckDataSize); + bytes memory trigggerConfig = randomBytes(100); + bytes memory offchainConfig = randomBytes(100); + + uint256 upkeepCount = registry.getNumUpkeeps(); + + uint256 upkeepID = registry.registerUpkeep( + address(TARGET1), + config.maxPerformGas, + UPKEEP_ADMIN, + uint8(Trigger.LOG), + address(linkToken), + checkData, + trigggerConfig, + offchainConfig + ); + + assertEq(registry.getNumUpkeeps(), upkeepCount + 1); + assertEq(registry.getUpkeep(upkeepID).target, address(TARGET1)); + assertEq(registry.getUpkeep(upkeepID).performGas, config.maxPerformGas); + assertEq(registry.getUpkeep(upkeepID).checkData, checkData); + assertEq(registry.getUpkeep(upkeepID).balance, 0); + assertEq(registry.getUpkeep(upkeepID).admin, UPKEEP_ADMIN); + assertEq(registry.getUpkeep(upkeepID).offchainConfig, offchainConfig); + assertEq(registry.getUpkeepTriggerConfig(upkeepID), trigggerConfig); + assertEq(uint8(registry.getTriggerType(upkeepID)), uint8(Trigger.LOG)); + } +} + +contract OnTokenTransfer is SetUp { + function test_RevertsWhen_NotCalledByTheLinkToken() public { + vm.expectRevert(Registry.OnlyCallableByLINKToken.selector); + registry.onTokenTransfer(UPKEEP_ADMIN, 100, abi.encode(linkUpkeepID)); + } + + function test_RevertsWhen_NotCalledWithExactly32Bytes() public { + vm.startPrank(address(linkToken)); + vm.expectRevert(Registry.InvalidDataLength.selector); + registry.onTokenTransfer(UPKEEP_ADMIN, 100, randomBytes(31)); + vm.expectRevert(Registry.InvalidDataLength.selector); + registry.onTokenTransfer(UPKEEP_ADMIN, 100, randomBytes(33)); + } + + function test_RevertsWhen_TheUpkeepIsCancelledOrDNE() public { + vm.startPrank(address(linkToken)); + vm.expectRevert(Registry.UpkeepCancelled.selector); + registry.onTokenTransfer(UPKEEP_ADMIN, 100, abi.encode(randomNumber())); + } + + function test_RevertsWhen_TheUpkeepDoesNotUseLINKAsItsBillingToken() public { + vm.startPrank(address(linkToken)); + vm.expectRevert(Registry.InvalidToken.selector); + registry.onTokenTransfer(UPKEEP_ADMIN, 100, abi.encode(usdUpkeepID)); + } + + function test_Happy() public { + vm.startPrank(address(linkToken)); + uint256 beforeBalance = registry.getBalance(linkUpkeepID); + registry.onTokenTransfer(UPKEEP_ADMIN, 100, abi.encode(linkUpkeepID)); + assertEq(registry.getBalance(linkUpkeepID), beforeBalance + 100); + } +} + +contract GetMinBalanceForUpkeep is SetUp { + function test_accountsForFlatFee() public { + // set fee to 0 + AutomationRegistryBase2_3.BillingConfig memory usdTokenConfig = registry.getBillingTokenConfig(address(usdToken)); + usdTokenConfig.flatFeeMilliCents = 0; + _updateBillingTokenConfig(registry, address(usdToken), usdTokenConfig); + + uint256 minBalanceBefore = registry.getMinBalanceForUpkeep(usdUpkeepID); + + // set fee to non-zero + usdTokenConfig.flatFeeMilliCents = 100; + _updateBillingTokenConfig(registry, address(usdToken), usdTokenConfig); + + uint256 minBalanceAfter = registry.getMinBalanceForUpkeep(usdUpkeepID); + assertEq(minBalanceAfter, minBalanceBefore + (uint256(usdTokenConfig.flatFeeMilliCents) * 1e13)); + } +} + +contract BillingOverrides is SetUp { + event BillingConfigOverridden(uint256 indexed id, AutomationRegistryBase2_3.BillingOverrides overrides); + event BillingConfigOverrideRemoved(uint256 indexed id); + + function test_RevertsWhen_NotPrivilegeManager() public { + AutomationRegistryBase2_3.BillingOverrides memory billingOverrides = AutomationRegistryBase2_3.BillingOverrides({ + gasFeePPB: 5_000, + flatFeeMilliCents: 20_000 + }); + + vm.expectRevert(Registry.OnlyCallableByUpkeepPrivilegeManager.selector); + registry.setBillingOverrides(linkUpkeepID, billingOverrides); + } + + function test_RevertsWhen_UpkeepCancelled() public { + AutomationRegistryBase2_3.BillingOverrides memory billingOverrides = AutomationRegistryBase2_3.BillingOverrides({ + gasFeePPB: 5_000, + flatFeeMilliCents: 20_000 + }); + + registry.cancelUpkeep(linkUpkeepID); + + vm.startPrank(PRIVILEGE_MANAGER); + vm.expectRevert(Registry.UpkeepCancelled.selector); + registry.setBillingOverrides(linkUpkeepID, billingOverrides); + } + + function test_Happy_SetBillingOverrides() public { + AutomationRegistryBase2_3.BillingOverrides memory billingOverrides = AutomationRegistryBase2_3.BillingOverrides({ + gasFeePPB: 5_000, + flatFeeMilliCents: 20_000 + }); + + vm.startPrank(PRIVILEGE_MANAGER); + + vm.expectEmit(); + emit BillingConfigOverridden(linkUpkeepID, billingOverrides); + registry.setBillingOverrides(linkUpkeepID, billingOverrides); + } + + function test_Happy_RemoveBillingOverrides() public { + vm.startPrank(PRIVILEGE_MANAGER); + + vm.expectEmit(); + emit BillingConfigOverrideRemoved(linkUpkeepID); + registry.removeBillingOverrides(linkUpkeepID); + } + + function test_Happy_MaxGasPayment_WithBillingOverrides() public { + uint96 maxPayment1 = registry.getMaxPaymentForGas(linkUpkeepID, 0, 5_000_000, address(linkToken)); + + // Double the two billing values + AutomationRegistryBase2_3.BillingOverrides memory billingOverrides = AutomationRegistryBase2_3.BillingOverrides({ + gasFeePPB: DEFAULT_GAS_FEE_PPB * 2, + flatFeeMilliCents: DEFAULT_FLAT_FEE_MILLI_CENTS * 2 + }); + + vm.startPrank(PRIVILEGE_MANAGER); + registry.setBillingOverrides(linkUpkeepID, billingOverrides); + + // maxPayment2 should be greater than maxPayment1 after the overrides + // The 2 numbers should follow this: maxPayment2 - maxPayment1 == 2 * recepit.premium + // We do not apply the exact equation since we couldn't get the receipt.premium value + uint96 maxPayment2 = registry.getMaxPaymentForGas(linkUpkeepID, 0, 5_000_000, address(linkToken)); + assertGt(maxPayment2, maxPayment1); + } +} + +contract Transmit is SetUp { + function test_handlesMixedBatchOfBillingTokens() external { + uint256[] memory prevUpkeepBalances = new uint256[](3); + prevUpkeepBalances[0] = registry.getBalance(linkUpkeepID); + prevUpkeepBalances[1] = registry.getBalance(usdUpkeepID); + prevUpkeepBalances[2] = registry.getBalance(nativeUpkeepID); + uint256[] memory prevTokenBalances = new uint256[](3); + prevTokenBalances[0] = linkToken.balanceOf(address(registry)); + prevTokenBalances[1] = usdToken.balanceOf(address(registry)); + prevTokenBalances[2] = weth.balanceOf(address(registry)); + uint256[] memory prevReserveBalances = new uint256[](3); + prevReserveBalances[0] = registry.getReserveAmount(address(linkToken)); + prevReserveBalances[1] = registry.getReserveAmount(address(usdToken)); + prevReserveBalances[2] = registry.getReserveAmount(address(weth)); + uint256[] memory upkeepIDs = new uint256[](3); + upkeepIDs[0] = linkUpkeepID; + upkeepIDs[1] = usdUpkeepID; + upkeepIDs[2] = nativeUpkeepID; + // do the thing + _transmit(upkeepIDs, registry); + // assert upkeep balances have decreased + require(prevUpkeepBalances[0] > registry.getBalance(linkUpkeepID), "link upkeep balance should have decreased"); + require(prevUpkeepBalances[1] > registry.getBalance(usdUpkeepID), "usd upkeep balance should have decreased"); + require(prevUpkeepBalances[2] > registry.getBalance(nativeUpkeepID), "native upkeep balance should have decreased"); + // assert token balances have not changed + assertEq(prevTokenBalances[0], linkToken.balanceOf(address(registry))); + assertEq(prevTokenBalances[1], usdToken.balanceOf(address(registry))); + assertEq(prevTokenBalances[2], weth.balanceOf(address(registry))); + // assert reserve amounts have adjusted accordingly + require( + prevReserveBalances[0] < registry.getReserveAmount(address(linkToken)), + "usd reserve amount should have increased" + ); // link reserve amount increases in value equal to the decrease of the other reserve amounts + require( + prevReserveBalances[1] > registry.getReserveAmount(address(usdToken)), + "usd reserve amount should have decreased" + ); + require( + prevReserveBalances[2] > registry.getReserveAmount(address(weth)), + "native reserve amount should have decreased" + ); + } +} + +contract MigrateReceive is SetUp { + event UpkeepMigrated(uint256 indexed id, uint256 remainingBalance, address destination); + event UpkeepReceived(uint256 indexed id, uint256 startingBalance, address importedFrom); + + Registry newRegistry; + uint256[] idsToMigrate; + + function setUp() public override { + super.setUp(); + (newRegistry, ) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.ON_CHAIN); + idsToMigrate.push(linkUpkeepID); + idsToMigrate.push(usdUpkeepID); + idsToMigrate.push(nativeUpkeepID); + registry.setPeerRegistryMigrationPermission(address(newRegistry), 1); + newRegistry.setPeerRegistryMigrationPermission(address(registry), 2); + } + + function test_RevertsWhen_PermissionsNotSet() external { + // no permissions + registry.setPeerRegistryMigrationPermission(address(newRegistry), 0); + newRegistry.setPeerRegistryMigrationPermission(address(registry), 0); + vm.expectRevert(Registry.MigrationNotPermitted.selector); + vm.prank(UPKEEP_ADMIN); + registry.migrateUpkeeps(idsToMigrate, address(newRegistry)); + + // only outgoing permissions + registry.setPeerRegistryMigrationPermission(address(newRegistry), 1); + newRegistry.setPeerRegistryMigrationPermission(address(registry), 0); + vm.expectRevert(Registry.MigrationNotPermitted.selector); + vm.prank(UPKEEP_ADMIN); + registry.migrateUpkeeps(idsToMigrate, address(newRegistry)); + + // only incoming permissions + registry.setPeerRegistryMigrationPermission(address(newRegistry), 0); + newRegistry.setPeerRegistryMigrationPermission(address(registry), 2); + vm.expectRevert(Registry.MigrationNotPermitted.selector); + vm.prank(UPKEEP_ADMIN); + registry.migrateUpkeeps(idsToMigrate, address(newRegistry)); + + // permissions opposite direction + registry.setPeerRegistryMigrationPermission(address(newRegistry), 2); + newRegistry.setPeerRegistryMigrationPermission(address(registry), 1); + vm.expectRevert(Registry.MigrationNotPermitted.selector); + vm.prank(UPKEEP_ADMIN); + registry.migrateUpkeeps(idsToMigrate, address(newRegistry)); + } + + function test_RevertsWhen_ReceivingRegistryDoesNotSupportToken() external { + _removeBillingTokenConfig(newRegistry, address(weth)); + vm.expectRevert(Registry.InvalidToken.selector); + vm.prank(UPKEEP_ADMIN); + registry.migrateUpkeeps(idsToMigrate, address(newRegistry)); + idsToMigrate.pop(); // remove native upkeep id + vm.prank(UPKEEP_ADMIN); + registry.migrateUpkeeps(idsToMigrate, address(newRegistry)); // should succeed now + } + + function test_RevertsWhen_CalledByNonAdmin() external { + vm.expectRevert(Registry.OnlyCallableByAdmin.selector); + vm.prank(STRANGER); + registry.migrateUpkeeps(idsToMigrate, address(newRegistry)); + } + + function test_Success() external { + vm.startPrank(UPKEEP_ADMIN); + + // add some changes in upkeep data to the mix + registry.pauseUpkeep(usdUpkeepID); + registry.setUpkeepTriggerConfig(linkUpkeepID, randomBytes(100)); + registry.setUpkeepCheckData(nativeUpkeepID, randomBytes(25)); + + // record previous state + uint256[] memory prevUpkeepBalances = new uint256[](3); + prevUpkeepBalances[0] = registry.getBalance(linkUpkeepID); + prevUpkeepBalances[1] = registry.getBalance(usdUpkeepID); + prevUpkeepBalances[2] = registry.getBalance(nativeUpkeepID); + uint256[] memory prevReserveBalances = new uint256[](3); + prevReserveBalances[0] = registry.getReserveAmount(address(linkToken)); + prevReserveBalances[1] = registry.getReserveAmount(address(usdToken)); + prevReserveBalances[2] = registry.getReserveAmount(address(weth)); + uint256[] memory prevTokenBalances = new uint256[](3); + prevTokenBalances[0] = linkToken.balanceOf(address(registry)); + prevTokenBalances[1] = usdToken.balanceOf(address(registry)); + prevTokenBalances[2] = weth.balanceOf(address(registry)); + bytes[] memory prevUpkeepData = new bytes[](3); + prevUpkeepData[0] = abi.encode(registry.getUpkeep(linkUpkeepID)); + prevUpkeepData[1] = abi.encode(registry.getUpkeep(usdUpkeepID)); + prevUpkeepData[2] = abi.encode(registry.getUpkeep(nativeUpkeepID)); + bytes[] memory prevUpkeepTriggerData = new bytes[](3); + prevUpkeepTriggerData[0] = registry.getUpkeepTriggerConfig(linkUpkeepID); + prevUpkeepTriggerData[1] = registry.getUpkeepTriggerConfig(usdUpkeepID); + prevUpkeepTriggerData[2] = registry.getUpkeepTriggerConfig(nativeUpkeepID); + + // event expectations + vm.expectEmit(address(registry)); + emit UpkeepMigrated(linkUpkeepID, prevUpkeepBalances[0], address(newRegistry)); + vm.expectEmit(address(registry)); + emit UpkeepMigrated(usdUpkeepID, prevUpkeepBalances[1], address(newRegistry)); + vm.expectEmit(address(registry)); + emit UpkeepMigrated(nativeUpkeepID, prevUpkeepBalances[2], address(newRegistry)); + vm.expectEmit(address(newRegistry)); + emit UpkeepReceived(linkUpkeepID, prevUpkeepBalances[0], address(registry)); + vm.expectEmit(address(newRegistry)); + emit UpkeepReceived(usdUpkeepID, prevUpkeepBalances[1], address(registry)); + vm.expectEmit(address(newRegistry)); + emit UpkeepReceived(nativeUpkeepID, prevUpkeepBalances[2], address(registry)); + + // do the thing + registry.migrateUpkeeps(idsToMigrate, address(newRegistry)); + + // assert upkeep balances have been migrated + assertEq(registry.getBalance(linkUpkeepID), 0); + assertEq(registry.getBalance(usdUpkeepID), 0); + assertEq(registry.getBalance(nativeUpkeepID), 0); + assertEq(newRegistry.getBalance(linkUpkeepID), prevUpkeepBalances[0]); + assertEq(newRegistry.getBalance(usdUpkeepID), prevUpkeepBalances[1]); + assertEq(newRegistry.getBalance(nativeUpkeepID), prevUpkeepBalances[2]); + + // assert reserve balances have been adjusted + assertEq(newRegistry.getReserveAmount(address(linkToken)), newRegistry.getBalance(linkUpkeepID)); + assertEq(newRegistry.getReserveAmount(address(usdToken)), newRegistry.getBalance(usdUpkeepID)); + assertEq(newRegistry.getReserveAmount(address(weth)), newRegistry.getBalance(nativeUpkeepID)); + assertEq( + newRegistry.getReserveAmount(address(linkToken)), + prevReserveBalances[0] - registry.getReserveAmount(address(linkToken)) + ); + assertEq( + newRegistry.getReserveAmount(address(usdToken)), + prevReserveBalances[1] - registry.getReserveAmount(address(usdToken)) + ); + assertEq( + newRegistry.getReserveAmount(address(weth)), + prevReserveBalances[2] - registry.getReserveAmount(address(weth)) + ); + + // assert token have been transfered + assertEq(linkToken.balanceOf(address(newRegistry)), newRegistry.getBalance(linkUpkeepID)); + assertEq(usdToken.balanceOf(address(newRegistry)), newRegistry.getBalance(usdUpkeepID)); + assertEq(weth.balanceOf(address(newRegistry)), newRegistry.getBalance(nativeUpkeepID)); + assertEq(linkToken.balanceOf(address(registry)), prevTokenBalances[0] - linkToken.balanceOf(address(newRegistry))); + assertEq(usdToken.balanceOf(address(registry)), prevTokenBalances[1] - usdToken.balanceOf(address(newRegistry))); + assertEq(weth.balanceOf(address(registry)), prevTokenBalances[2] - weth.balanceOf(address(newRegistry))); + + // assert upkeep data matches + assertEq(prevUpkeepData[0], abi.encode(newRegistry.getUpkeep(linkUpkeepID))); + assertEq(prevUpkeepData[1], abi.encode(newRegistry.getUpkeep(usdUpkeepID))); + assertEq(prevUpkeepData[2], abi.encode(newRegistry.getUpkeep(nativeUpkeepID))); + assertEq(prevUpkeepTriggerData[0], newRegistry.getUpkeepTriggerConfig(linkUpkeepID)); + assertEq(prevUpkeepTriggerData[1], newRegistry.getUpkeepTriggerConfig(usdUpkeepID)); + assertEq(prevUpkeepTriggerData[2], newRegistry.getUpkeepTriggerConfig(nativeUpkeepID)); + + vm.stopPrank(); + } +} diff --git a/contracts/src/v0.8/automation/dev/test/BaseTest.t.sol b/contracts/src/v0.8/automation/dev/test/BaseTest.t.sol index 790afcff4c7..eae07a8bab7 100644 --- a/contracts/src/v0.8/automation/dev/test/BaseTest.t.sol +++ b/contracts/src/v0.8/automation/dev/test/BaseTest.t.sol @@ -3,11 +3,453 @@ pragma solidity 0.8.19; import "forge-std/Test.sol"; +import {LinkToken} from "../../../shared/token/ERC677/LinkToken.sol"; +import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol"; +import {MockV3Aggregator} from "../../../tests/MockV3Aggregator.sol"; +import {AutomationForwarderLogic} from "../../AutomationForwarderLogic.sol"; +import {UpkeepTranscoder5_0 as Transcoder} from "../v2_3/UpkeepTranscoder5_0.sol"; +import {AutomationRegistry2_3} from "../v2_3/AutomationRegistry2_3.sol"; +import {AutomationRegistryBase2_3 as AutoBase} from "../v2_3/AutomationRegistryBase2_3.sol"; +import {AutomationRegistryLogicA2_3} from "../v2_3/AutomationRegistryLogicA2_3.sol"; +import {AutomationRegistryLogicB2_3} from "../v2_3/AutomationRegistryLogicB2_3.sol"; +import {AutomationRegistryLogicC2_3} from "../v2_3/AutomationRegistryLogicC2_3.sol"; +import {IAutomationRegistryMaster2_3 as Registry, AutomationRegistryBase2_3} from "../interfaces/v2_3/IAutomationRegistryMaster2_3.sol"; +import {AutomationRegistrar2_3} from "../v2_3/AutomationRegistrar2_3.sol"; +import {ChainModuleBase} from "../../chains/ChainModuleBase.sol"; +import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {MockUpkeep} from "../../mocks/MockUpkeep.sol"; +import {IWrappedNative} from "../interfaces/v2_3/IWrappedNative.sol"; +import {WETH9} from "./WETH9.sol"; + +/** + * @title BaseTest provides basic test setup procedures and dependencies for use by other + * unit tests + */ contract BaseTest is Test { - address internal OWNER = 0x00007e64E1fB0C487F25dd6D3601ff6aF8d32e4e; + // test state (not exposed to derrived tests) + uint256 private nonce; + + // constants + address internal constant ZERO_ADDRESS = address(0); + uint32 internal constant DEFAULT_GAS_FEE_PPB = 10_000_000; + uint24 internal constant DEFAULT_FLAT_FEE_MILLI_CENTS = 2_000; + + // config + uint8 internal constant F = 1; // number of faulty nodes + uint64 internal constant OFFCHAIN_CONFIG_VERSION = 30; // 2 for OCR2 + + // contracts + LinkToken internal linkToken; + ERC20Mock internal usdToken; + WETH9 internal weth; + MockV3Aggregator internal LINK_USD_FEED; + MockV3Aggregator internal NATIVE_USD_FEED; + MockV3Aggregator internal USDTOKEN_USD_FEED; + MockV3Aggregator internal FAST_GAS_FEED; + MockUpkeep internal TARGET1; + MockUpkeep internal TARGET2; + Transcoder internal TRANSCODER; + + // roles + address internal constant OWNER = address(uint160(uint256(keccak256("OWNER")))); + address internal constant UPKEEP_ADMIN = address(uint160(uint256(keccak256("UPKEEP_ADMIN")))); + address internal constant FINANCE_ADMIN = address(uint160(uint256(keccak256("FINANCE_ADMIN")))); + address internal constant STRANGER = address(uint160(uint256(keccak256("STRANGER")))); + address internal constant BROKE_USER = address(uint160(uint256(keccak256("BROKE_USER")))); // do not mint to this address + address internal constant PRIVILEGE_MANAGER = address(uint160(uint256(keccak256("PRIVILEGE_MANAGER")))); + + // nodes + uint256 internal constant SIGNING_KEY0 = 0x7b2e97fe057e6de99d6872a2ef2abf52c9b4469bc848c2465ac3fcd8d336e81d; + uint256 internal constant SIGNING_KEY1 = 0xab56160806b05ef1796789248e1d7f34a6465c5280899159d645218cd216cee6; + uint256 internal constant SIGNING_KEY2 = 0x6ec7caa8406a49b76736602810e0a2871959fbbb675e23a8590839e4717f1f7f; + uint256 internal constant SIGNING_KEY3 = 0x80f14b11da94ae7f29d9a7713ea13dc838e31960a5c0f2baf45ed458947b730a; + address[] internal SIGNERS = new address[](4); + address[] internal TRANSMITTERS = new address[](4); + address[] internal NEW_TRANSMITTERS = new address[](4); + address[] internal PAYEES = new address[](4); + address[] internal NEW_PAYEES = new address[](4); function setUp() public virtual { vm.startPrank(OWNER); - deal(OWNER, 1e20); + linkToken = new LinkToken(); + linkToken.grantMintRole(OWNER); + usdToken = new ERC20Mock("MOCK_ERC20", "MOCK_ERC20", OWNER, 0); + weth = new WETH9(); + + LINK_USD_FEED = new MockV3Aggregator(8, 2_000_000_000); // $20 + NATIVE_USD_FEED = new MockV3Aggregator(8, 400_000_000_000); // $4,000 + USDTOKEN_USD_FEED = new MockV3Aggregator(8, 100_000_000); // $1 + FAST_GAS_FEED = new MockV3Aggregator(0, 1_000_000_000); // 1 gwei + + TARGET1 = new MockUpkeep(); + TARGET2 = new MockUpkeep(); + + TRANSCODER = new Transcoder(); + + SIGNERS[0] = vm.addr(SIGNING_KEY0); //0xc110458BE52CaA6bB68E66969C3218A4D9Db0211 + SIGNERS[1] = vm.addr(SIGNING_KEY1); //0xc110a19c08f1da7F5FfB281dc93630923F8E3719 + SIGNERS[2] = vm.addr(SIGNING_KEY2); //0xc110fdF6e8fD679C7Cc11602d1cd829211A18e9b + SIGNERS[3] = vm.addr(SIGNING_KEY3); //0xc11028017c9b445B6bF8aE7da951B5cC28B326C0 + + TRANSMITTERS[0] = address(uint160(uint256(keccak256("TRANSMITTER1")))); + TRANSMITTERS[1] = address(uint160(uint256(keccak256("TRANSMITTER2")))); + TRANSMITTERS[2] = address(uint160(uint256(keccak256("TRANSMITTER3")))); + TRANSMITTERS[3] = address(uint160(uint256(keccak256("TRANSMITTER4")))); + NEW_TRANSMITTERS[0] = address(uint160(uint256(keccak256("TRANSMITTER1")))); + NEW_TRANSMITTERS[1] = address(uint160(uint256(keccak256("TRANSMITTER2")))); + NEW_TRANSMITTERS[2] = address(uint160(uint256(keccak256("TRANSMITTER5")))); + NEW_TRANSMITTERS[3] = address(uint160(uint256(keccak256("TRANSMITTER6")))); + + PAYEES[0] = address(100); + PAYEES[1] = address(101); + PAYEES[2] = address(102); + PAYEES[3] = address(103); + NEW_PAYEES[0] = address(100); + NEW_PAYEES[1] = address(101); + NEW_PAYEES[2] = address(106); + NEW_PAYEES[3] = address(107); + + // mint funds + vm.deal(OWNER, 100 ether); + vm.deal(UPKEEP_ADMIN, 100 ether); + vm.deal(FINANCE_ADMIN, 100 ether); + vm.deal(STRANGER, 100 ether); + linkToken.mint(OWNER, 1000e18); + linkToken.mint(UPKEEP_ADMIN, 1000e18); + linkToken.mint(FINANCE_ADMIN, 1000e18); + linkToken.mint(STRANGER, 1000e18); + usdToken.mint(OWNER, 1000e18); + usdToken.mint(UPKEEP_ADMIN, 1000e18); + usdToken.mint(FINANCE_ADMIN, 1000e18); + usdToken.mint(STRANGER, 1000e18); + weth.mint(OWNER, 1000e18); + weth.mint(UPKEEP_ADMIN, 1000e18); + weth.mint(FINANCE_ADMIN, 1000e18); + weth.mint(STRANGER, 1000e18); + + vm.stopPrank(); + } + + /// @notice deploys the component parts of a registry, but nothing more + function deployRegistry(AutoBase.PayoutMode payoutMode) internal returns (Registry) { + AutomationForwarderLogic forwarderLogic = new AutomationForwarderLogic(); + AutomationRegistryLogicC2_3 logicC2_3 = new AutomationRegistryLogicC2_3( + address(linkToken), + address(LINK_USD_FEED), + address(NATIVE_USD_FEED), + address(FAST_GAS_FEED), + address(forwarderLogic), + ZERO_ADDRESS, + payoutMode, + address(weth) + ); + AutomationRegistryLogicB2_3 logicB2_3 = new AutomationRegistryLogicB2_3(logicC2_3); + AutomationRegistryLogicA2_3 logicA2_3 = new AutomationRegistryLogicA2_3(logicB2_3); + return Registry(payable(address(new AutomationRegistry2_3(logicA2_3)))); + } + + /// @notice deploys and configures a registry, registrar, and everything needed for most tests + function deployAndConfigureRegistryAndRegistrar( + AutoBase.PayoutMode payoutMode + ) internal returns (Registry, AutomationRegistrar2_3) { + Registry registry = deployRegistry(payoutMode); + + IERC20[] memory billingTokens = new IERC20[](3); + billingTokens[0] = IERC20(address(usdToken)); + billingTokens[1] = IERC20(address(weth)); + billingTokens[2] = IERC20(address(linkToken)); + uint256[] memory minRegistrationFees = new uint256[](billingTokens.length); + minRegistrationFees[0] = 100000000000000000000; // 100 USD + minRegistrationFees[1] = 5000000000000000000; // 5 Native + minRegistrationFees[2] = 5000000000000000000; // 5 LINK + address[] memory billingTokenAddresses = new address[](billingTokens.length); + for (uint256 i = 0; i < billingTokens.length; i++) { + billingTokenAddresses[i] = address(billingTokens[i]); + } + AutomationRegistryBase2_3.BillingConfig[] + memory billingTokenConfigs = new AutomationRegistryBase2_3.BillingConfig[](billingTokens.length); + billingTokenConfigs[0] = AutomationRegistryBase2_3.BillingConfig({ + gasFeePPB: DEFAULT_GAS_FEE_PPB, // 15% + flatFeeMilliCents: DEFAULT_FLAT_FEE_MILLI_CENTS, // 2 cents + priceFeed: address(USDTOKEN_USD_FEED), + fallbackPrice: 100_000_000, // $1 + minSpend: 1000000000000000000 // 1 USD + }); + billingTokenConfigs[1] = AutomationRegistryBase2_3.BillingConfig({ + gasFeePPB: DEFAULT_GAS_FEE_PPB, // 15% + flatFeeMilliCents: DEFAULT_FLAT_FEE_MILLI_CENTS, // 2 cents + priceFeed: address(NATIVE_USD_FEED), + fallbackPrice: 100_000_000, // $1 + minSpend: 5000000000000000000 // 5 Native + }); + billingTokenConfigs[2] = AutomationRegistryBase2_3.BillingConfig({ + gasFeePPB: DEFAULT_GAS_FEE_PPB, // 10% + flatFeeMilliCents: DEFAULT_FLAT_FEE_MILLI_CENTS, // 2 cents + priceFeed: address(LINK_USD_FEED), + fallbackPrice: 1_000_000_000, // $10 + minSpend: 1000000000000000000 // 1 LINK + }); + + if (payoutMode == AutoBase.PayoutMode.OFF_CHAIN) { + // remove LINK as a payment method if we are settling offchain + assembly { + mstore(billingTokens, 2) + mstore(minRegistrationFees, 2) + mstore(billingTokenAddresses, 2) + mstore(billingTokenConfigs, 2) + } + } + + // deploy registrar + AutomationRegistrar2_3.InitialTriggerConfig[] + memory triggerConfigs = new AutomationRegistrar2_3.InitialTriggerConfig[](2); + triggerConfigs[0] = AutomationRegistrar2_3.InitialTriggerConfig({ + triggerType: 0, // condition + autoApproveType: AutomationRegistrar2_3.AutoApproveType.DISABLED, + autoApproveMaxAllowed: 0 + }); + triggerConfigs[1] = AutomationRegistrar2_3.InitialTriggerConfig({ + triggerType: 1, // log + autoApproveType: AutomationRegistrar2_3.AutoApproveType.DISABLED, + autoApproveMaxAllowed: 0 + }); + AutomationRegistrar2_3 registrar = new AutomationRegistrar2_3( + address(linkToken), + registry, + triggerConfigs, + billingTokens, + minRegistrationFees, + IWrappedNative(address(weth)) + ); + + address[] memory registrars; + registrars = new address[](1); + registrars[0] = address(registrar); + + AutomationRegistryBase2_3.OnchainConfig memory cfg = AutomationRegistryBase2_3.OnchainConfig({ + checkGasLimit: 5_000_000, + stalenessSeconds: 90_000, + gasCeilingMultiplier: 2, + maxPerformGas: 10_000_000, + maxCheckDataSize: 5_000, + maxPerformDataSize: 5_000, + maxRevertDataSize: 5_000, + fallbackGasPrice: 20_000_000_000, + fallbackLinkPrice: 2_000_000_000, // $20 + fallbackNativePrice: 400_000_000_000, // $4,000 + transcoder: address(TRANSCODER), + registrars: registrars, + upkeepPrivilegeManager: PRIVILEGE_MANAGER, + chainModule: address(new ChainModuleBase()), + reorgProtectionEnabled: true, + financeAdmin: FINANCE_ADMIN + }); + + registry.setConfigTypeSafe( + SIGNERS, + TRANSMITTERS, + F, + cfg, + OFFCHAIN_CONFIG_VERSION, + "", + billingTokenAddresses, + billingTokenConfigs + ); + registry.setPayees(PAYEES); + return (registry, registrar); + } + + /// @notice this function updates the billing config for the provided token on the provided registry, + /// and throws an error if the token is not found + function _updateBillingTokenConfig( + Registry registry, + address billingToken, + AutomationRegistryBase2_3.BillingConfig memory newConfig + ) internal { + (, , address[] memory signers, address[] memory transmitters, uint8 f) = registry.getState(); + AutomationRegistryBase2_3.OnchainConfig memory config = registry.getConfig(); + address[] memory billingTokens = registry.getBillingTokens(); + + AutomationRegistryBase2_3.BillingConfig[] + memory billingTokenConfigs = new AutomationRegistryBase2_3.BillingConfig[](billingTokens.length); + + bool found = false; + for (uint256 i = 0; i < billingTokens.length; i++) { + if (billingTokens[i] == billingToken) { + found = true; + billingTokenConfigs[i] = newConfig; + } else { + billingTokenConfigs[i] = registry.getBillingTokenConfig(billingTokens[i]); + } + } + require(found, "could not find billing token provided on registry"); + + registry.setConfigTypeSafe( + signers, + transmitters, + f, + config, + OFFCHAIN_CONFIG_VERSION, + "", + billingTokens, + billingTokenConfigs + ); + } + + /// @notice this function removes a billing token from the registry + function _removeBillingTokenConfig(Registry registry, address billingToken) internal { + (, , address[] memory signers, address[] memory transmitters, uint8 f) = registry.getState(); + AutomationRegistryBase2_3.OnchainConfig memory config = registry.getConfig(); + address[] memory billingTokens = registry.getBillingTokens(); + + address[] memory newBillingTokens = new address[](billingTokens.length - 1); + AutomationRegistryBase2_3.BillingConfig[] + memory billingTokenConfigs = new AutomationRegistryBase2_3.BillingConfig[](billingTokens.length - 1); + + uint256 j = 0; + for (uint256 i = 0; i < billingTokens.length; i++) { + if (billingTokens[i] != billingToken) { + if (j == newBillingTokens.length) revert("could not find billing token provided on registry"); + newBillingTokens[j] = billingTokens[i]; + billingTokenConfigs[j] = registry.getBillingTokenConfig(billingTokens[i]); + j++; + } + } + + registry.setConfigTypeSafe( + signers, + transmitters, + f, + config, + OFFCHAIN_CONFIG_VERSION, + "", + newBillingTokens, + billingTokenConfigs + ); + } + + function _transmit(uint256 id, Registry registry) internal { + uint256[] memory ids = new uint256[](1); + ids[0] = id; + _transmit(ids, registry); + } + + function _transmit(uint256[] memory ids, Registry registry) internal { + uint256[] memory upkeepIds = new uint256[](ids.length); + uint256[] memory gasLimits = new uint256[](ids.length); + bytes[] memory performDatas = new bytes[](ids.length); + bytes[] memory triggers = new bytes[](ids.length); + for (uint256 i = 0; i < ids.length; i++) { + upkeepIds[i] = ids[i]; + gasLimits[i] = registry.getUpkeep(ids[i]).performGas; + performDatas[i] = new bytes(0); + uint8 triggerType = registry.getTriggerType(ids[i]); + if (triggerType == 0) { + triggers[i] = _encodeConditionalTrigger( + AutoBase.ConditionalTrigger(uint32(block.number - 1), blockhash(block.number - 1)) + ); + } else { + revert("not implemented"); + } + } + AutoBase.Report memory report = AutoBase.Report( + uint256(1000000000), + uint256(2000000000), + upkeepIds, + gasLimits, + triggers, + performDatas + ); + + bytes memory reportBytes = _encodeReport(report); + (, , bytes32 configDigest) = registry.latestConfigDetails(); + bytes32[3] memory reportContext = [configDigest, configDigest, configDigest]; + uint256[] memory signerPKs = new uint256[](2); + signerPKs[0] = SIGNING_KEY0; + signerPKs[1] = SIGNING_KEY1; + (bytes32[] memory rs, bytes32[] memory ss, bytes32 vs) = _signReport(reportBytes, reportContext, signerPKs); + + vm.startPrank(TRANSMITTERS[0]); + registry.transmit(reportContext, reportBytes, rs, ss, vs); + vm.stopPrank(); + } + + /// @notice Gather signatures on report data + /// @param report - Report bytes generated from `_buildReport` + /// @param reportContext - Report context bytes32 generated from `_buildReport` + /// @param signerPrivateKeys - One or more addresses that will sign the report data + /// @return rawRs - Signature rs + /// @return rawSs - Signature ss + /// @return rawVs - Signature vs + function _signReport( + bytes memory report, + bytes32[3] memory reportContext, + uint256[] memory signerPrivateKeys + ) internal pure returns (bytes32[] memory, bytes32[] memory, bytes32) { + bytes32[] memory rs = new bytes32[](signerPrivateKeys.length); + bytes32[] memory ss = new bytes32[](signerPrivateKeys.length); + bytes memory vs = new bytes(signerPrivateKeys.length); + + bytes32 reportDigest = keccak256(abi.encodePacked(keccak256(report), reportContext)); + + for (uint256 i = 0; i < signerPrivateKeys.length; i++) { + (uint8 v, bytes32 r, bytes32 s) = vm.sign(signerPrivateKeys[i], reportDigest); + rs[i] = r; + ss[i] = s; + vs[i] = bytes1(v - 27); + } + + return (rs, ss, bytes32(vs)); + } + + function _encodeReport(AutoBase.Report memory report) internal pure returns (bytes memory reportBytes) { + return abi.encode(report); + } + + function _encodeConditionalTrigger( + AutoBase.ConditionalTrigger memory trigger + ) internal pure returns (bytes memory triggerBytes) { + return abi.encode(trigger.blockNum, trigger.blockHash); + } + + /// @dev mints LINK to the recipient + function _mintLink(address recipient, uint256 amount) internal { + vm.prank(OWNER); + linkToken.mint(recipient, amount); + } + + /// @dev mints USDToken to the recipient + function _mintERC20(address recipient, uint256 amount) internal { + vm.prank(OWNER); + usdToken.mint(recipient, amount); + } + + /// @dev returns a pseudo-random 32 bytes + function _random() private returns (bytes32) { + nonce++; + return keccak256(abi.encode(block.timestamp, nonce)); + } + + /// @dev returns a pseudo-random number + function randomNumber() internal returns (uint256) { + return uint256(_random()); + } + + /// @dev returns a pseudo-random address + function randomAddress() internal returns (address) { + return address(uint160(randomNumber())); + } + + /// @dev returns a pseudo-random byte array + function randomBytes(uint256 length) internal returns (bytes memory) { + bytes memory result = new bytes(length); + bytes32 entropy; + for (uint256 i = 0; i < length; i++) { + if (i % 32 == 0) { + entropy = _random(); + } + result[i] = entropy[i % 32]; + } + return result; } } diff --git a/contracts/src/v0.8/automation/dev/test/WETH9.sol b/contracts/src/v0.8/automation/dev/test/WETH9.sol new file mode 100644 index 00000000000..b8452d832b0 --- /dev/null +++ b/contracts/src/v0.8/automation/dev/test/WETH9.sol @@ -0,0 +1,93 @@ +// Submitted for verification at Etherscan.io on 2017-12-12 + +// Copyright (C) 2015, 2016, 2017 Dapphub + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +pragma solidity 0.8.19; + +contract WETH9 { + string public name = "Wrapped Ether"; + string public symbol = "WETH"; + uint8 public decimals = 18; + + event Approval(address indexed src, address indexed guy, uint256 wad); + event Transfer(address indexed src, address indexed dst, uint256 wad); + event Deposit(address indexed dst, uint256 wad); + event Withdrawal(address indexed src, uint256 wad); + + error InsufficientBalance(); + + mapping(address => uint256) public balanceOf; + mapping(address => mapping(address => uint256)) public allowance; + + receive() external payable { + _deposit(); + } + + function _deposit() internal { + balanceOf[msg.sender] += msg.value; + emit Deposit(msg.sender, msg.value); + } + + function deposit() external payable { + _deposit(); + } + + function mint(address account, uint256 amount) public { + balanceOf[account] += amount; + } + + function withdraw(uint256 wad) external { + if (balanceOf[msg.sender] < wad) { + revert InsufficientBalance(); + } + balanceOf[msg.sender] -= wad; + payable(msg.sender).transfer(wad); + emit Withdrawal(msg.sender, wad); + } + + function totalSupply() public view returns (uint256) { + return address(this).balance; + } + + function approve(address guy, uint256 wad) public returns (bool) { + allowance[msg.sender][guy] = wad; + emit Approval(msg.sender, guy, wad); + return true; + } + + function transfer(address dst, uint256 wad) public returns (bool) { + return transferFrom(msg.sender, dst, wad); + } + + function transferFrom(address src, address dst, uint256 wad) public returns (bool) { + if (balanceOf[src] < wad) { + revert InsufficientBalance(); + } + + if (src != msg.sender && allowance[src][msg.sender] != type(uint128).max) { + if (allowance[src][msg.sender] < wad) { + revert InsufficientBalance(); + } + allowance[src][msg.sender] -= wad; + } + + balanceOf[src] -= wad; + balanceOf[dst] += wad; + + emit Transfer(src, dst, wad); + + return true; + } +} diff --git a/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistrar2_3.sol b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistrar2_3.sol index 6614a5faaa5..ed0dd717998 100644 --- a/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistrar2_3.sol +++ b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistrar2_3.sol @@ -6,6 +6,9 @@ import {IAutomationRegistryMaster2_3} from "../interfaces/v2_3/IAutomationRegist import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; import {IERC677Receiver} from "../../../shared/interfaces/IERC677Receiver.sol"; +import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {IWrappedNative} from "../interfaces/v2_3/IWrappedNative.sol"; +import {SafeCast} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SafeCast.sol"; /** * @notice Contract to accept requests for upkeep registrations @@ -29,13 +32,6 @@ contract AutomationRegistrar2_3 is TypeAndVersionInterface, ConfirmedOwner, IERC ENABLED_ALL } - bytes4 private constant REGISTER_REQUEST_SELECTOR = this.register.selector; - - mapping(bytes32 => PendingRequest) private s_pendingRequests; - mapping(uint8 => TriggerRegistrationStorage) private s_triggerRegistrations; - - LinkTokenInterface public immutable LINK; - /** * @notice versions: * - KeeperRegistrar 2.3.0: Update for compatability with registry 2.3.0 @@ -75,32 +71,49 @@ contract AutomationRegistrar2_3 is TypeAndVersionInterface, ConfirmedOwner, IERC uint32 autoApproveMaxAllowed; } - struct RegistrarConfig { - IAutomationRegistryMaster2_3 AutomationRegistry; - uint96 minLINKJuels; - } - struct PendingRequest { address admin; uint96 balance; } - + /** + * @member upkeepContract address to perform upkeep on + * @member amount quantity of LINK upkeep is funded with (specified in wei) + * @member adminAddress address to cancel upkeep and withdraw remaining funds + * @member gasLimit amount of gas to provide the target contract when performing upkeep + * @member triggerType the type of trigger for the upkeep + * @member billingToken the token to pay with + * @member name string of the upkeep to be registered + * @member encryptedEmail email address of upkeep contact + * @member checkData data passed to the contract when checking for upkeep + * @member triggerConfig the config for the trigger + * @member offchainConfig offchainConfig for upkeep in bytes + */ struct RegistrationParams { - string name; - bytes encryptedEmail; address upkeepContract; - uint32 gasLimit; + uint96 amount; + // 1 word full address adminAddress; + uint32 gasLimit; uint8 triggerType; + // 7 bytes left in 2nd word + IERC20 billingToken; + // 12 bytes left in 3rd word + string name; + bytes encryptedEmail; bytes checkData; bytes triggerConfig; bytes offchainConfig; - uint96 amount; } - RegistrarConfig private s_config; - // Only applicable if s_config.configType is ENABLED_SENDER_ALLOWLIST + LinkTokenInterface public immutable i_LINK; + IWrappedNative public immutable i_WRAPPED_NATIVE_TOKEN; + IAutomationRegistryMaster2_3 private s_registry; + + // Only applicable if trigger config is set to ENABLED_SENDER_ALLOWLIST mapping(address => bool) private s_autoApproveAllowedSenders; + mapping(IERC20 => uint256) private s_minRegistrationAmounts; + mapping(bytes32 => PendingRequest) private s_pendingRequests; + mapping(uint8 => TriggerRegistrationStorage) private s_triggerRegistrations; event RegistrationRequested( bytes32 indexed hash, @@ -122,37 +135,39 @@ contract AutomationRegistrar2_3 is TypeAndVersionInterface, ConfirmedOwner, IERC event AutoApproveAllowedSenderSet(address indexed senderAddress, bool allowed); - event ConfigChanged(address AutomationRegistry, uint96 minLINKJuels); + event ConfigChanged(); event TriggerConfigSet(uint8 triggerType, AutoApproveType autoApproveType, uint32 autoApproveMaxAllowed); - error InvalidAdminAddress(); - error RequestNotFound(); error HashMismatch(); - error OnlyAdminOrOwner(); error InsufficientPayment(); - error RegistrationRequestFailed(); - error OnlyLink(); - error AmountMismatch(); - error SenderMismatch(); - error FunctionNotPermitted(); - error LinkTransferFailed(address to); + error InvalidAdminAddress(); + error InvalidBillingToken(); error InvalidDataLength(); + error TransferFailed(address to); + error OnlyAdminOrOwner(); + error OnlyLink(); + error RequestNotFound(); /** * @param LINKAddress Address of Link token - * @param AutomationRegistry keeper registry address - * @param minLINKJuels minimum LINK that new registrations should fund their upkeep with + * @param registry keeper registry address * @param triggerConfigs the initial config for individual triggers + * @param billingTokens the tokens allowed for billing + * @param minRegistrationFees the minimum amount for registering with each billing token + * @param wrappedNativeToken wrapped native token */ constructor( address LINKAddress, - address AutomationRegistry, - uint96 minLINKJuels, - InitialTriggerConfig[] memory triggerConfigs + IAutomationRegistryMaster2_3 registry, + InitialTriggerConfig[] memory triggerConfigs, + IERC20[] memory billingTokens, + uint256[] memory minRegistrationFees, + IWrappedNative wrappedNativeToken ) ConfirmedOwner(msg.sender) { - LINK = LinkTokenInterface(LINKAddress); - setConfig(AutomationRegistry, minLINKJuels); + i_LINK = LinkTokenInterface(LINKAddress); + i_WRAPPED_NATIVE_TOKEN = wrappedNativeToken; + setConfig(registry, billingTokens, minRegistrationFees); for (uint256 idx = 0; idx < triggerConfigs.length; idx++) { setTriggerConfig( triggerConfigs[idx].triggerType, @@ -164,104 +179,41 @@ contract AutomationRegistrar2_3 is TypeAndVersionInterface, ConfirmedOwner, IERC //EXTERNAL - /** - * @notice register can only be called through transferAndCall on LINK contract - * @param name string of the upkeep to be registered - * @param encryptedEmail email address of upkeep contact - * @param upkeepContract address to perform upkeep on - * @param gasLimit amount of gas to provide the target contract when performing upkeep - * @param adminAddress address to cancel upkeep and withdraw remaining funds - * @param triggerType the type of trigger for the upkeep - * @param checkData data passed to the contract when checking for upkeep - * @param triggerConfig the config for the trigger - * @param offchainConfig offchainConfig for upkeep in bytes - * @param amount quantity of LINK upkeep is funded with (specified in Juels) - * @param sender address of the sender making the request - */ - function register( - string memory name, - bytes calldata encryptedEmail, - address upkeepContract, - uint32 gasLimit, - address adminAddress, - uint8 triggerType, - bytes memory checkData, - bytes memory triggerConfig, - bytes memory offchainConfig, - uint96 amount, - address sender - ) external onlyLINK { - _register( - RegistrationParams({ - name: name, - encryptedEmail: encryptedEmail, - upkeepContract: upkeepContract, - gasLimit: gasLimit, - adminAddress: adminAddress, - triggerType: triggerType, - checkData: checkData, - triggerConfig: triggerConfig, - offchainConfig: offchainConfig, - amount: amount - }), - sender - ); - } - /** * @notice Allows external users to register upkeeps; assumes amount is approved for transfer by the contract * @param requestParams struct of all possible registration parameters */ - function registerUpkeep(RegistrationParams calldata requestParams) external returns (uint256) { - if (requestParams.amount < s_config.minLINKJuels) { - revert InsufficientPayment(); + function registerUpkeep(RegistrationParams memory requestParams) external payable returns (uint256) { + if (requestParams.billingToken == IERC20(i_WRAPPED_NATIVE_TOKEN) && msg.value != 0) { + requestParams.amount = SafeCast.toUint96(msg.value); + // wrap and send native payment + i_WRAPPED_NATIVE_TOKEN.deposit{value: msg.value}(); + } else { + // send ERC20 payment, including wrapped native token + if (!requestParams.billingToken.transferFrom(msg.sender, address(this), requestParams.amount)) { + revert TransferFailed(address(this)); + } } - LINK.transferFrom(msg.sender, address(this), requestParams.amount); - return _register(requestParams, msg.sender); } /** * @dev register upkeep on AutomationRegistry contract and emit RegistrationApproved event + * @param requestParams struct of all possible registration parameters + * @param hash the committment of the registration request */ - function approve( - string memory name, - address upkeepContract, - uint32 gasLimit, - address adminAddress, - uint8 triggerType, - bytes calldata checkData, - bytes memory triggerConfig, - bytes calldata offchainConfig, - bytes32 hash - ) external onlyOwner { + function approve(RegistrationParams calldata requestParams, bytes32 hash) external onlyOwner { PendingRequest memory request = s_pendingRequests[hash]; if (request.admin == address(0)) { revert RequestNotFound(); } - bytes32 expectedHash = keccak256( - abi.encode(upkeepContract, gasLimit, adminAddress, triggerType, checkData, triggerConfig, offchainConfig) - ); + bytes32 expectedHash = keccak256(abi.encode(requestParams)); if (hash != expectedHash) { revert HashMismatch(); } delete s_pendingRequests[hash]; - _approve( - RegistrationParams({ - name: name, - encryptedEmail: "", - upkeepContract: upkeepContract, - gasLimit: gasLimit, - adminAddress: adminAddress, - triggerType: triggerType, - checkData: checkData, - triggerConfig: triggerConfig, - offchainConfig: offchainConfig, - amount: request.balance - }), - expectedHash - ); + _approve(requestParams, expectedHash); } /** @@ -277,24 +229,30 @@ contract AutomationRegistrar2_3 is TypeAndVersionInterface, ConfirmedOwner, IERC revert RequestNotFound(); } delete s_pendingRequests[hash]; - bool success = LINK.transfer(request.admin, request.balance); + bool success = i_LINK.transfer(request.admin, request.balance); if (!success) { - revert LinkTransferFailed(request.admin); + revert TransferFailed(request.admin); } emit RegistrationRejected(hash); } /** * @notice owner calls this function to set contract config - * @param AutomationRegistry new keeper registry address - * @param minLINKJuels minimum LINK that new registrations should fund their upkeep with + * @param registry new keeper registry address + * @param billingTokens the billing tokens that this registrar supports (registy must also support these) + * @param minBalances minimum balances that users must supply to register with the corresponding billing token */ - function setConfig(address AutomationRegistry, uint96 minLINKJuels) public onlyOwner { - s_config = RegistrarConfig({ - minLINKJuels: minLINKJuels, - AutomationRegistry: IAutomationRegistryMaster2_3(AutomationRegistry) - }); - emit ConfigChanged(AutomationRegistry, minLINKJuels); + function setConfig( + IAutomationRegistryMaster2_3 registry, + IERC20[] memory billingTokens, + uint256[] memory minBalances + ) public onlyOwner { + if (billingTokens.length != minBalances.length) revert InvalidDataLength(); + s_registry = registry; + for (uint256 i = 0; i < billingTokens.length; i++) { + s_minRegistrationAmounts[billingTokens[i]] = minBalances[i]; + } + emit ConfigChanged(); } /** @@ -333,11 +291,17 @@ contract AutomationRegistrar2_3 is TypeAndVersionInterface, ConfirmedOwner, IERC } /** - * @notice read the current registration configuration + * @notice gets the registry that this registrar is pointed to */ - function getConfig() external view returns (address AutomationRegistry, uint256 minLINKJuels) { - RegistrarConfig memory config = s_config; - return (address(config.AutomationRegistry), config.minLINKJuels); + function getRegistry() external view returns (IAutomationRegistryMaster2_3) { + return s_registry; + } + + /** + * @notice get the minimum registration fee for a particular billing token + */ + function getMinimumRegistrationAmount(IERC20 billingToken) external view returns (uint256) { + return s_minRegistrationAmounts[billingToken]; } /** @@ -362,26 +326,12 @@ contract AutomationRegistrar2_3 is TypeAndVersionInterface, ConfirmedOwner, IERC * @param amount Amount of LINK sent (specified in Juels) * @param data Payload of the transaction */ - function onTokenTransfer( - address sender, - uint256 amount, - bytes calldata data - ) - external - override - onlyLINK - permittedFunctionsForLINK(data) - isActualAmount(amount, data) - isActualSender(sender, data) - { - if (amount < s_config.minLINKJuels) { - revert InsufficientPayment(); - } - (bool success, ) = address(this).delegatecall(data); - // calls register - if (!success) { - revert RegistrationRequestFailed(); - } + function onTokenTransfer(address sender, uint256 amount, bytes calldata data) external override { + if (msg.sender != address(i_LINK)) revert OnlyLink(); + RegistrationParams memory params = abi.decode(data, (RegistrationParams)); + if (address(params.billingToken) != address(i_LINK)) revert OnlyLink(); + params.amount = uint96(amount); // ignore whatever is sent in registration params, use actual value; casting safe because max supply LINK < 2^96 + _register(params, sender); } // ================================================================ @@ -390,22 +340,21 @@ contract AutomationRegistrar2_3 is TypeAndVersionInterface, ConfirmedOwner, IERC /** * @dev verify registration request and emit RegistrationRequested event + * @dev we currently allow multiple duplicate registrations by adding to the original registration's balance + * we could make this much simpler by using a nonce to differentiate otherwise identical requests and then + * we don't have to worry about identical registrations */ function _register(RegistrationParams memory params, address sender) private returns (uint256) { + if (params.amount < s_minRegistrationAmounts[params.billingToken]) { + revert InsufficientPayment(); + } if (params.adminAddress == address(0)) { revert InvalidAdminAddress(); } - bytes32 hash = keccak256( - abi.encode( - params.upkeepContract, - params.gasLimit, - params.adminAddress, - params.triggerType, - params.checkData, - params.triggerConfig, - params.offchainConfig - ) - ); + if (!s_registry.supportsBillingToken(address(params.billingToken))) { + revert InvalidBillingToken(); + } + bytes32 hash = keccak256(abi.encode(params)); emit RegistrationRequested( hash, @@ -437,19 +386,28 @@ contract AutomationRegistrar2_3 is TypeAndVersionInterface, ConfirmedOwner, IERC * @dev register upkeep on AutomationRegistry contract and emit RegistrationApproved event */ function _approve(RegistrationParams memory params, bytes32 hash) private returns (uint256) { - IAutomationRegistryMaster2_3 AutomationRegistry = s_config.AutomationRegistry; - uint256 upkeepId = AutomationRegistry.registerUpkeep( + IAutomationRegistryMaster2_3 registry = s_registry; + uint256 upkeepId = registry.registerUpkeep( params.upkeepContract, params.gasLimit, params.adminAddress, params.triggerType, + address(params.billingToken), // have to cast as address because master interface doesn't use contract types params.checkData, params.triggerConfig, params.offchainConfig ); - bool success = LINK.transferAndCall(address(AutomationRegistry), params.amount, abi.encode(upkeepId)); + bool success; + if (address(params.billingToken) == address(i_LINK)) { + success = i_LINK.transferAndCall(address(registry), params.amount, abi.encode(upkeepId)); + } else { + success = params.billingToken.approve(address(registry), params.amount); + if (success) { + registry.addFunds(upkeepId, params.amount); + } + } if (!success) { - revert LinkTransferFailed(address(AutomationRegistry)); + revert TransferFailed(address(registry)); } emit RegistrationApproved(hash, params.name, upkeepId); return upkeepId; @@ -470,68 +428,4 @@ contract AutomationRegistrar2_3 is TypeAndVersionInterface, ConfirmedOwner, IERC } return false; } - - // ================================================================ - // | MODIFIERS | - // ================================================================ - - /** - * @dev Reverts if not sent from the LINK token - */ - modifier onlyLINK() { - if (msg.sender != address(LINK)) { - revert OnlyLink(); - } - _; - } - - /** - * @dev Reverts if the given data does not begin with the `register` function selector - * @param _data The data payload of the request - */ - modifier permittedFunctionsForLINK(bytes memory _data) { - bytes4 funcSelector; - assembly { - // solhint-disable-next-line avoid-low-level-calls - funcSelector := mload(add(_data, 32)) // First 32 bytes contain length of data - } - if (funcSelector != REGISTER_REQUEST_SELECTOR) { - revert FunctionNotPermitted(); - } - _; - } - - /** - * @dev Reverts if the actual amount passed does not match the expected amount - * @param expected amount that should match the actual amount - * @param data bytes - */ - modifier isActualAmount(uint256 expected, bytes calldata data) { - // decode register function arguments to get actual amount - (, , , , , , , , , uint96 amount, ) = abi.decode( - data[4:], - (string, bytes, address, uint32, address, uint8, bytes, bytes, bytes, uint96, address) - ); - if (expected != amount) { - revert AmountMismatch(); - } - _; - } - - /** - * @dev Reverts if the actual sender address does not match the expected sender address - * @param expected address that should match the actual sender address - * @param data bytes - */ - modifier isActualSender(address expected, bytes calldata data) { - // decode register function arguments to get actual sender - (, , , , , , , , , , address sender) = abi.decode( - data[4:], - (string, bytes, address, uint32, address, uint8, bytes, bytes, bytes, uint96, address) - ); - if (expected != sender) { - revert SenderMismatch(); - } - _; - } } diff --git a/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistry2_3.sol b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistry2_3.sol index 2b9a6a4fe12..074d9c93327 100644 --- a/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistry2_3.sol +++ b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistry2_3.sol @@ -4,11 +4,13 @@ pragma solidity 0.8.19; import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; import {AutomationRegistryBase2_3} from "./AutomationRegistryBase2_3.sol"; -import {AutomationRegistryLogicB2_3} from "./AutomationRegistryLogicB2_3.sol"; +import {AutomationRegistryLogicA2_3} from "./AutomationRegistryLogicA2_3.sol"; +import {AutomationRegistryLogicC2_3} from "./AutomationRegistryLogicC2_3.sol"; import {Chainable} from "../../Chainable.sol"; import {IERC677Receiver} from "../../../shared/interfaces/IERC677Receiver.sol"; import {OCR2Abstract} from "../../../shared/ocr2/OCR2Abstract.sol"; import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {SafeCast} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SafeCast.sol"; /** * @notice Registry for adding work for Chainlink nodes to perform on client @@ -22,6 +24,8 @@ contract AutomationRegistry2_3 is AutomationRegistryBase2_3, OCR2Abstract, Chain /** * @notice versions: * AutomationRegistry 2.3.0: supports native and ERC20 billing + * changes flat fee to USD-denominated + * adds support for custom billing overrides * AutomationRegistry 2.2.0: moves chain-specific integration code into a separate module * KeeperRegistry 2.1.0: introduces support for log triggers * removes the need for "wrapped perform data" @@ -44,18 +48,21 @@ contract AutomationRegistry2_3 is AutomationRegistryBase2_3, OCR2Abstract, Chain string public constant override typeAndVersion = "AutomationRegistry 2.3.0"; /** - * @param logicA the address of the first logic contract, but cast as logicB in order to call logicB functions (via fallback) + * @param logicA the address of the first logic contract + * @dev we cast the contract to logicC in order to call logicC functions (via fallback) */ constructor( - AutomationRegistryLogicB2_3 logicA + AutomationRegistryLogicA2_3 logicA ) AutomationRegistryBase2_3( - logicA.getLinkAddress(), - logicA.getLinkUSDFeedAddress(), - logicA.getNativeUSDFeedAddress(), - logicA.getFastGasFeedAddress(), - logicA.getAutomationForwarderLogic(), - logicA.getAllowedReadOnlyAddress() + AutomationRegistryLogicC2_3(address(logicA)).getLinkAddress(), + AutomationRegistryLogicC2_3(address(logicA)).getLinkUSDFeedAddress(), + AutomationRegistryLogicC2_3(address(logicA)).getNativeUSDFeedAddress(), + AutomationRegistryLogicC2_3(address(logicA)).getFastGasFeedAddress(), + AutomationRegistryLogicC2_3(address(logicA)).getAutomationForwarderLogic(), + AutomationRegistryLogicC2_3(address(logicA)).getAllowedReadOnlyAddress(), + AutomationRegistryLogicC2_3(address(logicA)).getPayoutMode(), + AutomationRegistryLogicC2_3(address(logicA)).getWrappedNativeTokenAddress() ) Chainable(address(logicA)) {} @@ -65,13 +72,13 @@ contract AutomationRegistry2_3 is AutomationRegistryBase2_3, OCR2Abstract, Chain */ struct TransmitVars { uint16 numUpkeepsPassedChecks; - uint256 totalCalldataWeight; uint96 totalReimbursement; uint96 totalPremium; + uint256 totalCalldataWeight; } // ================================================================ - // | ACTIONS | + // | HOT PATH ACTIONS | // ================================================================ /** @@ -107,6 +114,15 @@ contract AutomationRegistry2_3 is AutomationRegistryBase2_3, OCR2Abstract, Chain } } + /** + * @notice handles the report by performing the upkeeps and updating the state + * @param hotVars the hot variables of the registry + * @param report the report to be handled (already verified and decoded) + * @param gasOverhead the running tally of gas overhead to be split across the upkeeps + * @dev had to split this function from transmit() to avoid stack too deep errors + * @dev all other internal / private functions are generally defined in the Base contract + * we leave this here because it is essentially a continuation of the transmit() function, + */ function _handleReport(HotVars memory hotVars, Report memory report, uint256 gasOverhead) private { UpkeepTransmitInfo[] memory upkeepTransmitInfo = new UpkeepTransmitInfo[](report.upkeepIds.length); TransmitVars memory transmitVars = TransmitVars({ @@ -152,7 +168,7 @@ contract AutomationRegistry2_3 is AutomationRegistryBase2_3, OCR2Abstract, Chain (TRANSMIT_CALLDATA_PER_SIGNER_BYTES_OVERHEAD * (hotVars.f + 1)); transmitVars.totalCalldataWeight += upkeepTransmitInfo[i].calldataWeight; - // Deduct that gasUsed by upkeep from our running counter + // Deduct the gasUsed by upkeep from the overhead tally - upkeeps pay for their own gas individually gasOverhead -= upkeepTransmitInfo[i].gasUsed; // Store last perform block number / deduping key for upkeep @@ -169,8 +185,13 @@ contract AutomationRegistry2_3 is AutomationRegistryBase2_3, OCR2Abstract, Chain gasOverhead = gasOverhead / transmitVars.numUpkeepsPassedChecks + ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD; { + BillingTokenPaymentParams memory billingTokenParams; + uint256 nativeUSD = _getNativeUSD(hotVars); for (uint256 i = 0; i < report.upkeepIds.length; i++) { if (upkeepTransmitInfo[i].earlyChecksPassed) { + if (i == 0 || upkeepTransmitInfo[i].upkeep.billingToken != upkeepTransmitInfo[i - 1].upkeep.billingToken) { + billingTokenParams = _getBillingTokenPaymentParams(hotVars, upkeepTransmitInfo[i].upkeep.billingToken); + } PaymentReceipt memory receipt = _handlePayment( hotVars, PaymentParams({ @@ -179,18 +200,21 @@ contract AutomationRegistry2_3 is AutomationRegistryBase2_3, OCR2Abstract, Chain l1CostWei: (l1Fee * upkeepTransmitInfo[i].calldataWeight) / transmitVars.totalCalldataWeight, fastGasWei: report.fastGasWei, linkUSD: report.linkUSD, - nativeUSD: _getNativeUSD(hotVars), + nativeUSD: nativeUSD, + billingToken: upkeepTransmitInfo[i].upkeep.billingToken, + billingTokenParams: billingTokenParams, isTransaction: true }), - report.upkeepIds[i] + report.upkeepIds[i], + upkeepTransmitInfo[i].upkeep ); - transmitVars.totalPremium += receipt.premium; - transmitVars.totalReimbursement += receipt.reimbursement; + transmitVars.totalPremium += receipt.premiumJuels; + transmitVars.totalReimbursement += receipt.gasReimbursementJuels; emit UpkeepPerformed( report.upkeepIds[i], upkeepTransmitInfo[i].performSuccess, - receipt.reimbursement + receipt.premium, + receipt.gasReimbursementJuels + receipt.premiumJuels, // TODO - this is currently the LINK amount, but may change to billing token upkeepTransmitInfo[i].gasUsed, gasOverhead, report.triggers[i] @@ -201,25 +225,38 @@ contract AutomationRegistry2_3 is AutomationRegistryBase2_3, OCR2Abstract, Chain // record payments s_transmitters[msg.sender].balance += transmitVars.totalReimbursement; s_hotVars.totalPremium += transmitVars.totalPremium; + s_reserveAmounts[IERC20(address(i_link))] += transmitVars.totalReimbursement + transmitVars.totalPremium; } /** - * @notice simulates the upkeep with the perform data returned from checkUpkeep - * @param id identifier of the upkeep to execute the data with. - * @param performData calldata parameter to be passed to the target upkeep. - * @return success whether the call reverted or not - * @return gasUsed the amount of gas the target contract consumed + * @notice adds fund to an upkeep + * @param id the upkeepID + * @param amount the amount of funds to add, in the upkeep's billing token */ - function simulatePerformUpkeep( - uint256 id, - bytes calldata performData - ) external returns (bool success, uint256 gasUsed) { - _preventExecution(); - - if (s_hotVars.paused) revert RegistryPaused(); + function addFunds(uint256 id, uint96 amount) external payable { Upkeep memory upkeep = s_upkeep[id]; - (success, gasUsed) = _performUpkeep(upkeep.forwarder, upkeep.performGas, performData); - return (success, gasUsed); + if (upkeep.maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled(); + + if (msg.value != 0) { + if (upkeep.billingToken != IERC20(i_wrappedNativeToken)) { + revert InvalidToken(); + } + amount = SafeCast.toUint96(msg.value); + } + + s_upkeep[id].balance = upkeep.balance + amount; + s_reserveAmounts[upkeep.billingToken] = s_reserveAmounts[upkeep.billingToken] + amount; + + if (msg.value == 0) { + // ERC20 payment + bool success = upkeep.billingToken.transferFrom(msg.sender, address(this), amount); + if (!success) revert TransferFailed(); + } else { + // native payment + i_wrappedNativeToken.deposit{value: amount}(); + } + + emit FundsAdded(id, msg.sender, amount); } /** @@ -233,18 +270,20 @@ contract AutomationRegistry2_3 is AutomationRegistryBase2_3, OCR2Abstract, Chain if (data.length != 32) revert InvalidDataLength(); uint256 id = abi.decode(data, (uint256)); if (s_upkeep[id].maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled(); + if (address(s_upkeep[id].billingToken) != address(i_link)) revert InvalidToken(); s_upkeep[id].balance = s_upkeep[id].balance + uint96(amount); - s_reserveAmounts[address(i_link)] = s_reserveAmounts[address(i_link)] + amount; + s_reserveAmounts[IERC20(address(i_link))] = s_reserveAmounts[IERC20(address(i_link))] + amount; emit FundsAdded(id, sender, uint96(amount)); } // ================================================================ - // | SETTERS | + // | OCR2ABSTRACT | // ================================================================ /** * @inheritdoc OCR2Abstract * @dev prefer the type-safe version of setConfig (below) whenever possible. The OnchainConfig could differ between registry versions + * @dev this function takes up precious space on the root contract, but must be implemented to conform to the OCR2Abstract interface */ function setConfig( address[] memory signers, @@ -271,6 +310,17 @@ contract AutomationRegistry2_3 is AutomationRegistryBase2_3, OCR2Abstract, Chain ); } + /** + * @notice sets the configuration for the registry + * @param signers the list of permitted signers + * @param transmitters the list of permitted transmitters + * @param f the maximum tolerance for faulty nodes + * @param onchainConfig configuration values that are used on-chain + * @param offchainConfigVersion the version of the offchainConfig + * @param offchainConfig configuration values that are used off-chain + * @param billingTokens the list of valid billing tokens + * @param billingConfigs the configurations for each billing token + */ function setConfigTypeSafe( address[] memory signers, address[] memory transmitters, @@ -288,56 +338,10 @@ contract AutomationRegistry2_3 is AutomationRegistryBase2_3, OCR2Abstract, Chain // set billing config for tokens _setBillingConfig(billingTokens, billingConfigs); - // move all pooled payments out of the pool to each transmitter's balance - for (uint256 i = 0; i < s_transmittersList.length; i++) { - _updateTransmitterBalanceFromPool( - s_transmittersList[i], - s_hotVars.totalPremium, - uint96(s_transmittersList.length) - ); - } - - // remove any old signer/transmitter addresses - address signerAddress; - address transmitterAddress; - for (uint256 i = 0; i < s_transmittersList.length; i++) { - signerAddress = s_signersList[i]; - transmitterAddress = s_transmittersList[i]; - delete s_signers[signerAddress]; - // Do not delete the whole transmitter struct as it has balance information stored - s_transmitters[transmitterAddress].active = false; - } - delete s_signersList; - delete s_transmittersList; - - // add new signer/transmitter addresses - { - Transmitter memory transmitter; - address temp; - for (uint256 i = 0; i < signers.length; i++) { - if (s_signers[signers[i]].active) revert RepeatedSigner(); - if (signers[i] == ZERO_ADDRESS) revert InvalidSigner(); - s_signers[signers[i]] = Signer({active: true, index: uint8(i)}); - - temp = transmitters[i]; - if (temp == ZERO_ADDRESS) revert InvalidTransmitter(); - transmitter = s_transmitters[temp]; - if (transmitter.active) revert RepeatedTransmitter(); - transmitter.active = true; - transmitter.index = uint8(i); - // new transmitters start afresh from current totalPremium - // some spare change of premium from previous pool will be forfeited - transmitter.lastCollected = s_hotVars.totalPremium; - s_transmitters[temp] = transmitter; - } - } - s_signersList = signers; - s_transmittersList = transmitters; + _updateTransmitters(signers, transmitters); s_hotVars = HotVars({ f: f, - paymentPremiumPPB: onchainConfig.paymentPremiumPPB, - flatFeeMicroLink: onchainConfig.flatFeeMicroLink, stalenessSeconds: onchainConfig.stalenessSeconds, gasCeilingMultiplier: onchainConfig.gasCeilingMultiplier, paused: s_hotVars.paused, @@ -350,7 +354,6 @@ contract AutomationRegistry2_3 is AutomationRegistryBase2_3, OCR2Abstract, Chain s_storage = Storage({ checkGasLimit: onchainConfig.checkGasLimit, - minUpkeepSpend: onchainConfig.minUpkeepSpend, maxPerformGas: onchainConfig.maxPerformGas, transcoder: onchainConfig.transcoder, maxCheckDataSize: onchainConfig.maxCheckDataSize, @@ -384,9 +387,7 @@ contract AutomationRegistry2_3 is AutomationRegistryBase2_3, OCR2Abstract, Chain offchainConfig ); - for (uint256 idx = 0; idx < s_registrars.length(); idx++) { - s_registrars.remove(s_registrars.at(idx)); - } + delete s_registrars; for (uint256 idx = 0; idx < onchainConfig.registrars.length; idx++) { s_registrars.add(onchainConfig.registrars[idx]); @@ -405,12 +406,9 @@ contract AutomationRegistry2_3 is AutomationRegistryBase2_3, OCR2Abstract, Chain ); } - // ================================================================ - // | GETTERS | - // ================================================================ - /** * @inheritdoc OCR2Abstract + * @dev this function takes up precious space on the root contract, but must be implemented to conform to the OCR2Abstract interface */ function latestConfigDetails() external @@ -423,6 +421,7 @@ contract AutomationRegistry2_3 is AutomationRegistryBase2_3, OCR2Abstract, Chain /** * @inheritdoc OCR2Abstract + * @dev this function takes up precious space on the root contract, but must be implemented to conform to the OCR2Abstract interface */ function latestConfigDigestAndEpoch() external diff --git a/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryBase2_3.sol b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryBase2_3.sol index eaca9d0941f..087d907ab44 100644 --- a/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryBase2_3.sol +++ b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryBase2_3.sol @@ -10,9 +10,10 @@ import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; import {AggregatorV3Interface} from "../../../shared/interfaces/AggregatorV3Interface.sol"; import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; import {KeeperCompatibleInterface} from "../../interfaces/KeeperCompatibleInterface.sol"; -import {UpkeepFormat} from "../../interfaces/UpkeepTranscoderInterface.sol"; import {IChainModule} from "../../interfaces/IChainModule.sol"; import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {SafeCast} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SafeCast.sol"; +import {IWrappedNative} from "../interfaces/v2_3/IWrappedNative.sol"; /** * @notice Base Keeper Registry contract, contains shared logic between @@ -35,22 +36,15 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { uint256 internal constant PERFORM_GAS_CUSHION = 5_000; uint256 internal constant PPB_BASE = 1_000_000_000; uint32 internal constant UINT32_MAX = type(uint32).max; - uint96 internal constant LINK_TOTAL_SUPPLY = 1e27; // The first byte of the mask can be 0, because we only ever have 31 oracles uint256 internal constant ORACLE_MASK = 0x0001010101010101010101010101010101010101010101010101010101010101; - /** - * @dev UPKEEP_TRANSCODER_VERSION_BASE is temporary necessity for backwards compatibility with - * MigratableAutomationRegistryInterfaceV1 - it should be removed in future versions in favor of - * UPKEEP_VERSION_BASE and MigratableAutomationRegistryInterfaceV2 - */ - UpkeepFormat internal constant UPKEEP_TRANSCODER_VERSION_BASE = UpkeepFormat.V1; - uint8 internal constant UPKEEP_VERSION_BASE = 3; + uint8 internal constant UPKEEP_VERSION_BASE = 4; // Next block of constants are only used in maxPayment estimation during checkUpkeep simulation // These values are calibrated using hardhat tests which simulates various cases and verifies that // the variables result in accurate estimation - uint256 internal constant REGISTRY_CONDITIONAL_OVERHEAD = 60_000; // Fixed gas overhead for conditional upkeeps - uint256 internal constant REGISTRY_LOG_OVERHEAD = 85_000; // Fixed gas overhead for log upkeeps + uint256 internal constant REGISTRY_CONDITIONAL_OVERHEAD = 93_000; // Fixed gas overhead for conditional upkeeps + uint256 internal constant REGISTRY_LOG_OVERHEAD = 118_000; // Fixed gas overhead for log upkeeps uint256 internal constant REGISTRY_PER_SIGNER_GAS_OVERHEAD = 5_600; // Value scales with f uint256 internal constant REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD = 24; // Per perform data byte overhead @@ -64,8 +58,8 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { // tx itself, but since payment processing itself takes gas, and it needs the overhead as input, we use fixed constants // to account for gas used in payment processing. These values are calibrated using hardhat tests which simulates various cases and verifies that // the variables result in accurate estimation - uint256 internal constant ACCOUNTING_FIXED_GAS_OVERHEAD = 22_000; // Fixed overhead per tx - uint256 internal constant ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD = 7_000; // Overhead per upkeep performed in batch + uint256 internal constant ACCOUNTING_FIXED_GAS_OVERHEAD = 51_000; // Fixed overhead per tx + uint256 internal constant ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD = 9_000; // Overhead per upkeep performed in batch LinkTokenInterface internal immutable i_link; AggregatorV3Interface internal immutable i_linkUSDFeed; @@ -73,6 +67,7 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { AggregatorV3Interface internal immutable i_fastGasFeed; address internal immutable i_automationForwarderLogic; address internal immutable i_allowedReadOnlyAddress; + IWrappedNative internal immutable i_wrappedNativeToken; /** * @dev - The storage is gas optimised for one and only one function - transmit. All the storage accessed in transmit @@ -92,6 +87,7 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { mapping(address => Signer) internal s_signers; address[] internal s_signersList; // s_signersList contains the signing address of each oracle address[] internal s_transmittersList; // s_transmittersList contains the transmission address of each oracle + EnumerableSet.AddressSet internal s_deactivatedTransmitters; mapping(address => address) internal s_transmitterPayees; // s_payees contains the mapping from transmitter to payee. mapping(address => address) internal s_proposedPayee; // proposed payee for a transmitter bytes32 internal s_latestConfigDigest; // Read on transmit path in case of signature verification @@ -100,15 +96,17 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { uint256 internal s_fallbackGasPrice; uint256 internal s_fallbackLinkPrice; uint256 internal s_fallbackNativePrice; - mapping(address billingToken => uint256 reserveAmount) internal s_reserveAmounts; // unspent user deposits + unwithdrawn NOP payments mapping(address => MigrationPermission) internal s_peerRegistryMigrationPermission; // Permissions for migration to and fro mapping(uint256 => bytes) internal s_upkeepTriggerConfig; // upkeep triggers mapping(uint256 => bytes) internal s_upkeepOffchainConfig; // general config set by users for each upkeep mapping(uint256 => bytes) internal s_upkeepPrivilegeConfig; // general config set by an administrative role for an upkeep mapping(address => bytes) internal s_adminPrivilegeConfig; // general config set by an administrative role for an admin // billing + mapping(IERC20 billingToken => uint256 reserveAmount) internal s_reserveAmounts; // unspent user deposits + unwithdrawn NOP payments mapping(IERC20 billingToken => BillingConfig billingConfig) internal s_billingConfigs; // billing configurations for different tokens + mapping(uint256 upkeepID => BillingOverrides billingOverrides) internal s_billingOverrides; // billing overrides for specific upkeeps IERC20[] internal s_billingTokens; // list of billing tokens + PayoutMode internal s_payoutMode; error ArrayHasNoEntries(); error CannotCancel(); @@ -123,6 +121,7 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { error IncorrectNumberOfSigners(); error IndexOutOfRange(); error InsufficientBalance(uint256 available, uint256 requested); + error InsufficientLinkLiquidity(); error InvalidDataLength(); error InvalidFeed(); error InvalidTrigger(); @@ -130,11 +129,12 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { error InvalidRecipient(); error InvalidReport(); error InvalidSigner(); + error InvalidToken(); error InvalidTransmitter(); error InvalidTriggerType(); - error MaxCheckDataSizeCanOnlyIncrease(); - error MaxPerformDataSizeCanOnlyIncrease(); error MigrationNotPermitted(); + error MustSettleOffchain(); + error MustSettleOnchain(); error NotAContract(); error OnlyActiveSigners(); error OnlyActiveTransmitters(); @@ -151,7 +151,6 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { error OnlySimulatedBackend(); error OnlyUnpausedUpkeep(); error ParameterLengthError(); - error PaymentGreaterThanAllLINK(); error ReentrantCall(); error RegistryPaused(); error RepeatedSigner(); @@ -192,62 +191,19 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { REGISTRY_PAUSED } - /** - * @notice OnchainConfigLegacy of the registry - * @dev only used in params and return values - * @member paymentPremiumPPB payment premium rate oracles receive on top of - * being reimbursed for gas, measured in parts per billion - * @member flatFeeMicroLink flat fee paid to oracles for performing upkeeps, - * priced in MicroLink; can be used in conjunction with or independently of - * paymentPremiumPPB - * @member checkGasLimit gas limit when checking for upkeep - * @member stalenessSeconds number of seconds that is allowed for feed data to - * be stale before switching to the fallback pricing - * @member gasCeilingMultiplier multiplier to apply to the fast gas feed price - * when calculating the payment ceiling for keepers - * @member minUpkeepSpend minimum LINK that an upkeep must spend before cancelling - * @member maxPerformGas max performGas allowed for an upkeep on this registry - * @member maxCheckDataSize max length of checkData bytes - * @member maxPerformDataSize max length of performData bytes - * @member maxRevertDataSize max length of revertData bytes - * @member fallbackGasPrice gas price used if the gas price feed is stale - * @member fallbackLinkPrice LINK price used if the LINK price feed is stale - * @member transcoder address of the transcoder contract - * @member registrars addresses of the registrar contracts - * @member upkeepPrivilegeManager address which can set privilege for upkeeps - */ - struct OnchainConfigLegacy { - uint32 paymentPremiumPPB; - uint32 flatFeeMicroLink; // min 0.000001 LINK, max 4294 LINK - uint32 checkGasLimit; - uint24 stalenessSeconds; - uint16 gasCeilingMultiplier; - uint96 minUpkeepSpend; - uint32 maxPerformGas; - uint32 maxCheckDataSize; - uint32 maxPerformDataSize; - uint32 maxRevertDataSize; - uint256 fallbackGasPrice; - uint256 fallbackLinkPrice; - address transcoder; - address[] registrars; - address upkeepPrivilegeManager; + enum PayoutMode { + ON_CHAIN, + OFF_CHAIN } /** * @notice OnchainConfig of the registry * @dev used only in setConfig() - * @member paymentPremiumPPB payment premium rate oracles receive on top of - * being reimbursed for gas, measured in parts per billion - * @member flatFeeMicroLink flat fee paid to oracles for performing upkeeps, - * priced in MicroLink; can be used in conjunction with or independently of - * paymentPremiumPPB * @member checkGasLimit gas limit when checking for upkeep * @member stalenessSeconds number of seconds that is allowed for feed data to * be stale before switching to the fallback pricing * @member gasCeilingMultiplier multiplier to apply to the fast gas feed price * when calculating the payment ceiling for keepers - * @member minUpkeepSpend minimum LINK that an upkeep must spend before cancelling * @member maxPerformGas max performGas allowed for an upkeep on this registry * @member maxCheckDataSize max length of checkData bytes * @member maxPerformDataSize max length of performData bytes @@ -261,137 +217,82 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { * @member chainModule the chain specific module */ struct OnchainConfig { - uint32 paymentPremiumPPB; - uint32 flatFeeMicroLink; // min 0.000001 LINK, max 4294 LINK uint32 checkGasLimit; - uint24 stalenessSeconds; - uint16 gasCeilingMultiplier; - uint96 minUpkeepSpend; uint32 maxPerformGas; uint32 maxCheckDataSize; + address transcoder; + // 1 word full + bool reorgProtectionEnabled; + uint24 stalenessSeconds; uint32 maxPerformDataSize; uint32 maxRevertDataSize; + address upkeepPrivilegeManager; + // 2 words full + uint16 gasCeilingMultiplier; + address financeAdmin; + // 3 words uint256 fallbackGasPrice; uint256 fallbackLinkPrice; uint256 fallbackNativePrice; - address transcoder; address[] registrars; - address upkeepPrivilegeManager; IChainModule chainModule; - bool reorgProtectionEnabled; - address financeAdmin; // TODO: pack this struct better - } - - /** - * @notice state of the registry - * @dev only used in params and return values - * @dev this will likely be deprecated in a future version of the registry in favor of individual getters - * @member nonce used for ID generation - * @member expectedLinkBalance the expected balance of LINK of the registry - * @member totalPremium the total premium collected on registry so far - * @member numUpkeeps total number of upkeeps on the registry - * @member configCount ordinal number of current config, out of all configs applied to this contract so far - * @member latestConfigBlockNumber last block at which this config was set - * @member latestConfigDigest domain-separation tag for current config - * @member latestEpoch for which a report was transmitted - * @member paused freeze on execution scoped to the entire registry - */ - struct State { - uint32 nonce; - uint96 ownerLinkBalance; - uint256 expectedLinkBalance; - uint96 totalPremium; - uint256 numUpkeeps; - uint32 configCount; - uint32 latestConfigBlockNumber; - bytes32 latestConfigDigest; - uint32 latestEpoch; - bool paused; } /** * @notice relevant state of an upkeep which is used in transmit function * @member paused if this upkeep has been paused + * @member overridesEnabled if this upkeep has overrides enabled * @member performGas the gas limit of upkeep execution * @member maxValidBlocknumber until which block this upkeep is valid * @member forwarder the forwarder contract to use for this upkeep - * @member amountSpent the amount this upkeep has spent + * @member amountSpent the amount this upkeep has spent, in the upkeep's billing token * @member balance the balance of this upkeep * @member lastPerformedBlockNumber the last block number when this upkeep was performed */ struct Upkeep { bool paused; + bool overridesEnabled; uint32 performGas; uint32 maxValidBlocknumber; IAutomationForwarder forwarder; - // 0 bytes left in 1st EVM word - not written to in transmit - uint96 amountSpent; - uint96 balance; - uint32 lastPerformedBlockNumber; - // 2 bytes left in 2nd EVM word - written in transmit path - } - - /** - * @notice all information about an upkeep - * @dev only used in return values - * @dev this will likely be deprecated in a future version of the registry - * @member target the contract which needs to be serviced - * @member performGas the gas limit of upkeep execution - * @member checkData the checkData bytes for this upkeep - * @member balance the balance of this upkeep - * @member admin for this upkeep - * @member maxValidBlocknumber until which block this upkeep is valid - * @member lastPerformedBlockNumber the last block number when this upkeep was performed - * @member amountSpent the amount this upkeep has spent - * @member paused if this upkeep has been paused - * @member offchainConfig the off-chain config of this upkeep - */ - struct UpkeepInfo { - address target; - uint32 performGas; - bytes checkData; + // 2 bytes left in 1st EVM word - read in transmit path + uint128 amountSpent; uint96 balance; - address admin; - uint64 maxValidBlocknumber; uint32 lastPerformedBlockNumber; - uint96 amountSpent; - bool paused; - bytes offchainConfig; + // 0 bytes left in 2nd EVM word - written in transmit path + IERC20 billingToken; + // 12 bytes left in 3rd EVM word - read in transmit path } /// @dev Config + State storage struct which is on hot transmit path struct HotVars { uint96 totalPremium; // ─────────╮ total historical payment to oracles for premium - uint32 paymentPremiumPPB; // │ premium percentage charged to user over tx cost - uint32 flatFeeMicroLink; // │ flat fee charged to user for every perform uint32 latestEpoch; // │ latest epoch for which a report was transmitted uint24 stalenessSeconds; // │ Staleness tolerance for feeds uint16 gasCeilingMultiplier; // │ multiplier on top of fast gas feed for upper bound uint8 f; // │ maximum number of faulty oracles bool paused; // │ pause switch for all upkeeps in the registry - bool reentrancyGuard; // ────────╯ guard against reentrancy - bool reorgProtectionEnabled; // if this registry should enable re-org protection mechanism + bool reentrancyGuard; // | guard against reentrancy + bool reorgProtectionEnabled; // ─╯ if this registry should enable the re-org protection mechanism IChainModule chainModule; // the interface of chain specific module } /// @dev Config + State storage struct which is not on hot transmit path struct Storage { - uint96 minUpkeepSpend; // Minimum amount an upkeep must spend address transcoder; // Address of transcoder contract used in migrations - // 1 EVM word full uint32 checkGasLimit; // Gas limit allowed in checkUpkeep uint32 maxPerformGas; // Max gas an upkeep can use on this registry uint32 nonce; // Nonce for each upkeep created - uint32 configCount; // incremented each time a new config is posted, The count - // is incorporated into the config digest to prevent replay attacks. + // 1 EVM word full + address upkeepPrivilegeManager; // address which can set privilege for upkeeps + uint32 configCount; // incremented each time a new config is posted, The count is incorporated into the config digest to prevent replay attacks. uint32 latestConfigBlockNumber; // makes it easier for offchain systems to extract config from logs - // 2 EVM word full uint32 maxCheckDataSize; // max length of checkData bytes + // 2 EVM word full + address financeAdmin; // address which can withdraw funds from the contract uint32 maxPerformDataSize; // max length of performData bytes uint32 maxRevertDataSize; // max length of revertData bytes - address upkeepPrivilegeManager; // address which can set privilege for upkeeps - // 3 EVM word full - address financeAdmin; // address which can withdraw funds from the contract + // 4 bytes left in 3rd EVM word } /// @dev Report transmitted by OCR to transmit function @@ -424,9 +325,17 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { bytes32 dedupID; } + /** + * @notice holds information about a transmiter / node in the DON + * @member active can this transmitter submit reports + * @member index of oracle in s_signersList/s_transmittersList + * @member balance a node's balance in LINK + * @member lastCollected the total balance at which the node last withdrew + @ @dev uint96 is safe for balance / last collected because transmitters are only ever paid in LINK + */ struct Transmitter { bool active; - uint8 index; // Index of oracle in s_signersList/s_transmittersList + uint8 index; uint96 balance; uint96 lastCollected; } @@ -460,11 +369,35 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { /** * @notice the billing config of a token + * @dev this is a storage struct */ struct BillingConfig { uint32 gasFeePPB; - uint24 flatFeeMicroLink; - address priceFeed; + uint24 flatFeeMilliCents; // min fee is $0.00001, max fee is $167 + AggregatorV3Interface priceFeed; + // 1st word, read in calculating BillingTokenPaymentParams + uint256 fallbackPrice; + // 2nd word only read if stale + uint96 minSpend; + // 3rd word only read during cancellation + } + + /** + * @notice override-able billing params of a billing token + */ + struct BillingOverrides { + uint32 gasFeePPB; + uint24 flatFeeMilliCents; + } + + /** + * @notice pricing params for a billing token + * @dev this is a memory-only struct, so struct packing is less important + */ + struct BillingTokenPaymentParams { + uint32 gasFeePPB; + uint24 flatFeeMilliCents; + uint256 priceUSD; } /** @@ -475,6 +408,8 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { * @member fastGasWei the fast gas price * @member linkUSD the exchange ratio between LINK and USD * @member nativeUSD the exchange ratio between the chain's native token and USD + * @member billingToken the billing token + * @member billingTokenParams the payment params specific to a particular payment token * @member isTransaction is this an eth_call or a transaction */ struct PaymentParams { @@ -484,26 +419,37 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { uint256 fastGasWei; uint256 linkUSD; uint256 nativeUSD; + IERC20 billingToken; + BillingTokenPaymentParams billingTokenParams; bool isTransaction; } /** - * @notice struct containing receipt information after a payment is made - * @member reimbursement the amount to reimburse a node for gas spent + * @notice struct containing receipt information about a payment or cost estimation + * @member gasCharge the amount to charge a user for gas spent * @member premium the premium charged to the user, shared between all nodes + * @member gasReimbursementJuels the amount to reimburse a node for gas spent + * @member premiumJuels the premium paid to NOPs, shared between all nodes */ struct PaymentReceipt { - uint96 reimbursement; + uint96 gasCharge; uint96 premium; + uint96 gasReimbursementJuels; + uint96 premiumJuels; } event AdminPrivilegeConfigSet(address indexed admin, bytes privilegeConfig); + event BillingConfigOverridden(uint256 indexed id, BillingOverrides overrides); + event BillingConfigOverrideRemoved(uint256 indexed id); + event BillingConfigSet(IERC20 indexed token, BillingConfig config); event CancelledUpkeepReport(uint256 indexed id, bytes trigger); event ChainSpecificModuleUpdated(address newModule); event DedupKeyAdded(bytes32 indexed dedupKey); + event FeesWithdrawn(address indexed assetAddress, address indexed recipient, uint256 amount); event FundsAdded(uint256 indexed id, address indexed from, uint96 amount); event FundsWithdrawn(uint256 indexed id, uint256 amount, address to); event InsufficientFundsUpkeepReport(uint256 indexed id, bytes trigger); + event NOPsSettledOffchain(address[] payees, uint256[] payments); event Paused(address account); event PayeesUpdated(address[] transmitters, address[] payees); event PayeeshipTransferRequested(address indexed transmitter, address indexed from, address indexed to); @@ -533,9 +479,6 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { event UpkeepTriggerConfigSet(uint256 indexed id, bytes triggerConfig); event UpkeepUnpaused(uint256 indexed id); event Unpaused(address account); - // Event to emit when a billing configuration is set - event BillingConfigSet(IERC20 indexed token, BillingConfig config); - event FeesWithdrawn(address indexed recipient, address indexed assetAddress, uint256 amount); /** * @param link address of the LINK Token @@ -544,6 +487,7 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { * @param fastGasFeed address of the Fast Gas price feed * @param automationForwarderLogic the address of automation forwarder logic * @param allowedReadOnlyAddress the address of the allowed read only address + * @param payoutMode the payout mode */ constructor( address link, @@ -551,7 +495,9 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { address nativeUSDFeed, address fastGasFeed, address automationForwarderLogic, - address allowedReadOnlyAddress + address allowedReadOnlyAddress, + PayoutMode payoutMode, + address wrappedNativeTokenAddress ) ConfirmedOwner(msg.sender) { i_link = LinkTokenInterface(link); i_linkUSDFeed = AggregatorV3Interface(linkUSDFeed); @@ -559,6 +505,8 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { i_fastGasFeed = AggregatorV3Interface(fastGasFeed); i_automationForwarderLogic = automationForwarderLogic; i_allowedReadOnlyAddress = allowedReadOnlyAddress; + s_payoutMode = payoutMode; + i_wrappedNativeToken = IWrappedNative(wrappedNativeTokenAddress); if (i_linkUSDFeed.decimals() != i_nativeUSDFeed.decimals()) { revert InvalidFeed(); } @@ -590,10 +538,11 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { if (upkeep.performGas < PERFORM_GAS_MIN || upkeep.performGas > s_storage.maxPerformGas) revert GasLimitOutsideRange(); if (address(s_upkeep[id].forwarder) != address(0)) revert UpkeepAlreadyExists(); + if (address(s_billingConfigs[upkeep.billingToken].priceFeed) == address(0)) revert InvalidToken(); s_upkeep[id] = upkeep; s_upkeepAdmin[id] = admin; s_checkData[id] = checkData; - s_reserveAmounts[address(i_link)] = s_reserveAmounts[address(i_link)] + upkeep.balance; + s_reserveAmounts[upkeep.billingToken] = s_reserveAmounts[upkeep.billingToken] + upkeep.balance; s_upkeepTriggerConfig[id] = triggerConfig; s_upkeepOffchainConfig[id] = offchainConfig; s_upkeepIDs.add(id); @@ -653,7 +602,6 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { } else { linkUSD = uint256(feedValue); } - (, feedValue, , timestamp, ) = i_nativeUSDFeed.latestRoundData(); return (gasWei, linkUSD, _getNativeUSD(hotVars)); } @@ -675,66 +623,109 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { } } + /** + * @dev gets the price and billing params for a specific billing token + */ + function _getBillingTokenPaymentParams( + HotVars memory hotVars, + IERC20 billingToken + ) internal view returns (BillingTokenPaymentParams memory paymentParams) { + BillingConfig storage config = s_billingConfigs[billingToken]; + paymentParams.flatFeeMilliCents = config.flatFeeMilliCents; + paymentParams.gasFeePPB = config.gasFeePPB; + (, int256 feedValue, , uint256 timestamp, ) = config.priceFeed.latestRoundData(); + if ( + feedValue <= 0 || + block.timestamp < timestamp || + (hotVars.stalenessSeconds > 0 && hotVars.stalenessSeconds < block.timestamp - timestamp) + ) { + paymentParams.priceUSD = config.fallbackPrice; + } else { + paymentParams.priceUSD = uint256(feedValue); + } + return paymentParams; + } + /** * @dev calculates LINK paid for gas spent plus a configure premium percentage * @param hotVars the hot path variables * @param paymentParams the pricing data and gas usage data - * @dev use of PaymentParams is solely to avoid stack too deep errors + * @return receipt the receipt of payment with pricing breakdown + * @dev use of PaymentParams struct is necessary to avoid stack too deep errors + * @dev 1 USD = 1e18 attoUSD + * @dev 1 USD = 1e26 hexaicosaUSD (had to borrow this prefix from geometry because there is no metric prefix for 1e-26) + * @dev 1 millicent = 1e-5 USD = 1e13 attoUSD */ function _calculatePaymentAmount( HotVars memory hotVars, PaymentParams memory paymentParams - ) internal view returns (uint96, uint96) { + ) internal view returns (PaymentReceipt memory receipt) { uint256 gasWei = paymentParams.fastGasWei * hotVars.gasCeilingMultiplier; // in case it's actual execution use actual gas price, capped by fastGasWei * gasCeilingMultiplier if (paymentParams.isTransaction && tx.gasprice < gasWei) { gasWei = tx.gasprice; } - uint256 gasPayment = ((gasWei * (paymentParams.gasLimit + paymentParams.gasOverhead) + paymentParams.l1CostWei) * - paymentParams.nativeUSD) / paymentParams.linkUSD; - uint256 premium = (((gasWei * paymentParams.gasLimit) + paymentParams.l1CostWei) * - hotVars.paymentPremiumPPB * - paymentParams.nativeUSD) / - (paymentParams.linkUSD * 1e9) + - uint256(hotVars.flatFeeMicroLink) * - 1e12; - // LINK_TOTAL_SUPPLY < UINT96_MAX - if (gasPayment + premium > LINK_TOTAL_SUPPLY) revert PaymentGreaterThanAllLINK(); - return (uint96(gasPayment), uint96(premium)); + + uint256 gasPaymentHexaicosaUSD = (gasWei * + (paymentParams.gasLimit + paymentParams.gasOverhead) + + paymentParams.l1CostWei) * paymentParams.nativeUSD; // gasPaymentHexaicosaUSD has an extra 8 zeros because of decimals on nativeUSD feed + receipt.gasCharge = SafeCast.toUint96(gasPaymentHexaicosaUSD / paymentParams.billingTokenParams.priceUSD); // has units of attoBillingToken, or "wei" + receipt.gasReimbursementJuels = SafeCast.toUint96(gasPaymentHexaicosaUSD / paymentParams.linkUSD); + uint256 flatFeeHexaicosaUSD = uint256(paymentParams.billingTokenParams.flatFeeMilliCents) * 1e21; // 1e13 for milliCents to attoUSD and 1e8 for attoUSD to hexaicosaUSD + uint256 premiumHexaicosaUSD = ((((gasWei * paymentParams.gasLimit) + paymentParams.l1CostWei) * + paymentParams.billingTokenParams.gasFeePPB * + paymentParams.nativeUSD) / 1e9) + flatFeeHexaicosaUSD; + receipt.premium = SafeCast.toUint96(premiumHexaicosaUSD / paymentParams.billingTokenParams.priceUSD); + receipt.premiumJuels = SafeCast.toUint96(premiumHexaicosaUSD / paymentParams.linkUSD); + + return receipt; } /** - * @dev calculates the max LINK payment for an upkeep. Called during checkUpkeep simulation and assumes + * @dev calculates the max payment for an upkeep. Called during checkUpkeep simulation and assumes * maximum gas overhead, L1 fee */ - function _getMaxLinkPayment( + function _getMaxPayment( + uint256 upkeepId, HotVars memory hotVars, Trigger triggerType, uint32 performGas, uint256 fastGasWei, uint256 linkUSD, - uint256 nativeUSD + uint256 nativeUSD, + IERC20 billingToken ) internal view returns (uint96) { + uint256 maxL1Fee; uint256 maxGasOverhead; - if (triggerType == Trigger.CONDITION) { - maxGasOverhead = REGISTRY_CONDITIONAL_OVERHEAD; - } else if (triggerType == Trigger.LOG) { - maxGasOverhead = REGISTRY_LOG_OVERHEAD; - } else { - revert InvalidTriggerType(); + + { + if (triggerType == Trigger.CONDITION) { + maxGasOverhead = REGISTRY_CONDITIONAL_OVERHEAD; + } else if (triggerType == Trigger.LOG) { + maxGasOverhead = REGISTRY_LOG_OVERHEAD; + } else { + revert InvalidTriggerType(); + } + uint256 maxCalldataSize = s_storage.maxPerformDataSize + + TRANSMIT_CALLDATA_FIXED_BYTES_OVERHEAD + + (TRANSMIT_CALLDATA_PER_SIGNER_BYTES_OVERHEAD * (hotVars.f + 1)); + (uint256 chainModuleFixedOverhead, uint256 chainModulePerByteOverhead) = s_hotVars.chainModule.getGasOverhead(); + maxGasOverhead += + (REGISTRY_PER_SIGNER_GAS_OVERHEAD * (hotVars.f + 1)) + + ((REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD + chainModulePerByteOverhead) * maxCalldataSize) + + chainModuleFixedOverhead; + maxL1Fee = hotVars.gasCeilingMultiplier * hotVars.chainModule.getMaxL1Fee(maxCalldataSize); } - uint256 maxCalldataSize = s_storage.maxPerformDataSize + - TRANSMIT_CALLDATA_FIXED_BYTES_OVERHEAD + - (TRANSMIT_CALLDATA_PER_SIGNER_BYTES_OVERHEAD * (hotVars.f + 1)); - (uint256 chainModuleFixedOverhead, uint256 chainModulePerByteOverhead) = s_hotVars.chainModule.getGasOverhead(); - maxGasOverhead += - (REGISTRY_PER_SIGNER_GAS_OVERHEAD * (hotVars.f + 1)) + - ((REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD + chainModulePerByteOverhead) * maxCalldataSize) + - chainModuleFixedOverhead; - - uint256 maxL1Fee = hotVars.gasCeilingMultiplier * hotVars.chainModule.getMaxL1Fee(maxCalldataSize); - - (uint96 reimbursement, uint96 premium) = _calculatePaymentAmount( + + BillingTokenPaymentParams memory paymentParams = _getBillingTokenPaymentParams(hotVars, billingToken); + if (s_upkeep[upkeepId].overridesEnabled) { + BillingOverrides memory billingOverrides = s_billingOverrides[upkeepId]; + // use the overridden configs + paymentParams.gasFeePPB = billingOverrides.gasFeePPB; + paymentParams.flatFeeMilliCents = billingOverrides.flatFeeMilliCents; + } + + PaymentReceipt memory receipt = _calculatePaymentAmount( hotVars, PaymentParams({ gasLimit: performGas, @@ -743,11 +734,13 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { fastGasWei: fastGasWei, linkUSD: linkUSD, nativeUSD: nativeUSD, + billingToken: billingToken, + billingTokenParams: paymentParams, isTransaction: false }) ); - return reimbursement + premium; + return receipt.gasCharge + receipt.premium; } /** @@ -970,28 +963,43 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { function _handlePayment( HotVars memory hotVars, PaymentParams memory paymentParams, - uint256 upkeepId + uint256 upkeepId, + Upkeep memory upkeep ) internal returns (PaymentReceipt memory) { - (uint96 gasReimbursement, uint96 premium) = _calculatePaymentAmount(hotVars, paymentParams); + if (upkeep.overridesEnabled) { + BillingOverrides memory billingOverrides = s_billingOverrides[upkeepId]; + // use the overridden configs + paymentParams.billingTokenParams.gasFeePPB = billingOverrides.gasFeePPB; + paymentParams.billingTokenParams.flatFeeMilliCents = billingOverrides.flatFeeMilliCents; + } + + PaymentReceipt memory receipt = _calculatePaymentAmount(hotVars, paymentParams); - uint96 balance = s_upkeep[upkeepId].balance; - uint96 payment = gasReimbursement + premium; + uint96 balance = upkeep.balance; + uint96 payment = receipt.gasCharge + receipt.premium; // this shouldn't happen, but in rare edge cases, we charge the full balance in case the user // can't cover the amount owed - if (balance < gasReimbursement) { + if (balance < receipt.gasCharge) { + // if the user can't cover the gas fee, then direct all of the payment to the transmitter and distribute no premium to the DON payment = balance; - gasReimbursement = balance; - premium = 0; + receipt.gasReimbursementJuels = SafeCast.toUint96( + (balance * paymentParams.billingTokenParams.priceUSD) / paymentParams.linkUSD + ); + receipt.premiumJuels = 0; } else if (balance < payment) { + // if the user can cover the gas fee, but not the premium, then reduce the premium payment = balance; - premium = payment - gasReimbursement; + receipt.premiumJuels = SafeCast.toUint96( + ((balance * paymentParams.billingTokenParams.priceUSD) / paymentParams.linkUSD) - receipt.gasReimbursementJuels + ); } s_upkeep[upkeepId].balance -= payment; s_upkeep[upkeepId].amountSpent += payment; + s_reserveAmounts[paymentParams.billingToken] -= payment; - return PaymentReceipt({reimbursement: gasReimbursement, premium: premium}); + return receipt; } /** @@ -1030,6 +1038,15 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { } } + /** + * @notice only allows privilege manager to call the function + */ + function _onlyPrivilegeManagerAllowed() internal view { + if (msg.sender != s_storage.upkeepPrivilegeManager) { + revert OnlyCallableByUpkeepPrivilegeManager(); + } + } + /** * @notice sets billing configuration for a token * @param billingTokens the addresses of tokens @@ -1042,16 +1059,21 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { } delete s_billingTokens; + PayoutMode mode = s_payoutMode; for (uint256 i = 0; i < billingTokens.length; i++) { IERC20 token = billingTokens[i]; BillingConfig memory config = billingConfigs[i]; - if (address(token) == ZERO_ADDRESS || config.priceFeed == ZERO_ADDRESS) { + // if LINK is a billing option, payout mode must be ON_CHAIN + if (address(token) == address(i_link) && mode == PayoutMode.OFF_CHAIN) { + revert InvalidToken(); + } + if (address(token) == ZERO_ADDRESS || address(config.priceFeed) == ZERO_ADDRESS) { revert ZeroAddressNotAllowed(); } // if this is a new token, add it to tokens list. Otherwise revert - if (s_billingConfigs[token].priceFeed != ZERO_ADDRESS) { + if (address(s_billingConfigs[token].priceFeed) != ZERO_ADDRESS) { revert DuplicateEntry(); } s_billingTokens.push(token); @@ -1062,4 +1084,66 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner { emit BillingConfigSet(token, config); } } + + /** + * @notice updates the signers and transmitters lists + */ + function _updateTransmitters(address[] memory signers, address[] memory transmitters) internal { + // move all pooled payments out of the pool to each transmitter's balance + for (uint256 i = 0; i < s_transmittersList.length; i++) { + _updateTransmitterBalanceFromPool( + s_transmittersList[i], + s_hotVars.totalPremium, + uint96(s_transmittersList.length) + ); + } + + // remove any old signer/transmitter addresses + address transmitterAddress; + PayoutMode mode = s_payoutMode; + for (uint256 i = 0; i < s_transmittersList.length; i++) { + transmitterAddress = s_transmittersList[i]; + delete s_signers[s_signersList[i]]; + // Do not delete the whole transmitter struct as it has balance information stored + s_transmitters[transmitterAddress].active = false; + if (mode == PayoutMode.OFF_CHAIN && s_transmitters[transmitterAddress].balance > 0) { + s_deactivatedTransmitters.add(transmitterAddress); + } + } + delete s_signersList; + delete s_transmittersList; + + // add new signer/transmitter addresses + Transmitter memory transmitter; + for (uint256 i = 0; i < signers.length; i++) { + if (s_signers[signers[i]].active) revert RepeatedSigner(); + if (signers[i] == ZERO_ADDRESS) revert InvalidSigner(); + s_signers[signers[i]] = Signer({active: true, index: uint8(i)}); + + transmitterAddress = transmitters[i]; + if (transmitterAddress == ZERO_ADDRESS) revert InvalidTransmitter(); + transmitter = s_transmitters[transmitterAddress]; + if (transmitter.active) revert RepeatedTransmitter(); + transmitter.active = true; + transmitter.index = uint8(i); + // new transmitters start afresh from current totalPremium + // some spare change of premium from previous pool will be forfeited + transmitter.lastCollected = s_hotVars.totalPremium; + s_transmitters[transmitterAddress] = transmitter; + if (mode == PayoutMode.OFF_CHAIN) { + s_deactivatedTransmitters.remove(transmitterAddress); + } + } + + s_signersList = signers; + s_transmittersList = transmitters; + } + + /** + * @notice returns the size of the LINK liquidity pool + # @dev LINK max supply < 2^96, so casting to int256 is safe + */ + function _linkAvailableForPayment() internal view returns (int256) { + return int256(i_link.balanceOf(address(this))) - int256(s_reserveAmounts[IERC20(address(i_link))]); + } } diff --git a/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryLogicA2_3.sol b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryLogicA2_3.sol index f0c19b9938e..22753cc4ac3 100644 --- a/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryLogicA2_3.sol +++ b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryLogicA2_3.sol @@ -4,12 +4,15 @@ pragma solidity 0.8.19; import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; import {AutomationRegistryBase2_3} from "./AutomationRegistryBase2_3.sol"; +import {AutomationRegistryLogicC2_3} from "./AutomationRegistryLogicC2_3.sol"; import {AutomationRegistryLogicB2_3} from "./AutomationRegistryLogicB2_3.sol"; import {Chainable} from "../../Chainable.sol"; import {AutomationForwarder} from "../../AutomationForwarder.sol"; import {IAutomationForwarder} from "../../interfaces/IAutomationForwarder.sol"; import {UpkeepTranscoderInterfaceV2} from "../../interfaces/UpkeepTranscoderInterfaceV2.sol"; import {MigratableKeeperRegistryInterfaceV2} from "../../interfaces/MigratableKeeperRegistryInterfaceV2.sol"; +import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; /** * @notice Logic contract, works in tandem with AutomationRegistry as a proxy @@ -18,186 +21,31 @@ contract AutomationRegistryLogicA2_3 is AutomationRegistryBase2_3, Chainable { using Address for address; using EnumerableSet for EnumerableSet.UintSet; using EnumerableSet for EnumerableSet.AddressSet; + using SafeERC20 for IERC20; /** * @param logicB the address of the second logic contract + * @dev we cast the contract to logicC in order to call logicC functions (via fallback) */ constructor( AutomationRegistryLogicB2_3 logicB ) AutomationRegistryBase2_3( - logicB.getLinkAddress(), - logicB.getLinkUSDFeedAddress(), - logicB.getNativeUSDFeedAddress(), - logicB.getFastGasFeedAddress(), - logicB.getAutomationForwarderLogic(), - logicB.getAllowedReadOnlyAddress() + AutomationRegistryLogicC2_3(address(logicB)).getLinkAddress(), + AutomationRegistryLogicC2_3(address(logicB)).getLinkUSDFeedAddress(), + AutomationRegistryLogicC2_3(address(logicB)).getNativeUSDFeedAddress(), + AutomationRegistryLogicC2_3(address(logicB)).getFastGasFeedAddress(), + AutomationRegistryLogicC2_3(address(logicB)).getAutomationForwarderLogic(), + AutomationRegistryLogicC2_3(address(logicB)).getAllowedReadOnlyAddress(), + AutomationRegistryLogicC2_3(address(logicB)).getPayoutMode(), + AutomationRegistryLogicC2_3(address(logicB)).getWrappedNativeTokenAddress() ) Chainable(address(logicB)) {} - /** - * @notice called by the automation DON to check if work is needed - * @param id the upkeep ID to check for work needed - * @param triggerData extra contextual data about the trigger (not used in all code paths) - * @dev this one of the core functions called in the hot path - * @dev there is a 2nd checkUpkeep function (below) that is being maintained for backwards compatibility - * @dev there is an incongruency on what gets returned during failure modes - * ex sometimes we include price data, sometimes we omit it depending on the failure - */ - function checkUpkeep( - uint256 id, - bytes memory triggerData - ) - public - returns ( - bool upkeepNeeded, - bytes memory performData, - UpkeepFailureReason upkeepFailureReason, - uint256 gasUsed, - uint256 gasLimit, - uint256 fastGasWei, - uint256 linkUSD - ) - { - _preventExecution(); - - Trigger triggerType = _getTriggerType(id); - HotVars memory hotVars = s_hotVars; - Upkeep memory upkeep = s_upkeep[id]; - - { - uint256 nativeUSD; - uint96 maxLinkPayment; - if (hotVars.paused) return (false, bytes(""), UpkeepFailureReason.REGISTRY_PAUSED, 0, upkeep.performGas, 0, 0); - if (upkeep.maxValidBlocknumber != UINT32_MAX) - return (false, bytes(""), UpkeepFailureReason.UPKEEP_CANCELLED, 0, upkeep.performGas, 0, 0); - if (upkeep.paused) return (false, bytes(""), UpkeepFailureReason.UPKEEP_PAUSED, 0, upkeep.performGas, 0, 0); - (fastGasWei, linkUSD, nativeUSD) = _getFeedData(hotVars); - maxLinkPayment = _getMaxLinkPayment(hotVars, triggerType, upkeep.performGas, fastGasWei, linkUSD, nativeUSD); - if (upkeep.balance < maxLinkPayment) { - return (false, bytes(""), UpkeepFailureReason.INSUFFICIENT_BALANCE, 0, upkeep.performGas, 0, 0); - } - } - - bytes memory callData = _checkPayload(id, triggerType, triggerData); - - gasUsed = gasleft(); - (bool success, bytes memory result) = upkeep.forwarder.getTarget().call{gas: s_storage.checkGasLimit}(callData); - gasUsed = gasUsed - gasleft(); - - if (!success) { - // User's target check reverted. We capture the revert data here and pass it within performData - if (result.length > s_storage.maxRevertDataSize) { - return ( - false, - bytes(""), - UpkeepFailureReason.REVERT_DATA_EXCEEDS_LIMIT, - gasUsed, - upkeep.performGas, - fastGasWei, - linkUSD - ); - } - return ( - upkeepNeeded, - result, - UpkeepFailureReason.TARGET_CHECK_REVERTED, - gasUsed, - upkeep.performGas, - fastGasWei, - linkUSD - ); - } - - (upkeepNeeded, performData) = abi.decode(result, (bool, bytes)); - if (!upkeepNeeded) - return (false, bytes(""), UpkeepFailureReason.UPKEEP_NOT_NEEDED, gasUsed, upkeep.performGas, fastGasWei, linkUSD); - - if (performData.length > s_storage.maxPerformDataSize) - return ( - false, - bytes(""), - UpkeepFailureReason.PERFORM_DATA_EXCEEDS_LIMIT, - gasUsed, - upkeep.performGas, - fastGasWei, - linkUSD - ); - - return (upkeepNeeded, performData, upkeepFailureReason, gasUsed, upkeep.performGas, fastGasWei, linkUSD); - } - - /** - * @notice see other checkUpkeep function for description - * @dev this function may be deprecated in a future version of chainlink automation - */ - function checkUpkeep( - uint256 id - ) - external - returns ( - bool upkeepNeeded, - bytes memory performData, - UpkeepFailureReason upkeepFailureReason, - uint256 gasUsed, - uint256 gasLimit, - uint256 fastGasWei, - uint256 linkUSD - ) - { - return checkUpkeep(id, bytes("")); - } - - /** - * @dev checkCallback is used specifically for automation data streams lookups (see StreamsLookupCompatibleInterface.sol) - * @param id the upkeepID to execute a callback for - * @param values the values returned from the data streams lookup - * @param extraData the user-provided extra context data - */ - function checkCallback( - uint256 id, - bytes[] memory values, - bytes calldata extraData - ) - external - returns (bool upkeepNeeded, bytes memory performData, UpkeepFailureReason upkeepFailureReason, uint256 gasUsed) - { - bytes memory payload = abi.encodeWithSelector(CHECK_CALLBACK_SELECTOR, values, extraData); - return executeCallback(id, payload); - } - - /** - * @notice this is a generic callback executor that forwards a call to a user's contract with the configured - * gas limit - * @param id the upkeepID to execute a callback for - * @param payload the data (including function selector) to call on the upkeep target contract - */ - function executeCallback( - uint256 id, - bytes memory payload - ) - public - returns (bool upkeepNeeded, bytes memory performData, UpkeepFailureReason upkeepFailureReason, uint256 gasUsed) - { - _preventExecution(); - - Upkeep memory upkeep = s_upkeep[id]; - gasUsed = gasleft(); - (bool success, bytes memory result) = upkeep.forwarder.getTarget().call{gas: s_storage.checkGasLimit}(payload); - gasUsed = gasUsed - gasleft(); - if (!success) { - return (false, bytes(""), UpkeepFailureReason.CALLBACK_REVERTED, gasUsed); - } - (upkeepNeeded, performData) = abi.decode(result, (bool, bytes)); - if (!upkeepNeeded) { - return (false, bytes(""), UpkeepFailureReason.UPKEEP_NOT_NEEDED, gasUsed); - } - if (performData.length > s_storage.maxPerformDataSize) { - return (false, bytes(""), UpkeepFailureReason.PERFORM_DATA_EXCEEDS_LIMIT, gasUsed); - } - return (upkeepNeeded, performData, upkeepFailureReason, gasUsed); - } + // ================================================================ + // | UPKEEP MANAGEMENT | + // ================================================================ /** * @notice adds a new upkeep @@ -206,6 +54,7 @@ contract AutomationRegistryLogicA2_3 is AutomationRegistryBase2_3, Chainable { * performing upkeep * @param admin address to cancel upkeep and withdraw remaining funds * @param triggerType the trigger for the upkeep + * @param billingToken the billing token for the upkeep * @param checkData data passed to the contract when checking for upkeep * @param triggerConfig the config for the trigger * @param offchainConfig arbitrary offchain config for the upkeep @@ -215,6 +64,7 @@ contract AutomationRegistryLogicA2_3 is AutomationRegistryBase2_3, Chainable { uint32 gasLimit, address admin, Trigger triggerType, + IERC20 billingToken, bytes calldata checkData, bytes memory triggerConfig, bytes memory offchainConfig @@ -228,13 +78,15 @@ contract AutomationRegistryLogicA2_3 is AutomationRegistryBase2_3, Chainable { _createUpkeep( id, Upkeep({ + overridesEnabled: false, performGas: gasLimit, balance: 0, maxValidBlocknumber: UINT32_MAX, lastPerformedBlockNumber: 0, amountSpent: 0, paused: false, - forwarder: forwarder + forwarder: forwarder, + billingToken: billingToken }), admin, checkData, @@ -249,20 +101,6 @@ contract AutomationRegistryLogicA2_3 is AutomationRegistryBase2_3, Chainable { return (id); } - /** - * @notice this function registers a conditional upkeep, using a backwards compatible function signature - * @dev this function is backwards compatible with versions <=2.0, but may be removed in a future version - */ - function registerUpkeep( - address target, - uint32 gasLimit, - address admin, - bytes calldata checkData, - bytes calldata offchainConfig - ) external returns (uint256 id) { - return registerUpkeep(target, gasLimit, admin, Trigger.CONDITION, checkData, bytes(""), offchainConfig); - } - /** * @notice cancels an upkeep * @param id the upkeepID to cancel @@ -272,6 +110,7 @@ contract AutomationRegistryLogicA2_3 is AutomationRegistryBase2_3, Chainable { function cancelUpkeep(uint256 id) external { Upkeep memory upkeep = s_upkeep[id]; bool isOwner = msg.sender == owner(); + uint96 minSpend = s_billingConfigs[upkeep.billingToken].minSpend; uint256 height = s_hotVars.chainModule.blockNumber(); if (upkeep.maxValidBlocknumber == 0) revert CannotCancel(); @@ -284,36 +123,21 @@ contract AutomationRegistryLogicA2_3 is AutomationRegistryBase2_3, Chainable { s_upkeep[id].maxValidBlocknumber = uint32(height); s_upkeepIDs.remove(id); - // charge the cancellation fee if the minUpkeepSpend is not met - uint96 minUpkeepSpend = s_storage.minUpkeepSpend; + // charge the cancellation fee if the minSpend is not met uint96 cancellationFee = 0; - // cancellationFee is supposed to be min(max(minUpkeepSpend - amountSpent,0), amountLeft) - if (upkeep.amountSpent < minUpkeepSpend) { - cancellationFee = minUpkeepSpend - upkeep.amountSpent; + // cancellationFee is min(max(minSpend - amountSpent, 0), amountLeft) + if (upkeep.amountSpent < minSpend) { + cancellationFee = minSpend - uint96(upkeep.amountSpent); if (cancellationFee > upkeep.balance) { cancellationFee = upkeep.balance; } } s_upkeep[id].balance = upkeep.balance - cancellationFee; - s_reserveAmounts[address(i_link)] = s_reserveAmounts[address(i_link)] - cancellationFee; + s_reserveAmounts[upkeep.billingToken] = s_reserveAmounts[upkeep.billingToken] - cancellationFee; emit UpkeepCanceled(id, uint64(height)); } - /** - * @notice adds fund to an upkeep - * @param id the upkeepID - * @param amount the amount of LINK to fund, in jules (jules = "wei" of LINK) - */ - function addFunds(uint256 id, uint96 amount) external { - Upkeep memory upkeep = s_upkeep[id]; - if (upkeep.maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled(); - s_upkeep[id].balance = upkeep.balance + amount; - s_reserveAmounts[address(i_link)] = s_reserveAmounts[address(i_link)] + amount; - i_link.transferFrom(msg.sender, address(this), amount); - emit FundsAdded(id, msg.sender, amount); - } - /** * @notice migrates upkeeps from one registry to another * @param ids the upkeepIDs to migrate @@ -321,6 +145,7 @@ contract AutomationRegistryLogicA2_3 is AutomationRegistryBase2_3, Chainable { * @dev a transcoder must be set in order to enable migration * @dev migration permissions must be set on *both* sending and receiving registries * @dev only an upkeep admin can migrate their upkeeps + * @dev this function is most gas-efficient if upkeepIDs are sorted by billing token */ function migrateUpkeeps(uint256[] calldata ids, address destination) external { if ( @@ -329,9 +154,10 @@ contract AutomationRegistryLogicA2_3 is AutomationRegistryBase2_3, Chainable { ) revert MigrationNotPermitted(); if (s_storage.transcoder == ZERO_ADDRESS) revert TranscoderNotSet(); if (ids.length == 0) revert ArrayHasNoEntries(); + IERC20 billingToken; + uint256 balanceToTransfer; uint256 id; Upkeep memory upkeep; - uint256 totalBalanceRemaining; address[] memory admins = new address[](ids.length); Upkeep[] memory upkeeps = new Upkeep[](ids.length); bytes[] memory checkDatas = new bytes[](ids.length); @@ -340,6 +166,19 @@ contract AutomationRegistryLogicA2_3 is AutomationRegistryBase2_3, Chainable { for (uint256 idx = 0; idx < ids.length; idx++) { id = ids[idx]; upkeep = s_upkeep[id]; + + if (idx == 0) { + billingToken = s_upkeep[id].billingToken; + balanceToTransfer = upkeep.balance; + } + + // if we encounter a new billing token, send the sum from the last billing token to the destination registry + if (upkeep.billingToken != billingToken) { + s_reserveAmounts[billingToken] = s_reserveAmounts[billingToken] - balanceToTransfer; + billingToken.safeTransfer(destination, balanceToTransfer); + billingToken = upkeep.billingToken; + balanceToTransfer = upkeep.balance; + } _requireAdminAndNotCancelled(id); upkeep.forwarder.updateRegistry(destination); upkeeps[idx] = upkeep; @@ -347,7 +186,6 @@ contract AutomationRegistryLogicA2_3 is AutomationRegistryBase2_3, Chainable { checkDatas[idx] = s_checkData[id]; triggerConfigs[idx] = s_upkeepTriggerConfig[id]; offchainConfigs[idx] = s_upkeepOffchainConfig[id]; - totalBalanceRemaining = totalBalanceRemaining + upkeep.balance; delete s_upkeep[id]; delete s_checkData[id]; delete s_upkeepTriggerConfig[id]; @@ -356,8 +194,13 @@ contract AutomationRegistryLogicA2_3 is AutomationRegistryBase2_3, Chainable { delete s_proposedAdmin[id]; s_upkeepIDs.remove(id); emit UpkeepMigrated(id, upkeep.balance, destination); + + // always transfer the rolling sum at the end of the array + if (idx == ids.length - 1) { + s_reserveAmounts[billingToken] = s_reserveAmounts[billingToken] - balanceToTransfer; + billingToken.safeTransfer(destination, balanceToTransfer); + } } - s_reserveAmounts[address(i_link)] = s_reserveAmounts[address(i_link)] - totalBalanceRemaining; bytes memory encodedUpkeeps = abi.encode( ids, upkeeps, @@ -374,7 +217,6 @@ contract AutomationRegistryLogicA2_3 is AutomationRegistryBase2_3, Chainable { encodedUpkeeps ) ); - i_link.transfer(destination, totalBalanceRemaining); } /** @@ -413,15 +255,4 @@ contract AutomationRegistryLogicA2_3 is AutomationRegistryBase2_3, Chainable { emit UpkeepReceived(ids[idx], upkeeps[idx].balance, msg.sender); } } - - /** - * @notice sets the upkeep trigger config - * @param id the upkeepID to change the trigger for - * @param triggerConfig the new trigger config - */ - function setUpkeepTriggerConfig(uint256 id, bytes calldata triggerConfig) external { - _requireAdminAndNotCancelled(id); - s_upkeepTriggerConfig[id] = triggerConfig; - emit UpkeepTriggerConfigSet(id, triggerConfig); - } } diff --git a/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryLogicB2_3.sol b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryLogicB2_3.sol index e2710c8f93a..5063bd48dd8 100644 --- a/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryLogicB2_3.sol +++ b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryLogicB2_3.sol @@ -4,41 +4,261 @@ pragma solidity 0.8.19; import {AutomationRegistryBase2_3} from "./AutomationRegistryBase2_3.sol"; import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; -import {UpkeepFormat} from "../../interfaces/UpkeepTranscoderInterface.sol"; -import {IAutomationForwarder} from "../../interfaces/IAutomationForwarder.sol"; -import {IChainModule} from "../../interfaces/IChainModule.sol"; +import {AutomationRegistryLogicC2_3} from "./AutomationRegistryLogicC2_3.sol"; +import {Chainable} from "../../Chainable.sol"; import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol"; -contract AutomationRegistryLogicB2_3 is AutomationRegistryBase2_3 { +contract AutomationRegistryLogicB2_3 is AutomationRegistryBase2_3, Chainable { using Address for address; using EnumerableSet for EnumerableSet.UintSet; using EnumerableSet for EnumerableSet.AddressSet; + using SafeERC20 for IERC20; /** - * @dev see AutomationRegistry master contract for constructor description + * @param logicC the address of the third logic contract */ constructor( - address link, - address linkUSDFeed, - address nativeUSDFeed, - address fastGasFeed, - address automationForwarderLogic, - address allowedReadOnlyAddress + AutomationRegistryLogicC2_3 logicC ) AutomationRegistryBase2_3( - link, - linkUSDFeed, - nativeUSDFeed, - fastGasFeed, - automationForwarderLogic, - allowedReadOnlyAddress + logicC.getLinkAddress(), + logicC.getLinkUSDFeedAddress(), + logicC.getNativeUSDFeedAddress(), + logicC.getFastGasFeedAddress(), + logicC.getAutomationForwarderLogic(), + logicC.getAllowedReadOnlyAddress(), + logicC.getPayoutMode(), + logicC.getWrappedNativeTokenAddress() ) + Chainable(address(logicC)) {} + // ================================================================ + // | PIPELINE FUNCTIONS | + // ================================================================ + + /** + * @notice called by the automation DON to check if work is needed + * @param id the upkeep ID to check for work needed + * @param triggerData extra contextual data about the trigger (not used in all code paths) + * @dev this one of the core functions called in the hot path + * @dev there is a 2nd checkUpkeep function (below) that is being maintained for backwards compatibility + * @dev there is an incongruency on what gets returned during failure modes + * ex sometimes we include price data, sometimes we omit it depending on the failure + */ + function checkUpkeep( + uint256 id, + bytes memory triggerData + ) + public + returns ( + bool upkeepNeeded, + bytes memory performData, + UpkeepFailureReason upkeepFailureReason, + uint256 gasUsed, + uint256 gasLimit, + uint256 fastGasWei, + uint256 linkUSD + ) + { + _preventExecution(); + + Trigger triggerType = _getTriggerType(id); + HotVars memory hotVars = s_hotVars; + Upkeep memory upkeep = s_upkeep[id]; + + { + uint256 nativeUSD; + uint96 maxPayment; + if (hotVars.paused) return (false, bytes(""), UpkeepFailureReason.REGISTRY_PAUSED, 0, upkeep.performGas, 0, 0); + if (upkeep.maxValidBlocknumber != UINT32_MAX) + return (false, bytes(""), UpkeepFailureReason.UPKEEP_CANCELLED, 0, upkeep.performGas, 0, 0); + if (upkeep.paused) return (false, bytes(""), UpkeepFailureReason.UPKEEP_PAUSED, 0, upkeep.performGas, 0, 0); + (fastGasWei, linkUSD, nativeUSD) = _getFeedData(hotVars); + maxPayment = _getMaxPayment( + id, + hotVars, + triggerType, + upkeep.performGas, + fastGasWei, + linkUSD, + nativeUSD, + upkeep.billingToken + ); + if (upkeep.balance < maxPayment) { + return (false, bytes(""), UpkeepFailureReason.INSUFFICIENT_BALANCE, 0, upkeep.performGas, 0, 0); + } + } + + bytes memory callData = _checkPayload(id, triggerType, triggerData); + + gasUsed = gasleft(); + (bool success, bytes memory result) = upkeep.forwarder.getTarget().call{gas: s_storage.checkGasLimit}(callData); + gasUsed = gasUsed - gasleft(); + + if (!success) { + // User's target check reverted. We capture the revert data here and pass it within performData + if (result.length > s_storage.maxRevertDataSize) { + return ( + false, + bytes(""), + UpkeepFailureReason.REVERT_DATA_EXCEEDS_LIMIT, + gasUsed, + upkeep.performGas, + fastGasWei, + linkUSD + ); + } + return ( + upkeepNeeded, + result, + UpkeepFailureReason.TARGET_CHECK_REVERTED, + gasUsed, + upkeep.performGas, + fastGasWei, + linkUSD + ); + } + + (upkeepNeeded, performData) = abi.decode(result, (bool, bytes)); + if (!upkeepNeeded) + return (false, bytes(""), UpkeepFailureReason.UPKEEP_NOT_NEEDED, gasUsed, upkeep.performGas, fastGasWei, linkUSD); + + if (performData.length > s_storage.maxPerformDataSize) + return ( + false, + bytes(""), + UpkeepFailureReason.PERFORM_DATA_EXCEEDS_LIMIT, + gasUsed, + upkeep.performGas, + fastGasWei, + linkUSD + ); + + return (upkeepNeeded, performData, upkeepFailureReason, gasUsed, upkeep.performGas, fastGasWei, linkUSD); + } + + /** + * @notice see other checkUpkeep function for description + * @dev this function may be deprecated in a future version of chainlink automation + */ + function checkUpkeep( + uint256 id + ) + external + returns ( + bool upkeepNeeded, + bytes memory performData, + UpkeepFailureReason upkeepFailureReason, + uint256 gasUsed, + uint256 gasLimit, + uint256 fastGasWei, + uint256 linkUSD + ) + { + return checkUpkeep(id, bytes("")); + } + + /** + * @dev checkCallback is used specifically for automation data streams lookups (see StreamsLookupCompatibleInterface.sol) + * @param id the upkeepID to execute a callback for + * @param values the values returned from the data streams lookup + * @param extraData the user-provided extra context data + */ + function checkCallback( + uint256 id, + bytes[] memory values, + bytes calldata extraData + ) + external + returns (bool upkeepNeeded, bytes memory performData, UpkeepFailureReason upkeepFailureReason, uint256 gasUsed) + { + bytes memory payload = abi.encodeWithSelector(CHECK_CALLBACK_SELECTOR, values, extraData); + return executeCallback(id, payload); + } + + /** + * @notice this is a generic callback executor that forwards a call to a user's contract with the configured + * gas limit + * @param id the upkeepID to execute a callback for + * @param payload the data (including function selector) to call on the upkeep target contract + */ + function executeCallback( + uint256 id, + bytes memory payload + ) + public + returns (bool upkeepNeeded, bytes memory performData, UpkeepFailureReason upkeepFailureReason, uint256 gasUsed) + { + _preventExecution(); + + Upkeep memory upkeep = s_upkeep[id]; + gasUsed = gasleft(); + (bool success, bytes memory result) = upkeep.forwarder.getTarget().call{gas: s_storage.checkGasLimit}(payload); + gasUsed = gasUsed - gasleft(); + if (!success) { + return (false, bytes(""), UpkeepFailureReason.CALLBACK_REVERTED, gasUsed); + } + (upkeepNeeded, performData) = abi.decode(result, (bool, bytes)); + if (!upkeepNeeded) { + return (false, bytes(""), UpkeepFailureReason.UPKEEP_NOT_NEEDED, gasUsed); + } + if (performData.length > s_storage.maxPerformDataSize) { + return (false, bytes(""), UpkeepFailureReason.PERFORM_DATA_EXCEEDS_LIMIT, gasUsed); + } + return (upkeepNeeded, performData, upkeepFailureReason, gasUsed); + } + + /** + * @notice simulates the upkeep with the perform data returned from checkUpkeep + * @param id identifier of the upkeep to execute the data with. + * @param performData calldata parameter to be passed to the target upkeep. + * @return success whether the call reverted or not + * @return gasUsed the amount of gas the target contract consumed + */ + function simulatePerformUpkeep( + uint256 id, + bytes calldata performData + ) external returns (bool success, uint256 gasUsed) { + _preventExecution(); + + if (s_hotVars.paused) revert RegistryPaused(); + Upkeep memory upkeep = s_upkeep[id]; + (success, gasUsed) = _performUpkeep(upkeep.forwarder, upkeep.performGas, performData); + return (success, gasUsed); + } + // ================================================================ // | UPKEEP MANAGEMENT | // ================================================================ + /** + * @notice overrides the billing config for an upkeep + * @param id the upkeepID + * @param billingOverrides the override-able billing config + */ + function setBillingOverrides(uint256 id, BillingOverrides calldata billingOverrides) external { + _onlyPrivilegeManagerAllowed(); + if (s_upkeep[id].maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled(); + + s_upkeep[id].overridesEnabled = true; + s_billingOverrides[id] = billingOverrides; + emit BillingConfigOverridden(id, billingOverrides); + } + + /** + * @notice remove the overridden billing config for an upkeep + * @param id the upkeepID + */ + function removeBillingOverrides(uint256 id) external { + _onlyPrivilegeManagerAllowed(); + + s_upkeep[id].overridesEnabled = false; + delete s_billingOverrides[id]; + emit BillingConfigOverrideRemoved(id); + } + /** * @notice transfers the address of an admin for an upkeep */ @@ -121,7 +341,18 @@ contract AutomationRegistryLogicB2_3 is AutomationRegistryBase2_3 { } /** - * @notice withdraws LINK funds from an upkeep + * @notice sets the upkeep trigger config + * @param id the upkeepID to change the trigger for + * @param triggerConfig the new trigger config + */ + function setUpkeepTriggerConfig(uint256 id, bytes calldata triggerConfig) external { + _requireAdminAndNotCancelled(id); + s_upkeepTriggerConfig[id] = triggerConfig; + emit UpkeepTriggerConfigSet(id, triggerConfig); + } + + /** + * @notice withdraws an upkeep's funds from an upkeep * @dev note that an upkeep must be cancelled first!! */ function withdrawFunds(uint256 id, address to) external nonReentrant { @@ -130,454 +361,56 @@ contract AutomationRegistryLogicB2_3 is AutomationRegistryBase2_3 { if (s_upkeepAdmin[id] != msg.sender) revert OnlyCallableByAdmin(); if (upkeep.maxValidBlocknumber > s_hotVars.chainModule.blockNumber()) revert UpkeepNotCanceled(); uint96 amountToWithdraw = s_upkeep[id].balance; - s_reserveAmounts[address(i_link)] = s_reserveAmounts[address(i_link)] - amountToWithdraw; + s_reserveAmounts[upkeep.billingToken] = s_reserveAmounts[upkeep.billingToken] - amountToWithdraw; s_upkeep[id].balance = 0; - i_link.transfer(to, amountToWithdraw); + upkeep.billingToken.safeTransfer(to, amountToWithdraw); emit FundsWithdrawn(id, amountToWithdraw, to); } + // ================================================================ + // | FINANCE ACTIONS | + // ================================================================ + /** - * @notice LINK available to withdraw by the finance team + * @notice withdraws excess LINK from the liquidity pool + * @param to the address to send the fees to + * @param amount the amount to withdraw */ - function linkAvailableForPayment() public view returns (uint256) { - return i_link.balanceOf(address(this)) - s_reserveAmounts[address(i_link)]; - } - - function withdrawLinkFees(address to, uint256 amount) external { + function withdrawLink(address to, uint256 amount) external { _onlyFinanceAdminAllowed(); if (to == ZERO_ADDRESS) revert InvalidRecipient(); - uint256 available = linkAvailableForPayment(); - if (amount > available) revert InsufficientBalance(available, amount); - - bool transferStatus = i_link.transfer(to, amount); - if (!transferStatus) { - revert TransferFailed(); + int256 available = _linkAvailableForPayment(); + if (available < 0) { + revert InsufficientBalance(0, amount); + } else if (amount > uint256(available)) { + revert InsufficientBalance(uint256(available), amount); } - emit FeesWithdrawn(to, address(i_link), amount); - } - - function withdrawERC20Fees(address assetAddress, address to, uint256 amount) external { - _onlyFinanceAdminAllowed(); - if (to == ZERO_ADDRESS) revert InvalidRecipient(); - bool transferStatus = IERC20(assetAddress).transfer(to, amount); + bool transferStatus = i_link.transfer(to, amount); if (!transferStatus) { revert TransferFailed(); } - - emit FeesWithdrawn(to, assetAddress, amount); - } - - // ================================================================ - // | NODE MANAGEMENT | - // ================================================================ - - /** - * @notice transfers the address of payee for a transmitter - */ - function transferPayeeship(address transmitter, address proposed) external { - if (s_transmitterPayees[transmitter] != msg.sender) revert OnlyCallableByPayee(); - if (proposed == msg.sender) revert ValueNotChanged(); - - if (s_proposedPayee[transmitter] != proposed) { - s_proposedPayee[transmitter] = proposed; - emit PayeeshipTransferRequested(transmitter, msg.sender, proposed); - } - } - - /** - * @notice accepts the transfer of the payee - */ - function acceptPayeeship(address transmitter) external { - if (s_proposedPayee[transmitter] != msg.sender) revert OnlyCallableByProposedPayee(); - address past = s_transmitterPayees[transmitter]; - s_transmitterPayees[transmitter] = msg.sender; - s_proposedPayee[transmitter] = ZERO_ADDRESS; - - emit PayeeshipTransferred(transmitter, past, msg.sender); + emit FeesWithdrawn(address(i_link), to, amount); } /** - * @notice withdraws LINK received as payment for work performed + * @notice withdraws non-LINK fees earned by the contract + * @param asset the asset to withdraw + * @param to the address to send the fees to + * @param amount the amount to withdraw + * @dev we prevent withdrawing non-LINK fees unless there is sufficient LINK liquidity + * to cover all outstanding debts on the registry */ - function withdrawPayment(address from, address to) external { + function withdrawERC20Fees(IERC20 asset, address to, uint256 amount) external { + _onlyFinanceAdminAllowed(); if (to == ZERO_ADDRESS) revert InvalidRecipient(); - if (s_transmitterPayees[from] != msg.sender) revert OnlyCallableByPayee(); - uint96 balance = _updateTransmitterBalanceFromPool(from, s_hotVars.totalPremium, uint96(s_transmittersList.length)); - s_transmitters[from].balance = 0; - s_reserveAmounts[address(i_link)] = s_reserveAmounts[address(i_link)] - balance; - i_link.transfer(to, balance); - emit PaymentWithdrawn(from, balance, to, msg.sender); - } - - // ================================================================ - // | OWNER / MANAGER ACTIONS | - // ================================================================ - - /** - * @notice sets the privilege config for an upkeep - */ - function setUpkeepPrivilegeConfig(uint256 upkeepId, bytes calldata newPrivilegeConfig) external { - if (msg.sender != s_storage.upkeepPrivilegeManager) { - revert OnlyCallableByUpkeepPrivilegeManager(); - } - s_upkeepPrivilegeConfig[upkeepId] = newPrivilegeConfig; - emit UpkeepPrivilegeConfigSet(upkeepId, newPrivilegeConfig); - } - - /** - * @notice sets the payees for the transmitters - */ - function setPayees(address[] calldata payees) external onlyOwner { - if (s_transmittersList.length != payees.length) revert ParameterLengthError(); - for (uint256 i = 0; i < s_transmittersList.length; i++) { - address transmitter = s_transmittersList[i]; - address oldPayee = s_transmitterPayees[transmitter]; - address newPayee = payees[i]; - if ( - (newPayee == ZERO_ADDRESS) || (oldPayee != ZERO_ADDRESS && oldPayee != newPayee && newPayee != IGNORE_ADDRESS) - ) revert InvalidPayee(); - if (newPayee != IGNORE_ADDRESS) { - s_transmitterPayees[transmitter] = newPayee; - } - } - emit PayeesUpdated(s_transmittersList, payees); - } - - /** - * @notice sets the migration permission for a peer registry - * @dev this must be done before upkeeps can be migrated to/from another registry - */ - function setPeerRegistryMigrationPermission(address peer, MigrationPermission permission) external onlyOwner { - s_peerRegistryMigrationPermission[peer] = permission; - } - - /** - * @notice pauses the entire registry - */ - function pause() external onlyOwner { - s_hotVars.paused = true; - emit Paused(msg.sender); - } - - /** - * @notice unpauses the entire registry - */ - function unpause() external onlyOwner { - s_hotVars.paused = false; - emit Unpaused(msg.sender); - } - - /** - * @notice sets a generic bytes field used to indicate the privilege that this admin address had - * @param admin the address to set privilege for - * @param newPrivilegeConfig the privileges that this admin has - */ - function setAdminPrivilegeConfig(address admin, bytes calldata newPrivilegeConfig) external { - if (msg.sender != s_storage.upkeepPrivilegeManager) { - revert OnlyCallableByUpkeepPrivilegeManager(); - } - s_adminPrivilegeConfig[admin] = newPrivilegeConfig; - emit AdminPrivilegeConfigSet(admin, newPrivilegeConfig); - } - - // ================================================================ - // | GETTERS | - // ================================================================ - - function getConditionalGasOverhead() external pure returns (uint256) { - return REGISTRY_CONDITIONAL_OVERHEAD; - } - - function getLogGasOverhead() external pure returns (uint256) { - return REGISTRY_LOG_OVERHEAD; - } - - function getPerPerformByteGasOverhead() external pure returns (uint256) { - return REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD; - } - - function getPerSignerGasOverhead() external pure returns (uint256) { - return REGISTRY_PER_SIGNER_GAS_OVERHEAD; - } - - function getTransmitCalldataFixedBytesOverhead() external pure returns (uint256) { - return TRANSMIT_CALLDATA_FIXED_BYTES_OVERHEAD; - } - - function getTransmitCalldataPerSignerBytesOverhead() external pure returns (uint256) { - return TRANSMIT_CALLDATA_PER_SIGNER_BYTES_OVERHEAD; - } - - function getCancellationDelay() external pure returns (uint256) { - return CANCELLATION_DELAY; - } - - function getLinkAddress() external view returns (address) { - return address(i_link); - } - - function getLinkUSDFeedAddress() external view returns (address) { - return address(i_linkUSDFeed); - } - - function getNativeUSDFeedAddress() external view returns (address) { - return address(i_nativeUSDFeed); - } - - function getFastGasFeedAddress() external view returns (address) { - return address(i_fastGasFeed); - } - - function getAutomationForwarderLogic() external view returns (address) { - return i_automationForwarderLogic; - } - - function getAllowedReadOnlyAddress() external view returns (address) { - return i_allowedReadOnlyAddress; - } - - function getBillingTokens() external view returns (IERC20[] memory) { - return s_billingTokens; - } - - function getBillingTokenConfig(IERC20 token) external view returns (BillingConfig memory) { - return s_billingConfigs[token]; - } - - function upkeepTranscoderVersion() public pure returns (UpkeepFormat) { - return UPKEEP_TRANSCODER_VERSION_BASE; - } - - function upkeepVersion() public pure returns (uint8) { - return UPKEEP_VERSION_BASE; - } - - /** - * @notice read all of the details about an upkeep - * @dev this function may be deprecated in a future version of automation in favor of individual - * getters for each field - */ - function getUpkeep(uint256 id) external view returns (UpkeepInfo memory upkeepInfo) { - Upkeep memory reg = s_upkeep[id]; - address target = address(reg.forwarder) == address(0) ? address(0) : reg.forwarder.getTarget(); - upkeepInfo = UpkeepInfo({ - target: target, - performGas: reg.performGas, - checkData: s_checkData[id], - balance: reg.balance, - admin: s_upkeepAdmin[id], - maxValidBlocknumber: reg.maxValidBlocknumber, - lastPerformedBlockNumber: reg.lastPerformedBlockNumber, - amountSpent: reg.amountSpent, - paused: reg.paused, - offchainConfig: s_upkeepOffchainConfig[id] - }); - return upkeepInfo; - } - - /** - * @notice retrieve active upkeep IDs. Active upkeep is defined as an upkeep which is not paused and not canceled. - * @param startIndex starting index in list - * @param maxCount max count to retrieve (0 = unlimited) - * @dev the order of IDs in the list is **not guaranteed**, therefore, if making successive calls, one - * should consider keeping the blockheight constant to ensure a holistic picture of the contract state - */ - function getActiveUpkeepIDs(uint256 startIndex, uint256 maxCount) external view returns (uint256[] memory) { - uint256 numUpkeeps = s_upkeepIDs.length(); - if (startIndex >= numUpkeeps) revert IndexOutOfRange(); - uint256 endIndex = startIndex + maxCount; - endIndex = endIndex > numUpkeeps || maxCount == 0 ? numUpkeeps : endIndex; - uint256[] memory ids = new uint256[](endIndex - startIndex); - for (uint256 idx = 0; idx < ids.length; idx++) { - ids[idx] = s_upkeepIDs.at(idx + startIndex); - } - return ids; - } - - /** - * @notice returns the upkeep's trigger type - */ - function getTriggerType(uint256 upkeepId) external pure returns (Trigger) { - return _getTriggerType(upkeepId); - } - - /** - * @notice returns the trigger config for an upkeeep - */ - function getUpkeepTriggerConfig(uint256 upkeepId) public view returns (bytes memory) { - return s_upkeepTriggerConfig[upkeepId]; - } - - /** - * @notice read the current info about any transmitter address - */ - function getTransmitterInfo( - address query - ) external view returns (bool active, uint8 index, uint96 balance, uint96 lastCollected, address payee) { - Transmitter memory transmitter = s_transmitters[query]; - - uint96 pooledShare = 0; - if (transmitter.active) { - uint96 totalDifference = s_hotVars.totalPremium - transmitter.lastCollected; - pooledShare = totalDifference / uint96(s_transmittersList.length); - } - - return ( - transmitter.active, - transmitter.index, - (transmitter.balance + pooledShare), - transmitter.lastCollected, - s_transmitterPayees[query] - ); - } - - /** - * @notice read the current info about any signer address - */ - function getSignerInfo(address query) external view returns (bool active, uint8 index) { - Signer memory signer = s_signers[query]; - return (signer.active, signer.index); - } - - /** - * @notice read the current state of the registry - * @dev this function is deprecated - */ - function getState() - external - view - returns ( - State memory state, - OnchainConfigLegacy memory config, - address[] memory signers, - address[] memory transmitters, - uint8 f - ) - { - state = State({ - nonce: s_storage.nonce, - ownerLinkBalance: 0, - expectedLinkBalance: s_reserveAmounts[address(i_link)], - totalPremium: s_hotVars.totalPremium, - numUpkeeps: s_upkeepIDs.length(), - configCount: s_storage.configCount, - latestConfigBlockNumber: s_storage.latestConfigBlockNumber, - latestConfigDigest: s_latestConfigDigest, - latestEpoch: s_hotVars.latestEpoch, - paused: s_hotVars.paused - }); - - config = OnchainConfigLegacy({ - paymentPremiumPPB: s_hotVars.paymentPremiumPPB, - flatFeeMicroLink: s_hotVars.flatFeeMicroLink, - checkGasLimit: s_storage.checkGasLimit, - stalenessSeconds: s_hotVars.stalenessSeconds, - gasCeilingMultiplier: s_hotVars.gasCeilingMultiplier, - minUpkeepSpend: s_storage.minUpkeepSpend, - maxPerformGas: s_storage.maxPerformGas, - maxCheckDataSize: s_storage.maxCheckDataSize, - maxPerformDataSize: s_storage.maxPerformDataSize, - maxRevertDataSize: s_storage.maxRevertDataSize, - fallbackGasPrice: s_fallbackGasPrice, - fallbackLinkPrice: s_fallbackLinkPrice, - transcoder: s_storage.transcoder, - registrars: s_registrars.values(), - upkeepPrivilegeManager: s_storage.upkeepPrivilegeManager - }); - - return (state, config, s_signersList, s_transmittersList, s_hotVars.f); - } - - /** - * @notice get the chain module - */ - function getChainModule() external view returns (IChainModule chainModule) { - return s_hotVars.chainModule; - } - - /** - * @notice if this registry has reorg protection enabled - */ - function getReorgProtectionEnabled() external view returns (bool reorgProtectionEnabled) { - return s_hotVars.reorgProtectionEnabled; - } - - /** - * @notice calculates the minimum balance required for an upkeep to remain eligible - * @param id the upkeep id to calculate minimum balance for - */ - function getBalance(uint256 id) external view returns (uint96 balance) { - return s_upkeep[id].balance; - } - - /** - * @notice calculates the minimum balance required for an upkeep to remain eligible - * @param id the upkeep id to calculate minimum balance for - */ - function getMinBalance(uint256 id) external view returns (uint96) { - return getMinBalanceForUpkeep(id); - } - - /** - * @notice calculates the minimum balance required for an upkeep to remain eligible - * @param id the upkeep id to calculate minimum balance for - * @dev this will be deprecated in a future version in favor of getMinBalance - */ - function getMinBalanceForUpkeep(uint256 id) public view returns (uint96 minBalance) { - return getMaxPaymentForGas(_getTriggerType(id), s_upkeep[id].performGas); - } - - /** - * @notice calculates the maximum payment for a given gas limit - * @param gasLimit the gas to calculate payment for - */ - function getMaxPaymentForGas(Trigger triggerType, uint32 gasLimit) public view returns (uint96 maxPayment) { - HotVars memory hotVars = s_hotVars; - (uint256 fastGasWei, uint256 linkUSD, uint256 nativeUSD) = _getFeedData(hotVars); - return _getMaxLinkPayment(hotVars, triggerType, gasLimit, fastGasWei, linkUSD, nativeUSD); - } - - /** - * @notice retrieves the migration permission for a peer registry - */ - function getPeerRegistryMigrationPermission(address peer) external view returns (MigrationPermission) { - return s_peerRegistryMigrationPermission[peer]; - } - - /** - * @notice returns the upkeep privilege config - */ - function getUpkeepPrivilegeConfig(uint256 upkeepId) external view returns (bytes memory) { - return s_upkeepPrivilegeConfig[upkeepId]; - } - - /** - * @notice returns the upkeep privilege config - */ - function getAdminPrivilegeConfig(address admin) external view returns (bytes memory) { - return s_adminPrivilegeConfig[admin]; - } - - /** - * @notice returns the upkeep's forwarder contract - */ - function getForwarder(uint256 upkeepID) external view returns (IAutomationForwarder) { - return s_upkeep[upkeepID].forwarder; - } - - /** - * @notice returns the upkeep's forwarder contract - */ - function hasDedupKey(bytes32 dedupKey) external view returns (bool) { - return s_dedupKeys[dedupKey]; - } + if (address(asset) == address(i_link)) revert InvalidToken(); + if (_linkAvailableForPayment() < 0) revert InsufficientLinkLiquidity(); + uint256 available = asset.balanceOf(address(this)) - s_reserveAmounts[asset]; + if (amount > available) revert InsufficientBalance(available, amount); - /** - * @notice returns the fallback native price - */ - function getFallbackNativePrice() external view returns (uint256) { - return s_fallbackNativePrice; + asset.safeTransfer(to, amount); + emit FeesWithdrawn(address(asset), to, amount); } } diff --git a/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryLogicC2_3.sol b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryLogicC2_3.sol new file mode 100644 index 00000000000..ad8512bef33 --- /dev/null +++ b/contracts/src/v0.8/automation/dev/v2_3/AutomationRegistryLogicC2_3.sol @@ -0,0 +1,577 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.19; + +import {AutomationRegistryBase2_3} from "./AutomationRegistryBase2_3.sol"; +import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; +import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; +import {IAutomationForwarder} from "../../interfaces/IAutomationForwarder.sol"; +import {IChainModule} from "../../interfaces/IChainModule.sol"; +import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {IAutomationV21PlusCommon} from "../../interfaces/IAutomationV21PlusCommon.sol"; + +contract AutomationRegistryLogicC2_3 is AutomationRegistryBase2_3 { + using Address for address; + using EnumerableSet for EnumerableSet.UintSet; + using EnumerableSet for EnumerableSet.AddressSet; + + /** + * @dev see AutomationRegistry master contract for constructor description + */ + constructor( + address link, + address linkUSDFeed, + address nativeUSDFeed, + address fastGasFeed, + address automationForwarderLogic, + address allowedReadOnlyAddress, + PayoutMode payoutMode, + address wrappedNativeTokenAddress + ) + AutomationRegistryBase2_3( + link, + linkUSDFeed, + nativeUSDFeed, + fastGasFeed, + automationForwarderLogic, + allowedReadOnlyAddress, + payoutMode, + wrappedNativeTokenAddress + ) + {} + + // ================================================================ + // | NODE ACTIONS | + // ================================================================ + + /** + * @notice transfers the address of payee for a transmitter + */ + function transferPayeeship(address transmitter, address proposed) external { + if (s_transmitterPayees[transmitter] != msg.sender) revert OnlyCallableByPayee(); + if (proposed == msg.sender) revert ValueNotChanged(); + + if (s_proposedPayee[transmitter] != proposed) { + s_proposedPayee[transmitter] = proposed; + emit PayeeshipTransferRequested(transmitter, msg.sender, proposed); + } + } + + /** + * @notice accepts the transfer of the payee + */ + function acceptPayeeship(address transmitter) external { + if (s_proposedPayee[transmitter] != msg.sender) revert OnlyCallableByProposedPayee(); + address past = s_transmitterPayees[transmitter]; + s_transmitterPayees[transmitter] = msg.sender; + s_proposedPayee[transmitter] = ZERO_ADDRESS; + + emit PayeeshipTransferred(transmitter, past, msg.sender); + } + + /** + * @notice withdraws LINK received as payment for work performed + */ + function withdrawPayment(address from, address to) external { + if (to == ZERO_ADDRESS) revert InvalidRecipient(); + if (s_payoutMode == PayoutMode.OFF_CHAIN) revert MustSettleOffchain(); + if (s_transmitterPayees[from] != msg.sender) revert OnlyCallableByPayee(); + uint96 balance = _updateTransmitterBalanceFromPool(from, s_hotVars.totalPremium, uint96(s_transmittersList.length)); + s_transmitters[from].balance = 0; + s_reserveAmounts[IERC20(address(i_link))] = s_reserveAmounts[IERC20(address(i_link))] - balance; + i_link.transfer(to, balance); + emit PaymentWithdrawn(from, balance, to, msg.sender); + } + + // ================================================================ + // | OWNER / MANAGER ACTIONS | + // ================================================================ + + /** + * @notice sets the privilege config for an upkeep + */ + function setUpkeepPrivilegeConfig(uint256 upkeepId, bytes calldata newPrivilegeConfig) external { + _onlyPrivilegeManagerAllowed(); + s_upkeepPrivilegeConfig[upkeepId] = newPrivilegeConfig; + emit UpkeepPrivilegeConfigSet(upkeepId, newPrivilegeConfig); + } + + /** + * @notice sets the payees for the transmitters + */ + function setPayees(address[] calldata payees) external onlyOwner { + if (s_transmittersList.length != payees.length) revert ParameterLengthError(); + for (uint256 i = 0; i < s_transmittersList.length; i++) { + address transmitter = s_transmittersList[i]; + address oldPayee = s_transmitterPayees[transmitter]; + address newPayee = payees[i]; + if ( + (newPayee == ZERO_ADDRESS) || (oldPayee != ZERO_ADDRESS && oldPayee != newPayee && newPayee != IGNORE_ADDRESS) + ) revert InvalidPayee(); + if (newPayee != IGNORE_ADDRESS) { + s_transmitterPayees[transmitter] = newPayee; + } + } + emit PayeesUpdated(s_transmittersList, payees); + } + + /** + * @notice sets the migration permission for a peer registry + * @dev this must be done before upkeeps can be migrated to/from another registry + */ + function setPeerRegistryMigrationPermission(address peer, MigrationPermission permission) external onlyOwner { + s_peerRegistryMigrationPermission[peer] = permission; + } + + /** + * @notice pauses the entire registry + */ + function pause() external onlyOwner { + s_hotVars.paused = true; + emit Paused(msg.sender); + } + + /** + * @notice unpauses the entire registry + */ + function unpause() external onlyOwner { + s_hotVars.paused = false; + emit Unpaused(msg.sender); + } + + /** + * @notice sets a generic bytes field used to indicate the privilege that this admin address had + * @param admin the address to set privilege for + * @param newPrivilegeConfig the privileges that this admin has + */ + function setAdminPrivilegeConfig(address admin, bytes calldata newPrivilegeConfig) external { + _onlyPrivilegeManagerAllowed(); + s_adminPrivilegeConfig[admin] = newPrivilegeConfig; + emit AdminPrivilegeConfigSet(admin, newPrivilegeConfig); + } + + /** + * @notice settles NOPs' LINK payment offchain + */ + function settleNOPsOffchain() external { + _onlyFinanceAdminAllowed(); + if (s_payoutMode == PayoutMode.ON_CHAIN) revert MustSettleOnchain(); + + uint256 activeTransmittersLength = s_transmittersList.length; + uint256 deactivatedTransmittersLength = s_deactivatedTransmitters.length(); + uint256 length = activeTransmittersLength + deactivatedTransmittersLength; + uint256[] memory payments = new uint256[](length); + address[] memory payees = new address[](length); + for (uint256 i = 0; i < activeTransmittersLength; i++) { + address transmitterAddr = s_transmittersList[i]; + uint96 balance = _updateTransmitterBalanceFromPool( + transmitterAddr, + s_hotVars.totalPremium, + uint96(activeTransmittersLength) + ); + payments[i] = balance; + payees[i] = s_transmitterPayees[transmitterAddr]; + s_transmitters[transmitterAddr].balance = 0; + } + for (uint256 i = 0; i < deactivatedTransmittersLength; i++) { + address deactivatedAddr = s_deactivatedTransmitters.at(i); + Transmitter memory transmitter = s_transmitters[deactivatedAddr]; + payees[i + activeTransmittersLength] = s_transmitterPayees[deactivatedAddr]; + payments[i + activeTransmittersLength] = transmitter.balance; + s_transmitters[deactivatedAddr].balance = 0; + } + delete s_deactivatedTransmitters; + + emit NOPsSettledOffchain(payees, payments); + } + + /** + * @notice disables offchain payment for NOPs + */ + function disableOffchainPayments() external onlyOwner { + s_payoutMode = PayoutMode.ON_CHAIN; + } + + // ================================================================ + // | GETTERS | + // ================================================================ + + function getConditionalGasOverhead() external pure returns (uint256) { + return REGISTRY_CONDITIONAL_OVERHEAD; + } + + function getLogGasOverhead() external pure returns (uint256) { + return REGISTRY_LOG_OVERHEAD; + } + + function getPerPerformByteGasOverhead() external pure returns (uint256) { + return REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD; + } + + function getPerSignerGasOverhead() external pure returns (uint256) { + return REGISTRY_PER_SIGNER_GAS_OVERHEAD; + } + + function getTransmitCalldataFixedBytesOverhead() external pure returns (uint256) { + return TRANSMIT_CALLDATA_FIXED_BYTES_OVERHEAD; + } + + function getTransmitCalldataPerSignerBytesOverhead() external pure returns (uint256) { + return TRANSMIT_CALLDATA_PER_SIGNER_BYTES_OVERHEAD; + } + + function getCancellationDelay() external pure returns (uint256) { + return CANCELLATION_DELAY; + } + + function getLinkAddress() external view returns (address) { + return address(i_link); + } + + function getLinkUSDFeedAddress() external view returns (address) { + return address(i_linkUSDFeed); + } + + function getNativeUSDFeedAddress() external view returns (address) { + return address(i_nativeUSDFeed); + } + + function getFastGasFeedAddress() external view returns (address) { + return address(i_fastGasFeed); + } + + function getAutomationForwarderLogic() external view returns (address) { + return i_automationForwarderLogic; + } + + function getAllowedReadOnlyAddress() external view returns (address) { + return i_allowedReadOnlyAddress; + } + + function getWrappedNativeTokenAddress() external view returns (address) { + return address(i_wrappedNativeToken); + } + + function getBillingToken(uint256 upkeepID) external view returns (IERC20) { + return s_upkeep[upkeepID].billingToken; + } + + function getBillingTokens() external view returns (IERC20[] memory) { + return s_billingTokens; + } + + function supportsBillingToken(IERC20 token) external view returns (bool) { + return address(s_billingConfigs[token].priceFeed) != address(0); + } + + function getBillingTokenConfig(IERC20 token) external view returns (BillingConfig memory) { + return s_billingConfigs[token]; + } + + function getPayoutMode() external view returns (PayoutMode) { + return s_payoutMode; + } + + function upkeepVersion() public pure returns (uint8) { + return UPKEEP_VERSION_BASE; + } + + /** + * @notice gets the number of upkeeps on the registry + */ + function getNumUpkeeps() external view returns (uint256) { + return s_upkeepIDs.length(); + } + + /** + * @notice read all of the details about an upkeep + * @dev this function may be deprecated in a future version of automation in favor of individual + * getters for each field + */ + function getUpkeep(uint256 id) external view returns (IAutomationV21PlusCommon.UpkeepInfoLegacy memory upkeepInfo) { + Upkeep memory reg = s_upkeep[id]; + address target = address(reg.forwarder) == address(0) ? address(0) : reg.forwarder.getTarget(); + upkeepInfo = IAutomationV21PlusCommon.UpkeepInfoLegacy({ + target: target, + performGas: reg.performGas, + checkData: s_checkData[id], + balance: reg.balance, + admin: s_upkeepAdmin[id], + maxValidBlocknumber: reg.maxValidBlocknumber, + lastPerformedBlockNumber: reg.lastPerformedBlockNumber, + amountSpent: uint96(reg.amountSpent), // force casting to uint96 for backwards compatibility. Not an issue if it overflows. + paused: reg.paused, + offchainConfig: s_upkeepOffchainConfig[id] + }); + return upkeepInfo; + } + + /** + * @notice retrieve active upkeep IDs. Active upkeep is defined as an upkeep which is not paused and not canceled. + * @param startIndex starting index in list + * @param maxCount max count to retrieve (0 = unlimited) + * @dev the order of IDs in the list is **not guaranteed**, therefore, if making successive calls, one + * should consider keeping the blockheight constant to ensure a holistic picture of the contract state + */ + function getActiveUpkeepIDs(uint256 startIndex, uint256 maxCount) external view returns (uint256[] memory) { + uint256 numUpkeeps = s_upkeepIDs.length(); + if (startIndex >= numUpkeeps) revert IndexOutOfRange(); + uint256 endIndex = startIndex + maxCount; + endIndex = endIndex > numUpkeeps || maxCount == 0 ? numUpkeeps : endIndex; + uint256[] memory ids = new uint256[](endIndex - startIndex); + for (uint256 idx = 0; idx < ids.length; idx++) { + ids[idx] = s_upkeepIDs.at(idx + startIndex); + } + return ids; + } + + /** + * @notice returns the upkeep's trigger type + */ + function getTriggerType(uint256 upkeepId) external pure returns (Trigger) { + return _getTriggerType(upkeepId); + } + + /** + * @notice returns the trigger config for an upkeeep + */ + function getUpkeepTriggerConfig(uint256 upkeepId) public view returns (bytes memory) { + return s_upkeepTriggerConfig[upkeepId]; + } + + /** + * @notice read the current info about any transmitter address + */ + function getTransmitterInfo( + address query + ) external view returns (bool active, uint8 index, uint96 balance, uint96 lastCollected, address payee) { + Transmitter memory transmitter = s_transmitters[query]; + + uint96 pooledShare = 0; + if (transmitter.active) { + uint96 totalDifference = s_hotVars.totalPremium - transmitter.lastCollected; + pooledShare = totalDifference / uint96(s_transmittersList.length); + } + + return ( + transmitter.active, + transmitter.index, + (transmitter.balance + pooledShare), + transmitter.lastCollected, + s_transmitterPayees[query] + ); + } + + /** + * @notice read the current info about any signer address + */ + function getSignerInfo(address query) external view returns (bool active, uint8 index) { + Signer memory signer = s_signers[query]; + return (signer.active, signer.index); + } + + /** + * @notice read the current on-chain config of the registry + * @dev this function will change between versions, it should never be used where + * backwards compatibility matters! + */ + function getConfig() external view returns (OnchainConfig memory) { + return + OnchainConfig({ + checkGasLimit: s_storage.checkGasLimit, + stalenessSeconds: s_hotVars.stalenessSeconds, + gasCeilingMultiplier: s_hotVars.gasCeilingMultiplier, + maxPerformGas: s_storage.maxPerformGas, + maxCheckDataSize: s_storage.maxCheckDataSize, + maxPerformDataSize: s_storage.maxPerformDataSize, + maxRevertDataSize: s_storage.maxRevertDataSize, + fallbackGasPrice: s_fallbackGasPrice, + fallbackLinkPrice: s_fallbackLinkPrice, + fallbackNativePrice: s_fallbackNativePrice, + transcoder: s_storage.transcoder, + registrars: s_registrars.values(), + upkeepPrivilegeManager: s_storage.upkeepPrivilegeManager, + chainModule: s_hotVars.chainModule, + reorgProtectionEnabled: s_hotVars.reorgProtectionEnabled, + financeAdmin: s_storage.financeAdmin + }); + } + + /** + * @notice read the current state of the registry + * @dev this function is deprecated + */ + function getState() + external + view + returns ( + IAutomationV21PlusCommon.StateLegacy memory state, + IAutomationV21PlusCommon.OnchainConfigLegacy memory config, + address[] memory signers, + address[] memory transmitters, + uint8 f + ) + { + state = IAutomationV21PlusCommon.StateLegacy({ + nonce: s_storage.nonce, + ownerLinkBalance: 0, // deprecated + expectedLinkBalance: 0, // deprecated + totalPremium: s_hotVars.totalPremium, + numUpkeeps: s_upkeepIDs.length(), + configCount: s_storage.configCount, + latestConfigBlockNumber: s_storage.latestConfigBlockNumber, + latestConfigDigest: s_latestConfigDigest, + latestEpoch: s_hotVars.latestEpoch, + paused: s_hotVars.paused + }); + + config = IAutomationV21PlusCommon.OnchainConfigLegacy({ + paymentPremiumPPB: 0, // deprecated + flatFeeMicroLink: 0, // deprecated + checkGasLimit: s_storage.checkGasLimit, + stalenessSeconds: s_hotVars.stalenessSeconds, + gasCeilingMultiplier: s_hotVars.gasCeilingMultiplier, + minUpkeepSpend: 0, // deprecated + maxPerformGas: s_storage.maxPerformGas, + maxCheckDataSize: s_storage.maxCheckDataSize, + maxPerformDataSize: s_storage.maxPerformDataSize, + maxRevertDataSize: s_storage.maxRevertDataSize, + fallbackGasPrice: s_fallbackGasPrice, + fallbackLinkPrice: s_fallbackLinkPrice, + transcoder: s_storage.transcoder, + registrars: s_registrars.values(), + upkeepPrivilegeManager: s_storage.upkeepPrivilegeManager + }); + + return (state, config, s_signersList, s_transmittersList, s_hotVars.f); + } + + /** + * @notice read the Storage data + * @dev this function signature will change with each version of automation + * this should not be treated as a stable function + */ + function getStorage() external view returns (Storage memory) { + return s_storage; + } + + /** + * @notice read the HotVars data + * @dev this function signature will change with each version of automation + * this should not be treated as a stable function + */ + function getHotVars() external view returns (HotVars memory) { + return s_hotVars; + } + + /** + * @notice get the chain module + */ + function getChainModule() external view returns (IChainModule chainModule) { + return s_hotVars.chainModule; + } + + /** + * @notice if this registry has reorg protection enabled + */ + function getReorgProtectionEnabled() external view returns (bool reorgProtectionEnabled) { + return s_hotVars.reorgProtectionEnabled; + } + + /** + * @notice calculates the minimum balance required for an upkeep to remain eligible + * @param id the upkeep id to calculate minimum balance for + */ + function getBalance(uint256 id) external view returns (uint96 balance) { + return s_upkeep[id].balance; + } + + /** + * @notice calculates the minimum balance required for an upkeep to remain eligible + * @param id the upkeep id to calculate minimum balance for + */ + function getMinBalance(uint256 id) external view returns (uint96) { + return getMinBalanceForUpkeep(id); + } + + /** + * @notice calculates the minimum balance required for an upkeep to remain eligible + * @param id the upkeep id to calculate minimum balance for + * @dev this will be deprecated in a future version in favor of getMinBalance + */ + function getMinBalanceForUpkeep(uint256 id) public view returns (uint96 minBalance) { + Upkeep memory upkeep = s_upkeep[id]; + return getMaxPaymentForGas(id, _getTriggerType(id), upkeep.performGas, upkeep.billingToken); + } + + /** + * @notice calculates the maximum payment for a given gas limit + * @param gasLimit the gas to calculate payment for + */ + function getMaxPaymentForGas( + uint256 id, + Trigger triggerType, + uint32 gasLimit, + IERC20 billingToken + ) public view returns (uint96 maxPayment) { + HotVars memory hotVars = s_hotVars; + (uint256 fastGasWei, uint256 linkUSD, uint256 nativeUSD) = _getFeedData(hotVars); + return _getMaxPayment(id, hotVars, triggerType, gasLimit, fastGasWei, linkUSD, nativeUSD, billingToken); + } + + /** + * @notice retrieves the migration permission for a peer registry + */ + function getPeerRegistryMigrationPermission(address peer) external view returns (MigrationPermission) { + return s_peerRegistryMigrationPermission[peer]; + } + + /** + * @notice returns the upkeep privilege config + */ + function getUpkeepPrivilegeConfig(uint256 upkeepId) external view returns (bytes memory) { + return s_upkeepPrivilegeConfig[upkeepId]; + } + + /** + * @notice returns the upkeep privilege config + */ + function getAdminPrivilegeConfig(address admin) external view returns (bytes memory) { + return s_adminPrivilegeConfig[admin]; + } + + /** + * @notice returns the upkeep's forwarder contract + */ + function getForwarder(uint256 upkeepID) external view returns (IAutomationForwarder) { + return s_upkeep[upkeepID].forwarder; + } + + /** + * @notice returns the upkeep's forwarder contract + */ + function hasDedupKey(bytes32 dedupKey) external view returns (bool) { + return s_dedupKeys[dedupKey]; + } + + /** + * @notice returns the fallback native price + */ + function getFallbackNativePrice() external view returns (uint256) { + return s_fallbackNativePrice; + } + + /** + * @notice returns the amount of a particular token that is reserved as + * user deposits / NOP payments + */ + function getReserveAmount(IERC20 billingToken) external view returns (uint256) { + return s_reserveAmounts[billingToken]; + } + + /** + * @notice returns the size of the LINK liquidity pool + */ + function linkAvailableForPayment() public view returns (int256) { + return _linkAvailableForPayment(); + } +} diff --git a/contracts/src/v0.8/automation/dev/v2_3/AutomationUtils2_3.sol b/contracts/src/v0.8/automation/dev/v2_3/AutomationUtils2_3.sol index 5f0a40527b5..59081b7f19b 100644 --- a/contracts/src/v0.8/automation/dev/v2_3/AutomationUtils2_3.sol +++ b/contracts/src/v0.8/automation/dev/v2_3/AutomationUtils2_3.sol @@ -2,7 +2,6 @@ pragma solidity 0.8.19; import {AutomationRegistryBase2_3} from "./AutomationRegistryBase2_3.sol"; -import {Log} from "../../interfaces/ILogAutomation.sol"; /** * @notice this file exposes structs that are otherwise internal to the automation registry @@ -10,35 +9,9 @@ import {Log} from "../../interfaces/ILogAutomation.sol"; * and tests because generated wrappers are made available */ -/** - * @notice structure of trigger for log triggers - */ -struct LogTriggerConfig { - address contractAddress; - uint8 filterSelector; // denotes which topics apply to filter ex 000, 101, 111...only last 3 bits apply - bytes32 topic0; - bytes32 topic1; - bytes32 topic2; - bytes32 topic3; -} - contract AutomationUtils2_3 { /** - * @dev this can be removed as OnchainConfig is now exposed directly from the registry + * @dev this uses the v2.3 Report, which uses linkUSD instead of linkNative (as in v2.2 and prior). This should be used only in typescript tests. */ - function _onChainConfig( - AutomationRegistryBase2_3.OnchainConfig memory, - address[] memory, - AutomationRegistryBase2_3.BillingConfig[] memory - ) external {} - function _report(AutomationRegistryBase2_3.Report memory) external {} // 0xe65d6546 - - function _logTriggerConfig(LogTriggerConfig memory) external {} // 0x21f373d7 - - function _logTrigger(AutomationRegistryBase2_3.LogTrigger memory) external {} // 0x1c8d8260 - - function _conditionalTrigger(AutomationRegistryBase2_3.ConditionalTrigger memory) external {} // 0x4b6df294 - - function _log(Log memory) external {} // 0xe9720a49 } diff --git a/contracts/src/v0.8/automation/dev/v2_3/UpkeepTranscoder5_0.sol b/contracts/src/v0.8/automation/dev/v2_3/UpkeepTranscoder5_0.sol new file mode 100644 index 00000000000..6f3d5567555 --- /dev/null +++ b/contracts/src/v0.8/automation/dev/v2_3/UpkeepTranscoder5_0.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: BUSL-1.1 + +pragma solidity 0.8.19; + +import {UpkeepTranscoderInterfaceV2} from "../../interfaces/UpkeepTranscoderInterfaceV2.sol"; +import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; + +enum RegistryVersion { + V12, + V13, + V20, + V21, + V23 +} + +/** + * @notice UpkeepTranscoder is a contract that allows converting upkeep data from previous registry versions to newer versions + * @dev it currently only supports 2.3 -> 2.3 migrations + */ +contract UpkeepTranscoder5_0 is UpkeepTranscoderInterfaceV2, TypeAndVersionInterface { + error InvalidTranscoding(); + + string public constant override typeAndVersion = "UpkeepTranscoder 5.0.0"; + + /** + * @notice transcodeUpkeeps transforms upkeep data from the format expected by + * one registry to the format expected by another. It future-proofs migrations + * by allowing automation team to customize migration paths and set sensible defaults + * when new fields are added + * @param fromVersion version the upkeep is migrating from + * @param toVersion version the upkeep is migrating to + * @param encodedUpkeeps encoded upkeep data + * @dev this transcoder should ONLY be use for V23->V23 migrations for now + */ + function transcodeUpkeeps( + uint8 fromVersion, + uint8 toVersion, + bytes calldata encodedUpkeeps + ) external view override returns (bytes memory) { + if (toVersion == uint8(RegistryVersion.V23) && fromVersion == uint8(RegistryVersion.V23)) { + return encodedUpkeeps; + } + + revert InvalidTranscoding(); + } +} diff --git a/contracts/src/v0.8/automation/mocks/MockUpkeep.sol b/contracts/src/v0.8/automation/mocks/MockUpkeep.sol new file mode 100644 index 00000000000..17899f4cade --- /dev/null +++ b/contracts/src/v0.8/automation/mocks/MockUpkeep.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract MockUpkeep { + bool public shouldCheckRevert; + bool public shouldPerformRevert; + bool public checkResult = true; + bytes public performData; + uint256 public checkGasToBurn; + uint256 public performGasToBurn; + + event UpkeepPerformedWith(bytes upkeepData); + error CheckRevert(); + error PerformRevert(); + + function setShouldCheckRevert(bool value) public { + shouldCheckRevert = value; + } + + function setShouldPerformRevert(bool value) public { + shouldPerformRevert = value; + } + + function setCheckResult(bool value) public { + checkResult = value; + } + + function setPerformData(bytes calldata data) public { + performData = data; + } + + function setCheckGasToBurn(uint256 value) public { + checkGasToBurn = value; + } + + function setPerformGasToBurn(uint256 value) public { + performGasToBurn = value; + } + + function checkUpkeep(bytes calldata) external view returns (bool callable, bytes memory executedata) { + if (shouldCheckRevert) revert CheckRevert(); + uint256 startGas = gasleft(); + while (startGas - gasleft() < checkGasToBurn) {} // burn gas + return (checkResult, performData); + } + + function performUpkeep(bytes calldata data) external { + if (shouldPerformRevert) revert PerformRevert(); + uint256 startGas = gasleft(); + while (startGas - gasleft() < performGasToBurn) {} // burn gas + emit UpkeepPerformedWith(data); + } +} diff --git a/contracts/src/v0.8/automation/testhelpers/SimpleLogUpkeepCounter.sol b/contracts/src/v0.8/automation/testhelpers/SimpleLogUpkeepCounter.sol index 979cc6138ac..c4d577134c2 100644 --- a/contracts/src/v0.8/automation/testhelpers/SimpleLogUpkeepCounter.sol +++ b/contracts/src/v0.8/automation/testhelpers/SimpleLogUpkeepCounter.sol @@ -3,14 +3,16 @@ pragma solidity 0.8.6; import {ILogAutomation, Log} from "../interfaces/ILogAutomation.sol"; +import "../interfaces/StreamsLookupCompatibleInterface.sol"; struct CheckData { uint256 checkBurnAmount; uint256 performBurnAmount; bytes32 eventSig; + string[] feeds; } -contract SimpleLogUpkeepCounter is ILogAutomation { +contract SimpleLogUpkeepCounter is ILogAutomation, StreamsLookupCompatibleInterface { event PerformingUpkeep( address indexed from, uint256 initialBlock, @@ -27,36 +29,77 @@ contract SimpleLogUpkeepCounter is ILogAutomation { uint256 public initialBlock; uint256 public counter; uint256 public timeToPerform; - bool public isRecovered; + bool internal isRecovered; + bool public isStreamsLookup; + bool public shouldRetryOnError; + string public feedParamKey = "feedIDs"; + string public timeParamKey = "timestamp"; - constructor() { + constructor(bool _isStreamsLookup) { previousPerformBlock = 0; lastBlock = block.number; initialBlock = 0; counter = 0; + isStreamsLookup = _isStreamsLookup; } function _checkDataConfig(CheckData memory) external {} + function setTimeParamKey(string memory timeParam) external { + timeParamKey = timeParam; + } + + function setFeedParamKey(string memory feedParam) external { + feedParamKey = feedParam; + } + + function setShouldRetryOnErrorBool(bool value) public { + shouldRetryOnError = value; + } + function checkLog(Log calldata log, bytes calldata checkData) external view override returns (bool, bytes memory) { - (uint256 checkBurnAmount, uint256 performBurnAmount, bytes32 eventSig) = abi.decode( - checkData, - (uint256, uint256, bytes32) - ); + CheckData memory _checkData = abi.decode(checkData, (CheckData)); uint256 startGas = gasleft(); bytes32 dummyIndex = blockhash(block.number - 1); bool dummy; // burn gas - if (checkBurnAmount > 0) { - while (startGas - gasleft() < checkBurnAmount) { + if (_checkData.checkBurnAmount > 0) { + while (startGas - gasleft() < _checkData.checkBurnAmount) { dummy = dummy && dummyMap[dummyIndex]; // arbitrary storage reads dummyIndex = keccak256(abi.encode(dummyIndex, address(this))); } } - if (log.topics[2] == eventSig) { - return (true, abi.encode(log, block.number, checkData)); + bytes[] memory values = new bytes[](2); + values[0] = abi.encode(0x00); + values[1] = abi.encode(0x00); + bytes memory extraData = abi.encode(log, block.number, checkData); + if (log.topics[2] == _checkData.eventSig) { + if (isStreamsLookup) { + revert StreamsLookup(feedParamKey, _checkData.feeds, timeParamKey, block.timestamp, extraData); + } + return (true, abi.encode(values, extraData)); } - return (false, abi.encode(log, block.number, checkData)); + return (false, abi.encode(values, extraData)); + } + + function checkCallback( + bytes[] memory values, + bytes memory extraData + ) external view override returns (bool, bytes memory) { + // do sth about the chainlinkBlob data in values and extraData + bytes memory performData = abi.encode(values, extraData); + return (true, performData); + } + + function checkErrorHandler( + uint256 errCode, + bytes memory extraData + ) external view override returns (bool upkeepNeeded, bytes memory performData) { + bytes[] memory values = new bytes[](2); + values[0] = abi.encode(errCode); + values[1] = abi.encode(extraData); + bytes memory returnData = abi.encode(values, extraData); + return (shouldRetryOnError, returnData); } function performUpkeep(bytes calldata performData) external override { @@ -66,22 +109,23 @@ contract SimpleLogUpkeepCounter is ILogAutomation { lastBlock = block.number; counter = counter + 1; previousPerformBlock = lastBlock; - (Log memory log, uint256 checkBlock, bytes memory extraData) = abi.decode(performData, (Log, uint256, bytes)); + (, bytes memory extraData) = abi.decode(performData, (bytes[], bytes)); + (Log memory log, uint256 checkBlock, bytes memory checkData) = abi.decode(extraData, (Log, uint256, bytes)); timeToPerform = block.timestamp - log.timestamp; isRecovered = false; if (checkBlock != log.blockNumber) { isRecovered = true; } - (uint256 checkBurnAmount, uint256 performBurnAmount, bytes32 eventSig) = abi.decode( - extraData, - (uint256, uint256, bytes32) - ); + CheckData memory _checkData = abi.decode(checkData, (CheckData)); uint256 startGas = gasleft(); bytes32 dummyIndex = blockhash(block.number - 1); bool dummy; + if (log.topics[2] != _checkData.eventSig) { + revert("Invalid event signature"); + } // burn gas - if (performBurnAmount > 0) { - while (startGas - gasleft() < performBurnAmount) { + if (_checkData.performBurnAmount > 0) { + while (startGas - gasleft() < _checkData.performBurnAmount) { dummy = dummy && dummyMap[dummyIndex]; // arbitrary storage reads dummyIndex = keccak256(abi.encode(dummyIndex, address(this))); } diff --git a/contracts/src/v0.7/tests/UpkeepAutoFunder.sol b/contracts/src/v0.8/automation/testhelpers/UpkeepAutoFunder.sol similarity index 64% rename from contracts/src/v0.7/tests/UpkeepAutoFunder.sol rename to contracts/src/v0.8/automation/testhelpers/UpkeepAutoFunder.sol index 9de92d03ff8..263aad5492f 100644 --- a/contracts/src/v0.7/tests/UpkeepAutoFunder.sol +++ b/contracts/src/v0.8/automation/testhelpers/UpkeepAutoFunder.sol @@ -1,22 +1,22 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; +pragma solidity ^0.8.0; -import "../KeeperCompatible.sol"; -import "../interfaces/LinkTokenInterface.sol"; -import "../interfaces/KeeperRegistryInterface.sol"; -import "../ConfirmedOwner.sol"; +import {AutomationCompatible} from "../AutomationCompatible.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {AutomationRegistryBaseInterface} from "../interfaces/v2_0/AutomationRegistryInterface2_0.sol"; -contract UpkeepAutoFunder is KeeperCompatible, ConfirmedOwner { +contract UpkeepAutoFunder is AutomationCompatible, ConfirmedOwner { bool public s_isEligible; bool public s_shouldCancel; uint256 public s_upkeepId; uint96 public s_autoFundLink; LinkTokenInterface public immutable LINK; - KeeperRegistryBaseInterface public immutable s_keeperRegistry; + AutomationRegistryBaseInterface public immutable s_keeperRegistry; constructor(address linkAddress, address registryAddress) ConfirmedOwner(msg.sender) { LINK = LinkTokenInterface(linkAddress); - s_keeperRegistry = KeeperRegistryBaseInterface(registryAddress); + s_keeperRegistry = AutomationRegistryBaseInterface(registryAddress); s_isEligible = false; s_shouldCancel = false; @@ -40,12 +40,9 @@ contract UpkeepAutoFunder is KeeperCompatible, ConfirmedOwner { s_upkeepId = value; } - function checkUpkeep(bytes calldata data) - external - override - cannotExecute - returns (bool callable, bytes calldata executedata) - { + function checkUpkeep( + bytes calldata data + ) external override cannotExecute returns (bool callable, bytes calldata executedata) { return (s_isEligible, data); } diff --git a/contracts/src/v0.7/tests/UpkeepMock.sol b/contracts/src/v0.8/automation/testhelpers/UpkeepMock.sol similarity index 93% rename from contracts/src/v0.7/tests/UpkeepMock.sol rename to contracts/src/v0.8/automation/testhelpers/UpkeepMock.sol index a4708eb1cad..392700ea3d6 100644 --- a/contracts/src/v0.7/tests/UpkeepMock.sol +++ b/contracts/src/v0.8/automation/testhelpers/UpkeepMock.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; +pragma solidity ^0.8.0; -import "../KeeperCompatible.sol"; +import {AutomationCompatible} from "../AutomationCompatible.sol"; -contract UpkeepMock is KeeperCompatible { +contract UpkeepMock is AutomationCompatible { bool public shouldRevertCheck; bool public canCheck; bool public canPerform; @@ -56,7 +56,7 @@ contract UpkeepMock is KeeperCompatible { } function checkUpkeep( - bytes calldata data + bytes calldata ) external override cannotExecute returns (bool callable, bytes memory executedata) { require(!shouldRevertCheck, checkRevertReason); uint256 startGas = gasleft(); diff --git a/contracts/src/v0.8/automation/testhelpers/UpkeepReverter.sol b/contracts/src/v0.8/automation/testhelpers/UpkeepReverter.sol new file mode 100644 index 00000000000..1d140ccf6d0 --- /dev/null +++ b/contracts/src/v0.8/automation/testhelpers/UpkeepReverter.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {AutomationCompatible} from "../AutomationCompatible.sol"; + +contract UpkeepReverter is AutomationCompatible { + function checkUpkeep( + bytes calldata data + ) public view override cannotExecute returns (bool callable, bytes calldata executedata) { + require(false, "!working"); + return (true, data); + } + + function performUpkeep(bytes calldata) external pure override { + require(false, "!working"); + } +} diff --git a/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol b/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol index ea01678fe76..6bf74de275d 100644 --- a/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol +++ b/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol @@ -266,6 +266,7 @@ contract LinkAvailableBalanceMonitor is AccessControl, AutomationCompatibleInter for (uint256 idx = 0; idx < targetAddresses.length; idx++) { address targetAddress = targetAddresses[idx]; contractToFund = s_targets[targetAddress]; + s_targets[targetAddress].lastTopUpTimestamp = uint56(block.timestamp); if ( localBalance >= contractToFund.topUpAmount && _needsFunding( @@ -278,12 +279,13 @@ contract LinkAvailableBalanceMonitor is AccessControl, AutomationCompatibleInter bool success = i_linkToken.transfer(targetAddress, contractToFund.topUpAmount); if (success) { localBalance -= contractToFund.topUpAmount; - s_targets[targetAddress].lastTopUpTimestamp = uint56(block.timestamp); emit TopUpSucceeded(targetAddress); } else { + s_targets[targetAddress].lastTopUpTimestamp = contractToFund.lastTopUpTimestamp; emit TopUpFailed(targetAddress); } } else { + s_targets[targetAddress].lastTopUpTimestamp = contractToFund.lastTopUpTimestamp; emit TopUpBlocked(targetAddress); } } diff --git a/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol b/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol index b6b65c4e556..c973f55a715 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol @@ -106,13 +106,13 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { /// @inheritdoc IFunctionsBilling function getDONFeeJuels(bytes memory /* requestData */) public view override returns (uint72) { - // s_config.donFee is in cents of USD. Get Juel amount then convert to dollars. + // s_config.donFee is in cents of USD. Convert to dollars amount then get amount of Juels. return SafeCast.toUint72(_getJuelsFromUsd(s_config.donFeeCentsUsd) / 100); } /// @inheritdoc IFunctionsBilling function getOperationFeeJuels() public view override returns (uint72) { - // s_config.donFee is in cents of USD. Get Juel amount then convert to dollars. + // s_config.donFee is in cents of USD. Convert to dollars then get amount of Juels. return SafeCast.toUint72(_getJuelsFromUsd(s_config.operationFeeCentsUsd) / 100); } @@ -124,6 +124,7 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { /// @inheritdoc IFunctionsBilling function getWeiPerUnitLink() public view returns (uint256) { (, int256 weiPerUnitLink, , uint256 timestamp, ) = s_linkToNativeFeed.latestRoundData(); + // Only fallback if feedStalenessSeconds is set // solhint-disable-next-line not-rely-on-time if (s_config.feedStalenessSeconds < block.timestamp - timestamp && s_config.feedStalenessSeconds > 0) { return s_config.fallbackNativePerUnitLink; @@ -143,6 +144,7 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { /// @inheritdoc IFunctionsBilling function getUsdPerUnitLink() public view returns (uint256, uint8) { (, int256 usdPerUnitLink, , uint256 timestamp, ) = s_linkToUsdFeed.latestRoundData(); + // Only fallback if feedStalenessSeconds is set // solhint-disable-next-line not-rely-on-time if (s_config.feedStalenessSeconds < block.timestamp - timestamp && s_config.feedStalenessSeconds > 0) { return (s_config.fallbackUsdPerUnitLink, s_config.fallbackUsdPerUnitLinkDecimals); @@ -420,6 +422,10 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { revert NoTransmittersSet(); } uint96 feePoolShare = s_feePool / uint96(numberOfTransmitters); + if (feePoolShare == 0) { + // Dust cannot be evenly distributed to all transmitters + return; + } // Bounded by "maxNumOracles" on OCR2Abstract.sol for (uint256 i = 0; i < numberOfTransmitters; ++i) { s_withdrawableTokens[transmitters[i]] += feePoolShare; diff --git a/contracts/src/v0.8/functions/dev/v1_X/FunctionsClient.sol b/contracts/src/v0.8/functions/dev/v1_X/FunctionsClient.sol index 4aabef01f28..378714dac85 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsClient.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsClient.sol @@ -25,7 +25,8 @@ abstract contract FunctionsClient is IFunctionsClient { /// @notice Sends a Chainlink Functions request /// @param data The CBOR encoded bytes data for a Functions request /// @param subscriptionId The subscription ID that will be charged to service the request - /// @param callbackGasLimit the amount of gas that will be available for the fulfillment callback + /// @param callbackGasLimit - The amount of gas that will be available for the fulfillment callback + /// @param donId - An identifier used to determine which route to send the request along /// @return requestId The generated request ID for this request function _sendRequest( bytes memory data, diff --git a/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol b/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol index a70a8a752bb..f0bec7c3e9c 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol @@ -16,7 +16,6 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli using FunctionsResponse for FunctionsResponse.FulfillResult; /// @inheritdoc ITypeAndVersion - // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override typeAndVersion = "Functions Coordinator v1.3.0"; event OracleRequest( diff --git a/contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol b/contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol index d86d881151c..5cdb119354a 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol @@ -18,7 +18,6 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, using FunctionsResponse for FunctionsResponse.Commitment; using FunctionsResponse for FunctionsResponse.FulfillResult; - // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override typeAndVersion = "Functions Router v2.0.0"; // We limit return data to a selector plus 4 words. This is to avoid diff --git a/contracts/src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol b/contracts/src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol index fe4ebe983ef..04604e67974 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol @@ -16,7 +16,6 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, using EnumerableSet for EnumerableSet.AddressSet; /// @inheritdoc ITypeAndVersion - // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override typeAndVersion = "Functions Terms of Service Allow List v1.1.0"; EnumerableSet.AddressSet private s_allowedSenders; @@ -128,11 +127,7 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, uint64 allowedSenderIdxStart, uint64 allowedSenderIdxEnd ) external view override returns (address[] memory allowedSenders) { - if ( - allowedSenderIdxStart > allowedSenderIdxEnd || - allowedSenderIdxEnd >= s_allowedSenders.length() || - s_allowedSenders.length() == 0 - ) { + if (allowedSenderIdxStart > allowedSenderIdxEnd || allowedSenderIdxEnd >= s_allowedSenders.length()) { revert InvalidCalldata(); } diff --git a/contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsBilling.sol b/contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsBilling.sol index 79806f1eb18..ecf15c68f0d 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsBilling.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsBilling.sol @@ -59,7 +59,7 @@ interface IFunctionsBilling { struct FunctionsBillingConfig { uint32 fulfillmentGasPriceOverEstimationBP; // ══╗ Percentage of gas price overestimation to account for changes in gas price between request and response. Held as basis points (one hundredth of 1 percentage point) - uint32 feedStalenessSeconds; // ║ How long before we consider the feed price to be stale and fallback to fallbackNativePerUnitLink. + uint32 feedStalenessSeconds; // ║ How long before we consider the feed price to be stale and fallback to fallbackNativePerUnitLink. Default of 0 means no fallback. uint32 gasOverheadBeforeCallback; // ║ Represents the average gas execution cost before the fulfillment callback. This amount is always billed for every request. uint32 gasOverheadAfterCallback; // ║ Represents the average gas execution cost after the fulfillment callback. This amount is always billed for every request. uint40 minimumEstimateGasPriceWei; // ║ The lowest amount of wei that will be used as the tx.gasprice when estimating the cost to fulfill the request diff --git a/contracts/src/v0.8/functions/dev/v1_X/ocr/OCR2Base.sol b/contracts/src/v0.8/functions/dev/v1_X/ocr/OCR2Base.sol index cf461bdb217..02ea5cf3721 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/ocr/OCR2Base.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/ocr/OCR2Base.sol @@ -22,12 +22,12 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { // to extract config from logs. // Storing these fields used on the hot path in a ConfigInfo variable reduces the - // retrieval of all of them to a single SLOAD. If any further fields are - // added, make sure that storage of the struct still takes at most 32 bytes. + // retrieval of all of them into two SLOADs. If any further fields are + // added, make sure that storage of the struct still takes at most 64 bytes. struct ConfigInfo { bytes32 latestConfigDigest; - uint8 f; // TODO: could be optimized by squeezing into one slot - uint8 n; + uint8 f; // ───╮ + uint8 n; // ───╯ } ConfigInfo internal s_configInfo; @@ -215,7 +215,7 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { ); uint256 prefixMask = type(uint256).max << (256 - 16); // 0xFFFF00..00 uint256 prefix = 0x0001 << (256 - 16); // 0x000100..00 - return bytes32((prefix & prefixMask) | (h & ~prefixMask)); + return bytes32(prefix | (h & ~prefixMask)); } /** diff --git a/contracts/src/v0.8/functions/v1_1_0/FunctionsCoordinator.sol b/contracts/src/v0.8/functions/v1_1_0/FunctionsCoordinator.sol index 0a5da643a57..188e217b804 100644 --- a/contracts/src/v0.8/functions/v1_1_0/FunctionsCoordinator.sol +++ b/contracts/src/v0.8/functions/v1_1_0/FunctionsCoordinator.sol @@ -16,7 +16,6 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli using FunctionsResponse for FunctionsResponse.FulfillResult; /// @inheritdoc ITypeAndVersion - // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override typeAndVersion = "Functions Coordinator v1.1.0"; event OracleRequest( diff --git a/contracts/src/v0.8/functions/v1_3_0/FunctionsBilling.sol b/contracts/src/v0.8/functions/v1_3_0/FunctionsBilling.sol new file mode 100644 index 00000000000..49ecf3d6652 --- /dev/null +++ b/contracts/src/v0.8/functions/v1_3_0/FunctionsBilling.sol @@ -0,0 +1,440 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {IFunctionsSubscriptions} from "../v1_0_0/interfaces/IFunctionsSubscriptions.sol"; +import {AggregatorV3Interface} from "../../shared/interfaces/AggregatorV3Interface.sol"; +import {IFunctionsBilling, FunctionsBillingConfig} from "./interfaces/IFunctionsBilling.sol"; + +import {Routable} from "../v1_0_0/Routable.sol"; +import {FunctionsResponse} from "../v1_0_0/libraries/FunctionsResponse.sol"; + +import {SafeCast} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SafeCast.sol"; + +import {ChainSpecificUtil} from "../v1_1_0/libraries/ChainSpecificUtil.sol"; + +/// @title Functions Billing contract +/// @notice Contract that calculates payment from users to the nodes of the Decentralized Oracle Network (DON). +abstract contract FunctionsBilling is Routable, IFunctionsBilling { + using FunctionsResponse for FunctionsResponse.RequestMeta; + using FunctionsResponse for FunctionsResponse.Commitment; + using FunctionsResponse for FunctionsResponse.FulfillResult; + + uint256 private constant REASONABLE_GAS_PRICE_CEILING = 1_000_000_000_000_000; // 1 million gwei + + event RequestBilled( + bytes32 indexed requestId, + uint96 juelsPerGas, + uint256 l1FeeShareWei, + uint96 callbackCostJuels, + uint72 donFeeJuels, + uint72 adminFeeJuels, + uint72 operationFeeJuels + ); + + // ================================================================ + // | Request Commitment state | + // ================================================================ + + mapping(bytes32 requestId => bytes32 commitmentHash) private s_requestCommitments; + + event CommitmentDeleted(bytes32 requestId); + + FunctionsBillingConfig private s_config; + + event ConfigUpdated(FunctionsBillingConfig config); + + error UnsupportedRequestDataVersion(); + error InsufficientBalance(); + error InvalidSubscription(); + error UnauthorizedSender(); + error MustBeSubOwner(address owner); + error InvalidLinkWeiPrice(int256 linkWei); + error InvalidUsdLinkPrice(int256 usdLink); + error PaymentTooLarge(); + error NoTransmittersSet(); + error InvalidCalldata(); + + // ================================================================ + // | Balance state | + // ================================================================ + + mapping(address transmitter => uint96 balanceJuelsLink) private s_withdrawableTokens; + // Pool together collected DON fees + // Disperse them on withdrawal or change in OCR configuration + uint96 internal s_feePool; + + AggregatorV3Interface private s_linkToNativeFeed; + AggregatorV3Interface private s_linkToUsdFeed; + + // ================================================================ + // | Initialization | + // ================================================================ + constructor( + address router, + FunctionsBillingConfig memory config, + address linkToNativeFeed, + address linkToUsdFeed + ) Routable(router) { + s_linkToNativeFeed = AggregatorV3Interface(linkToNativeFeed); + s_linkToUsdFeed = AggregatorV3Interface(linkToUsdFeed); + + updateConfig(config); + } + + // ================================================================ + // | Configuration | + // ================================================================ + + /// @notice Gets the Chainlink Coordinator's billing configuration + /// @return config + function getConfig() external view returns (FunctionsBillingConfig memory) { + return s_config; + } + + /// @notice Sets the Chainlink Coordinator's billing configuration + /// @param config - See the contents of the FunctionsBillingConfig struct in IFunctionsBilling.sol for more information + function updateConfig(FunctionsBillingConfig memory config) public { + _onlyOwner(); + + s_config = config; + emit ConfigUpdated(config); + } + + // ================================================================ + // | Fee Calculation | + // ================================================================ + + /// @inheritdoc IFunctionsBilling + function getDONFeeJuels(bytes memory /* requestData */) public view override returns (uint72) { + // s_config.donFee is in cents of USD. Get Juel amount then convert to dollars. + return SafeCast.toUint72(_getJuelsFromUsd(s_config.donFeeCentsUsd) / 100); + } + + /// @inheritdoc IFunctionsBilling + function getOperationFeeJuels() public view override returns (uint72) { + // s_config.donFee is in cents of USD. Get Juel amount then convert to dollars. + return SafeCast.toUint72(_getJuelsFromUsd(s_config.operationFeeCentsUsd) / 100); + } + + /// @inheritdoc IFunctionsBilling + function getAdminFeeJuels() public view override returns (uint72) { + return _getRouter().getAdminFee(); + } + + /// @inheritdoc IFunctionsBilling + function getWeiPerUnitLink() public view returns (uint256) { + (, int256 weiPerUnitLink, , uint256 timestamp, ) = s_linkToNativeFeed.latestRoundData(); + // solhint-disable-next-line not-rely-on-time + if (s_config.feedStalenessSeconds < block.timestamp - timestamp && s_config.feedStalenessSeconds > 0) { + return s_config.fallbackNativePerUnitLink; + } + if (weiPerUnitLink <= 0) { + revert InvalidLinkWeiPrice(weiPerUnitLink); + } + return uint256(weiPerUnitLink); + } + + function _getJuelsFromWei(uint256 amountWei) private view returns (uint96) { + // (1e18 juels/link) * wei / (wei/link) = juels + // There are only 1e9*1e18 = 1e27 juels in existence, should not exceed uint96 (2^96 ~ 7e28) + return SafeCast.toUint96((1e18 * amountWei) / getWeiPerUnitLink()); + } + + /// @inheritdoc IFunctionsBilling + function getUsdPerUnitLink() public view returns (uint256, uint8) { + (, int256 usdPerUnitLink, , uint256 timestamp, ) = s_linkToUsdFeed.latestRoundData(); + // solhint-disable-next-line not-rely-on-time + if (s_config.feedStalenessSeconds < block.timestamp - timestamp && s_config.feedStalenessSeconds > 0) { + return (s_config.fallbackUsdPerUnitLink, s_config.fallbackUsdPerUnitLinkDecimals); + } + if (usdPerUnitLink <= 0) { + revert InvalidUsdLinkPrice(usdPerUnitLink); + } + return (uint256(usdPerUnitLink), s_linkToUsdFeed.decimals()); + } + + function _getJuelsFromUsd(uint256 amountUsd) private view returns (uint96) { + (uint256 usdPerLink, uint8 decimals) = getUsdPerUnitLink(); + // (usd) * (10**18 juels/link) * (10**decimals) / (link / usd) = juels + // There are only 1e9*1e18 = 1e27 juels in existence, should not exceed uint96 (2^96 ~ 7e28) + return SafeCast.toUint96((amountUsd * 10 ** (18 + decimals)) / usdPerLink); + } + + // ================================================================ + // | Cost Estimation | + // ================================================================ + + /// @inheritdoc IFunctionsBilling + function estimateCost( + uint64 subscriptionId, + bytes calldata data, + uint32 callbackGasLimit, + uint256 gasPriceWei + ) external view override returns (uint96) { + _getRouter().isValidCallbackGasLimit(subscriptionId, callbackGasLimit); + // Reasonable ceilings to prevent integer overflows + if (gasPriceWei > REASONABLE_GAS_PRICE_CEILING) { + revert InvalidCalldata(); + } + uint72 adminFee = getAdminFeeJuels(); + uint72 donFee = getDONFeeJuels(data); + uint72 operationFee = getOperationFeeJuels(); + return _calculateCostEstimate(callbackGasLimit, gasPriceWei, donFee, adminFee, operationFee); + } + + /// @notice Estimate the cost in Juels of LINK + // that will be charged to a subscription to fulfill a Functions request + // Gas Price can be overestimated to account for flucuations between request and response time + function _calculateCostEstimate( + uint32 callbackGasLimit, + uint256 gasPriceWei, + uint72 donFeeJuels, + uint72 adminFeeJuels, + uint72 operationFeeJuels + ) internal view returns (uint96) { + // If gas price is less than the minimum fulfillment gas price, override to using the minimum + if (gasPriceWei < s_config.minimumEstimateGasPriceWei) { + gasPriceWei = s_config.minimumEstimateGasPriceWei; + } + + uint256 gasPriceWithOverestimation = gasPriceWei + + ((gasPriceWei * s_config.fulfillmentGasPriceOverEstimationBP) / 10_000); + /// @NOTE: Basis Points are 1/100th of 1%, divide by 10_000 to bring back to original units + + uint256 executionGas = s_config.gasOverheadBeforeCallback + s_config.gasOverheadAfterCallback + callbackGasLimit; + uint256 l1FeeWei = ChainSpecificUtil._getCurrentTxL1GasFees(msg.data); + uint96 estimatedGasReimbursementJuels = _getJuelsFromWei((gasPriceWithOverestimation * executionGas) + l1FeeWei); + + uint96 feesJuels = uint96(donFeeJuels) + uint96(adminFeeJuels) + uint96(operationFeeJuels); + + return estimatedGasReimbursementJuels + feesJuels; + } + + // ================================================================ + // | Billing | + // ================================================================ + + /// @notice Initiate the billing process for an Functions request + /// @dev Only callable by the Functions Router + /// @param request - Chainlink Functions request data, see FunctionsResponse.RequestMeta for the structure + /// @return commitment - The parameters of the request that must be held consistent at response time + function _startBilling( + FunctionsResponse.RequestMeta memory request + ) internal returns (FunctionsResponse.Commitment memory commitment, uint72 operationFee) { + // Nodes should support all past versions of the structure + if (request.dataVersion > s_config.maxSupportedRequestDataVersion) { + revert UnsupportedRequestDataVersion(); + } + + uint72 donFee = getDONFeeJuels(request.data); + operationFee = getOperationFeeJuels(); + uint96 estimatedTotalCostJuels = _calculateCostEstimate( + request.callbackGasLimit, + tx.gasprice, + donFee, + request.adminFee, + operationFee + ); + + // Check that subscription can afford the estimated cost + if ((request.availableBalance) < estimatedTotalCostJuels) { + revert InsufficientBalance(); + } + + uint32 timeoutTimestamp = uint32(block.timestamp + s_config.requestTimeoutSeconds); + bytes32 requestId = keccak256( + abi.encode( + address(this), + request.requestingContract, + request.subscriptionId, + request.initiatedRequests + 1, + keccak256(request.data), + request.dataVersion, + request.callbackGasLimit, + estimatedTotalCostJuels, + timeoutTimestamp, + // solhint-disable-next-line avoid-tx-origin + tx.origin + ) + ); + + commitment = FunctionsResponse.Commitment({ + adminFee: request.adminFee, + coordinator: address(this), + client: request.requestingContract, + subscriptionId: request.subscriptionId, + callbackGasLimit: request.callbackGasLimit, + estimatedTotalCostJuels: estimatedTotalCostJuels, + timeoutTimestamp: timeoutTimestamp, + requestId: requestId, + donFee: donFee, + gasOverheadBeforeCallback: s_config.gasOverheadBeforeCallback, + gasOverheadAfterCallback: s_config.gasOverheadAfterCallback + }); + + s_requestCommitments[requestId] = keccak256(abi.encode(commitment)); + + return (commitment, operationFee); + } + + /// @notice Finalize billing process for an Functions request by sending a callback to the Client contract and then charging the subscription + /// @param requestId identifier for the request that was generated by the Registry in the beginBilling commitment + /// @param response response data from DON consensus + /// @param err error from DON consensus + /// @param reportBatchSize the number of fulfillments in the transmitter's report + /// @return result fulfillment result + /// @dev Only callable by a node that has been approved on the Coordinator + /// @dev simulated offchain to determine if sufficient balance is present to fulfill the request + function _fulfillAndBill( + bytes32 requestId, + bytes memory response, + bytes memory err, + bytes memory onchainMetadata, + bytes memory /* offchainMetadata TODO: use in getDonFee() for dynamic billing */, + uint8 reportBatchSize + ) internal returns (FunctionsResponse.FulfillResult) { + FunctionsResponse.Commitment memory commitment = abi.decode(onchainMetadata, (FunctionsResponse.Commitment)); + + uint256 gasOverheadWei = (commitment.gasOverheadBeforeCallback + commitment.gasOverheadAfterCallback) * tx.gasprice; + uint256 l1FeeShareWei = ChainSpecificUtil._getCurrentTxL1GasFees(msg.data) / reportBatchSize; + // Gas overhead without callback + uint96 gasOverheadJuels = _getJuelsFromWei(gasOverheadWei + l1FeeShareWei); + uint96 juelsPerGas = _getJuelsFromWei(tx.gasprice); + + // The Functions Router will perform the callback to the client contract + (FunctionsResponse.FulfillResult resultCode, uint96 callbackCostJuels) = _getRouter().fulfill( + response, + err, + juelsPerGas, + // The following line represents: "cost without callback or admin fee, those will be added by the Router" + // But because the _offchain_ Commitment is using operation fee in the place of the admin fee, this now adds admin fee (actually operation fee) + // Admin fee is configured to 0 in the Router + gasOverheadJuels + commitment.donFee + commitment.adminFee, + msg.sender, + FunctionsResponse.Commitment({ + adminFee: 0, // The Router should have adminFee set to 0. If it does not this will cause fulfillments to fail with INVALID_COMMITMENT instead of carrying out incorrect bookkeeping. + coordinator: commitment.coordinator, + client: commitment.client, + subscriptionId: commitment.subscriptionId, + callbackGasLimit: commitment.callbackGasLimit, + estimatedTotalCostJuels: commitment.estimatedTotalCostJuels, + timeoutTimestamp: commitment.timeoutTimestamp, + requestId: commitment.requestId, + donFee: commitment.donFee, + gasOverheadBeforeCallback: commitment.gasOverheadBeforeCallback, + gasOverheadAfterCallback: commitment.gasOverheadAfterCallback + }) + ); + + // The router will only pay the DON on successfully processing the fulfillment + // In these two fulfillment results the user has been charged + // Otherwise, the Coordinator should hold on to the request commitment + if ( + resultCode == FunctionsResponse.FulfillResult.FULFILLED || + resultCode == FunctionsResponse.FulfillResult.USER_CALLBACK_ERROR + ) { + delete s_requestCommitments[requestId]; + // Reimburse the transmitter for the fulfillment gas cost + s_withdrawableTokens[msg.sender] += gasOverheadJuels + callbackCostJuels; + // Put donFee into the pool of fees, to be split later + // Saves on storage writes that would otherwise be charged to the user + s_feePool += commitment.donFee; + // Pay the operation fee to the Coordinator owner + s_withdrawableTokens[_owner()] += commitment.adminFee; // OperationFee is used in the slot for Admin Fee in the Offchain Commitment. Admin Fee is set to 0 in the Router (enforced by line 316 in FunctionsBilling.sol). + emit RequestBilled({ + requestId: requestId, + juelsPerGas: juelsPerGas, + l1FeeShareWei: l1FeeShareWei, + callbackCostJuels: callbackCostJuels, + donFeeJuels: commitment.donFee, + // The following two lines are because of OperationFee being used in the Offchain Commitment + adminFeeJuels: 0, + operationFeeJuels: commitment.adminFee + }); + } + return resultCode; + } + + // ================================================================ + // | Request Timeout | + // ================================================================ + + /// @inheritdoc IFunctionsBilling + /// @dev Only callable by the Router + /// @dev Used by FunctionsRouter.sol during timeout of a request + function deleteCommitment(bytes32 requestId) external override onlyRouter { + // Delete commitment + delete s_requestCommitments[requestId]; + emit CommitmentDeleted(requestId); + } + + // ================================================================ + // | Fund withdrawal | + // ================================================================ + + /// @inheritdoc IFunctionsBilling + function oracleWithdraw(address recipient, uint96 amount) external { + _disperseFeePool(); + + if (amount == 0) { + amount = s_withdrawableTokens[msg.sender]; + } else if (s_withdrawableTokens[msg.sender] < amount) { + revert InsufficientBalance(); + } + s_withdrawableTokens[msg.sender] -= amount; + IFunctionsSubscriptions(address(_getRouter())).oracleWithdraw(recipient, amount); + } + + /// @inheritdoc IFunctionsBilling + /// @dev Only callable by the Coordinator owner + function oracleWithdrawAll() external { + _onlyOwner(); + _disperseFeePool(); + + address[] memory transmitters = _getTransmitters(); + + // Bounded by "maxNumOracles" on OCR2Abstract.sol + for (uint256 i = 0; i < transmitters.length; ++i) { + uint96 balance = s_withdrawableTokens[transmitters[i]]; + if (balance > 0) { + s_withdrawableTokens[transmitters[i]] = 0; + IFunctionsSubscriptions(address(_getRouter())).oracleWithdraw(transmitters[i], balance); + } + } + } + + // Overriden in FunctionsCoordinator, which has visibility into transmitters + function _getTransmitters() internal view virtual returns (address[] memory); + + // DON fees are collected into a pool s_feePool + // When OCR configuration changes, or any oracle withdraws, this must be dispersed + function _disperseFeePool() internal { + if (s_feePool == 0) { + return; + } + // All transmitters are assumed to also be observers + // Pay out the DON fee to all transmitters + address[] memory transmitters = _getTransmitters(); + uint256 numberOfTransmitters = transmitters.length; + if (numberOfTransmitters == 0) { + revert NoTransmittersSet(); + } + uint96 feePoolShare = s_feePool / uint96(numberOfTransmitters); + // Bounded by "maxNumOracles" on OCR2Abstract.sol + for (uint256 i = 0; i < numberOfTransmitters; ++i) { + s_withdrawableTokens[transmitters[i]] += feePoolShare; + } + s_feePool -= feePoolShare * uint96(numberOfTransmitters); + } + + // Overriden in FunctionsCoordinator.sol + function _onlyOwner() internal view virtual; + + // Used in FunctionsCoordinator.sol + function _isExistingRequest(bytes32 requestId) internal view returns (bool) { + return s_requestCommitments[requestId] != bytes32(0); + } + + // Overriden in FunctionsCoordinator.sol + function _owner() internal view virtual returns (address owner); +} diff --git a/contracts/src/v0.8/functions/v1_3_0/FunctionsClient.sol b/contracts/src/v0.8/functions/v1_3_0/FunctionsClient.sol new file mode 100644 index 00000000000..84b64146516 --- /dev/null +++ b/contracts/src/v0.8/functions/v1_3_0/FunctionsClient.sol @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {IFunctionsRouter} from "../v1_0_0/interfaces/IFunctionsRouter.sol"; +import {IFunctionsClient} from "../v1_0_0/interfaces/IFunctionsClient.sol"; + +import {FunctionsRequest} from "../v1_0_0/libraries/FunctionsRequest.sol"; + +/// @title The Chainlink Functions client contract +/// @notice Contract developers can inherit this contract in order to make Chainlink Functions requests +abstract contract FunctionsClient is IFunctionsClient { + using FunctionsRequest for FunctionsRequest.Request; + + IFunctionsRouter internal immutable i_functionsRouter; + + event RequestSent(bytes32 indexed id); + event RequestFulfilled(bytes32 indexed id); + + error OnlyRouterCanFulfill(); + + constructor(address router) { + i_functionsRouter = IFunctionsRouter(router); + } + + /// @notice Sends a Chainlink Functions request + /// @param data The CBOR encoded bytes data for a Functions request + /// @param subscriptionId The subscription ID that will be charged to service the request + /// @param callbackGasLimit the amount of gas that will be available for the fulfillment callback + /// @return requestId The generated request ID for this request + function _sendRequest( + bytes memory data, + uint64 subscriptionId, + uint32 callbackGasLimit, + bytes32 donId + ) internal returns (bytes32) { + bytes32 requestId = i_functionsRouter.sendRequest( + subscriptionId, + data, + FunctionsRequest.REQUEST_DATA_VERSION, + callbackGasLimit, + donId + ); + emit RequestSent(requestId); + return requestId; + } + + /// @notice User defined function to handle a response from the DON + /// @param requestId The request ID, returned by sendRequest() + /// @param response Aggregated response from the execution of the user's source code + /// @param err Aggregated error from the execution of the user code or from the execution pipeline + /// @dev Either response or error parameter will be set, but never both + function _fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal virtual; + + /// @inheritdoc IFunctionsClient + function handleOracleFulfillment(bytes32 requestId, bytes memory response, bytes memory err) external override { + if (msg.sender != address(i_functionsRouter)) { + revert OnlyRouterCanFulfill(); + } + _fulfillRequest(requestId, response, err); + emit RequestFulfilled(requestId); + } +} diff --git a/contracts/src/v0.8/functions/v1_3_0/FunctionsCoordinator.sol b/contracts/src/v0.8/functions/v1_3_0/FunctionsCoordinator.sol new file mode 100644 index 00000000000..9c7f3598711 --- /dev/null +++ b/contracts/src/v0.8/functions/v1_3_0/FunctionsCoordinator.sol @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {IFunctionsCoordinator} from "../v1_0_0/interfaces/IFunctionsCoordinator.sol"; +import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; + +import {FunctionsBilling, FunctionsBillingConfig} from "./FunctionsBilling.sol"; +import {OCR2Base} from "./ocr/OCR2Base.sol"; +import {FunctionsResponse} from "../v1_0_0/libraries/FunctionsResponse.sol"; + +/// @title Functions Coordinator contract +/// @notice Contract that nodes of a Decentralized Oracle Network (DON) interact with +contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilling { + using FunctionsResponse for FunctionsResponse.RequestMeta; + using FunctionsResponse for FunctionsResponse.Commitment; + using FunctionsResponse for FunctionsResponse.FulfillResult; + + /// @inheritdoc ITypeAndVersion + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + string public constant override typeAndVersion = "Functions Coordinator v1.3.0"; + + event OracleRequest( + bytes32 indexed requestId, + address indexed requestingContract, + address requestInitiator, + uint64 subscriptionId, + address subscriptionOwner, + bytes data, + uint16 dataVersion, + bytes32 flags, + uint64 callbackGasLimit, + FunctionsResponse.Commitment commitment + ); + event OracleResponse(bytes32 indexed requestId, address transmitter); + + error InconsistentReportData(); + error EmptyPublicKey(); + error UnauthorizedPublicKeyChange(); + + bytes private s_donPublicKey; + bytes private s_thresholdPublicKey; + + constructor( + address router, + FunctionsBillingConfig memory config, + address linkToNativeFeed, + address linkToUsdFeed + ) OCR2Base() FunctionsBilling(router, config, linkToNativeFeed, linkToUsdFeed) {} + + /// @inheritdoc IFunctionsCoordinator + function getThresholdPublicKey() external view override returns (bytes memory) { + if (s_thresholdPublicKey.length == 0) { + revert EmptyPublicKey(); + } + return s_thresholdPublicKey; + } + + /// @inheritdoc IFunctionsCoordinator + function setThresholdPublicKey(bytes calldata thresholdPublicKey) external override onlyOwner { + if (thresholdPublicKey.length == 0) { + revert EmptyPublicKey(); + } + s_thresholdPublicKey = thresholdPublicKey; + } + + /// @inheritdoc IFunctionsCoordinator + function getDONPublicKey() external view override returns (bytes memory) { + if (s_donPublicKey.length == 0) { + revert EmptyPublicKey(); + } + return s_donPublicKey; + } + + /// @inheritdoc IFunctionsCoordinator + function setDONPublicKey(bytes calldata donPublicKey) external override onlyOwner { + if (donPublicKey.length == 0) { + revert EmptyPublicKey(); + } + s_donPublicKey = donPublicKey; + } + + /// @dev check if node is in current transmitter list + function _isTransmitter(address node) internal view returns (bool) { + // Bounded by "maxNumOracles" on OCR2Abstract.sol + for (uint256 i = 0; i < s_transmitters.length; ++i) { + if (s_transmitters[i] == node) { + return true; + } + } + return false; + } + + /// @inheritdoc IFunctionsCoordinator + function startRequest( + FunctionsResponse.RequestMeta calldata request + ) external override onlyRouter returns (FunctionsResponse.Commitment memory commitment) { + uint72 operationFee; + (commitment, operationFee) = _startBilling(request); + + emit OracleRequest( + commitment.requestId, + request.requestingContract, + // solhint-disable-next-line avoid-tx-origin + tx.origin, + request.subscriptionId, + request.subscriptionOwner, + request.data, + request.dataVersion, + request.flags, + request.callbackGasLimit, + FunctionsResponse.Commitment({ + coordinator: commitment.coordinator, + client: commitment.client, + subscriptionId: commitment.subscriptionId, + callbackGasLimit: commitment.callbackGasLimit, + estimatedTotalCostJuels: commitment.estimatedTotalCostJuels, + timeoutTimestamp: commitment.timeoutTimestamp, + requestId: commitment.requestId, + donFee: commitment.donFee, + gasOverheadBeforeCallback: commitment.gasOverheadBeforeCallback, + gasOverheadAfterCallback: commitment.gasOverheadAfterCallback, + // The following line is done to use the Coordinator's operationFee in place of the Router's operation fee + // With this in place the Router.adminFee must be set to 0 in the Router. + adminFee: operationFee + }) + ); + + return commitment; + } + + /// @dev DON fees are pooled together. If the OCR configuration is going to change, these need to be distributed. + function _beforeSetConfig(uint8 /* _f */, bytes memory /* _onchainConfig */) internal override { + if (_getTransmitters().length > 0) { + _disperseFeePool(); + } + } + + /// @dev Used by FunctionsBilling.sol + function _getTransmitters() internal view override returns (address[] memory) { + return s_transmitters; + } + + function _beforeTransmit( + bytes calldata report + ) internal view override returns (bool shouldStop, DecodedReport memory decodedReport) { + ( + bytes32[] memory requestIds, + bytes[] memory results, + bytes[] memory errors, + bytes[] memory onchainMetadata, + bytes[] memory offchainMetadata + ) = abi.decode(report, (bytes32[], bytes[], bytes[], bytes[], bytes[])); + uint256 numberOfFulfillments = uint8(requestIds.length); + + if ( + numberOfFulfillments == 0 || + numberOfFulfillments != results.length || + numberOfFulfillments != errors.length || + numberOfFulfillments != onchainMetadata.length || + numberOfFulfillments != offchainMetadata.length + ) { + revert ReportInvalid("Fields must be equal length"); + } + + for (uint256 i = 0; i < numberOfFulfillments; ++i) { + if (_isExistingRequest(requestIds[i])) { + // If there is an existing request, validate report + // Leave shouldStop to default, false + break; + } + if (i == numberOfFulfillments - 1) { + // If the last fulfillment on the report does not exist, then all are duplicates + // Indicate that it's safe to stop to save on the gas of validating the report + shouldStop = true; + } + } + + return ( + shouldStop, + DecodedReport({ + requestIds: requestIds, + results: results, + errors: errors, + onchainMetadata: onchainMetadata, + offchainMetadata: offchainMetadata + }) + ); + } + + /// @dev Report hook called within OCR2Base.sol + function _report(DecodedReport memory decodedReport) internal override { + uint256 numberOfFulfillments = uint8(decodedReport.requestIds.length); + + // Bounded by "MaxRequestBatchSize" on the Job's ReportingPluginConfig + for (uint256 i = 0; i < numberOfFulfillments; ++i) { + FunctionsResponse.FulfillResult result = FunctionsResponse.FulfillResult( + _fulfillAndBill( + decodedReport.requestIds[i], + decodedReport.results[i], + decodedReport.errors[i], + decodedReport.onchainMetadata[i], + decodedReport.offchainMetadata[i], + uint8(numberOfFulfillments) // will not exceed "MaxRequestBatchSize" on the Job's ReportingPluginConfig + ) + ); + + // Emit on successfully processing the fulfillment + // In these two fulfillment results the user has been charged + // Otherwise, the DON will re-try + if ( + result == FunctionsResponse.FulfillResult.FULFILLED || + result == FunctionsResponse.FulfillResult.USER_CALLBACK_ERROR + ) { + emit OracleResponse(decodedReport.requestIds[i], msg.sender); + } + } + } + + /// @dev Used in FunctionsBilling.sol + function _onlyOwner() internal view override { + _validateOwnership(); + } + + /// @dev Used in FunctionsBilling.sol + function _owner() internal view override returns (address owner) { + return this.owner(); + } +} diff --git a/contracts/src/v0.8/functions/v1_3_0/accessControl/TermsOfServiceAllowList.sol b/contracts/src/v0.8/functions/v1_3_0/accessControl/TermsOfServiceAllowList.sol new file mode 100644 index 00000000000..1d9a3b915b1 --- /dev/null +++ b/contracts/src/v0.8/functions/v1_3_0/accessControl/TermsOfServiceAllowList.sol @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {ITermsOfServiceAllowList, TermsOfServiceAllowListConfig} from "./interfaces/ITermsOfServiceAllowList.sol"; +import {IAccessController} from "../../../shared/interfaces/IAccessController.sol"; +import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; + +import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; + +import {Address} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/Address.sol"; +import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol"; + +/// @notice A contract to handle access control of subscription management dependent on signing a Terms of Service +contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, ITypeAndVersion, ConfirmedOwner { + using Address for address; + using EnumerableSet for EnumerableSet.AddressSet; + + /// @inheritdoc ITypeAndVersion + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + string public constant override typeAndVersion = "Functions Terms of Service Allow List v1.1.0"; + + EnumerableSet.AddressSet private s_allowedSenders; + EnumerableSet.AddressSet private s_blockedSenders; + + event AddedAccess(address user); + event BlockedAccess(address user); + event UnblockedAccess(address user); + + error InvalidSignature(); + error InvalidUsage(); + error RecipientIsBlocked(); + error InvalidCalldata(); + + TermsOfServiceAllowListConfig private s_config; + + event ConfigUpdated(TermsOfServiceAllowListConfig config); + + // ================================================================ + // | Initialization | + // ================================================================ + + constructor( + TermsOfServiceAllowListConfig memory config, + address[] memory initialAllowedSenders, + address[] memory initialBlockedSenders + ) ConfirmedOwner(msg.sender) { + updateConfig(config); + + for (uint256 i = 0; i < initialAllowedSenders.length; ++i) { + s_allowedSenders.add(initialAllowedSenders[i]); + } + + for (uint256 j = 0; j < initialBlockedSenders.length; ++j) { + if (s_allowedSenders.contains(initialBlockedSenders[j])) { + // Allowed senders cannot also be blocked + revert InvalidCalldata(); + } + s_blockedSenders.add(initialBlockedSenders[j]); + } + } + + // ================================================================ + // | Configuration | + // ================================================================ + + /// @notice Gets the contracts's configuration + /// @return config + function getConfig() external view returns (TermsOfServiceAllowListConfig memory) { + return s_config; + } + + /// @notice Sets the contracts's configuration + /// @param config - See the contents of the TermsOfServiceAllowListConfig struct in ITermsOfServiceAllowList.sol for more information + function updateConfig(TermsOfServiceAllowListConfig memory config) public onlyOwner { + s_config = config; + emit ConfigUpdated(config); + } + + // ================================================================ + // | Allow methods | + // ================================================================ + + /// @inheritdoc ITermsOfServiceAllowList + function getMessage(address acceptor, address recipient) public pure override returns (bytes32) { + return keccak256(abi.encodePacked(acceptor, recipient)); + } + + /// @inheritdoc ITermsOfServiceAllowList + function acceptTermsOfService(address acceptor, address recipient, bytes32 r, bytes32 s, uint8 v) external override { + if (s_blockedSenders.contains(recipient)) { + revert RecipientIsBlocked(); + } + + // Validate that the signature is correct and the correct data has been signed + bytes32 prefixedMessage = keccak256( + abi.encodePacked("\x19Ethereum Signed Message:\n32", getMessage(acceptor, recipient)) + ); + if (ecrecover(prefixedMessage, v, r, s) != s_config.signerPublicKey) { + revert InvalidSignature(); + } + + // If contract, validate that msg.sender == recipient + // This is to prevent EoAs from claiming contracts that they are not in control of + // If EoA, validate that msg.sender == acceptor == recipient + // This is to prevent EoAs from accepting for other EoAs + if (msg.sender != recipient || (msg.sender != acceptor && !msg.sender.isContract())) { + revert InvalidUsage(); + } + + // Add recipient to the allow list + if (s_allowedSenders.add(recipient)) { + emit AddedAccess(recipient); + } + } + + /// @inheritdoc ITermsOfServiceAllowList + function getAllAllowedSenders() external view override returns (address[] memory) { + return s_allowedSenders.values(); + } + + /// @inheritdoc ITermsOfServiceAllowList + function getAllowedSendersCount() external view override returns (uint64) { + return uint64(s_allowedSenders.length()); + } + + /// @inheritdoc ITermsOfServiceAllowList + function getAllowedSendersInRange( + uint64 allowedSenderIdxStart, + uint64 allowedSenderIdxEnd + ) external view override returns (address[] memory allowedSenders) { + if ( + allowedSenderIdxStart > allowedSenderIdxEnd || + allowedSenderIdxEnd >= s_allowedSenders.length() || + s_allowedSenders.length() == 0 + ) { + revert InvalidCalldata(); + } + + allowedSenders = new address[]((allowedSenderIdxEnd - allowedSenderIdxStart) + 1); + for (uint256 i = 0; i <= allowedSenderIdxEnd - allowedSenderIdxStart; ++i) { + allowedSenders[i] = s_allowedSenders.at(uint256(allowedSenderIdxStart + i)); + } + + return allowedSenders; + } + + /// @inheritdoc IAccessController + function hasAccess(address user, bytes calldata /* data */) external view override returns (bool) { + if (!s_config.enabled) { + return true; + } + return s_allowedSenders.contains(user); + } + + // ================================================================ + // | Block methods | + // ================================================================ + + /// @inheritdoc ITermsOfServiceAllowList + function isBlockedSender(address sender) external view override returns (bool) { + if (!s_config.enabled) { + return false; + } + return s_blockedSenders.contains(sender); + } + + /// @inheritdoc ITermsOfServiceAllowList + function blockSender(address sender) external override onlyOwner { + s_allowedSenders.remove(sender); + s_blockedSenders.add(sender); + emit BlockedAccess(sender); + } + + /// @inheritdoc ITermsOfServiceAllowList + function unblockSender(address sender) external override onlyOwner { + s_blockedSenders.remove(sender); + emit UnblockedAccess(sender); + } + + /// @inheritdoc ITermsOfServiceAllowList + function getBlockedSendersCount() external view override returns (uint64) { + return uint64(s_blockedSenders.length()); + } + + /// @inheritdoc ITermsOfServiceAllowList + function getBlockedSendersInRange( + uint64 blockedSenderIdxStart, + uint64 blockedSenderIdxEnd + ) external view override returns (address[] memory blockedSenders) { + if ( + blockedSenderIdxStart > blockedSenderIdxEnd || + blockedSenderIdxEnd >= s_blockedSenders.length() || + s_blockedSenders.length() == 0 + ) { + revert InvalidCalldata(); + } + + blockedSenders = new address[]((blockedSenderIdxEnd - blockedSenderIdxStart) + 1); + for (uint256 i = 0; i <= blockedSenderIdxEnd - blockedSenderIdxStart; ++i) { + blockedSenders[i] = s_blockedSenders.at(uint256(blockedSenderIdxStart + i)); + } + + return blockedSenders; + } +} diff --git a/contracts/src/v0.8/functions/v1_3_0/accessControl/interfaces/ITermsOfServiceAllowList.sol b/contracts/src/v0.8/functions/v1_3_0/accessControl/interfaces/ITermsOfServiceAllowList.sol new file mode 100644 index 00000000000..65db9c42b69 --- /dev/null +++ b/contracts/src/v0.8/functions/v1_3_0/accessControl/interfaces/ITermsOfServiceAllowList.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +/// @notice A contract to handle access control of subscription management dependent on signing a Terms of Service +interface ITermsOfServiceAllowList { + /// @notice Return the message data for the proof given to accept the Terms of Service + /// @param acceptor - The wallet address that has accepted the Terms of Service on the UI + /// @param recipient - The recipient address that the acceptor is taking responsibility for + /// @return Hash of the message data + function getMessage(address acceptor, address recipient) external pure returns (bytes32); + + /// @notice Check if the address is blocked for usage + /// @param sender The transaction sender's address + /// @return True or false + function isBlockedSender(address sender) external returns (bool); + + /// @notice Get a list of all allowed senders + /// @dev WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + /// to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + /// this function has an unbounded cost, and using it as part of a state-changing function may render the function + /// uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + /// @return addresses - all allowed addresses + function getAllAllowedSenders() external view returns (address[] memory); + + /// @notice Get details about the total number of allowed senders + /// @return count - total number of allowed senders in the system + function getAllowedSendersCount() external view returns (uint64); + + /// @notice Retrieve a list of allowed senders using an inclusive range + /// @dev WARNING: getAllowedSendersInRange uses EnumerableSet .length() and .at() methods to iterate over the list + /// without the need for an extra mapping. These method can not guarantee the ordering when new elements are added. + /// Evaluate if eventual consistency will satisfy your usecase before using it. + /// @param allowedSenderIdxStart - index of the allowed sender to start the range at + /// @param allowedSenderIdxEnd - index of the allowed sender to end the range at + /// @return allowedSenders - allowed addresses in the range provided + function getAllowedSendersInRange( + uint64 allowedSenderIdxStart, + uint64 allowedSenderIdxEnd + ) external view returns (address[] memory allowedSenders); + + /// @notice Allows access to the sender based on acceptance of the Terms of Service + /// @param acceptor - The wallet address that has accepted the Terms of Service on the UI + /// @param recipient - The recipient address that the acceptor is taking responsibility for + /// @param r - ECDSA signature r data produced by the Chainlink Functions Subscription UI + /// @param s - ECDSA signature s produced by the Chainlink Functions Subscription UI + /// @param v - ECDSA signature v produced by the Chainlink Functions Subscription UI + function acceptTermsOfService(address acceptor, address recipient, bytes32 r, bytes32 s, uint8 v) external; + + /// @notice Removes a sender's access if already authorized, and disallows re-accepting the Terms of Service + /// @param sender - Address of the sender to block + function blockSender(address sender) external; + + /// @notice Re-allows a previously blocked sender to accept the Terms of Service + /// @param sender - Address of the sender to unblock + function unblockSender(address sender) external; + + /// @notice Get details about the total number of blocked senders + /// @return count - total number of blocked senders in the system + function getBlockedSendersCount() external view returns (uint64); + + /// @notice Retrieve a list of blocked senders using an inclusive range + /// @dev WARNING: getBlockedSendersInRange uses EnumerableSet .length() and .at() methods to iterate over the list + /// without the need for an extra mapping. These method can not guarantee the ordering when new elements are added. + /// Evaluate if eventual consistency will satisfy your usecase before using it. + /// @param blockedSenderIdxStart - index of the blocked sender to start the range at + /// @param blockedSenderIdxEnd - index of the blocked sender to end the range at + /// @return blockedSenders - blocked addresses in the range provided + function getBlockedSendersInRange( + uint64 blockedSenderIdxStart, + uint64 blockedSenderIdxEnd + ) external view returns (address[] memory blockedSenders); +} + +// ================================================================ +// | Configuration state | +// ================================================================ +struct TermsOfServiceAllowListConfig { + bool enabled; // ═════════════╗ When enabled, access will be checked against s_allowedSenders. When disabled, all access will be allowed. + address signerPublicKey; // ══╝ The key pair that needs to sign the acceptance data +} diff --git a/contracts/src/v0.8/functions/v1_3_0/interfaces/IFunctionsBilling.sol b/contracts/src/v0.8/functions/v1_3_0/interfaces/IFunctionsBilling.sol new file mode 100644 index 00000000000..79806f1eb18 --- /dev/null +++ b/contracts/src/v0.8/functions/v1_3_0/interfaces/IFunctionsBilling.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +/// @title Chainlink Functions DON billing interface. +interface IFunctionsBilling { + /// @notice Return the current conversion from WEI of ETH to LINK from the configured Chainlink data feed + /// @return weiPerUnitLink - The amount of WEI in one LINK + function getWeiPerUnitLink() external view returns (uint256); + + /// @notice Return the current conversion from LINK to USD from the configured Chainlink data feed + /// @return weiPerUnitLink - The amount of USD that one LINK is worth + /// @return decimals - The number of decimals that should be represented in the price feed's response + function getUsdPerUnitLink() external view returns (uint256, uint8); + + /// @notice Determine the fee that will be split between Node Operators for servicing a request + /// @param requestCBOR - CBOR encoded Chainlink Functions request data, use FunctionsRequest library to encode a request + /// @return fee - Cost in Juels (1e18) of LINK + function getDONFeeJuels(bytes memory requestCBOR) external view returns (uint72); + + /// @notice Determine the fee that will be paid to the Coordinator owner for operating the network + /// @return fee - Cost in Juels (1e18) of LINK + function getOperationFeeJuels() external view returns (uint72); + + /// @notice Determine the fee that will be paid to the Router owner for operating the network + /// @return fee - Cost in Juels (1e18) of LINK + function getAdminFeeJuels() external view returns (uint72); + + /// @notice Estimate the total cost that will be charged to a subscription to make a request: transmitter gas re-reimbursement, plus DON fee, plus Registry fee + /// @param - subscriptionId An identifier of the billing account + /// @param - data Encoded Chainlink Functions request data, use FunctionsClient API to encode a request + /// @param - callbackGasLimit Gas limit for the fulfillment callback + /// @param - gasPriceWei The blockchain's gas price to estimate with + /// @return - billedCost Cost in Juels (1e18) of LINK + function estimateCost( + uint64 subscriptionId, + bytes calldata data, + uint32 callbackGasLimit, + uint256 gasPriceWei + ) external view returns (uint96); + + /// @notice Remove a request commitment that the Router has determined to be stale + /// @param requestId - The request ID to remove + function deleteCommitment(bytes32 requestId) external; + + /// @notice Oracle withdraw LINK earned through fulfilling requests + /// @notice If amount is 0 the full balance will be withdrawn + /// @param recipient where to send the funds + /// @param amount amount to withdraw + function oracleWithdraw(address recipient, uint96 amount) external; + + /// @notice Withdraw all LINK earned by Oracles through fulfilling requests + /// @dev transmitter addresses must support LINK tokens to avoid tokens from getting stuck as oracleWithdrawAll() calls will forward tokens directly to transmitters + function oracleWithdrawAll() external; +} + +// ================================================================ +// | Configuration state | +// ================================================================ + +struct FunctionsBillingConfig { + uint32 fulfillmentGasPriceOverEstimationBP; // ══╗ Percentage of gas price overestimation to account for changes in gas price between request and response. Held as basis points (one hundredth of 1 percentage point) + uint32 feedStalenessSeconds; // ║ How long before we consider the feed price to be stale and fallback to fallbackNativePerUnitLink. + uint32 gasOverheadBeforeCallback; // ║ Represents the average gas execution cost before the fulfillment callback. This amount is always billed for every request. + uint32 gasOverheadAfterCallback; // ║ Represents the average gas execution cost after the fulfillment callback. This amount is always billed for every request. + uint40 minimumEstimateGasPriceWei; // ║ The lowest amount of wei that will be used as the tx.gasprice when estimating the cost to fulfill the request + uint16 maxSupportedRequestDataVersion; // ║ The highest support request data version supported by the node. All lower versions should also be supported. + uint64 fallbackUsdPerUnitLink; // ║ Fallback LINK / USD conversion rate if the data feed is stale + uint8 fallbackUsdPerUnitLinkDecimals; // ════════╝ Fallback LINK / USD conversion rate decimal places if the data feed is stale + uint224 fallbackNativePerUnitLink; // ═══════════╗ Fallback NATIVE CURRENCY / LINK conversion rate if the data feed is stale + uint32 requestTimeoutSeconds; // ════════════════╝ How many seconds it takes before we consider a request to be timed out + uint16 donFeeCentsUsd; // ═══════════════════════════════╗ Additional flat fee (denominated in cents of USD, paid as LINK) that will be split between Node Operators. + uint16 operationFeeCentsUsd; // ═════════════════════════╝ Additional flat fee (denominated in cents of USD, paid as LINK) that will be paid to the owner of the Coordinator contract. +} diff --git a/contracts/src/v0.8/functions/v1_3_0/ocr/OCR2Abstract.sol b/contracts/src/v0.8/functions/v1_3_0/ocr/OCR2Abstract.sol new file mode 100644 index 00000000000..4182227d645 --- /dev/null +++ b/contracts/src/v0.8/functions/v1_3_0/ocr/OCR2Abstract.sol @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; + +abstract contract OCR2Abstract is ITypeAndVersion { + // Maximum number of oracles the offchain reporting protocol is designed for + uint256 internal constant MAX_NUM_ORACLES = 31; + + /** + * @notice triggers a new run of the offchain reporting protocol + * @param previousConfigBlockNumber block in which the previous config was set, to simplify historic analysis + * @param configDigest configDigest of this configuration + * @param configCount ordinal number of this config setting among all config settings over the life of this contract + * @param signers ith element is address ith oracle uses to sign a report + * @param transmitters ith element is address ith oracle uses to transmit a report via the transmit method + * @param f maximum number of faulty/dishonest oracles the protocol can tolerate while still working correctly + * @param onchainConfig serialized configuration used by the contract (and possibly oracles) + * @param offchainConfigVersion version of the serialization format used for "offchainConfig" parameter + * @param offchainConfig serialized configuration used by the oracles exclusively and only passed through the contract + */ + event ConfigSet( + uint32 previousConfigBlockNumber, + bytes32 configDigest, + uint64 configCount, + address[] signers, + address[] transmitters, + uint8 f, + bytes onchainConfig, + uint64 offchainConfigVersion, + bytes offchainConfig + ); + + /** + * @notice sets offchain reporting protocol configuration incl. participating oracles + * @param signers addresses with which oracles sign the reports + * @param transmitters addresses oracles use to transmit the reports + * @param f number of faulty oracles the system can tolerate + * @param onchainConfig serialized configuration used by the contract (and possibly oracles) + * @param offchainConfigVersion version number for offchainEncoding schema + * @param offchainConfig serialized configuration used by the oracles exclusively and only passed through the contract + */ + function setConfig( + address[] memory signers, + address[] memory transmitters, + uint8 f, + bytes memory onchainConfig, + uint64 offchainConfigVersion, + bytes memory offchainConfig + ) external virtual; + + /** + * @notice information about current offchain reporting protocol configuration + * @return configCount ordinal number of current config, out of all configs applied to this contract so far + * @return blockNumber block at which this config was set + * @return configDigest domain-separation tag for current config (see _configDigestFromConfigData) + */ + function latestConfigDetails() + external + view + virtual + returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest); + + /** + * @notice optionally emited to indicate the latest configDigest and epoch for + which a report was successfully transmited. Alternatively, the contract may + use latestConfigDigestAndEpoch with scanLogs set to false. + */ + event Transmitted(bytes32 configDigest, uint32 epoch); + + /** + * @notice optionally returns the latest configDigest and epoch for which a + report was successfully transmitted. Alternatively, the contract may return + scanLogs set to true and use Transmitted events to provide this information + to offchain watchers. + * @return scanLogs indicates whether to rely on the configDigest and epoch + returned or whether to scan logs for the Transmitted event instead. + * @return configDigest + * @return epoch + */ + function latestConfigDigestAndEpoch() + external + view + virtual + returns (bool scanLogs, bytes32 configDigest, uint32 epoch); + + /** + * @notice transmit is called to post a new report to the contract + * @param report serialized report, which the signatures are signing. + * @param rs ith element is the R components of the ith signature on report. Must have at most maxNumOracles entries + * @param ss ith element is the S components of the ith signature on report. Must have at most maxNumOracles entries + * @param rawVs ith element is the the V component of the ith signature + */ + function transmit( + // NOTE: If these parameters are changed, expectedMsgDataLength and/or + // TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT need to be changed accordingly + bytes32[3] calldata reportContext, + bytes calldata report, + bytes32[] calldata rs, + bytes32[] calldata ss, + bytes32 rawVs // signatures + ) external virtual; +} diff --git a/contracts/src/v0.8/functions/v1_3_0/ocr/OCR2Base.sol b/contracts/src/v0.8/functions/v1_3_0/ocr/OCR2Base.sol new file mode 100644 index 00000000000..310107f2446 --- /dev/null +++ b/contracts/src/v0.8/functions/v1_3_0/ocr/OCR2Base.sol @@ -0,0 +1,356 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; +import {OCR2Abstract} from "./OCR2Abstract.sol"; + +/** + * @notice Onchain verification of reports from the offchain reporting protocol + * @dev For details on its operation, see the offchain reporting protocol design + * doc, which refers to this contract as simply the "contract". + */ +abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { + error ReportInvalid(string message); + error InvalidConfig(string message); + + constructor() ConfirmedOwner(msg.sender) {} + + // incremented each time a new config is posted. This count is incorporated + // into the config digest, to prevent replay attacks. + uint32 internal s_configCount; + uint32 internal s_latestConfigBlockNumber; // makes it easier for offchain systems + // to extract config from logs. + + // Storing these fields used on the hot path in a ConfigInfo variable reduces the + // retrieval of all of them to a single SLOAD. If any further fields are + // added, make sure that storage of the struct still takes at most 32 bytes. + struct ConfigInfo { + bytes32 latestConfigDigest; + uint8 f; // TODO: could be optimized by squeezing into one slot + uint8 n; + } + ConfigInfo internal s_configInfo; + + // Used for s_oracles[a].role, where a is an address, to track the purpose + // of the address, or to indicate that the address is unset. + enum Role { + // No oracle role has been set for address a + Unset, + // Signing address for the s_oracles[a].index'th oracle. I.e., report + // signatures from this oracle should ecrecover back to address a. + Signer, + // Transmission address for the s_oracles[a].index'th oracle. I.e., if a + // report is received by OCR2Aggregator.transmit in which msg.sender is + // a, it is attributed to the s_oracles[a].index'th oracle. + Transmitter + } + + struct Oracle { + uint8 index; // Index of oracle in s_signers/s_transmitters + Role role; // Role of the address which mapped to this struct + } + + mapping(address signerOrTransmitter => Oracle) internal s_oracles; + + // s_signers contains the signing address of each oracle + address[] internal s_signers; + + // s_transmitters contains the transmission address of each oracle, + // i.e. the address the oracle actually sends transactions to the contract from + address[] internal s_transmitters; + + struct DecodedReport { + bytes32[] requestIds; + bytes[] results; + bytes[] errors; + bytes[] onchainMetadata; + bytes[] offchainMetadata; + } + + /* + * Config logic + */ + + // Reverts transaction if config args are invalid + modifier checkConfigValid( + uint256 numSigners, + uint256 numTransmitters, + uint256 f + ) { + if (numSigners > MAX_NUM_ORACLES) revert InvalidConfig("too many signers"); + if (f == 0) revert InvalidConfig("f must be positive"); + if (numSigners != numTransmitters) revert InvalidConfig("oracle addresses out of registration"); + if (numSigners <= 3 * f) revert InvalidConfig("faulty-oracle f too high"); + _; + } + + struct SetConfigArgs { + address[] signers; + address[] transmitters; + uint8 f; + bytes onchainConfig; + uint64 offchainConfigVersion; + bytes offchainConfig; + } + + /// @inheritdoc OCR2Abstract + function latestConfigDigestAndEpoch() + external + view + virtual + override + returns (bool scanLogs, bytes32 configDigest, uint32 epoch) + { + return (true, bytes32(0), uint32(0)); + } + + /** + * @notice sets offchain reporting protocol configuration incl. participating oracles + * @param _signers addresses with which oracles sign the reports + * @param _transmitters addresses oracles use to transmit the reports + * @param _f number of faulty oracles the system can tolerate + * @param _onchainConfig encoded on-chain contract configuration + * @param _offchainConfigVersion version number for offchainEncoding schema + * @param _offchainConfig encoded off-chain oracle configuration + */ + function setConfig( + address[] memory _signers, + address[] memory _transmitters, + uint8 _f, + bytes memory _onchainConfig, + uint64 _offchainConfigVersion, + bytes memory _offchainConfig + ) external override checkConfigValid(_signers.length, _transmitters.length, _f) onlyOwner { + SetConfigArgs memory args = SetConfigArgs({ + signers: _signers, + transmitters: _transmitters, + f: _f, + onchainConfig: _onchainConfig, + offchainConfigVersion: _offchainConfigVersion, + offchainConfig: _offchainConfig + }); + + _beforeSetConfig(args.f, args.onchainConfig); + + while (s_signers.length != 0) { + // remove any old signer/transmitter addresses + uint256 lastIdx = s_signers.length - 1; + address signer = s_signers[lastIdx]; + address transmitter = s_transmitters[lastIdx]; + delete s_oracles[signer]; + delete s_oracles[transmitter]; + s_signers.pop(); + s_transmitters.pop(); + } + + // Bounded by MAX_NUM_ORACLES in OCR2Abstract.sol + for (uint256 i = 0; i < args.signers.length; i++) { + if (args.signers[i] == address(0)) revert InvalidConfig("signer must not be empty"); + if (args.transmitters[i] == address(0)) revert InvalidConfig("transmitter must not be empty"); + // add new signer/transmitter addresses + if (s_oracles[args.signers[i]].role != Role.Unset) revert InvalidConfig("repeated signer address"); + s_oracles[args.signers[i]] = Oracle(uint8(i), Role.Signer); + if (s_oracles[args.transmitters[i]].role != Role.Unset) revert InvalidConfig("repeated transmitter address"); + s_oracles[args.transmitters[i]] = Oracle(uint8(i), Role.Transmitter); + s_signers.push(args.signers[i]); + s_transmitters.push(args.transmitters[i]); + } + s_configInfo.f = args.f; + uint32 previousConfigBlockNumber = s_latestConfigBlockNumber; + s_latestConfigBlockNumber = uint32(block.number); + s_configCount += 1; + { + s_configInfo.latestConfigDigest = _configDigestFromConfigData( + block.chainid, + address(this), + s_configCount, + args.signers, + args.transmitters, + args.f, + args.onchainConfig, + args.offchainConfigVersion, + args.offchainConfig + ); + } + s_configInfo.n = uint8(args.signers.length); + + emit ConfigSet( + previousConfigBlockNumber, + s_configInfo.latestConfigDigest, + s_configCount, + args.signers, + args.transmitters, + args.f, + args.onchainConfig, + args.offchainConfigVersion, + args.offchainConfig + ); + } + + function _configDigestFromConfigData( + uint256 _chainId, + address _contractAddress, + uint64 _configCount, + address[] memory _signers, + address[] memory _transmitters, + uint8 _f, + bytes memory _onchainConfig, + uint64 _encodedConfigVersion, + bytes memory _encodedConfig + ) internal pure returns (bytes32) { + uint256 h = uint256( + keccak256( + abi.encode( + _chainId, + _contractAddress, + _configCount, + _signers, + _transmitters, + _f, + _onchainConfig, + _encodedConfigVersion, + _encodedConfig + ) + ) + ); + uint256 prefixMask = type(uint256).max << (256 - 16); // 0xFFFF00..00 + uint256 prefix = 0x0001 << (256 - 16); // 0x000100..00 + return bytes32((prefix & prefixMask) | (h & ~prefixMask)); + } + + /** + * @notice information about current offchain reporting protocol configuration + * @return configCount ordinal number of current config, out of all configs applied to this contract so far + * @return blockNumber block at which this config was set + * @return configDigest domain-separation tag for current config (see __configDigestFromConfigData) + */ + function latestConfigDetails() + external + view + override + returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest) + { + return (s_configCount, s_latestConfigBlockNumber, s_configInfo.latestConfigDigest); + } + + /** + * @return list of addresses permitted to transmit reports to this contract + * @dev The list will match the order used to specify the transmitter during setConfig + */ + function transmitters() external view returns (address[] memory) { + return s_transmitters; + } + + function _beforeSetConfig(uint8 _f, bytes memory _onchainConfig) internal virtual; + + /** + * @dev hook called after the report has been fully validated + * for the extending contract to handle additional logic, such as oracle payment + * @param decodedReport decodedReport + */ + function _report(DecodedReport memory decodedReport) internal virtual; + + // The constant-length components of the msg.data sent to transmit. + // See the "If we wanted to call sam" example on for example reasoning + // https://solidity.readthedocs.io/en/v0.7.2/abi-spec.html + uint16 private constant TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT = + 4 + // function selector + 32 * + 3 + // 3 words containing reportContext + 32 + // word containing start location of abiencoded report value + 32 + // word containing location start of abiencoded rs value + 32 + // word containing start location of abiencoded ss value + 32 + // rawVs value + 32 + // word containing length of report + 32 + // word containing length rs + 32 + // word containing length of ss + 0; // placeholder + + function _requireExpectedMsgDataLength( + bytes calldata report, + bytes32[] calldata rs, + bytes32[] calldata ss + ) private pure { + // calldata will never be big enough to make this overflow + uint256 expected = uint256(TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT) + + report.length + // one byte pure entry in _report + rs.length * + 32 + // 32 bytes per entry in _rs + ss.length * + 32 + // 32 bytes per entry in _ss + 0; // placeholder + if (msg.data.length != expected) revert ReportInvalid("calldata length mismatch"); + } + + function _beforeTransmit( + bytes calldata report + ) internal virtual returns (bool shouldStop, DecodedReport memory decodedReport); + + /** + * @notice transmit is called to post a new report to the contract + * @param report serialized report, which the signatures are signing. + * @param rs ith element is the R components of the ith signature on report. Must have at most maxNumOracles entries + * @param ss ith element is the S components of the ith signature on report. Must have at most maxNumOracles entries + * @param rawVs ith element is the the V component of the ith signature + */ + function transmit( + // NOTE: If these parameters are changed, expectedMsgDataLength and/or + // TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT need to be changed accordingly + bytes32[3] calldata reportContext, + bytes calldata report, + bytes32[] calldata rs, + bytes32[] calldata ss, + bytes32 rawVs // signatures + ) external override { + (bool shouldStop, DecodedReport memory decodedReport) = _beforeTransmit(report); + + if (shouldStop) { + return; + } + + { + // reportContext consists of: + // reportContext[0]: ConfigDigest + // reportContext[1]: 27 byte padding, 4-byte epoch and 1-byte round + // reportContext[2]: ExtraHash + bytes32 configDigest = reportContext[0]; + uint32 epochAndRound = uint32(uint256(reportContext[1])); + + emit Transmitted(configDigest, uint32(epochAndRound >> 8)); + + // The following check is disabled to allow both current and proposed routes to submit reports using the same OCR config digest + // Chainlink Functions uses globally unique request IDs. Metadata about the request is stored and checked in the Coordinator and Router + // require(configInfo.latestConfigDigest == configDigest, "configDigest mismatch"); + + _requireExpectedMsgDataLength(report, rs, ss); + + uint256 expectedNumSignatures = (s_configInfo.n + s_configInfo.f) / 2 + 1; + + if (rs.length != expectedNumSignatures) revert ReportInvalid("wrong number of signatures"); + if (rs.length != ss.length) revert ReportInvalid("report rs and ss must be of equal length"); + + Oracle memory transmitter = s_oracles[msg.sender]; + if (transmitter.role != Role.Transmitter && msg.sender != s_transmitters[transmitter.index]) + revert ReportInvalid("unauthorized transmitter"); + } + + address[MAX_NUM_ORACLES] memory signed; + + { + // Verify signatures attached to report + bytes32 h = keccak256(abi.encodePacked(keccak256(report), reportContext)); + + Oracle memory o; + // Bounded by MAX_NUM_ORACLES in OCR2Abstract.sol + for (uint256 i = 0; i < rs.length; ++i) { + address signer = ecrecover(h, uint8(rawVs[i]) + 27, rs[i], ss[i]); + o = s_oracles[signer]; + if (o.role != Role.Signer) revert ReportInvalid("address not authorized to sign"); + if (signed[o.index] != address(0)) revert ReportInvalid("non-unique signature"); + signed[o.index] = signer; + } + } + + _report(decodedReport); + } +} diff --git a/contracts/src/v0.8/keystone/KeystoneForwarder.sol b/contracts/src/v0.8/keystone/KeystoneForwarder.sol index 2fa3304addc..b4a9501e8f4 100644 --- a/contracts/src/v0.8/keystone/KeystoneForwarder.sol +++ b/contracts/src/v0.8/keystone/KeystoneForwarder.sol @@ -6,7 +6,7 @@ import {ConfirmedOwner} from "../shared/access/ConfirmedOwner.sol"; import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol"; import {Utils} from "./libraries/Utils.sol"; -// solhint-disable custom-errors, no-unused-vars +// solhint-disable gas-custom-errors, no-unused-vars contract KeystoneForwarder is IForwarder, ConfirmedOwner, TypeAndVersionInterface { error ReentrantCall(); diff --git a/contracts/src/v0.8/keystone/libraries/Utils.sol b/contracts/src/v0.8/keystone/libraries/Utils.sol index 3a11c0792a1..66e2635b908 100644 --- a/contracts/src/v0.8/keystone/libraries/Utils.sol +++ b/contracts/src/v0.8/keystone/libraries/Utils.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -// solhint-disable custom-errors +// solhint-disable gas-custom-errors library Utils { // solhint-disable avoid-low-level-calls, chainlink-solidity/explicit-returns function _splitSignature(bytes memory sig) internal pure returns (bytes32 r, bytes32 s, uint8 v) { diff --git a/contracts/src/v0.8/l2ep/dev/CrossDomainOwnable.sol b/contracts/src/v0.8/l2ep/dev/CrossDomainOwnable.sol index b9a435a7e21..f861da32a7c 100644 --- a/contracts/src/v0.8/l2ep/dev/CrossDomainOwnable.sol +++ b/contracts/src/v0.8/l2ep/dev/CrossDomainOwnable.sol @@ -42,7 +42,7 @@ contract CrossDomainOwnable is CrossDomainOwnableInterface, ConfirmedOwner { * @notice validate, transfer ownership, and emit relevant events */ function _transferL1Ownership(address to) internal { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(to != msg.sender, "Cannot transfer to self"); s_l1PendingOwner = to; @@ -65,7 +65,7 @@ contract CrossDomainOwnable is CrossDomainOwnableInterface, ConfirmedOwner { * @notice Reverts if called by anyone other than the L1 owner. */ modifier onlyL1Owner() virtual { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(msg.sender == s_l1Owner, "Only callable by L1 owner"); _; } @@ -74,7 +74,7 @@ contract CrossDomainOwnable is CrossDomainOwnableInterface, ConfirmedOwner { * @notice Reverts if called by anyone other than the L1 owner. */ modifier onlyProposedL1Owner() virtual { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(msg.sender == s_l1PendingOwner, "Only callable by proposed L1 owner"); _; } diff --git a/contracts/src/v0.8/l2ep/dev/Flags.sol b/contracts/src/v0.8/l2ep/dev/Flags.sol index b943c06d0c3..0fcd095ac8e 100644 --- a/contracts/src/v0.8/l2ep/dev/Flags.sol +++ b/contracts/src/v0.8/l2ep/dev/Flags.sol @@ -17,7 +17,7 @@ import {FlagsInterface} from "./interfaces/FlagsInterface.sol"; * An expected pattern is to allow addresses to raise flags on themselves, so if you are subscribing to * FlagOn events you should filter for addresses you care about. */ -// solhint-disable custom-errors +// solhint-disable gas-custom-errors contract Flags is ITypeAndVersion, FlagsInterface, SimpleReadAccessController { AccessControllerInterface public raisingAccessController; AccessControllerInterface public loweringAccessController; diff --git a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainForwarder.sol b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainForwarder.sol index cdab6d49612..158ffcc3042 100644 --- a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainForwarder.sol +++ b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainForwarder.sol @@ -56,7 +56,7 @@ contract ArbitrumCrossDomainForwarder is TypeAndVersionInterface, CrossDomainFor * @notice The call MUST come from the L1 owner (via cross-chain message.) Reverts otherwise. */ modifier onlyL1Owner() override { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(msg.sender == crossDomainMessenger(), "Sender is not the L2 messenger"); _; } @@ -65,7 +65,7 @@ contract ArbitrumCrossDomainForwarder is TypeAndVersionInterface, CrossDomainFor * @notice The call MUST come from the proposed L1 owner (via cross-chain message.) Reverts otherwise. */ modifier onlyProposedL1Owner() override { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(msg.sender == AddressAliasHelper.applyL1ToL2Alias(s_l1PendingOwner), "Must be proposed L1 owner"); _; } diff --git a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainGovernor.sol b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainGovernor.sol index 2f1d775e489..ebf579b8494 100644 --- a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainGovernor.sol +++ b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainGovernor.sol @@ -56,7 +56,7 @@ contract ArbitrumCrossDomainGovernor is DelegateForwarderInterface, ArbitrumCros * @notice The call MUST come from either the L1 owner (via cross-chain message) or the L2 owner. Reverts otherwise. */ modifier onlyLocalOrCrossDomainOwner() { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(msg.sender == crossDomainMessenger() || msg.sender == owner(), "Sender is not the L2 messenger or owner"); _; } diff --git a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol index 66fee5053ee..edcb62cae90 100644 --- a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol +++ b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol @@ -98,9 +98,9 @@ contract ArbitrumValidator is TypeAndVersionInterface, AggregatorValidatorInterf address gasPriceL1FeedAddr, PaymentStrategy _paymentStrategy ) { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(crossDomainMessengerAddr != address(0), "Invalid xDomain Messenger address"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(l2ArbitrumSequencerUptimeFeedAddr != address(0), "Invalid ArbitrumSequencerUptimeFeed contract address"); CROSS_DOMAIN_MESSENGER = crossDomainMessengerAddr; L2_SEQ_STATUS_RECORDER = l2ArbitrumSequencerUptimeFeedAddr; @@ -301,11 +301,11 @@ contract ArbitrumValidator is TypeAndVersionInterface, AggregatorValidatorInterf /// @notice internal method that stores the gas configuration function _setGasConfig(uint256 maxGas, uint256 gasPriceBid, uint256 baseFee, address gasPriceL1FeedAddr) internal { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(maxGas > 0, "Max gas is zero"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(gasPriceBid > 0, "Gas price bid is zero"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(gasPriceL1FeedAddr != address(0), "Gas price Aggregator is zero address"); s_gasConfig = GasConfig(maxGas, gasPriceBid, baseFee, gasPriceL1FeedAddr); emit GasConfigSet(maxGas, gasPriceBid, gasPriceL1FeedAddr); @@ -345,7 +345,7 @@ contract ArbitrumValidator is TypeAndVersionInterface, AggregatorValidatorInterf /// @dev reverts if the caller does not have access to change the configuration modifier onlyOwnerOrConfigAccess() { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require( msg.sender == owner() || (address(s_configAC) != address(0) && s_configAC.hasAccess(msg.sender, msg.data)), "No access" diff --git a/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainForwarder.sol b/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainForwarder.sol index 672720156db..37d9260b47b 100644 --- a/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainForwarder.sol +++ b/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainForwarder.sol @@ -29,7 +29,7 @@ contract OptimismCrossDomainForwarder is TypeAndVersionInterface, CrossDomainFor * @param l1OwnerAddr the L1 owner address that will be allowed to call the forward fn */ constructor(iOVM_CrossDomainMessenger crossDomainMessengerAddr, address l1OwnerAddr) CrossDomainOwnable(l1OwnerAddr) { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(address(crossDomainMessengerAddr) != address(0), "Invalid xDomain Messenger address"); OVM_CROSS_DOMAIN_MESSENGER = crossDomainMessengerAddr; } @@ -65,9 +65,9 @@ contract OptimismCrossDomainForwarder is TypeAndVersionInterface, CrossDomainFor * @notice The call MUST come from the L1 owner (via cross-chain message.) Reverts otherwise. */ modifier onlyL1Owner() override { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(msg.sender == crossDomainMessenger(), "Sender is not the L2 messenger"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require( iOVM_CrossDomainMessenger(crossDomainMessenger()).xDomainMessageSender() == l1Owner(), "xDomain sender is not the L1 owner" @@ -80,9 +80,9 @@ contract OptimismCrossDomainForwarder is TypeAndVersionInterface, CrossDomainFor */ modifier onlyProposedL1Owner() override { address messenger = crossDomainMessenger(); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(msg.sender == messenger, "Sender is not the L2 messenger"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require( iOVM_CrossDomainMessenger(messenger).xDomainMessageSender() == s_l1PendingOwner, "Must be proposed L1 owner" diff --git a/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainGovernor.sol b/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainGovernor.sol index 1f630a3fbde..ad780946911 100644 --- a/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainGovernor.sol +++ b/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainGovernor.sol @@ -59,11 +59,11 @@ contract OptimismCrossDomainGovernor is DelegateForwarderInterface, OptimismCros modifier onlyLocalOrCrossDomainOwner() { address messenger = crossDomainMessenger(); // 1. The delegatecall MUST come from either the L1 owner (via cross-chain message) or the L2 owner - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(msg.sender == messenger || msg.sender == owner(), "Sender is not the L2 messenger or owner"); // 2. The L2 Messenger's caller MUST be the L1 Owner if (msg.sender == messenger) { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require( iOVM_CrossDomainMessenger(messenger).xDomainMessageSender() == l1Owner(), "xDomain sender is not the L1 owner" diff --git a/contracts/src/v0.8/l2ep/dev/optimism/OptimismValidator.sol b/contracts/src/v0.8/l2ep/dev/optimism/OptimismValidator.sol index e41c61a4536..a54a56ee604 100644 --- a/contracts/src/v0.8/l2ep/dev/optimism/OptimismValidator.sol +++ b/contracts/src/v0.8/l2ep/dev/optimism/OptimismValidator.sol @@ -33,9 +33,9 @@ contract OptimismValidator is TypeAndVersionInterface, AggregatorValidatorInterf * @param gasLimit the gasLimit to use for sending a message from L1 to L2 */ constructor(address l1CrossDomainMessengerAddress, address l2UptimeFeedAddr, uint32 gasLimit) { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(l1CrossDomainMessengerAddress != address(0), "Invalid xDomain Messenger address"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(l2UptimeFeedAddr != address(0), "Invalid OptimismSequencerUptimeFeed contract address"); L1_CROSS_DOMAIN_MESSENGER_ADDRESS = l1CrossDomainMessengerAddress; L2_UPTIME_FEED_ADDR = l2UptimeFeedAddr; diff --git a/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainForwarder.sol b/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainForwarder.sol index f18f7c3270b..4ec51fc6938 100644 --- a/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainForwarder.sol +++ b/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainForwarder.sol @@ -15,7 +15,6 @@ import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/ut /// @dev Any other L2 contract which uses this contract's address as a privileged position, /// can be considered to be owned by the `l1Owner` contract ScrollCrossDomainForwarder is TypeAndVersionInterface, CrossDomainForwarder { - // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override typeAndVersion = "ScrollCrossDomainForwarder 1.0.0"; address internal immutable i_scrollCrossDomainMessenger; @@ -23,7 +22,7 @@ contract ScrollCrossDomainForwarder is TypeAndVersionInterface, CrossDomainForwa /// @param crossDomainMessengerAddr the xDomain bridge messenger (Scroll bridge L2) contract address /// @param l1OwnerAddr the L1 owner address that will be allowed to call the forward fn constructor(IScrollMessenger crossDomainMessengerAddr, address l1OwnerAddr) CrossDomainOwnable(l1OwnerAddr) { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(address(crossDomainMessengerAddr) != address(0), "Invalid xDomain Messenger address"); i_scrollCrossDomainMessenger = address(crossDomainMessengerAddr); } @@ -41,9 +40,9 @@ contract ScrollCrossDomainForwarder is TypeAndVersionInterface, CrossDomainForwa /// @notice The call MUST come from the L1 owner (via cross-chain message.) Reverts otherwise. modifier onlyL1Owner() override { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(msg.sender == i_scrollCrossDomainMessenger, "Sender is not the L2 messenger"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require( IScrollMessenger(i_scrollCrossDomainMessenger).xDomainMessageSender() == l1Owner(), "xDomain sender is not the L1 owner" @@ -53,9 +52,9 @@ contract ScrollCrossDomainForwarder is TypeAndVersionInterface, CrossDomainForwa /// @notice The call MUST come from the proposed L1 owner (via cross-chain message.) Reverts otherwise. modifier onlyProposedL1Owner() override { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(msg.sender == i_scrollCrossDomainMessenger, "Sender is not the L2 messenger"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require( IScrollMessenger(i_scrollCrossDomainMessenger).xDomainMessageSender() == s_l1PendingOwner, "Must be proposed L1 owner" diff --git a/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainGovernor.sol b/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainGovernor.sol index 00ef9219b26..f7d13059fe7 100644 --- a/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainGovernor.sol +++ b/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainGovernor.sol @@ -17,7 +17,6 @@ import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/ut /// @dev Any other L2 contract which uses this contract's address as a privileged position, /// can be considered to be simultaneously owned by the `l1Owner` and L2 `owner` contract ScrollCrossDomainGovernor is DelegateForwarderInterface, TypeAndVersionInterface, CrossDomainForwarder { - // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override typeAndVersion = "ScrollCrossDomainGovernor 1.0.0"; address internal immutable i_scrollCrossDomainMessenger; @@ -25,7 +24,7 @@ contract ScrollCrossDomainGovernor is DelegateForwarderInterface, TypeAndVersion /// @param crossDomainMessengerAddr the xDomain bridge messenger (Scroll bridge L2) contract address /// @param l1OwnerAddr the L1 owner address that will be allowed to call the forward fn constructor(IScrollMessenger crossDomainMessengerAddr, address l1OwnerAddr) CrossDomainOwnable(l1OwnerAddr) { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(address(crossDomainMessengerAddr) != address(0), "Invalid xDomain Messenger address"); i_scrollCrossDomainMessenger = address(crossDomainMessengerAddr); } @@ -49,9 +48,9 @@ contract ScrollCrossDomainGovernor is DelegateForwarderInterface, TypeAndVersion /// @notice The call MUST come from the L1 owner (via cross-chain message.) Reverts otherwise. modifier onlyL1Owner() override { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(msg.sender == i_scrollCrossDomainMessenger, "Sender is not the L2 messenger"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require( IScrollMessenger(i_scrollCrossDomainMessenger).xDomainMessageSender() == l1Owner(), "xDomain sender is not the L1 owner" @@ -62,14 +61,14 @@ contract ScrollCrossDomainGovernor is DelegateForwarderInterface, TypeAndVersion /// @notice The call MUST come from either the L1 owner (via cross-chain message) or the L2 owner. Reverts otherwise. modifier onlyLocalOrCrossDomainOwner() { // 1. The delegatecall MUST come from either the L1 owner (via cross-chain message) or the L2 owner - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require( msg.sender == i_scrollCrossDomainMessenger || msg.sender == owner(), "Sender is not the L2 messenger or owner" ); // 2. The L2 Messenger's caller MUST be the L1 Owner if (msg.sender == i_scrollCrossDomainMessenger) { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require( IScrollMessenger(i_scrollCrossDomainMessenger).xDomainMessageSender() == l1Owner(), "xDomain sender is not the L1 owner" @@ -80,9 +79,9 @@ contract ScrollCrossDomainGovernor is DelegateForwarderInterface, TypeAndVersion /// @notice The call MUST come from the proposed L1 owner (via cross-chain message.) Reverts otherwise. modifier onlyProposedL1Owner() override { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(msg.sender == i_scrollCrossDomainMessenger, "Sender is not the L2 messenger"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require( IScrollMessenger(i_scrollCrossDomainMessenger).xDomainMessageSender() == s_l1PendingOwner, "Must be proposed L1 owner" diff --git a/contracts/src/v0.8/l2ep/dev/scroll/ScrollSequencerUptimeFeed.sol b/contracts/src/v0.8/l2ep/dev/scroll/ScrollSequencerUptimeFeed.sol index 9df2b61238a..e60e8703b77 100644 --- a/contracts/src/v0.8/l2ep/dev/scroll/ScrollSequencerUptimeFeed.sol +++ b/contracts/src/v0.8/l2ep/dev/scroll/ScrollSequencerUptimeFeed.sol @@ -19,7 +19,6 @@ contract ScrollSequencerUptimeFeed is TypeAndVersionInterface, SimpleReadAccessController { - // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override typeAndVersion = "ScrollSequencerUptimeFeed 1.0.0"; /// @dev Round info (for uptime history) diff --git a/contracts/src/v0.8/l2ep/dev/scroll/ScrollValidator.sol b/contracts/src/v0.8/l2ep/dev/scroll/ScrollValidator.sol index 968b891b54a..9df4a12ac6e 100644 --- a/contracts/src/v0.8/l2ep/dev/scroll/ScrollValidator.sol +++ b/contracts/src/v0.8/l2ep/dev/scroll/ScrollValidator.sol @@ -19,7 +19,6 @@ contract ScrollValidator is TypeAndVersionInterface, AggregatorValidatorInterfac // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i address public immutable L1_MSG_QUEUE_ADDR; - // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override typeAndVersion = "ScrollValidator 1.0.0"; int256 private constant ANSWER_SEQ_OFFLINE = 1; uint32 private s_gasLimit; @@ -37,11 +36,11 @@ contract ScrollValidator is TypeAndVersionInterface, AggregatorValidatorInterfac address l1MessageQueueAddr, uint32 gasLimit ) { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(l1CrossDomainMessengerAddress != address(0), "Invalid xDomain Messenger address"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(l1MessageQueueAddr != address(0), "Invalid L1 message queue address"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(l2UptimeFeedAddr != address(0), "Invalid ScrollSequencerUptimeFeed contract address"); L1_CROSS_DOMAIN_MESSENGER_ADDRESS = l1CrossDomainMessengerAddress; L2_UPTIME_FEED_ADDR = l2UptimeFeedAddr; diff --git a/contracts/src/v0.8/l2ep/test/mocks/optimism/MockOVMCrossDomainMessenger.sol b/contracts/src/v0.8/l2ep/test/mocks/optimism/MockOVMCrossDomainMessenger.sol index 3a45cba347a..0c4193a38a2 100644 --- a/contracts/src/v0.8/l2ep/test/mocks/optimism/MockOVMCrossDomainMessenger.sol +++ b/contracts/src/v0.8/l2ep/test/mocks/optimism/MockOVMCrossDomainMessenger.sol @@ -1,6 +1,5 @@ // SPDX-License-Identifier: MIT - -pragma solidity >=0.7.6 <0.9.0; +pragma solidity ^0.8.0; import {iOVM_CrossDomainMessenger} from "../../../../vendor/@eth-optimism/contracts/v0.4.7/contracts/optimistic-ethereum/iOVM/bridge/messaging/iOVM_CrossDomainMessenger.sol"; diff --git a/contracts/src/v0.8/operatorforwarder/dev/AuthorizedForwarder.sol b/contracts/src/v0.8/operatorforwarder/dev/AuthorizedForwarder.sol index 1fe5e8f0cd6..824ffce6f0f 100644 --- a/contracts/src/v0.8/operatorforwarder/dev/AuthorizedForwarder.sol +++ b/contracts/src/v0.8/operatorforwarder/dev/AuthorizedForwarder.sol @@ -5,7 +5,7 @@ import {ConfirmedOwnerWithProposal} from "../../shared/access/ConfirmedOwnerWith import {AuthorizedReceiver} from "./AuthorizedReceiver.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; -// solhint-disable custom-errors +// solhint-disable gas-custom-errors contract AuthorizedForwarder is ConfirmedOwnerWithProposal, AuthorizedReceiver { using Address for address; @@ -27,7 +27,6 @@ contract AuthorizedForwarder is ConfirmedOwnerWithProposal, AuthorizedReceiver { } } - // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant typeAndVersion = "AuthorizedForwarder 1.1.0"; // @notice Forward a call to another contract diff --git a/contracts/src/v0.8/operatorforwarder/dev/AuthorizedReceiver.sol b/contracts/src/v0.8/operatorforwarder/dev/AuthorizedReceiver.sol index bc5f1c0e7e4..b741118895f 100644 --- a/contracts/src/v0.8/operatorforwarder/dev/AuthorizedReceiver.sol +++ b/contracts/src/v0.8/operatorforwarder/dev/AuthorizedReceiver.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.19; import {AuthorizedReceiverInterface} from "./interfaces/AuthorizedReceiverInterface.sol"; -// solhint-disable custom-errors +// solhint-disable gas-custom-errors abstract contract AuthorizedReceiver is AuthorizedReceiverInterface { mapping(address sender => bool authorized) private s_authorizedSenders; address[] private s_authorizedSenderList; diff --git a/contracts/src/v0.8/operatorforwarder/dev/LinkTokenReceiver.sol b/contracts/src/v0.8/operatorforwarder/dev/LinkTokenReceiver.sol index cfde9a4d583..dab259ca043 100644 --- a/contracts/src/v0.8/operatorforwarder/dev/LinkTokenReceiver.sol +++ b/contracts/src/v0.8/operatorforwarder/dev/LinkTokenReceiver.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.19; -// solhint-disable custom-errors +// solhint-disable gas-custom-errors abstract contract LinkTokenReceiver { // @notice Called when LINK is sent to the contract via `transferAndCall` // @dev The data payload's first 2 words will be overwritten by the `sender` and `amount` diff --git a/contracts/src/v0.8/operatorforwarder/dev/Operator.sol b/contracts/src/v0.8/operatorforwarder/dev/Operator.sol index 26295b27d16..ff193ef6066 100644 --- a/contracts/src/v0.8/operatorforwarder/dev/Operator.sol +++ b/contracts/src/v0.8/operatorforwarder/dev/Operator.sol @@ -15,7 +15,7 @@ import {SafeCast} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/util // @title The Chainlink Operator contract // @notice Node operators can deploy this contract to fulfill requests sent to them -// solhint-disable custom-errors +// solhint-disable gas-custom-errors contract Operator is AuthorizedReceiver, ConfirmedOwner, LinkTokenReceiver, OperatorInterface, WithdrawalInterface { using Address for address; @@ -72,7 +72,6 @@ contract Operator is AuthorizedReceiver, ConfirmedOwner, LinkTokenReceiver, Oper i_linkToken = LinkTokenInterface(link); // external but already deployed and unalterable } - // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant typeAndVersion = "Operator 1.0.0"; // @notice Creates the Chainlink request. This is a backwards compatible API @@ -337,7 +336,7 @@ contract Operator is AuthorizedReceiver, ConfirmedOwner, LinkTokenReceiver, Oper uint256 payment, bytes4 callbackFunc, uint256 expiration - ) external override { + ) public override { bytes31 paramsHash = _buildParamsHash(payment, msg.sender, callbackFunc, expiration); require(s_commitments[requestId].paramsHash == paramsHash, "Params do not match request ID"); // solhint-disable-next-line not-rely-on-time @@ -346,6 +345,8 @@ contract Operator is AuthorizedReceiver, ConfirmedOwner, LinkTokenReceiver, Oper delete s_commitments[requestId]; emit CancelOracleRequest(requestId); + // Free up the escrowed funds, as we're sending them back to the requester + s_tokensInEscrow -= payment; i_linkToken.transfer(msg.sender, payment); } @@ -363,16 +364,7 @@ contract Operator is AuthorizedReceiver, ConfirmedOwner, LinkTokenReceiver, Oper bytes4 callbackFunc, uint256 expiration ) external { - bytes32 requestId = keccak256(abi.encodePacked(msg.sender, nonce)); - bytes31 paramsHash = _buildParamsHash(payment, msg.sender, callbackFunc, expiration); - require(s_commitments[requestId].paramsHash == paramsHash, "Params do not match request ID"); - // solhint-disable-next-line not-rely-on-time - require(expiration <= block.timestamp, "Request is not expired"); - - delete s_commitments[requestId]; - emit CancelOracleRequest(requestId); - - i_linkToken.transfer(msg.sender, payment); + cancelOracleRequest(keccak256(abi.encodePacked(msg.sender, nonce)), payment, callbackFunc, expiration); } // @notice Returns the address of the LINK token diff --git a/contracts/src/v0.8/operatorforwarder/dev/OperatorFactory.sol b/contracts/src/v0.8/operatorforwarder/dev/OperatorFactory.sol index 0ff4bb6562e..15035355654 100644 --- a/contracts/src/v0.8/operatorforwarder/dev/OperatorFactory.sol +++ b/contracts/src/v0.8/operatorforwarder/dev/OperatorFactory.sol @@ -6,7 +6,7 @@ import {AuthorizedForwarder} from "./AuthorizedForwarder.sol"; // @title Operator Factory // @notice Creates Operator contracts for node operators -// solhint-disable custom-errors +// solhint-disable gas-custom-errors contract OperatorFactory { // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i address public immutable linkToken; @@ -20,7 +20,6 @@ contract OperatorFactory { linkToken = linkAddress; } - // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant typeAndVersion = "OperatorFactory 1.0.0"; // @notice creates a new Operator contract with the msg.sender as owner diff --git a/contracts/src/v0.8/operatorforwarder/dev/test/operator.t.sol b/contracts/src/v0.8/operatorforwarder/dev/test/operator.t.sol new file mode 100644 index 00000000000..96975a2baf4 --- /dev/null +++ b/contracts/src/v0.8/operatorforwarder/dev/test/operator.t.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {Test} from "forge-std/Test.sol"; +import {Operator} from "../Operator.sol"; +import {ChainlinkClientHelper} from "./testhelpers/ChainlinkClientHelper.sol"; +import {LinkToken} from "../../../shared/token/ERC677/LinkToken.sol"; + +contract Operator_cancelRequest is Test { + address public s_link; + ChainlinkClientHelper public s_client; + Operator public s_operator; + + function setUp() public { + s_link = address(new LinkToken()); + s_client = new ChainlinkClientHelper(s_link); + + address[] memory auth = new address[](1); + auth[0] = address(this); + s_operator = new Operator(s_link, address(this)); + s_operator.setAuthorizedSenders(auth); + } + + function test_Success(uint96 payment) public { + payment = uint96(bound(payment, 1, type(uint96).max)); + deal(s_link, address(s_client), payment); + // We're going to cancel one request and fulfil the other + bytes32 requestIdToCancel = s_client.sendRequest(address(s_operator), payment); + + // Nothing withdrawable + // 1 payment in escrow + // Client has zero link + assertEq(s_operator.withdrawable(), 0); + assertEq(LinkToken(s_link).balanceOf(address(s_operator)), payment); + assertEq(LinkToken(s_link).balanceOf(address(s_client)), 0); + + // Advance time so we can cancel + uint256 expiration = block.timestamp + s_operator.EXPIRYTIME(); + vm.warp(expiration + 1); + s_client.cancelRequest(requestIdToCancel, payment, expiration); + + // 1 payment has been returned due to the cancellation. + assertEq(s_operator.withdrawable(), 0); + assertEq(LinkToken(s_link).balanceOf(address(s_operator)), 0); + assertEq(LinkToken(s_link).balanceOf(address(s_client)), payment); + } + + function test_afterSuccessfulRequestSucess(uint96 payment) public { + payment = uint96(bound(payment, 1, type(uint96).max) / 2); + deal(s_link, address(s_client), 2 * payment); + + // Initial state, client has 2 payments, zero in escrow, zero in the operator, zeero withdrawable + assertEq(s_operator.withdrawable(), 0); + assertEq(LinkToken(s_link).balanceOf(address(s_operator)), 0); + assertEq(LinkToken(s_link).balanceOf(address(s_client)), 2 * payment); + + // We're going to cancel one request and fulfil the other + bytes32 requestId = s_client.sendRequest(address(s_operator), payment); + bytes32 requestIdToCancel = s_client.sendRequest(address(s_operator), payment); + + // Nothing withdrawable + // Operator now has the 2 payments in escrow + // Client has zero payments + assertEq(s_operator.withdrawable(), 0); + assertEq(LinkToken(s_link).balanceOf(address(s_operator)), 2 * payment); + assertEq(LinkToken(s_link).balanceOf(address(s_client)), 0); + + // Fulfill one request + uint256 expiration = block.timestamp + s_operator.EXPIRYTIME(); + s_operator.fulfillOracleRequest( + requestId, + payment, + address(s_client), + s_client.FULFILSELECTOR(), + expiration, + bytes32(hex"01") + ); + // 1 payment withdrawable from fulfilling `requestId`, 1 payment in escrow + assertEq(s_operator.withdrawable(), payment); + assertEq(LinkToken(s_link).balanceOf(address(s_operator)), 2 * payment); + assertEq(LinkToken(s_link).balanceOf(address(s_client)), 0); + + // Advance time so we can cancel + vm.warp(expiration + 1); + s_client.cancelRequest(requestIdToCancel, payment, expiration); + + // 1 payment has been returned due to the cancellation, 1 payment should be withdrawable + assertEq(s_operator.withdrawable(), payment); + assertEq(LinkToken(s_link).balanceOf(address(s_operator)), payment); + assertEq(LinkToken(s_link).balanceOf(address(s_client)), payment); + + // Withdraw the remaining payment + s_operator.withdraw(address(s_client), payment); + + // End state is exactly the same as the initial state. + assertEq(s_operator.withdrawable(), 0); + assertEq(LinkToken(s_link).balanceOf(address(s_operator)), 0); + assertEq(LinkToken(s_link).balanceOf(address(s_client)), 2 * payment); + } +} diff --git a/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/BasicConsumer.sol b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/BasicConsumer.sol new file mode 100644 index 00000000000..7004b53416a --- /dev/null +++ b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/BasicConsumer.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {Consumer} from "./Consumer.sol"; + +contract BasicConsumer is Consumer { + constructor(address _link, address _oracle, bytes32 _specId) { + _setChainlinkToken(_link); + _setChainlinkOracle(_oracle); + s_specId = _specId; + } +} diff --git a/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/ChainlinkClientHelper.sol b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/ChainlinkClientHelper.sol new file mode 100644 index 00000000000..d15eb07c8c9 --- /dev/null +++ b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/ChainlinkClientHelper.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {ChainlinkClient} from "../../../../ChainlinkClient.sol"; + +contract ChainlinkClientHelper is ChainlinkClient { + bytes4 public constant FULFILSELECTOR = this.fulfill.selector; + + constructor(address link) { + _setChainlinkToken(link); + } + + function sendRequest(address op, uint256 payment) external returns (bytes32) { + return _sendChainlinkRequestTo(op, _buildOperatorRequest(bytes32(hex"10"), FULFILSELECTOR), payment); + } + + function cancelRequest(bytes32 requestId, uint256 payment, uint256 expiration) external { + _cancelChainlinkRequest(requestId, payment, this.fulfill.selector, expiration); + } + + function fulfill(bytes32) external {} +} diff --git a/contracts/src/v0.4/Chainlinked.sol b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/Chainlinked.sol similarity index 72% rename from contracts/src/v0.4/Chainlinked.sol rename to contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/Chainlinked.sol index d537f9a48ea..86dc474e8a6 100644 --- a/contracts/src/v0.4/Chainlinked.sol +++ b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/Chainlinked.sol @@ -1,12 +1,13 @@ -pragma solidity ^0.4.24; +pragma solidity ^0.8.0; -import "./ChainlinkClient.sol"; +import {ChainlinkClient, Chainlink} from "../../../../ChainlinkClient.sol"; /** * @title The Chainlinked contract * @notice Contract writers can inherit this contract in order to create requests for the * Chainlink network. ChainlinkClient is an alias of the Chainlinked contract. */ +// solhint-disable contract Chainlinked is ChainlinkClient { /** * @notice Creates a request that can hold additional parameters @@ -20,7 +21,7 @@ contract Chainlinked is ChainlinkClient { address _callbackAddress, bytes4 _callbackFunctionSignature ) internal pure returns (Chainlink.Request memory) { - return buildChainlinkRequest(_specId, _callbackAddress, _callbackFunctionSignature); + return _buildChainlinkRequest(_specId, _callbackAddress, _callbackFunctionSignature); } /** @@ -30,11 +31,8 @@ contract Chainlinked is ChainlinkClient { * @param _payment The amount of LINK to send for the request * @return The request ID */ - function chainlinkRequest(Chainlink.Request memory _req, uint256 _payment) - internal - returns (bytes32) - { - return sendChainlinkRequest(_req, _payment); + function chainlinkRequest(Chainlink.Request memory _req, uint256 _payment) internal returns (bytes32) { + return _sendChainlinkRequest(_req, _payment); } /** @@ -45,13 +43,14 @@ contract Chainlinked is ChainlinkClient { * @param _oracle The address of the oracle for the request * @param _req The initialized Chainlink Request * @param _payment The amount of LINK to send for the request - * @return The request ID + * @return requestId The request ID */ - function chainlinkRequestTo(address _oracle, Chainlink.Request memory _req, uint256 _payment) - internal - returns (bytes32 requestId) - { - return sendChainlinkRequestTo(_oracle, _req, _payment); + function chainlinkRequestTo( + address _oracle, + Chainlink.Request memory _req, + uint256 _payment + ) internal returns (bytes32 requestId) { + return _sendChainlinkRequestTo(_oracle, _req, _payment); } /** @@ -59,7 +58,7 @@ contract Chainlinked is ChainlinkClient { * @param _oracle The address of the oracle contract */ function setOracle(address _oracle) internal { - setChainlinkOracle(_oracle); + _setChainlinkOracle(_oracle); } /** @@ -67,31 +66,23 @@ contract Chainlinked is ChainlinkClient { * @param _link The address of the LINK token contract */ function setLinkToken(address _link) internal { - setChainlinkToken(_link); + _setChainlinkToken(_link); } /** * @notice Retrieves the stored address of the LINK token * @return The address of the LINK token */ - function chainlinkToken() - internal - view - returns (address) - { - return chainlinkTokenAddress(); + function chainlinkToken() internal view returns (address) { + return _chainlinkTokenAddress(); } /** * @notice Retrieves the stored address of the oracle contract * @return The address of the oracle contract */ - function oracleAddress() - internal - view - returns (address) - { - return chainlinkOracleAddress(); + function oracleAddress() internal view returns (address) { + return _chainlinkOracleAddress(); } /** @@ -99,10 +90,11 @@ contract Chainlinked is ChainlinkClient { * @dev Use if the contract developer prefers methods instead of modifiers for validation * @param _requestId The request ID for fulfillment */ - function fulfillChainlinkRequest(bytes32 _requestId) + function fulfillChainlinkRequest( + bytes32 _requestId + ) internal - recordChainlinkFulfillment(_requestId) - // solhint-disable-next-line no-empty-blocks + recordChainlinkFulfillment(_requestId) // solhint-disable-next-line no-empty-blocks {} /** @@ -111,20 +103,16 @@ contract Chainlinked is ChainlinkClient { * @param _ens The address of the ENS contract * @param _node The ENS node hash */ - function setChainlinkWithENS(address _ens, bytes32 _node) - internal - { - useChainlinkWithENS(_ens, _node); + function setChainlinkWithENS(address _ens, bytes32 _node) internal { + _useChainlinkWithENS(_ens, _node); } /** * @notice Sets the stored oracle contract with the address resolved by ENS * @dev This may be called on its own as long as `setChainlinkWithENS` has been called previously */ - function setOracleWithENS() - internal - { - updateChainlinkOracleWithENS(); + function setOracleWithENS() internal { + _updateChainlinkOracleWithENS(); } /** @@ -133,9 +121,7 @@ contract Chainlinked is ChainlinkClient { * @param _oracle The address of the oracle contract that will fulfill the request * @param _requestId The request ID used for the response */ - function addExternalRequest(address _oracle, bytes32 _requestId) - internal - { - addChainlinkExternalRequest(_oracle, _requestId); + function addExternalRequest(address _oracle, bytes32 _requestId) internal { + _addChainlinkExternalRequest(_oracle, _requestId); } } diff --git a/contracts/src/v0.6/tests/Consumer.sol b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/Consumer.sol similarity index 58% rename from contracts/src/v0.6/tests/Consumer.sol rename to contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/Consumer.sol index 1e49bcef18f..0d01778e19e 100644 --- a/contracts/src/v0.6/tests/Consumer.sol +++ b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/Consumer.sol @@ -1,14 +1,17 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; +pragma solidity ^0.8.0; -import "../ChainlinkClient.sol"; +import {ChainlinkClient, ChainlinkRequestInterface, LinkTokenInterface} from "../../../../ChainlinkClient.sol"; +import {Chainlink} from "../../../../Chainlink.sol"; contract Consumer is ChainlinkClient { - bytes32 internal specId; + using Chainlink for Chainlink.Request; + + bytes32 internal s_specId; bytes32 public currentPrice; event RequestFulfilled( - bytes32 indexed requestId, // User-defined ID + bytes32 indexed requestId, // User-defined ID bytes32 indexed price ); @@ -17,12 +20,12 @@ contract Consumer is ChainlinkClient { } function requestEthereumPriceByCallback(string memory _currency, uint256 _payment, address _callback) public { - Chainlink.Request memory req = buildChainlinkRequest(specId, _callback, this.fulfill.selector); - req.add("get", "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD,EUR,JPY"); + Chainlink.Request memory req = _buildChainlinkRequest(s_specId, _callback, this.fulfill.selector); + req._add("get", "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD,EUR,JPY"); string[] memory path = new string[](1); path[0] = _currency; - req.addStringArray("path", path); - sendChainlinkRequest(req, _payment); + req._addStringArray("path", path); + _sendChainlinkRequest(req, _payment); } function cancelRequest( @@ -37,20 +40,16 @@ contract Consumer is ChainlinkClient { } function withdrawLink() public { - LinkTokenInterface _link = LinkTokenInterface(chainlinkTokenAddress()); + LinkTokenInterface _link = LinkTokenInterface(_chainlinkTokenAddress()); require(_link.transfer(msg.sender, _link.balanceOf(address(this))), "Unable to transfer"); } function addExternalRequest(address _oracle, bytes32 _requestId) external { - addChainlinkExternalRequest(_oracle, _requestId); + _addChainlinkExternalRequest(_oracle, _requestId); } - function fulfill(bytes32 _requestId, bytes32 _price) - public - recordChainlinkFulfillment(_requestId) - { + function fulfill(bytes32 _requestId, bytes32 _price) public recordChainlinkFulfillment(_requestId) { emit RequestFulfilled(_requestId, _price); currentPrice = _price; } - } diff --git a/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/EmptyOracle.sol b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/EmptyOracle.sol new file mode 100644 index 00000000000..2abe393151e --- /dev/null +++ b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/EmptyOracle.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {ChainlinkRequestInterface} from "../../../../interfaces/ChainlinkRequestInterface.sol"; +import {OracleInterface} from "../../../../interfaces/OracleInterface.sol"; + +/* solhint-disable no-empty-blocks */ +contract EmptyOracle is ChainlinkRequestInterface, OracleInterface { + function cancelOracleRequest(bytes32, uint256, bytes4, uint256) external override {} + function fulfillOracleRequest(bytes32, uint256, address, bytes4, uint256, bytes32) external override returns (bool) {} + function getAuthorizationStatus(address) external pure returns (bool) { + return false; + } + function onTokenTransfer(address, uint256, bytes calldata) external pure {} + function oracleRequest( + address, + uint256, + bytes32, + address, + bytes4, + uint256, + uint256, + bytes calldata + ) external override {} + function setFulfillmentPermission(address, bool) external {} + function withdraw(address, uint256) external override {} + function withdrawable() external view override returns (uint256) {} +} diff --git a/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/GasGuzzlingConsumer.sol b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/GasGuzzlingConsumer.sol new file mode 100644 index 00000000000..54ff0e30e66 --- /dev/null +++ b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/GasGuzzlingConsumer.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {Consumer} from "./Consumer.sol"; +import {Chainlink} from "../../../../Chainlink.sol"; + +contract GasGuzzlingConsumer is Consumer { + using Chainlink for Chainlink.Request; + + constructor(address _link, address _oracle, bytes32 _specId) { + _setChainlinkToken(_link); + _setChainlinkOracle(_oracle); + s_specId = _specId; + } + + function gassyRequestEthereumPrice(uint256 _payment) public { + Chainlink.Request memory req = _buildChainlinkRequest(s_specId, address(this), this.gassyFulfill.selector); + req._add("get", "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD,EUR,JPY"); + string[] memory path = new string[](1); + path[0] = "USD"; + req._addStringArray("path", path); + _sendChainlinkRequest(req, _payment); + } + + function gassyFulfill(bytes32 _requestId, bytes32) public recordChainlinkFulfillment(_requestId) { + while (true) {} + } + + function gassyMultiWordRequest(uint256 _payment) public { + Chainlink.Request memory req = _buildChainlinkRequest(s_specId, address(this), this.gassyMultiWordFulfill.selector); + req._add("get", "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD,EUR,JPY"); + string[] memory path = new string[](1); + path[0] = "USD"; + req._addStringArray("path", path); + _sendChainlinkRequest(req, _payment); + } + + function gassyMultiWordFulfill(bytes32 _requestId, bytes memory) public recordChainlinkFulfillment(_requestId) { + while (true) {} + } +} diff --git a/contracts/src/v0.5/tests/GetterSetter.sol b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/GetterSetter.sol similarity index 96% rename from contracts/src/v0.5/tests/GetterSetter.sol rename to contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/GetterSetter.sol index c765f5a3d8f..494da582e1b 100644 --- a/contracts/src/v0.5/tests/GetterSetter.sol +++ b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/GetterSetter.sol @@ -1,6 +1,7 @@ -pragma solidity 0.5.0; +pragma solidity ^0.8.0; // GetterSetter is a contract to aid debugging and testing during development. +// solhint-disable contract GetterSetter { bytes32 public getBytes32; uint256 public getUint256; diff --git a/contracts/src/v0.5/tests/MaliciousChainlink.sol b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/MaliciousChainlink.sol similarity index 80% rename from contracts/src/v0.5/tests/MaliciousChainlink.sol rename to contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/MaliciousChainlink.sol index b06d6613367..5cc343aa7f4 100644 --- a/contracts/src/v0.5/tests/MaliciousChainlink.sol +++ b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/MaliciousChainlink.sol @@ -1,8 +1,9 @@ -pragma solidity 0.5.0; +pragma solidity ^0.8.0; -import { CBOR as CBOR_Chainlink } from "../vendor/CBOR.sol"; -import { Buffer as Buffer_Chainlink } from "../vendor/Buffer.sol"; +import {CBORChainlink as CBOR_Chainlink} from "../../../../vendor/CBORChainlink.sol"; +import {BufferChainlink as Buffer_Chainlink} from "../../../../vendor/BufferChainlink.sol"; +// solhint-disable library MaliciousChainlink { using CBOR_Chainlink for Buffer_Chainlink.buffer; @@ -35,37 +36,27 @@ library MaliciousChainlink { return self; } - function add(Request memory self, string memory _key, string memory _value) - internal pure - { + function add(Request memory self, string memory _key, string memory _value) internal pure { self.buf.encodeString(_key); self.buf.encodeString(_value); } - function addBytes(Request memory self, string memory _key, bytes memory _value) - internal pure - { + function addBytes(Request memory self, string memory _key, bytes memory _value) internal pure { self.buf.encodeString(_key); self.buf.encodeBytes(_value); } - function addInt(Request memory self, string memory _key, int256 _value) - internal pure - { + function addInt(Request memory self, string memory _key, int256 _value) internal pure { self.buf.encodeString(_key); self.buf.encodeInt(_value); } - function addUint(Request memory self, string memory _key, uint256 _value) - internal pure - { + function addUint(Request memory self, string memory _key, uint256 _value) internal pure { self.buf.encodeString(_key); self.buf.encodeUInt(_value); } - function addStringArray(Request memory self, string memory _key, string[] memory _values) - internal pure - { + function addStringArray(Request memory self, string memory _key, string[] memory _values) internal pure { self.buf.encodeString(_key); self.buf.startArray(); for (uint256 i = 0; i < _values.length; i++) { diff --git a/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/MaliciousChainlinked.sol b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/MaliciousChainlinked.sol new file mode 100644 index 00000000000..722fbdd599b --- /dev/null +++ b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/MaliciousChainlinked.sol @@ -0,0 +1,116 @@ +pragma solidity ^0.8.0; + +import {MaliciousChainlink} from "./MaliciousChainlink.sol"; +import {Chainlinked, Chainlink} from "./Chainlinked.sol"; +import {LinkTokenInterface} from "../../../../shared/interfaces/LinkTokenInterface.sol"; + +// solhint-disable +contract MaliciousChainlinked is Chainlinked { + using MaliciousChainlink for MaliciousChainlink.Request; + using MaliciousChainlink for MaliciousChainlink.WithdrawRequest; + using Chainlink for Chainlink.Request; + + uint256 private maliciousRequests = 1; + mapping(bytes32 => address) private maliciousPendingRequests; + + function newWithdrawRequest( + bytes32 _specId, + address _callbackAddress, + bytes4 _callbackFunction + ) internal pure returns (MaliciousChainlink.WithdrawRequest memory) { + MaliciousChainlink.WithdrawRequest memory req; + return req.initializeWithdraw(_specId, _callbackAddress, _callbackFunction); + } + + function chainlinkTargetRequest( + address _target, + Chainlink.Request memory _req, + uint256 _amount + ) internal returns (bytes32 requestId) { + requestId = keccak256(abi.encodePacked(_target, maliciousRequests)); + _req.nonce = maliciousRequests; + maliciousPendingRequests[requestId] = oracleAddress(); + emit ChainlinkRequested(requestId); + LinkTokenInterface link = LinkTokenInterface(chainlinkToken()); + require( + link.transferAndCall(oracleAddress(), _amount, encodeTargetRequest(_req)), + "Unable to transferAndCall to oracle" + ); + maliciousRequests += 1; + + return requestId; + } + + function chainlinkPriceRequest(Chainlink.Request memory _req, uint256 _amount) internal returns (bytes32 requestId) { + requestId = keccak256(abi.encodePacked(this, maliciousRequests)); + _req.nonce = maliciousRequests; + maliciousPendingRequests[requestId] = oracleAddress(); + emit ChainlinkRequested(requestId); + LinkTokenInterface link = LinkTokenInterface(chainlinkToken()); + require( + link.transferAndCall(oracleAddress(), _amount, encodePriceRequest(_req)), + "Unable to transferAndCall to oracle" + ); + maliciousRequests += 1; + + return requestId; + } + + function chainlinkWithdrawRequest( + MaliciousChainlink.WithdrawRequest memory _req, + uint256 _wei + ) internal returns (bytes32 requestId) { + requestId = keccak256(abi.encodePacked(this, maliciousRequests)); + _req.nonce = maliciousRequests; + maliciousPendingRequests[requestId] = oracleAddress(); + emit ChainlinkRequested(requestId); + LinkTokenInterface link = LinkTokenInterface(chainlinkToken()); + require( + link.transferAndCall(oracleAddress(), _wei, encodeWithdrawRequest(_req)), + "Unable to transferAndCall to oracle" + ); + maliciousRequests += 1; + return requestId; + } + + function encodeWithdrawRequest(MaliciousChainlink.WithdrawRequest memory _req) internal pure returns (bytes memory) { + return + abi.encodeWithSelector( + bytes4(keccak256("withdraw(address,uint256)")), + _req.callbackAddress, + _req.callbackFunctionId, + _req.nonce, + _req.buf.buf + ); + } + + function encodeTargetRequest(Chainlink.Request memory _req) internal pure returns (bytes memory) { + return + abi.encodeWithSelector( + bytes4(keccak256("oracleRequest(address,uint256,bytes32,address,bytes4,uint256,uint256,bytes)")), + 0, // overridden by onTokenTransfer + 0, // overridden by onTokenTransfer + _req.id, + _req.callbackAddress, + _req.callbackFunctionId, + _req.nonce, + 1, + _req.buf.buf + ); + } + + function encodePriceRequest(Chainlink.Request memory _req) internal pure returns (bytes memory) { + return + abi.encodeWithSelector( + bytes4(keccak256("oracleRequest(address,uint256,bytes32,address,bytes4,uint256,uint256,bytes)")), + 0, // overridden by onTokenTransfer + 2000000000000000000, // overridden by onTokenTransfer + _req.id, + _req.callbackAddress, + _req.callbackFunctionId, + _req.nonce, + 1, + _req.buf.buf + ); + } +} diff --git a/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/MaliciousConsumer.sol b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/MaliciousConsumer.sol new file mode 100644 index 00000000000..003e628880f --- /dev/null +++ b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/MaliciousConsumer.sol @@ -0,0 +1,49 @@ +pragma solidity ^0.8.0; + +import {Chainlinked, Chainlink} from "./Chainlinked.sol"; + +// solhint-disable +contract MaliciousConsumer is Chainlinked { + uint256 private constant ORACLE_PAYMENT = 1 ether; + uint256 private expiration; + + constructor(address _link, address _oracle) public payable { + setLinkToken(_link); + setOracle(_oracle); + } + + fallback() external payable {} // solhint-disable-line no-empty-blocks + + function requestData(bytes32 _id, bytes memory _callbackFunc) public { + Chainlink.Request memory req = newRequest(_id, address(this), bytes4(keccak256(_callbackFunc))); + expiration = block.timestamp + 5 minutes; + chainlinkRequest(req, ORACLE_PAYMENT); + } + + function assertFail(bytes32, bytes32) public pure { + assert(1 == 2); + } + + function cancelRequestOnFulfill(bytes32 _requestId, bytes32) public { + _cancelChainlinkRequest(_requestId, ORACLE_PAYMENT, this.cancelRequestOnFulfill.selector, expiration); + } + + function remove() public { + selfdestruct(payable(address(0))); + } + + function stealEthCall(bytes32 _requestId, bytes32) public recordChainlinkFulfillment(_requestId) { + (bool success, ) = address(this).call{value: 100}(""); + require(success, "Call failed"); + } + + function stealEthSend(bytes32 _requestId, bytes32) public recordChainlinkFulfillment(_requestId) { + require(payable(address(this)).send(100), "Send failed"); + } + + function stealEthTransfer(bytes32 _requestId, bytes32) public recordChainlinkFulfillment(_requestId) { + payable(address(this)).transfer(100); + } + + function doesNothing(bytes32, bytes32) public pure {} // solhint-disable-line no-empty-blocks +} diff --git a/contracts/src/v0.6/tests/MaliciousMultiWordConsumer.sol b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/MaliciousMultiWordConsumer.sol similarity index 53% rename from contracts/src/v0.6/tests/MaliciousMultiWordConsumer.sol rename to contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/MaliciousMultiWordConsumer.sol index cd36836df12..272361f2dda 100644 --- a/contracts/src/v0.6/tests/MaliciousMultiWordConsumer.sol +++ b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/MaliciousMultiWordConsumer.sol @@ -1,26 +1,24 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.6.0; +pragma solidity ^0.8.0; -import "../ChainlinkClient.sol"; -import "../vendor/SafeMathChainlink.sol"; +import {ChainlinkClient} from "../../../../ChainlinkClient.sol"; +import {Chainlink} from "../../../../Chainlink.sol"; contract MaliciousMultiWordConsumer is ChainlinkClient { - using SafeMathChainlink for uint256; - - uint256 constant private ORACLE_PAYMENT = 1 * LINK; - uint256 private expiration; + uint256 private constant ORACLE_PAYMENT = 1 ether; + uint256 private s_expiration; constructor(address _link, address _oracle) public payable { - setChainlinkToken(_link); - setChainlinkOracle(_oracle); + _setChainlinkToken(_link); + _setChainlinkOracle(_oracle); } receive() external payable {} // solhint-disable-line no-empty-blocks function requestData(bytes32 _id, bytes memory _callbackFunc) public { - Chainlink.Request memory req = buildChainlinkRequest(_id, address(this), bytes4(keccak256(_callbackFunc))); - expiration = now.add(5 minutes); // solhint-disable-line not-rely-on-time - sendChainlinkRequest(req, ORACLE_PAYMENT); + Chainlink.Request memory req = _buildChainlinkRequest(_id, address(this), bytes4(keccak256(_callbackFunc))); + s_expiration = block.timestamp + 5 minutes; // solhint-disable-line not-rely-on-time + _sendChainlinkRequest(req, ORACLE_PAYMENT); } function assertFail(bytes32, bytes memory) public pure { @@ -28,30 +26,26 @@ contract MaliciousMultiWordConsumer is ChainlinkClient { } function cancelRequestOnFulfill(bytes32 _requestId, bytes memory) public { - cancelChainlinkRequest( - _requestId, - ORACLE_PAYMENT, - this.cancelRequestOnFulfill.selector, - expiration); + _cancelChainlinkRequest(_requestId, ORACLE_PAYMENT, this.cancelRequestOnFulfill.selector, s_expiration); } function remove() public { - selfdestruct(address(0)); + selfdestruct(payable(address(0))); } function stealEthCall(bytes32 _requestId, bytes memory) public recordChainlinkFulfillment(_requestId) { - (bool success,) = address(this).call.value(100)(""); // solhint-disable-line avoid-call-value + (bool success, ) = address(this).call{value: 100}(""); // solhint-disable-line avoid-call-value require(success, "Call failed"); } function stealEthSend(bytes32 _requestId, bytes memory) public recordChainlinkFulfillment(_requestId) { // solhint-disable-next-line check-send-result - bool success = address(this).send(100); // solhint-disable-line multiple-sends + bool success = payable(address(this)).send(100); // solhint-disable-line multiple-sends require(success, "Send failed"); } function stealEthTransfer(bytes32 _requestId, bytes memory) public recordChainlinkFulfillment(_requestId) { - address(this).transfer(100); + payable(address(this)).transfer(100); } function doesNothing(bytes32, bytes memory) public pure {} // solhint-disable-line no-empty-blocks diff --git a/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/MaliciousRequester.sol b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/MaliciousRequester.sol new file mode 100644 index 00000000000..9b19653722c --- /dev/null +++ b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/MaliciousRequester.sol @@ -0,0 +1,52 @@ +pragma solidity ^0.8.0; + +import {MaliciousChainlink} from "./MaliciousChainlink.sol"; +import {MaliciousChainlinked, Chainlink} from "./MaliciousChainlinked.sol"; +import {ChainlinkRequestInterface} from "../../../../interfaces/ChainlinkRequestInterface.sol"; + +contract MaliciousRequester is MaliciousChainlinked { + uint256 private constant ORACLE_PAYMENT = 1 ether; + uint256 private s_expiration; + + constructor(address _link, address _oracle) { + setLinkToken(_link); + setOracle(_oracle); + } + + function maliciousWithdraw() public { + MaliciousChainlink.WithdrawRequest memory req = newWithdrawRequest( + "specId", + address(this), + this.doesNothing.selector + ); + chainlinkWithdrawRequest(req, ORACLE_PAYMENT); + } + + function request(bytes32 _id, address _target, bytes memory _callbackFunc) public returns (bytes32 requestId) { + Chainlink.Request memory req = newRequest(_id, _target, bytes4(keccak256(_callbackFunc))); + s_expiration = block.timestamp + 5 minutes; // solhint-disable-line not-rely-on-time + return chainlinkRequest(req, ORACLE_PAYMENT); + } + + function maliciousPrice(bytes32 _id) public returns (bytes32 requestId) { + Chainlink.Request memory req = newRequest(_id, address(this), this.doesNothing.selector); + return chainlinkPriceRequest(req, ORACLE_PAYMENT); + } + + function maliciousTargetConsumer(address _target) public returns (bytes32 requestId) { + Chainlink.Request memory req = newRequest("specId", _target, bytes4(keccak256("fulfill(bytes32,bytes32)"))); + return chainlinkTargetRequest(_target, req, ORACLE_PAYMENT); + } + + function maliciousRequestCancel(bytes32 _id, bytes memory _callbackFunc) public { + ChainlinkRequestInterface oracle = ChainlinkRequestInterface(oracleAddress()); + oracle.cancelOracleRequest( + request(_id, address(this), _callbackFunc), + ORACLE_PAYMENT, + this.maliciousRequestCancel.selector, + s_expiration + ); + } + + function doesNothing(bytes32, bytes32) public pure {} // solhint-disable-line no-empty-blocks +} diff --git a/contracts/src/v0.7/tests/MultiWordConsumer.sol b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/MultiWordConsumer.sol similarity index 63% rename from contracts/src/v0.7/tests/MultiWordConsumer.sol rename to contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/MultiWordConsumer.sol index 7cadbb24db3..ce2bf1907c5 100644 --- a/contracts/src/v0.7/tests/MultiWordConsumer.sol +++ b/contracts/src/v0.8/operatorforwarder/dev/test/testhelpers/MultiWordConsumer.sol @@ -1,12 +1,12 @@ -pragma solidity ^0.7.0; +pragma solidity ^0.8.0; -import "../ChainlinkClient.sol"; -import "../Chainlink.sol"; +import {ChainlinkClient, ChainlinkRequestInterface, LinkTokenInterface} from "../../../../ChainlinkClient.sol"; +import {Chainlink} from "../../../../Chainlink.sol"; contract MultiWordConsumer is ChainlinkClient { using Chainlink for Chainlink.Request; - bytes32 internal specId; + bytes32 internal s_specId; bytes public currentPrice; bytes32 public usd; @@ -31,28 +31,24 @@ contract MultiWordConsumer is ChainlinkClient { uint256 jpy ); - constructor( - address _link, - address _oracle, - bytes32 _specId - ) public { - setChainlinkToken(_link); - setChainlinkOracle(_oracle); - specId = _specId; + constructor(address _link, address _oracle, bytes32 _specId) { + _setChainlinkToken(_link); + _setChainlinkOracle(_oracle); + s_specId = _specId; } function setSpecID(bytes32 _specId) public { - specId = _specId; + s_specId = _specId; } - function requestEthereumPrice(string memory _currency, uint256 _payment) public { - Chainlink.Request memory req = buildOperatorRequest(specId, this.fulfillBytes.selector); - sendOperatorRequest(req, _payment); + function requestEthereumPrice(string memory, uint256 _payment) public { + Chainlink.Request memory req = _buildOperatorRequest(s_specId, this.fulfillBytes.selector); + _sendOperatorRequest(req, _payment); } - function requestMultipleParameters(string memory _currency, uint256 _payment) public { - Chainlink.Request memory req = buildOperatorRequest(specId, this.fulfillMultipleParameters.selector); - sendOperatorRequest(req, _payment); + function requestMultipleParameters(string memory, uint256 _payment) public { + Chainlink.Request memory req = _buildOperatorRequest(s_specId, this.fulfillMultipleParameters.selector); + _sendOperatorRequest(req, _payment); } function requestMultipleParametersWithCustomURLs( @@ -64,14 +60,17 @@ contract MultiWordConsumer is ChainlinkClient { string memory _pathJPY, uint256 _payment ) public { - Chainlink.Request memory req = buildOperatorRequest(specId, this.fulfillMultipleParametersWithCustomURLs.selector); - req.add("urlUSD", _urlUSD); - req.add("pathUSD", _pathUSD); - req.add("urlEUR", _urlEUR); - req.add("pathEUR", _pathEUR); - req.add("urlJPY", _urlJPY); - req.add("pathJPY", _pathJPY); - sendOperatorRequest(req, _payment); + Chainlink.Request memory req = _buildOperatorRequest( + s_specId, + this.fulfillMultipleParametersWithCustomURLs.selector + ); + req._add("urlUSD", _urlUSD); + req._add("pathUSD", _pathUSD); + req._add("urlEUR", _urlEUR); + req._add("pathEUR", _pathEUR); + req._add("urlJPY", _urlJPY); + req._add("pathJPY", _pathJPY); + _sendOperatorRequest(req, _payment); } function cancelRequest( @@ -86,12 +85,12 @@ contract MultiWordConsumer is ChainlinkClient { } function withdrawLink() public { - LinkTokenInterface _link = LinkTokenInterface(chainlinkTokenAddress()); + LinkTokenInterface _link = LinkTokenInterface(_chainlinkTokenAddress()); require(_link.transfer(msg.sender, _link.balanceOf(address(this))), "Unable to transfer"); } function addExternalRequest(address _oracle, bytes32 _requestId) external { - addChainlinkExternalRequest(_oracle, _requestId); + _addChainlinkExternalRequest(_oracle, _requestId); } function fulfillMultipleParameters( @@ -124,6 +123,6 @@ contract MultiWordConsumer is ChainlinkClient { } function publicGetNextRequestCount() external view returns (uint256) { - return getNextRequestCount(); + return _getNextRequestCount(); } } diff --git a/contracts/src/v0.8/shared/access/ConfirmedOwnerWithProposal.sol b/contracts/src/v0.8/shared/access/ConfirmedOwnerWithProposal.sol index 7b68418754a..2a6dd94e103 100644 --- a/contracts/src/v0.8/shared/access/ConfirmedOwnerWithProposal.sol +++ b/contracts/src/v0.8/shared/access/ConfirmedOwnerWithProposal.sol @@ -13,7 +13,7 @@ contract ConfirmedOwnerWithProposal is IOwnable { event OwnershipTransferred(address indexed from, address indexed to); constructor(address newOwner, address pendingOwner) { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(newOwner != address(0), "Cannot set owner to zero"); s_owner = newOwner; @@ -29,7 +29,7 @@ contract ConfirmedOwnerWithProposal is IOwnable { /// @notice Allows an ownership transfer to be completed by the recipient. function acceptOwnership() external override { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(msg.sender == s_pendingOwner, "Must be proposed owner"); address oldOwner = s_owner; @@ -46,7 +46,7 @@ contract ConfirmedOwnerWithProposal is IOwnable { /// @notice validate, transfer ownership, and emit relevant events function _transferOwnership(address to) private { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(to != msg.sender, "Cannot transfer to self"); s_pendingOwner = to; @@ -56,7 +56,7 @@ contract ConfirmedOwnerWithProposal is IOwnable { /// @notice validate access function _validateOwnership() internal view { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(msg.sender == s_owner, "Only callable by owner"); } diff --git a/contracts/src/v0.8/shared/access/SimpleWriteAccessController.sol b/contracts/src/v0.8/shared/access/SimpleWriteAccessController.sol index b431331bc84..5a53bdf6137 100644 --- a/contracts/src/v0.8/shared/access/SimpleWriteAccessController.sol +++ b/contracts/src/v0.8/shared/access/SimpleWriteAccessController.sol @@ -66,7 +66,7 @@ contract SimpleWriteAccessController is AccessControllerInterface, ConfirmedOwne /// @dev reverts if the caller does not have access modifier checkAccess() { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(hasAccess(msg.sender, msg.data), "No access"); _; } diff --git a/contracts/src/v0.8/shared/mocks/WERC20Mock.sol b/contracts/src/v0.8/shared/mocks/WERC20Mock.sol index cee7fa7ff83..6155b38bdd6 100644 --- a/contracts/src/v0.8/shared/mocks/WERC20Mock.sol +++ b/contracts/src/v0.8/shared/mocks/WERC20Mock.sol @@ -19,7 +19,7 @@ contract WERC20Mock is ERC20 { } function withdraw(uint256 wad) public { - // solhint-disable-next-line custom-errors, reason-string + // solhint-disable-next-line gas-custom-errors, reason-string require(balanceOf(msg.sender) >= wad); _burn(msg.sender, wad); payable(msg.sender).transfer(wad); diff --git a/contracts/src/v0.8/shared/ocr2/OCR2Base.sol b/contracts/src/v0.8/shared/ocr2/OCR2Base.sol index baedac7710a..7884d4814f2 100644 --- a/contracts/src/v0.8/shared/ocr2/OCR2Base.sol +++ b/contracts/src/v0.8/shared/ocr2/OCR2Base.sol @@ -12,7 +12,7 @@ import {OCR2Abstract} from "./OCR2Abstract.sol"; /// However, for actual production contracts, it is expected that most of the logic of this contract /// will be folded directly into the application contract. Inheritance prevents us from doing lots /// of juicy storage layout optimizations, leading to a substantial increase in gas cost. -// solhint-disable custom-errors +// solhint-disable gas-custom-errors abstract contract OCR2Base is OwnerIsCreator, OCR2Abstract { error ReportInvalid(); diff --git a/contracts/src/v0.8/shared/test/helpers/ChainReaderTestContract.sol b/contracts/src/v0.8/shared/test/helpers/ChainReaderTestContract.sol index 050f5fb390e..217901c1901 100644 --- a/contracts/src/v0.8/shared/test/helpers/ChainReaderTestContract.sol +++ b/contracts/src/v0.8/shared/test/helpers/ChainReaderTestContract.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8; +pragma solidity ^0.8.0; struct TestStruct { int32 Field; diff --git a/contracts/src/v0.8/shared/test/helpers/LinkTokenTestHelper.sol b/contracts/src/v0.8/shared/test/helpers/LinkTokenTestHelper.sol new file mode 100644 index 00000000000..f2b2f19c134 --- /dev/null +++ b/contracts/src/v0.8/shared/test/helpers/LinkTokenTestHelper.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {LinkToken} from "../../token/ERC677/LinkToken.sol"; + +// This contract exists to mirror the functionality of the old token, which +// always deployed with 1b tokens sent to the deployer. +contract LinkTokenTestHelper is LinkToken { + constructor() { + _mint(msg.sender, 1e27); + } +} diff --git a/contracts/src/v0.7/tests/ConfirmedOwnerTestHelper.sol b/contracts/src/v0.8/shared/test/testhelpers/ConfirmedOwnerTestHelper.sol similarity index 71% rename from contracts/src/v0.7/tests/ConfirmedOwnerTestHelper.sol rename to contracts/src/v0.8/shared/test/testhelpers/ConfirmedOwnerTestHelper.sol index 99a077074df..47ecbb0cd1f 100644 --- a/contracts/src/v0.7/tests/ConfirmedOwnerTestHelper.sol +++ b/contracts/src/v0.8/shared/test/testhelpers/ConfirmedOwnerTestHelper.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; +pragma solidity ^0.8.0; -import "../ConfirmedOwner.sol"; +import {ConfirmedOwner} from "../../access/ConfirmedOwner.sol"; contract ConfirmedOwnerTestHelper is ConfirmedOwner { event Here(); diff --git a/contracts/src/v0.8/shared/token/ERC677/ERC677.sol b/contracts/src/v0.8/shared/token/ERC677/ERC677.sol index aa75a1170c7..5876ddfc2fa 100644 --- a/contracts/src/v0.8/shared/token/ERC677/ERC677.sol +++ b/contracts/src/v0.8/shared/token/ERC677/ERC677.sol @@ -4,19 +4,16 @@ pragma solidity ^0.8.0; import {IERC677} from "./IERC677.sol"; import {IERC677Receiver} from "../../interfaces/IERC677Receiver.sol"; -import {Address} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/Address.sol"; import {ERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/ERC20.sol"; contract ERC677 is IERC677, ERC20 { - using Address for address; - constructor(string memory name, string memory symbol) ERC20(name, symbol) {} /// @inheritdoc IERC677 function transferAndCall(address to, uint256 amount, bytes memory data) public returns (bool success) { super.transfer(to, amount); emit Transfer(msg.sender, to, amount, data); - if (to.isContract()) { + if (to.code.length > 0) { IERC677Receiver(to).onTokenTransfer(msg.sender, amount, data); } return true; diff --git a/contracts/src/v0.8/transmission/dev/ERC-4337/Paymaster.sol b/contracts/src/v0.8/transmission/dev/ERC-4337/Paymaster.sol index 38b6fb57983..932d35006c4 100644 --- a/contracts/src/v0.8/transmission/dev/ERC-4337/Paymaster.sol +++ b/contracts/src/v0.8/transmission/dev/ERC-4337/Paymaster.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.15; +pragma solidity ^0.8.19; import {IPaymaster} from "../../../vendor/entrypoint/interfaces/IPaymaster.sol"; import {SCALibrary} from "./SCALibrary.sol"; diff --git a/contracts/src/v0.8/transmission/dev/ERC-4337/SCA.sol b/contracts/src/v0.8/transmission/dev/ERC-4337/SCA.sol index 6a11eecfe00..589c55f5b3b 100644 --- a/contracts/src/v0.8/transmission/dev/ERC-4337/SCA.sol +++ b/contracts/src/v0.8/transmission/dev/ERC-4337/SCA.sol @@ -1,6 +1,5 @@ // SPDX-License-Identifier: MIT -/// TODO: decide on a compiler version. Must not be dynamic, and must be > 0.8.12. -pragma solidity 0.8.15; +pragma solidity 0.8.19; import {IAccount} from "../../../vendor/entrypoint/interfaces/IAccount.sol"; import {SCALibrary} from "./SCALibrary.sol"; diff --git a/contracts/src/v0.8/transmission/dev/ERC-4337/SCALibrary.sol b/contracts/src/v0.8/transmission/dev/ERC-4337/SCALibrary.sol index 35d666a2d3d..095a3428ef4 100644 --- a/contracts/src/v0.8/transmission/dev/ERC-4337/SCALibrary.sol +++ b/contracts/src/v0.8/transmission/dev/ERC-4337/SCALibrary.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.15; +pragma solidity ^0.8.19; library SCALibrary { // keccak256("EIP712Domain(uint256 chainId, address verifyingContract)"); diff --git a/contracts/src/v0.8/transmission/dev/ERC-4337/SmartContractAccountFactory.sol b/contracts/src/v0.8/transmission/dev/ERC-4337/SmartContractAccountFactory.sol index bb0f2dbde63..f27c8e15cf6 100644 --- a/contracts/src/v0.8/transmission/dev/ERC-4337/SmartContractAccountFactory.sol +++ b/contracts/src/v0.8/transmission/dev/ERC-4337/SmartContractAccountFactory.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.15; +pragma solidity ^0.8.19; contract SmartContractAccountFactory { event ContractCreated(address scaAddress); diff --git a/contracts/src/v0.8/transmission/dev/testhelpers/Greeter.sol b/contracts/src/v0.8/transmission/dev/testhelpers/Greeter.sol index 92e50b806fe..5851c86581e 100644 --- a/contracts/src/v0.8/transmission/dev/testhelpers/Greeter.sol +++ b/contracts/src/v0.8/transmission/dev/testhelpers/Greeter.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.15; +pragma solidity ^0.8.19; /// @dev Ownerless greeter contract. contract Greeter { diff --git a/contracts/src/v0.8/transmission/dev/testhelpers/SmartContractAccountHelper.sol b/contracts/src/v0.8/transmission/dev/testhelpers/SmartContractAccountHelper.sol index 014f296f077..b080484d8cc 100644 --- a/contracts/src/v0.8/transmission/dev/testhelpers/SmartContractAccountHelper.sol +++ b/contracts/src/v0.8/transmission/dev/testhelpers/SmartContractAccountHelper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.15; +pragma solidity ^0.8.19; import {SCA} from "../ERC-4337/SCA.sol"; import {SmartContractAccountFactory} from "../ERC-4337/SmartContractAccountFactory.sol"; diff --git a/contracts/test/v0.8/foundry/BaseTest.t.sol b/contracts/src/v0.8/transmission/test/BaseTest.t.sol similarity index 100% rename from contracts/test/v0.8/foundry/BaseTest.t.sol rename to contracts/src/v0.8/transmission/test/BaseTest.t.sol diff --git a/contracts/test/v0.8/foundry/transmission/EIP_712_1014_4337.t.sol b/contracts/src/v0.8/transmission/test/EIP_712_1014_4337.t.sol similarity index 91% rename from contracts/test/v0.8/foundry/transmission/EIP_712_1014_4337.t.sol rename to contracts/src/v0.8/transmission/test/EIP_712_1014_4337.t.sol index 8e43527af53..fdfe190de26 100644 --- a/contracts/test/v0.8/foundry/transmission/EIP_712_1014_4337.t.sol +++ b/contracts/src/v0.8/transmission/test/EIP_712_1014_4337.t.sol @@ -1,20 +1,22 @@ -pragma solidity ^0.8.15; - -import "../BaseTest.t.sol"; -import "../../../../src/v0.8/transmission/dev/ERC-4337/SmartContractAccountFactory.sol"; -import "../../../../src/v0.8/transmission/dev/testhelpers/SmartContractAccountHelper.sol"; -import "../../../../src/v0.8/transmission/dev/ERC-4337/SCA.sol"; -import "../../../../src/v0.8/transmission/dev/testhelpers/Greeter.sol"; -import "../../../../src/v0.8/transmission/dev/ERC-4337/Paymaster.sol"; -import "../../../../src/v0.8/vendor/entrypoint/interfaces/UserOperation.sol"; -import "../../../../src/v0.8/vendor/entrypoint/core/EntryPoint.sol"; -import "../../../../src/v0.8/vendor/entrypoint/interfaces/IEntryPoint.sol"; -import "../../../../src/v0.8/transmission/dev/ERC-4337/SCALibrary.sol"; -import "../../../../src/v0.8/mocks/MockLinkToken.sol"; -import "../../../../src/v0.8/shared/interfaces/LinkTokenInterface.sol"; -import "../../../../src/v0.8/vrf/mocks/VRFCoordinatorMock.sol"; -import "../../../../src/v0.8/tests/MockV3Aggregator.sol"; -import "../../../../src/v0.8/vrf/testhelpers/VRFConsumer.sol"; +pragma solidity 0.8.19; + +import "../../shared/interfaces/LinkTokenInterface.sol"; + +import "./BaseTest.t.sol"; +import "../dev/ERC-4337/SmartContractAccountFactory.sol"; +import "../dev/testhelpers/SmartContractAccountHelper.sol"; +import "../dev/ERC-4337/SCA.sol"; +import "../dev/testhelpers/Greeter.sol"; +import "../dev/ERC-4337/Paymaster.sol"; +import "../../transmission/dev/ERC-4337/SCALibrary.sol"; +import "../../mocks/MockLinkToken.sol"; +import "../../tests/MockV3Aggregator.sol"; +import "../../vrf/mocks/VRFCoordinatorMock.sol"; +import "../../vrf/testhelpers/VRFConsumer.sol"; + +import "../../vendor/entrypoint/interfaces/UserOperation.sol"; +import "../../vendor/entrypoint/core/EntryPoint.sol"; +import "../../vendor/entrypoint/interfaces/IEntryPoint.sol"; /*--------------------------------------------------------------------------------------------------------------------+ | EIP 712 + 1014 + 4337 | @@ -27,7 +29,7 @@ import "../../../../src/v0.8/vrf/testhelpers/VRFConsumer.sol"; | | | The below tests illustrate end-user flows for interacting with this meta-transaction system. For users with | | existing Smart Contract Accounts (SCAs), they simply sign off on the operation, after which the executor | -| invokes the EntryPoint that authorizes the operation on the end-user's SCA, and then exectute the transaction | +| invokes the EntryPoint that authorizes the operation on the end-user's SCA, and then execute the transaction | | as the SCA. For users without existing SCAs, EIP-1014 ensures that the address of an SCA can be known in advance, | | so users can sign-off on transactions that will be executed by a not-yet-deployed SCA. The EntryPoint contract | | takes advantage of this functionality and allows for the SCA to be created in the same user operation that invokes | @@ -40,12 +42,6 @@ import "../../../../src/v0.8/vrf/testhelpers/VRFConsumer.sol"; | | -+---------------------------------------------------------------------------------------------------------------------*/ -/*----------------------------+ -| TESTS | -| ________________ | -| | -+----------------------------*/ - contract EIP_712_1014_4337 is BaseTest { event RandomnessRequest(address indexed sender, bytes32 indexed keyHash, uint256 indexed seed, uint256 fee); @@ -69,7 +65,7 @@ contract EIP_712_1014_4337 is BaseTest { // Impersonate a LINK whale. changePrank(LINK_WHALE); - // Create simople greeter contract. + // Create simple greeter contract. greeter = new Greeter(); assertEq("", greeter.getGreeting()); @@ -178,7 +174,7 @@ contract EIP_712_1014_4337 is BaseTest { encodedGreetingCall ); - // Construct the user opeartion. + // Construct the user operation. UserOperation memory op = UserOperation({ sender: toDeployAddress, nonce: 0, @@ -322,7 +318,7 @@ contract EIP_712_1014_4337 is BaseTest { topupAmount: 10 ether }); - // Construct the user opeartion. + // Construct the user operation. UserOperation memory op = UserOperation({ sender: toDeployAddress, nonce: 0, @@ -344,7 +340,7 @@ contract EIP_712_1014_4337 is BaseTest { // Deposit funds for the transaction. entryPoint.depositTo{value: 10 ether}(address(paymaster)); - // Assert correct log is emmitted for the end-contract vrf request. + // Assert correct log is emitted for the end-contract vrf request. vm.expectEmit(true, true, true, true); emit RandomnessRequest( address(vrfConsumer), diff --git a/contracts/src/v0.8/vrf/BatchBlockhashStore.sol b/contracts/src/v0.8/vrf/BatchBlockhashStore.sol index e55616924cd..1cbf2aa0093 100644 --- a/contracts/src/v0.8/vrf/BatchBlockhashStore.sol +++ b/contracts/src/v0.8/vrf/BatchBlockhashStore.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT // solhint-disable-next-line one-contract-per-file -pragma solidity 0.8.6; +pragma solidity 0.8.19; import {ChainSpecificUtil} from "../ChainSpecificUtil.sol"; @@ -42,7 +42,7 @@ contract BatchBlockhashStore { * @param headers the rlp-encoded block headers of blockNumbers[i] + 1. */ function storeVerifyHeader(uint256[] memory blockNumbers, bytes[] memory headers) public { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(blockNumbers.length == headers.length, "input array arg lengths mismatch"); for (uint256 i = 0; i < blockNumbers.length; i++) { BHS.storeVerifyHeader(blockNumbers[i], headers[i]); diff --git a/contracts/src/v0.8/vrf/BatchVRFCoordinatorV2.sol b/contracts/src/v0.8/vrf/BatchVRFCoordinatorV2.sol index b35df41d1e3..2cb6948a9e3 100644 --- a/contracts/src/v0.8/vrf/BatchVRFCoordinatorV2.sol +++ b/contracts/src/v0.8/vrf/BatchVRFCoordinatorV2.sol @@ -26,7 +26,7 @@ contract BatchVRFCoordinatorV2 { * @param rcs the request commitments corresponding to the randomness proofs. */ function fulfillRandomWords(VRFTypes.Proof[] memory proofs, VRFTypes.RequestCommitment[] memory rcs) external { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(proofs.length == rcs.length, "input array arg lengths mismatch"); for (uint256 i = 0; i < proofs.length; i++) { try COORDINATOR.fulfillRandomWords(proofs[i], rcs[i]) returns (uint96 /* payment */) { diff --git a/contracts/src/v0.8/vrf/KeepersVRFConsumer.sol b/contracts/src/v0.8/vrf/KeepersVRFConsumer.sol index 20fd806b0cc..161800fcd48 100644 --- a/contracts/src/v0.8/vrf/KeepersVRFConsumer.sol +++ b/contracts/src/v0.8/vrf/KeepersVRFConsumer.sol @@ -89,7 +89,7 @@ contract KeepersVRFConsumer is KeeperCompatibleInterface, VRFConsumerBaseV2 { function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override { // Check that the request exists. If not, revert. RequestRecord memory record = s_requests[requestId]; - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(record.requestId == requestId, "request ID not found in map"); // Update the randomness in the record, and increment the response counter. diff --git a/contracts/src/v0.8/vrf/VRF.sol b/contracts/src/v0.8/vrf/VRF.sol index f7d62a272bc..efa7df44393 100644 --- a/contracts/src/v0.8/vrf/VRF.sol +++ b/contracts/src/v0.8/vrf/VRF.sol @@ -163,7 +163,7 @@ contract VRF { ) } if (callResult == 0) { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors revert("bigModExp failure!"); } return output[0]; @@ -189,9 +189,9 @@ contract VRF { function _isOnCurve(uint256[2] memory p) internal pure returns (bool) { // Section 2.3.6. in https://www.secg.org/sec1-v2.pdf // requires each ordinate to be in [0, ..., FIELD_SIZE-1] - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(p[0] < FIELD_SIZE, "invalid x-ordinate"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(p[1] < FIELD_SIZE, "invalid y-ordinate"); return _ySquared(p[0]) == mulmod(p[1], p[1], FIELD_SIZE); } @@ -268,7 +268,7 @@ contract VRF { uint256 scalar, uint256[2] memory product ) internal pure returns (bool verifies) { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(scalar != 0, "zero scalar"); // Rules out an ecrecover failure case uint256 x = multiplicand[0]; // x ordinate of multiplicand uint8 v = multiplicand[1] % 2 == 0 ? 27 : 28; // parity of y ordinate @@ -409,7 +409,7 @@ contract VRF { uint256 y; uint256 z; (x, y, z) = _projectiveECAdd(p1[0], p1[1], p2[0], p2[1]); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(mulmod(z, invZ, FIELD_SIZE) == 1, "invZ must be inverse of z"); // Clear the z ordinate of the projective representation by dividing through // by it, to obtain the affine representation @@ -426,7 +426,7 @@ contract VRF { ) internal pure returns (bool) { // Rule out ecrecover failure modes which return address 0. unchecked { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(lcWitness != address(0), "bad witness"); uint8 v = (p[1] % 2 == 0) ? 27 : 28; // parity of y-ordinate of p // Note this cannot wrap (X - Y % X), but we use unchecked to save @@ -462,11 +462,11 @@ contract VRF { ) internal pure returns (uint256[2] memory) { unchecked { // Note we are relying on the wrap around here - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require((cp1Witness[0] % FIELD_SIZE) != (sp2Witness[0] % FIELD_SIZE), "points in sum must be distinct"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(_ecmulVerify(p1, c, cp1Witness), "First mul check failed"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(_ecmulVerify(p2, s, sp2Witness), "Second mul check failed"); return _affineECAdd(cp1Witness, sp2Witness, zInv); } @@ -518,20 +518,20 @@ contract VRF { uint256 zInv ) internal view { unchecked { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(_isOnCurve(pk), "public key is not on curve"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(_isOnCurve(gamma), "gamma is not on curve"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(_isOnCurve(cGammaWitness), "cGammaWitness is not on curve"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(_isOnCurve(sHashWitness), "sHashWitness is not on curve"); // Step 5. of IETF draft section 5.3 (pk corresponds to 5.3's Y, and here // we use the address of u instead of u itself. Also, here we add the // terms instead of taking the difference, and in the proof construction in // vrf.GenerateProof, we correspondingly take the difference instead of // taking the sum as they do in step 7 of section 5.1.) - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(_verifyLinearCombinationWithGenerator(c, pk, s, uWitness), "addr(c*pk+s*g)!=_uWitness"); // Step 4. of IETF draft section 5.3 (pk corresponds to Y, seed to alpha_string) uint256[2] memory hash = _hashToCurve(pk, seed); @@ -539,7 +539,7 @@ contract VRF { uint256[2] memory v = _linearCombination(c, gamma, cGammaWitness, s, hash, sHashWitness, zInv); // Steps 7. and 8. of IETF draft section 5.3 uint256 derivedC = _scalarFromCurvePoints(hash, pk, gamma, uWitness, v); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(c == derivedC, "invalid proof"); } } diff --git a/contracts/src/v0.8/vrf/VRFConsumerBase.sol b/contracts/src/v0.8/vrf/VRFConsumerBase.sol index 7661ad40a30..3d73b70c1d9 100644 --- a/contracts/src/v0.8/vrf/VRFConsumerBase.sol +++ b/contracts/src/v0.8/vrf/VRFConsumerBase.sol @@ -193,7 +193,7 @@ abstract contract VRFConsumerBase is VRFRequestIDBase { // proof. rawFulfillRandomness then calls fulfillRandomness, after validating // the origin of the call function rawFulfillRandomness(bytes32 requestId, uint256 randomness) external { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(msg.sender == vrfCoordinator, "Only VRFCoordinator can fulfill"); fulfillRandomness(requestId, randomness); } diff --git a/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol b/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol index 5dfb51a4b13..f3e569f58d2 100644 --- a/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol +++ b/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol @@ -10,8 +10,7 @@ import {IERC677Receiver} from "../shared/interfaces/IERC677Receiver.sol"; import {VRF} from "./VRF.sol"; import {ConfirmedOwner} from "../shared/access/ConfirmedOwner.sol"; import {VRFConsumerBaseV2} from "./VRFConsumerBaseV2.sol"; -import {ChainSpecificUtil} from "../ChainSpecificUtil.sol"; - +import {ChainSpecificUtil} from "../ChainSpecificUtil_v0_8_6.sol"; contract VRFCoordinatorV2 is VRF, ConfirmedOwner, TypeAndVersionInterface, VRFCoordinatorV2Interface, IERC677Receiver { // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i LinkTokenInterface public immutable LINK; diff --git a/contracts/src/v0.8/vrf/VRFOwner.sol b/contracts/src/v0.8/vrf/VRFOwner.sol index 3b35eae8a47..366b85c4104 100644 --- a/contracts/src/v0.8/vrf/VRFOwner.sol +++ b/contracts/src/v0.8/vrf/VRFOwner.sol @@ -110,7 +110,7 @@ contract VRFOwner is ConfirmedOwner, AuthorizedReceiver { event RandomWordsForced(uint256 indexed requestId, uint64 indexed subId, address indexed sender); constructor(address _vrfCoordinator) ConfirmedOwner(msg.sender) { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(_vrfCoordinator != address(0), "vrf coordinator address must be non-zero"); s_vrfCoordinator = IVRFCoordinatorV2(_vrfCoordinator); } diff --git a/contracts/src/v0.8/vrf/VRFTypes.sol b/contracts/src/v0.8/vrf/VRFTypes.sol index be26051fef9..d1b35a268b2 100644 --- a/contracts/src/v0.8/vrf/VRFTypes.sol +++ b/contracts/src/v0.8/vrf/VRFTypes.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.6; +pragma solidity ^0.8.6; /** * @title VRFTypes diff --git a/contracts/src/v0.8/vrf/VRFV2Wrapper.sol b/contracts/src/v0.8/vrf/VRFV2Wrapper.sol index abe479cb20a..ae0e3cc8206 100644 --- a/contracts/src/v0.8/vrf/VRFV2Wrapper.sol +++ b/contracts/src/v0.8/vrf/VRFV2Wrapper.sol @@ -10,7 +10,7 @@ import {AggregatorV3Interface} from "../shared/interfaces/AggregatorV3Interface. import {VRFCoordinatorV2Interface} from "./interfaces/VRFCoordinatorV2Interface.sol"; import {VRFV2WrapperInterface} from "./interfaces/VRFV2WrapperInterface.sol"; import {VRFV2WrapperConsumerBase} from "./VRFV2WrapperConsumerBase.sol"; -import {ChainSpecificUtil} from "../ChainSpecificUtil.sol"; +import {ChainSpecificUtil} from "../ChainSpecificUtil_v0_8_6.sol"; /** * @notice A wrapper for VRFCoordinatorV2 that provides an interface better suited to one-off @@ -278,7 +278,7 @@ contract VRFV2Wrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsumerBas * uint16 requestConfirmations, and uint32 numWords. */ function onTokenTransfer(address _sender, uint256 _amount, bytes calldata _data) external onlyConfiguredNotDisabled { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(msg.sender == address(LINK), "only callable from LINK"); (uint32 callbackGasLimit, uint16 requestConfirmations, uint32 numWords) = abi.decode( @@ -288,9 +288,9 @@ contract VRFV2Wrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsumerBas uint32 eip150Overhead = _getEIP150Overhead(callbackGasLimit); int256 weiPerUnitLink = _getFeedData(); uint256 price = _calculateRequestPrice(callbackGasLimit, tx.gasprice, weiPerUnitLink); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(_amount >= price, "fee too low"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(numWords <= s_maxNumWords, "numWords too high"); uint256 requestId = COORDINATOR.requestRandomWords( @@ -340,7 +340,7 @@ contract VRFV2Wrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsumerBas function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { Callback memory callback = s_callbacks[_requestId]; delete s_callbacks[_requestId]; - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(callback.callbackAddress != address(0), "request not found"); // This should never happen VRFV2WrapperConsumerBase c; @@ -361,7 +361,7 @@ contract VRFV2Wrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsumerBas if (staleFallback && s_stalenessSeconds < block.timestamp - timestamp) { weiPerUnitLink = s_fallbackWeiPerUnitLink; } - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(weiPerUnitLink >= 0, "Invalid LINK wei price"); return weiPerUnitLink; } @@ -411,9 +411,9 @@ contract VRFV2Wrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsumerBas } modifier onlyConfiguredNotDisabled() { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(s_configured, "wrapper is not configured"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(!s_disabled, "wrapper is disabled"); _; } diff --git a/contracts/src/v0.8/vrf/VRFV2WrapperConsumerBase.sol b/contracts/src/v0.8/vrf/VRFV2WrapperConsumerBase.sol index 2876b19dd7b..79104318f10 100644 --- a/contracts/src/v0.8/vrf/VRFV2WrapperConsumerBase.sol +++ b/contracts/src/v0.8/vrf/VRFV2WrapperConsumerBase.sol @@ -79,7 +79,7 @@ abstract contract VRFV2WrapperConsumerBase { function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal virtual; function rawFulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) external { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(msg.sender == address(VRF_V2_WRAPPER), "only VRF V2 wrapper can fulfill"); fulfillRandomWords(_requestId, _randomWords); } diff --git a/contracts/src/v0.8/vrf/dev/BatchVRFCoordinatorV2Plus.sol b/contracts/src/v0.8/vrf/dev/BatchVRFCoordinatorV2Plus.sol index 3e6a5095bc7..b626aeb6189 100644 --- a/contracts/src/v0.8/vrf/dev/BatchVRFCoordinatorV2Plus.sol +++ b/contracts/src/v0.8/vrf/dev/BatchVRFCoordinatorV2Plus.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT // solhint-disable-next-line one-contract-per-file -pragma solidity 0.8.6; +pragma solidity 0.8.19; import {VRFTypes} from "../VRFTypes.sol"; @@ -11,13 +11,13 @@ import {VRFTypes} from "../VRFTypes.sol"; */ contract BatchVRFCoordinatorV2Plus { // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i - IVRFCoordinatorV2Plus public immutable COORDINATOR; + IVRFCoordinatorV2PlusFulfill public immutable COORDINATOR; event ErrorReturned(uint256 indexed requestId, string reason); event RawErrorReturned(uint256 indexed requestId, bytes lowLevelData); constructor(address coordinatorAddr) { - COORDINATOR = IVRFCoordinatorV2Plus(coordinatorAddr); + COORDINATOR = IVRFCoordinatorV2PlusFulfill(coordinatorAddr); } /** @@ -26,9 +26,9 @@ contract BatchVRFCoordinatorV2Plus { * @param rcs the request commitments corresponding to the randomness proofs. */ function fulfillRandomWords(VRFTypes.Proof[] memory proofs, VRFTypes.RequestCommitmentV2Plus[] memory rcs) external { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(proofs.length == rcs.length, "input array arg lengths mismatch"); - for (uint256 i = 0; i < proofs.length; i++) { + for (uint256 i = 0; i < proofs.length; ++i) { try COORDINATOR.fulfillRandomWords(proofs[i], rcs[i], false) returns (uint96 /* payment */) { continue; } catch Error(string memory reason) { @@ -59,7 +59,7 @@ contract BatchVRFCoordinatorV2Plus { } } -interface IVRFCoordinatorV2Plus { +interface IVRFCoordinatorV2PlusFulfill { function fulfillRandomWords( VRFTypes.Proof memory proof, VRFTypes.RequestCommitmentV2Plus memory rc, diff --git a/contracts/src/v0.8/vrf/dev/BlockhashStore.sol b/contracts/src/v0.8/vrf/dev/BlockhashStore.sol index b6389c9b15a..0bef7aeada5 100644 --- a/contracts/src/v0.8/vrf/dev/BlockhashStore.sol +++ b/contracts/src/v0.8/vrf/dev/BlockhashStore.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.6; +pragma solidity 0.8.19; import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; @@ -22,7 +22,7 @@ contract BlockhashStore { */ function store(uint256 n) public { bytes32 h = ChainSpecificUtil._getBlockhash(uint64(n)); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(h != 0x0, "blockhash(n) failed"); s_blockhashes[n] = h; } @@ -41,7 +41,7 @@ contract BlockhashStore { * that it hashes to a stored blockhash, and then extract parentHash to get the n-th blockhash. */ function storeVerifyHeader(uint256 n, bytes memory header) public { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(keccak256(header) == s_blockhashes[n + 1], "header has unknown blockhash"); // At this point, we know that header is the correct blockheader for block n+1. @@ -74,7 +74,7 @@ contract BlockhashStore { */ function getBlockhash(uint256 n) external view returns (bytes32) { bytes32 h = s_blockhashes[n]; - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(h != 0x0, "blockhash not found in store"); return h; } diff --git a/contracts/src/v0.8/vrf/dev/SubscriptionAPI.sol b/contracts/src/v0.8/vrf/dev/SubscriptionAPI.sol index 0ac1e903d42..d57af4290c5 100644 --- a/contracts/src/v0.8/vrf/dev/SubscriptionAPI.sol +++ b/contracts/src/v0.8/vrf/dev/SubscriptionAPI.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.19; import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; @@ -63,8 +63,9 @@ abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscr struct ConsumerConfig { bool active; uint64 nonce; + uint64 pendingReqCount; } - // Note a nonce of 0 indicates an the consumer is not assigned to that subscription. + // Note a nonce of 0 indicates the consumer is not assigned to that subscription. mapping(address => mapping(uint256 => ConsumerConfig)) /* consumerAddress */ /* subId */ /* consumerConfig */ internal s_consumers; mapping(uint256 => SubscriptionConfig) /* subId */ /* subscriptionConfig */ internal s_subscriptionConfigs; @@ -170,11 +171,11 @@ abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscr * @dev notably can be called even if there are pending requests, outstanding ones may fail onchain */ function ownerCancelSubscription(uint256 subId) external onlyOwner { - address owner = s_subscriptionConfigs[subId].owner; - if (owner == address(0)) { + address subOwner = s_subscriptionConfigs[subId].owner; + if (subOwner == address(0)) { revert InvalidSubscription(); } - _cancelSubscriptionHelper(subId, owner); + _cancelSubscriptionHelper(subId, subOwner); } /** @@ -310,17 +311,17 @@ abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscr public view override - returns (uint96 balance, uint96 nativeBalance, uint64 reqCount, address owner, address[] memory consumers) + returns (uint96 balance, uint96 nativeBalance, uint64 reqCount, address subOwner, address[] memory consumers) { - owner = s_subscriptionConfigs[subId].owner; - if (owner == address(0)) { + subOwner = s_subscriptionConfigs[subId].owner; + if (subOwner == address(0)) { revert InvalidSubscription(); } return ( s_subscriptions[subId].balance, s_subscriptions[subId].nativeBalance, s_subscriptions[subId].reqCount, - owner, + subOwner, s_subscriptionConfigs[subId].consumers ); } @@ -471,12 +472,12 @@ abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscr } function _onlySubOwner(uint256 subId) internal view { - address owner = s_subscriptionConfigs[subId].owner; - if (owner == address(0)) { + address subOwner = s_subscriptionConfigs[subId].owner; + if (subOwner == address(0)) { revert InvalidSubscription(); } - if (msg.sender != owner) { - revert MustBeSubOwner(owner); + if (msg.sender != subOwner) { + revert MustBeSubOwner(subOwner); } } } diff --git a/contracts/src/v0.8/vrf/dev/TrustedBlockhashStore.sol b/contracts/src/v0.8/vrf/dev/TrustedBlockhashStore.sol index b1a53b57163..b3b77c8095d 100644 --- a/contracts/src/v0.8/vrf/dev/TrustedBlockhashStore.sol +++ b/contracts/src/v0.8/vrf/dev/TrustedBlockhashStore.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.6; +pragma solidity 0.8.19; import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; diff --git a/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol b/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol index d666fc35a5c..5bff4b63221 100644 --- a/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol +++ b/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol @@ -111,6 +111,9 @@ abstract contract VRFConsumerBaseV2Plus is IVRFMigratableConsumerV2Plus, Confirm * @param _vrfCoordinator address of VRFCoordinator contract */ constructor(address _vrfCoordinator) ConfirmedOwner(msg.sender) { + if (_vrfCoordinator == address(0)) { + revert ZeroAddress(); + } s_vrfCoordinator = IVRFCoordinatorV2Plus(_vrfCoordinator); } @@ -144,7 +147,10 @@ abstract contract VRFConsumerBaseV2Plus is IVRFMigratableConsumerV2Plus, Confirm /** * @inheritdoc IVRFMigratableConsumerV2Plus */ - function setCoordinator(address _vrfCoordinator) public override onlyOwnerOrCoordinator { + function setCoordinator(address _vrfCoordinator) external override onlyOwnerOrCoordinator { + if (_vrfCoordinator == address(0)) { + revert ZeroAddress(); + } s_vrfCoordinator = IVRFCoordinatorV2Plus(_vrfCoordinator); emit CoordinatorSet(_vrfCoordinator); diff --git a/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Upgradeable.sol b/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Upgradeable.sol index e05e0190bd7..0de1b42ce44 100644 --- a/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Upgradeable.sol +++ b/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Upgradeable.sol @@ -122,7 +122,7 @@ abstract contract VRFConsumerBaseV2Upgradeable is Initializable { // solhint-disable-next-line func-name-mixedcase function __VRFConsumerBaseV2_init(address _vrfCoordinator) internal onlyInitializing { if (_vrfCoordinator == address(0)) { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors revert("must give valid coordinator address"); } diff --git a/contracts/src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol b/contracts/src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol index 2712dd27ce6..c070c7d1e17 100644 --- a/contracts/src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol +++ b/contracts/src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol @@ -1,8 +1,9 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.4; +pragma solidity 0.8.19; import {BlockhashStoreInterface} from "../interfaces/BlockhashStoreInterface.sol"; import {VRF} from "../../vrf/VRF.sol"; +import {VRFTypes} from "../VRFTypes.sol"; import {VRFConsumerBaseV2Plus, IVRFMigratableConsumerV2Plus} from "./VRFConsumerBaseV2Plus.sol"; import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; import {SubscriptionAPI} from "./SubscriptionAPI.sol"; @@ -35,21 +36,12 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { error InvalidLinkWeiPrice(int256 linkWei); error LinkDiscountTooHigh(uint32 flatFeeLinkDiscountPPM, uint32 flatFeeNativePPM); error InvalidPremiumPercentage(uint8 premiumPercentage, uint8 max); - error InsufficientGasForConsumer(uint256 have, uint256 want); error NoCorrespondingRequest(); error IncorrectCommitment(); error BlockhashNotInStore(uint256 blockNum); error PaymentTooLarge(); error InvalidExtraArgsTag(); error GasPriceExceeded(uint256 gasPrice, uint256 maxGas); - struct RequestCommitment { - uint64 blockNum; - uint256 subId; - uint32 callbackGasLimit; - uint32 numWords; - address sender; - bytes extraArgs; - } struct ProvingKey { bool exists; // proving key exists @@ -293,6 +285,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { // The consequence for users is that they can send requests // for invalid keyHashes which will simply not be fulfilled. ++consumerConfig.nonce; + ++consumerConfig.pendingReqCount; uint256 preSeed; (requestId, preSeed) = _computeRequestId(req.keyHash, msg.sender, subId, consumerConfig.nonce); @@ -375,7 +368,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { function _getRandomnessFromProof( Proof memory proof, - RequestCommitment memory rc + VRFTypes.RequestCommitmentV2Plus memory rc ) internal view returns (Output memory) { bytes32 keyHash = hashOfKey(proof.pk); ProvingKey memory key = s_provingKeys[keyHash]; @@ -424,7 +417,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { function _deliverRandomness( uint256 requestId, - RequestCommitment memory rc, + VRFTypes.RequestCommitmentV2Plus memory rc, uint256[] memory randomWords ) internal returns (bool success) { VRFConsumerBaseV2Plus v; @@ -451,7 +444,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { */ function fulfillRandomWords( Proof memory proof, - RequestCommitment memory rc, + VRFTypes.RequestCommitmentV2Plus memory rc, bool onlyPremium ) external nonReentrant returns (uint96 payment) { uint256 startGas = gasleft(); @@ -500,14 +493,18 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { // Increment the req count for the subscription. ++s_subscriptions[rc.subId].reqCount; + // Decrement the pending req count for the consumer. + --s_consumers[rc.sender][rc.subId].pendingReqCount; bool nativePayment = uint8(rc.extraArgs[rc.extraArgs.length - 1]) == 1; // stack too deep error { - // We want to charge users exactly for how much gas they use in their callback. - // The gasAfterPaymentCalculation is meant to cover these additional operations where we - // decrement the subscription balance and increment the oracles withdrawable balance. + // We want to charge users exactly for how much gas they use in their callback with + // an additional premium. If onlyPremium is true, only premium is charged without + // the gas cost. The gasAfterPaymentCalculation is meant to cover these additional + // operations where we decrement the subscription balance and increment the + // withdrawable balance. bool isFeedStale; (payment, isFeedStale) = _calculatePaymentAmount(startGas, gasPrice, nativePayment, onlyPremium); if (isFeedStale) { @@ -625,19 +622,9 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { if (consumersLength == 0) { return false; } - uint256 provingKeyHashesLength = s_provingKeyHashes.length; for (uint256 i = 0; i < consumersLength; ++i) { - address consumer = consumers[i]; - for (uint256 j = 0; j < provingKeyHashesLength; ++j) { - (uint256 reqId, ) = _computeRequestId( - s_provingKeyHashes[j], - consumer, - subId, - s_consumers[consumer][subId].nonce - ); - if (s_requestCommitments[reqId] != 0) { - return true; - } + if (s_consumers[consumers[i]][subId].pendingReqCount > 0) { + return true; } } return false; @@ -748,16 +735,16 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { if (!_isTargetRegistered(newCoordinator)) { revert CoordinatorNotRegistered(newCoordinator); } - (uint96 balance, uint96 nativeBalance, , address owner, address[] memory consumers) = getSubscription(subId); - // solhint-disable-next-line custom-errors - require(owner == msg.sender, "Not subscription owner"); - // solhint-disable-next-line custom-errors + (uint96 balance, uint96 nativeBalance, , address subOwner, address[] memory consumers) = getSubscription(subId); + // solhint-disable-next-line gas-custom-errors + require(subOwner == msg.sender, "Not subscription owner"); + // solhint-disable-next-line gas-custom-errors require(!pendingRequestExists(subId), "Pending request exists"); V1MigrationData memory migrationData = V1MigrationData({ fromVersion: 1, subId: subId, - subOwner: owner, + subOwner: subOwner, consumers: consumers, linkBalance: balance, nativeBalance: nativeBalance @@ -768,7 +755,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { // Only transfer LINK if the token is active and there is a balance. if (address(LINK) != address(0) && balance != 0) { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(LINK.transfer(address(newCoordinator), balance), "insufficient funds"); } diff --git a/contracts/src/v0.8/vrf/dev/VRFSubscriptionBalanceMonitor.sol b/contracts/src/v0.8/vrf/dev/VRFSubscriptionBalanceMonitor.sol index 2dd44c8b1a8..58dd25c62b2 100644 --- a/contracts/src/v0.8/vrf/dev/VRFSubscriptionBalanceMonitor.sol +++ b/contracts/src/v0.8/vrf/dev/VRFSubscriptionBalanceMonitor.sol @@ -197,7 +197,7 @@ contract VRFSubscriptionBalanceMonitor is ConfirmedOwner, Pausable, KeeperCompat * @param payee the address to pay */ function withdraw(uint256 amount, address payable payee) external onlyOwner { - // solhint-disable-next-line custom-errors, reason-string + // solhint-disable-next-line gas-custom-errors, reason-string require(payee != address(0)); emit FundsWithdrawn(amount, payee); LINKTOKEN.transfer(payee, amount); @@ -207,7 +207,7 @@ contract VRFSubscriptionBalanceMonitor is ConfirmedOwner, Pausable, KeeperCompat * @notice Sets the LINK token address. */ function setLinkTokenAddress(address linkTokenAddress) public onlyOwner { - // solhint-disable-next-line custom-errors, reason-string + // solhint-disable-next-line gas-custom-errors, reason-string require(linkTokenAddress != address(0)); emit LinkTokenAddressUpdated(address(LINKTOKEN), linkTokenAddress); LINKTOKEN = LinkTokenInterface(linkTokenAddress); @@ -217,7 +217,7 @@ contract VRFSubscriptionBalanceMonitor is ConfirmedOwner, Pausable, KeeperCompat * @notice Sets the VRF coordinator address. */ function setVRFCoordinatorV2Address(address coordinatorAddress) public onlyOwner { - // solhint-disable-next-line custom-errors, reason-string + // solhint-disable-next-line gas-custom-errors, reason-string require(coordinatorAddress != address(0)); emit VRFCoordinatorV2AddressUpdated(address(COORDINATOR), coordinatorAddress); COORDINATOR = VRFCoordinatorV2Interface(coordinatorAddress); @@ -227,7 +227,7 @@ contract VRFSubscriptionBalanceMonitor is ConfirmedOwner, Pausable, KeeperCompat * @notice Sets the keeper registry address. */ function setKeeperRegistryAddress(address keeperRegistryAddress) public onlyOwner { - // solhint-disable-next-line custom-errors, reason-string + // solhint-disable-next-line gas-custom-errors, reason-string require(keeperRegistryAddress != address(0)); emit KeeperRegistryAddressUpdated(s_keeperRegistryAddress, keeperRegistryAddress); s_keeperRegistryAddress = keeperRegistryAddress; diff --git a/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapper.sol b/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapper.sol index d2cfdb4cee6..1b80cc8838a 100644 --- a/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapper.sol +++ b/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapper.sol @@ -1,9 +1,8 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; +pragma solidity 0.8.19; import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; import {TypeAndVersionInterface} from "../../interfaces/TypeAndVersionInterface.sol"; -import {IVRFV2PlusMigrate} from "./interfaces/IVRFV2PlusMigrate.sol"; import {VRFConsumerBaseV2Plus} from "./VRFConsumerBaseV2Plus.sol"; import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; import {AggregatorV3Interface} from "../../shared/interfaces/AggregatorV3Interface.sol"; @@ -20,58 +19,68 @@ import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsumerBaseV2Plus, IVRFV2PlusWrapper { event WrapperFulfillmentFailed(uint256 indexed requestId, address indexed consumer); + // upper bound limit for premium percentages to make sure fee calculations don't overflow + uint8 private constant PREMIUM_PERCENTAGE_MAX = 155; + + // 5k is plenty for an EXTCODESIZE call (2600) + warm CALL (100) + // and some arithmetic operations. + uint256 private constant GAS_FOR_CALL_EXACT_CHECK = 5_000; + uint16 private constant EXPECTED_MIN_LENGTH = 36; + + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i + uint256 public immutable SUBSCRIPTION_ID; + LinkTokenInterface internal immutable i_link; + AggregatorV3Interface internal immutable i_link_native_feed; + error LinkAlreadySet(); + error LinkDiscountTooHigh(uint32 flatFeeLinkDiscountPPM, uint32 flatFeeNativePPM); + error InvalidPremiumPercentage(uint8 premiumPercentage, uint8 max); error FailedToTransferLink(); error IncorrectExtraArgsLength(uint16 expectedMinimumLength, uint16 actualLength); error NativePaymentInOnTokenTransfer(); error LINKPaymentInRequestRandomWordsInNative(); + error SubscriptionIdMissing(); /* Storage Slot 1: BEGIN */ - // s_keyHash is the key hash to use when requesting randomness. Fees are paid based on current gas - // fees, so this should be set to the highest gas lane on the network. - bytes32 internal s_keyHash; + // 20 bytes used by VRFConsumerBaseV2Plus.s_vrfCoordinator + + // s_configured tracks whether this contract has been configured. If not configured, randomness + // requests cannot be made. + bool public s_configured; + + // s_disabled disables the contract when true. When disabled, new VRF requests cannot be made + // but existing ones can still be fulfilled. + bool public s_disabled; + + // s_maxNumWords is the max number of words that can be requested in a single wrapped VRF request. + uint8 internal s_maxNumWords; + + // 9 bytes left /* Storage Slot 1: END */ /* Storage Slot 2: BEGIN */ - // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i - uint256 public immutable SUBSCRIPTION_ID; + // s_keyHash is the key hash to use when requesting randomness. Fees are paid based on current gas + // fees, so this should be set to the highest gas lane on the network. + bytes32 internal s_keyHash; /* Storage Slot 2: END */ /* Storage Slot 3: BEGIN */ - // 5k is plenty for an EXTCODESIZE call (2600) + warm CALL (100) - // and some arithmetic operations. - uint256 private constant GAS_FOR_CALL_EXACT_CHECK = 5_000; - /* Storage Slot 3: END */ - - /* Storage Slot 4: BEGIN */ // lastRequestId is the request ID of the most recent VRF V2 request made by this wrapper. This // should only be relied on within the same transaction the request was made. uint256 public override lastRequestId; - /* Storage Slot 4: END */ + /* Storage Slot 3: END */ - /* Storage Slot 5: BEGIN */ + /* Storage Slot 4: BEGIN */ // s_fallbackWeiPerUnitLink is the backup LINK exchange rate used when the LINK/NATIVE feed is // stale. int256 private s_fallbackWeiPerUnitLink; - /* Storage Slot 5: END */ + /* Storage Slot 4: END */ - /* Storage Slot 6: BEGIN */ + /* Storage Slot 5: BEGIN */ // s_stalenessSeconds is the number of seconds before we consider the feed price to be stale and // fallback to fallbackWeiPerUnitLink. uint32 private s_stalenessSeconds; - // s_fulfillmentFlatFeeLinkPPM is the flat fee in millionths of LINK that VRFCoordinatorV2 - // charges. - uint32 private s_fulfillmentFlatFeeLinkPPM; - - // s_fulfillmentFlatFeeLinkPPM is the flat fee in millionths of LINK that VRFCoordinatorV2 - // charges. - uint32 private s_fulfillmentFlatFeeNativePPM; - - LinkTokenInterface public s_link; - /* Storage Slot 6: END */ - - /* Storage Slot 7: BEGIN */ // s_wrapperGasOverhead reflects the gas overhead of the wrapper's fulfillRandomWords // function. The cost for this gas is passed to the user. uint32 private s_wrapperGasOverhead; @@ -92,27 +101,26 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume // payment calculation in the coordinator. uint32 private s_coordinatorGasOverhead; - AggregatorV3Interface public s_linkNativeFeed; - /* Storage Slot 7: END */ - - /* Storage Slot 8: BEGIN */ - // s_configured tracks whether this contract has been configured. If not configured, randomness - // requests cannot be made. - bool public s_configured; + // s_fulfillmentFlatFeeLinkPPM is the flat fee in millionths of native that VRFCoordinatorV2 + // charges for native payment. + uint32 private s_fulfillmentFlatFeeNativePPM; - // s_disabled disables the contract when true. When disabled, new VRF requests cannot be made - // but existing ones can still be fulfilled. - bool public s_disabled; + // s_fulfillmentFlatFeeLinkDiscountPPM is the flat fee discount in millionths of native that VRFCoordinatorV2 + // charges for link payment. + uint32 private s_fulfillmentFlatFeeLinkDiscountPPM; - // s_wrapperPremiumPercentage is the premium ratio in percentage. For example, a value of 0 - // indicates no premium. A value of 15 indicates a 15 percent premium. - uint8 private s_wrapperPremiumPercentage; + // s_coordinatorNativePremiumPercentage is the coordinator's premium ratio in percentage for native payment. + // For example, a value of 0 indicates no premium. A value of 15 indicates a 15 percent premium. + // Wrapper has no premium. This premium is for VRFCoordinator. + uint8 private s_coordinatorNativePremiumPercentage; - // s_maxNumWords is the max number of words that can be requested in a single wrapped VRF request. - uint8 internal s_maxNumWords; + // s_coordinatorLinkPremiumPercentage is the premium ratio in percentage for link payment. For example, a + // value of 0 indicates no premium. A value of 15 indicates a 15 percent premium. + // Wrapper has no premium. This premium is for VRFCoordinator. + uint8 private s_coordinatorLinkPremiumPercentage; - uint16 private constant EXPECTED_MIN_LENGTH = 36; - /* Storage Slot 8: END */ + // 6 bytes left + /* Storage Slot 5: END */ struct Callback { address callbackAddress; @@ -123,40 +131,32 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume // GasPrice is unlikely to be more than 14 ETH on most chains uint64 requestGasPrice; } - /* Storage Slot 9: BEGIN */ + /* Storage Slot 6: BEGIN */ mapping(uint256 => Callback) /* requestID */ /* callback */ public s_callbacks; + /* Storage Slot 6: END */ - /* Storage Slot 9: END */ - - constructor(address _link, address _linkNativeFeed, address _coordinator) VRFConsumerBaseV2Plus(_coordinator) { - if (_link != address(0)) { - s_link = LinkTokenInterface(_link); - } - if (_linkNativeFeed != address(0)) { - s_linkNativeFeed = AggregatorV3Interface(_linkNativeFeed); - } - - // Create this wrapper's subscription and add itself as a consumer. - uint256 subId = s_vrfCoordinator.createSubscription(); - SUBSCRIPTION_ID = subId; - s_vrfCoordinator.addConsumer(subId, address(this)); - } - - /** - * @notice set the link token and link native feed to be used by this wrapper - * @param link address of the link token - * @param linkNativeFeed address of the link native feed - */ - function setLinkAndLinkNativeFeed(address link, address linkNativeFeed) external onlyOwner { - // Disallow re-setting link token because the logic wouldn't really make sense - if (address(s_link) != address(0)) { - revert LinkAlreadySet(); + constructor( + address _link, + address _linkNativeFeed, + address _coordinator, + uint256 _subId + ) VRFConsumerBaseV2Plus(_coordinator) { + i_link = LinkTokenInterface(_link); + i_link_native_feed = AggregatorV3Interface(_linkNativeFeed); + + if (_subId == 0) { + revert SubscriptionIdMissing(); } - s_link = LinkTokenInterface(link); - s_linkNativeFeed = AggregatorV3Interface(linkNativeFeed); + // Sanity check: should revert if the subscription does not exist + s_vrfCoordinator.getSubscription(_subId); - emit LinkAndLinkNativeFeedSet(link, linkNativeFeed); + // Subscription for the wrapper is created and managed by an external account. + // Expectation is that wrapper contract address will be added as a consumer + // to this subscription by the external account (owner of the subscription). + // Migration of the wrapper's subscription to the new coordinator has to be + // handled by the external account (owner of the subscription). + SUBSCRIPTION_ID = _subId; } /** @@ -181,7 +181,9 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume * @param _coordinatorGasOverhead reflects the gas overhead of the coordinator's * fulfillRandomWords function. * - * @param _wrapperPremiumPercentage is the premium ratio in percentage for wrapper requests. + * @param _coordinatorNativePremiumPercentage is the coordinator's premium ratio in percentage for requests paid in native. + * + * @param _coordinatorLinkPremiumPercentage is the coordinator's premium ratio in percentage for requests paid in link. * * @param _keyHash to use for requesting randomness. * @param _maxNumWords is the max number of words that can be requested in a single wrapped VRF request @@ -191,26 +193,38 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume * @param _fallbackWeiPerUnitLink is the backup LINK exchange rate used when the LINK/NATIVE feed * is stale. * - * @param _fulfillmentFlatFeeLinkPPM is the flat fee in millionths of LINK that VRFCoordinatorV2Plus - * charges. - * * @param _fulfillmentFlatFeeNativePPM is the flat fee in millionths of native that VRFCoordinatorV2Plus - * charges. + * charges for native payment. + * + * @param _fulfillmentFlatFeeLinkDiscountPPM is the flat fee discount in millionths of native that VRFCoordinatorV2Plus + * charges for link payment. */ function setConfig( uint32 _wrapperGasOverhead, uint32 _coordinatorGasOverhead, - uint8 _wrapperPremiumPercentage, + uint8 _coordinatorNativePremiumPercentage, + uint8 _coordinatorLinkPremiumPercentage, bytes32 _keyHash, uint8 _maxNumWords, uint32 _stalenessSeconds, int256 _fallbackWeiPerUnitLink, - uint32 _fulfillmentFlatFeeLinkPPM, - uint32 _fulfillmentFlatFeeNativePPM + uint32 _fulfillmentFlatFeeNativePPM, + uint32 _fulfillmentFlatFeeLinkDiscountPPM ) external onlyOwner { + if (_fulfillmentFlatFeeLinkDiscountPPM > _fulfillmentFlatFeeNativePPM) { + revert LinkDiscountTooHigh(_fulfillmentFlatFeeLinkDiscountPPM, _fulfillmentFlatFeeNativePPM); + } + if (_coordinatorNativePremiumPercentage > PREMIUM_PERCENTAGE_MAX) { + revert InvalidPremiumPercentage(_coordinatorNativePremiumPercentage, PREMIUM_PERCENTAGE_MAX); + } + if (_coordinatorLinkPremiumPercentage > PREMIUM_PERCENTAGE_MAX) { + revert InvalidPremiumPercentage(_coordinatorLinkPremiumPercentage, PREMIUM_PERCENTAGE_MAX); + } + s_wrapperGasOverhead = _wrapperGasOverhead; s_coordinatorGasOverhead = _coordinatorGasOverhead; - s_wrapperPremiumPercentage = _wrapperPremiumPercentage; + s_coordinatorNativePremiumPercentage = _coordinatorNativePremiumPercentage; + s_coordinatorLinkPremiumPercentage = _coordinatorLinkPremiumPercentage; s_keyHash = _keyHash; s_maxNumWords = _maxNumWords; s_configured = true; @@ -218,19 +232,20 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume // Get other configuration from coordinator s_stalenessSeconds = _stalenessSeconds; s_fallbackWeiPerUnitLink = _fallbackWeiPerUnitLink; - s_fulfillmentFlatFeeLinkPPM = _fulfillmentFlatFeeLinkPPM; s_fulfillmentFlatFeeNativePPM = _fulfillmentFlatFeeNativePPM; + s_fulfillmentFlatFeeLinkDiscountPPM = _fulfillmentFlatFeeLinkDiscountPPM; emit ConfigSet( _wrapperGasOverhead, _coordinatorGasOverhead, - _wrapperPremiumPercentage, + _coordinatorNativePremiumPercentage, + _coordinatorLinkPremiumPercentage, _keyHash, _maxNumWords, _stalenessSeconds, _fallbackWeiPerUnitLink, - _fulfillmentFlatFeeLinkPPM, - _fulfillmentFlatFeeNativePPM + _fulfillmentFlatFeeNativePPM, + s_fulfillmentFlatFeeLinkDiscountPPM ); } @@ -243,11 +258,11 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume * @return stalenessSeconds is the number of seconds before we consider the feed price to be stale * and fallback to fallbackWeiPerUnitLink. * - * @return fulfillmentFlatFeeLinkPPM is the flat fee in millionths of LINK that VRFCoordinatorV2Plus - * charges. - * * @return fulfillmentFlatFeeNativePPM is the flat fee in millionths of native that VRFCoordinatorV2Plus - * charges. + * charges for native payment. + * + * @return fulfillmentFlatFeeLinkDiscountPPM is the flat fee discount in millionths of native that VRFCoordinatorV2Plus + * charges for link payment. * * @return wrapperGasOverhead reflects the gas overhead of the wrapper's fulfillRandomWords * function. The cost for this gas is passed to the user. @@ -255,7 +270,10 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume * @return coordinatorGasOverhead reflects the gas overhead of the coordinator's * fulfillRandomWords function. * - * @return wrapperPremiumPercentage is the premium ratio in percentage. For example, a value of 0 + * @return wrapperNativePremiumPercentage is the premium ratio in percentage for native payment. For example, a value of 0 + * indicates no premium. A value of 15 indicates a 15 percent premium. + * + * @return wrapperLinkPremiumPercentage is the premium ratio in percentage for link payment. For example, a value of 0 * indicates no premium. A value of 15 indicates a 15 percent premium. * * @return keyHash is the key hash to use when requesting randomness. Fees are paid based on @@ -270,11 +288,12 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume returns ( int256 fallbackWeiPerUnitLink, uint32 stalenessSeconds, - uint32 fulfillmentFlatFeeLinkPPM, uint32 fulfillmentFlatFeeNativePPM, + uint32 fulfillmentFlatFeeLinkDiscountPPM, uint32 wrapperGasOverhead, uint32 coordinatorGasOverhead, - uint8 wrapperPremiumPercentage, + uint8 wrapperNativePremiumPercentage, + uint8 wrapperLinkPremiumPercentage, bytes32 keyHash, uint8 maxNumWords ) @@ -282,11 +301,12 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume return ( s_fallbackWeiPerUnitLink, s_stalenessSeconds, - s_fulfillmentFlatFeeLinkPPM, s_fulfillmentFlatFeeNativePPM, + s_fulfillmentFlatFeeLinkDiscountPPM, s_wrapperGasOverhead, s_coordinatorGasOverhead, - s_wrapperPremiumPercentage, + s_coordinatorNativePremiumPercentage, + s_coordinatorLinkPremiumPercentage, s_keyHash, s_maxNumWords ); @@ -340,20 +360,21 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume function _calculateRequestPriceNative(uint256 _gas, uint256 _requestGasPrice) internal view returns (uint256) { // costWei is the base fee denominated in wei (native) - // costWei takes into account the L1 posting costs of the VRF fulfillment - // transaction, if we are on an L2. - uint256 costWei = (_requestGasPrice * - (_gas + s_wrapperGasOverhead + s_coordinatorGasOverhead) + - ChainSpecificUtil._getL1CalldataGasCost(s_fulfillmentTxSizeBytes)); - // ((wei/gas * (gas)) + l1wei) - // baseFee is the base fee denominated in wei - uint256 baseFee = costWei; - // feeWithPremium is the fee after the percentage premium is applied - uint256 feeWithPremium = (baseFee * (s_wrapperPremiumPercentage + 100)) / 100; - // feeWithFlatFee is the fee after the flat fee is applied on top of the premium - uint256 feeWithFlatFee = feeWithPremium + (1e12 * uint256(s_fulfillmentFlatFeeNativePPM)); - - return feeWithFlatFee; + // (wei/gas) * gas + uint256 wrapperCostWei = _requestGasPrice * s_wrapperGasOverhead; + + // coordinatorCostWei takes into account the L1 posting costs of the VRF fulfillment transaction, if we are on an L2. + // (wei/gas) * gas + l1wei + uint256 coordinatorCostWei = _requestGasPrice * + (_gas + s_coordinatorGasOverhead) + + ChainSpecificUtil._getL1CalldataGasCost(s_fulfillmentTxSizeBytes); + + // coordinatorCostWithPremiumAndFlatFeeWei is the coordinator cost with the percentage premium and flat fee applied + // coordinator cost * premium multiplier + flat fee + uint256 coordinatorCostWithPremiumAndFlatFeeWei = ((coordinatorCostWei * + (s_coordinatorNativePremiumPercentage + 100)) / 100) + (1e12 * uint256(s_fulfillmentFlatFeeNativePPM)); + + return wrapperCostWei + coordinatorCostWithPremiumAndFlatFeeWei; } function _calculateRequestPrice( @@ -362,20 +383,24 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume int256 _weiPerUnitLink ) internal view returns (uint256) { // costWei is the base fee denominated in wei (native) - // costWei takes into account the L1 posting costs of the VRF fulfillment - // transaction, if we are on an L2. - uint256 costWei = (_requestGasPrice * - (_gas + s_wrapperGasOverhead + s_coordinatorGasOverhead) + - ChainSpecificUtil._getL1CalldataGasCost(s_fulfillmentTxSizeBytes)); - // (1e18 juels/link) * ((wei/gas * (gas)) + l1wei) / (wei/link) == 1e18 juels * wei/link / (wei/link) == 1e18 juels * wei/link * link/wei == juels - // baseFee is the base fee denominated in juels (link) - uint256 baseFee = (1e18 * costWei) / uint256(_weiPerUnitLink); - // feeWithPremium is the fee after the percentage premium is applied - uint256 feeWithPremium = (baseFee * (s_wrapperPremiumPercentage + 100)) / 100; - // feeWithFlatFee is the fee after the flat fee is applied on top of the premium - uint256 feeWithFlatFee = feeWithPremium + (1e12 * uint256(s_fulfillmentFlatFeeLinkPPM)); - - return feeWithFlatFee; + // (wei/gas) * gas + uint256 wrapperCostWei = _requestGasPrice * s_wrapperGasOverhead; + + // coordinatorCostWei takes into account the L1 posting costs of the VRF fulfillment transaction, if we are on an L2. + // (wei/gas) * gas + l1wei + uint256 coordinatorCostWei = _requestGasPrice * + (_gas + s_coordinatorGasOverhead) + + ChainSpecificUtil._getL1CalldataGasCost(s_fulfillmentTxSizeBytes); + + // coordinatorCostWithPremiumAndFlatFeeWei is the coordinator cost with the percentage premium and flat fee applied + // coordinator cost * premium multiplier + flat fee + uint256 coordinatorCostWithPremiumAndFlatFeeWei = ((coordinatorCostWei * + (s_coordinatorLinkPremiumPercentage + 100)) / 100) + + (1e12 * uint256(s_fulfillmentFlatFeeNativePPM - s_fulfillmentFlatFeeLinkDiscountPPM)); + + // requestPrice is denominated in juels (link) + // (1e18 juels/link) * wei / (wei/link) = juels + return (1e18 * (wrapperCostWei + coordinatorCostWithPremiumAndFlatFeeWei)) / uint256(_weiPerUnitLink); } /** @@ -392,8 +417,8 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume * uint16 requestConfirmations, and uint32 numWords. */ function onTokenTransfer(address _sender, uint256 _amount, bytes calldata _data) external onlyConfiguredNotDisabled { - // solhint-disable-next-line custom-errors - require(msg.sender == address(s_link), "only callable from LINK"); + // solhint-disable-next-line gas-custom-errors + require(msg.sender == address(i_link), "only callable from LINK"); (uint32 callbackGasLimit, uint16 requestConfirmations, uint32 numWords, bytes memory extraArgs) = abi.decode( _data, @@ -403,9 +428,9 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume uint32 eip150Overhead = _getEIP150Overhead(callbackGasLimit); (int256 weiPerUnitLink, bool isFeedStale) = _getFeedData(); uint256 price = _calculateRequestPrice(callbackGasLimit, tx.gasprice, weiPerUnitLink); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(_amount >= price, "fee too low"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(numWords <= s_maxNumWords, "numWords too high"); VRFV2PlusClient.RandomWordsRequest memory req = VRFV2PlusClient.RandomWordsRequest({ keyHash: s_keyHash, @@ -457,14 +482,14 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume uint16 _requestConfirmations, uint32 _numWords, bytes calldata extraArgs - ) external payable override returns (uint256 requestId) { + ) external payable override onlyConfiguredNotDisabled returns (uint256 requestId) { checkPaymentMode(extraArgs, false); uint32 eip150Overhead = _getEIP150Overhead(_callbackGasLimit); uint256 price = _calculateRequestPriceNative(_callbackGasLimit, tx.gasprice); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(msg.value >= price, "fee too low"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(_numWords <= s_maxNumWords, "numWords too high"); VRFV2PlusClient.RandomWordsRequest memory req = VRFV2PlusClient.RandomWordsRequest({ keyHash: s_keyHash, @@ -490,8 +515,8 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume * @param _recipient is the address that should receive the LINK funds. */ function withdraw(address _recipient) external onlyOwner { - uint256 amount = s_link.balanceOf(address(this)); - if (!s_link.transfer(_recipient, amount)) { + uint256 amount = i_link.balanceOf(address(this)); + if (!i_link.transfer(_recipient, amount)) { revert FailedToTransferLink(); } @@ -506,7 +531,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume function withdrawNative(address _recipient) external onlyOwner { uint256 amount = address(this).balance; (bool success, ) = payable(_recipient).call{value: amount}(""); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(success, "failed to withdraw native"); emit NativeWithdrawn(_recipient, amount); @@ -535,28 +560,38 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { Callback memory callback = s_callbacks[_requestId]; delete s_callbacks[_requestId]; - // solhint-disable-next-line custom-errors - require(callback.callbackAddress != address(0), "request not found"); // This should never happen + + address callbackAddress = callback.callbackAddress; + // solhint-disable-next-line gas-custom-errors + require(callbackAddress != address(0), "request not found"); // This should never happen VRFV2PlusWrapperConsumerBase c; bytes memory resp = abi.encodeWithSelector(c.rawFulfillRandomWords.selector, _requestId, _randomWords); - bool success = _callWithExactGas(callback.callbackGasLimit, callback.callbackAddress, resp); + bool success = _callWithExactGas(callback.callbackGasLimit, callbackAddress, resp); if (!success) { - emit WrapperFulfillmentFailed(_requestId, callback.callbackAddress); + emit WrapperFulfillmentFailed(_requestId, callbackAddress); } } + function link() external view override returns (address) { + return address(i_link); + } + + function linkNativeFeed() external view override returns (address) { + return address(i_link_native_feed); + } + function _getFeedData() private view returns (int256 weiPerUnitLink, bool isFeedStale) { uint32 stalenessSeconds = s_stalenessSeconds; uint256 timestamp; - (, weiPerUnitLink, , timestamp, ) = s_linkNativeFeed.latestRoundData(); + (, weiPerUnitLink, , timestamp, ) = i_link_native_feed.latestRoundData(); // solhint-disable-next-line not-rely-on-time isFeedStale = stalenessSeconds > 0 && stalenessSeconds < block.timestamp - timestamp; if (isFeedStale) { weiPerUnitLink = s_fallbackWeiPerUnitLink; } - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(weiPerUnitLink >= 0, "Invalid LINK wei price"); return (weiPerUnitLink, isFeedStale); } @@ -602,22 +637,14 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume } function typeAndVersion() external pure virtual override returns (string memory) { - return "VRFV2Wrapper 1.0.0"; + return "VRFV2PlusWrapper 1.0.0"; } modifier onlyConfiguredNotDisabled() { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(s_configured, "wrapper is not configured"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(!s_disabled, "wrapper is disabled"); _; } - - /*************************************************************************** - * Section: Migration of VRFV2PlusWrapper to latest VRFV2PlusCoordinator - ***************************************************************************/ - - function migrate(address newCoordinator) external onlyOwner { - IVRFV2PlusMigrate(address(s_vrfCoordinator)).migrate(SUBSCRIPTION_ID, newCoordinator); - } } diff --git a/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapperConsumerBase.sol b/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapperConsumerBase.sol index ff9e2a838e3..07a3292facc 100644 --- a/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapperConsumerBase.sol +++ b/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapperConsumerBase.sol @@ -29,38 +29,19 @@ import {IVRFV2PlusWrapper} from "./interfaces/IVRFV2PlusWrapper.sol"; * @dev fulfillment with the randomness result. */ abstract contract VRFV2PlusWrapperConsumerBase { - event LinkTokenSet(address link); - - error LINKAlreadySet(); error OnlyVRFWrapperCanFulfill(address have, address want); - LinkTokenInterface internal s_linkToken; + LinkTokenInterface internal immutable i_linkToken; IVRFV2PlusWrapper public immutable i_vrfV2PlusWrapper; /** - * @param _link is the address of LinkToken * @param _vrfV2PlusWrapper is the address of the VRFV2Wrapper contract */ - constructor(address _link, address _vrfV2PlusWrapper) { - if (_link != address(0)) { - s_linkToken = LinkTokenInterface(_link); - } - - i_vrfV2PlusWrapper = IVRFV2PlusWrapper(_vrfV2PlusWrapper); - } - - /** - * @notice setLinkToken changes the LINK token address. - * @param _link is the address of the new LINK token contract - */ - function setLinkToken(address _link) external { - if (address(s_linkToken) != address(0)) { - revert LINKAlreadySet(); - } - - s_linkToken = LinkTokenInterface(_link); + constructor(address _vrfV2PlusWrapper) { + IVRFV2PlusWrapper vrfV2PlusWrapper = IVRFV2PlusWrapper(_vrfV2PlusWrapper); - emit LinkTokenSet(_link); + i_linkToken = LinkTokenInterface(vrfV2PlusWrapper.link()); + i_vrfV2PlusWrapper = vrfV2PlusWrapper; } /** @@ -83,7 +64,7 @@ abstract contract VRFV2PlusWrapperConsumerBase { bytes memory extraArgs ) internal returns (uint256 requestId, uint256 reqPrice) { reqPrice = i_vrfV2PlusWrapper.calculateRequestPrice(_callbackGasLimit); - s_linkToken.transferAndCall( + i_linkToken.transferAndCall( address(i_vrfV2PlusWrapper), reqPrice, abi.encode(_callbackGasLimit, _requestConfirmations, _numWords, extraArgs) @@ -135,6 +116,6 @@ abstract contract VRFV2PlusWrapperConsumerBase { /// @notice getLinkToken returns the link token contract function getLinkToken() public view returns (LinkTokenInterface) { - return s_linkToken; + return i_linkToken; } } diff --git a/contracts/src/v0.8/vrf/dev/interfaces/IVRFCoordinatorV2Plus.sol b/contracts/src/v0.8/vrf/dev/interfaces/IVRFCoordinatorV2Plus.sol index 846da0b1edc..b0d5a801694 100644 --- a/contracts/src/v0.8/vrf/dev/interfaces/IVRFCoordinatorV2Plus.sol +++ b/contracts/src/v0.8/vrf/dev/interfaces/IVRFCoordinatorV2Plus.sol @@ -9,7 +9,7 @@ import {IVRFSubscriptionV2Plus} from "./IVRFSubscriptionV2Plus.sol"; interface IVRFCoordinatorV2Plus is IVRFSubscriptionV2Plus { /** * @notice Request a set of random words. - * @param req - a struct containing following fiels for randomness request: + * @param req - a struct containing following fields for randomness request: * keyHash - Corresponds to a particular oracle job which uses * that key for generating the VRF proof. Different keyHash's have different gas price * ceilings, so you can select a specific one to bound your maximum per request cost. diff --git a/contracts/src/v0.8/vrf/dev/interfaces/IVRFMigratableConsumerV2Plus.sol b/contracts/src/v0.8/vrf/dev/interfaces/IVRFMigratableConsumerV2Plus.sol index 103d1f175cb..67d12b886e1 100644 --- a/contracts/src/v0.8/vrf/dev/interfaces/IVRFMigratableConsumerV2Plus.sol +++ b/contracts/src/v0.8/vrf/dev/interfaces/IVRFMigratableConsumerV2Plus.sol @@ -8,6 +8,6 @@ interface IVRFMigratableConsumerV2Plus { event CoordinatorSet(address vrfCoordinator); /// @notice Sets the VRF Coordinator address - /// @notice This method is should only be callable by the coordinator or contract owner + /// @notice This method should only be callable by the coordinator or contract owner function setCoordinator(address vrfCoordinator) external; } diff --git a/contracts/src/v0.8/vrf/dev/interfaces/IVRFSubscriptionV2Plus.sol b/contracts/src/v0.8/vrf/dev/interfaces/IVRFSubscriptionV2Plus.sol index 49c131988a6..b178ffb98b0 100644 --- a/contracts/src/v0.8/vrf/dev/interfaces/IVRFSubscriptionV2Plus.sol +++ b/contracts/src/v0.8/vrf/dev/interfaces/IVRFSubscriptionV2Plus.sol @@ -26,7 +26,7 @@ interface IVRFSubscriptionV2Plus { function cancelSubscription(uint256 subId, address to) external; /** - * @notice Request subscription owner transfer. + * @notice Accept subscription owner transfer. * @param subId - ID of the subscription * @dev will revert if original owner of subId has * not requested that msg.sender become the new owner. @@ -92,7 +92,7 @@ interface IVRFSubscriptionV2Plus { /** * @notice Fund a subscription with native. * @param subId - ID of the subscription - * @notice This method expects msg.value to be greater than 0. + * @notice This method expects msg.value to be greater than or equal to 0. */ function fundSubscriptionWithNative(uint256 subId) external payable; } diff --git a/contracts/src/v0.8/vrf/dev/interfaces/IVRFV2PlusWrapper.sol b/contracts/src/v0.8/vrf/dev/interfaces/IVRFV2PlusWrapper.sol index a00327b5bee..93f6bf0ef11 100644 --- a/contracts/src/v0.8/vrf/dev/interfaces/IVRFV2PlusWrapper.sol +++ b/contracts/src/v0.8/vrf/dev/interfaces/IVRFV2PlusWrapper.sol @@ -2,18 +2,18 @@ pragma solidity ^0.8.0; interface IVRFV2PlusWrapper { - event LinkAndLinkNativeFeedSet(address link, address linkNativeFeed); event FulfillmentTxSizeSet(uint32 size); event ConfigSet( uint32 wrapperGasOverhead, uint32 coordinatorGasOverhead, - uint8 wrapperPremiumPercentage, + uint8 coordinatorNativePremiumPercentage, + uint8 coordinatorLinkPremiumPercentage, bytes32 keyHash, uint8 maxNumWords, uint32 stalenessSeconds, int256 fallbackWeiPerUnitLink, - uint32 fulfillmentFlatFeeLinkPPM, - uint32 fulfillmentFlatFeeNativePPM + uint32 fulfillmentFlatFeeNativePPM, + uint32 fulfillmentFlatFeeLinkDiscountPPM ); event FallbackWeiPerUnitLinkUsed(uint256 requestId, int256 fallbackWeiPerUnitLink); event Withdrawn(address indexed to, uint256 amount); @@ -87,4 +87,7 @@ interface IVRFV2PlusWrapper { uint32 _numWords, bytes memory extraArgs ) external payable returns (uint256 requestId); + + function link() external view returns (address); + function linkNativeFeed() external view returns (address); } diff --git a/contracts/src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol b/contracts/src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol index 0f94571923e..3f4e799fb6d 100644 --- a/contracts/src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.4; import {VRFCoordinatorV2_5} from "../VRFCoordinatorV2_5.sol"; +import {VRFTypes} from "../../VRFTypes.sol"; import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; // solhint-disable-next-line contract-name-camelcase @@ -25,7 +26,7 @@ contract ExposedVRFCoordinatorV2_5 is VRFCoordinatorV2_5 { function getRandomnessFromProofExternal( Proof calldata proof, - RequestCommitment calldata rc + VRFTypes.RequestCommitmentV2Plus calldata rc ) external view returns (Output memory) { return _getRandomnessFromProof(proof, rc); } diff --git a/contracts/src/v0.8/vrf/dev/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol index 6d77a5d5de0..65a88df2c1e 100644 --- a/contracts/src/v0.8/vrf/dev/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol @@ -23,7 +23,7 @@ contract VRFConsumerV2PlusUpgradeableExample is Initializable, VRFConsumerBaseV2 // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(requestId == s_requestId, "request ID is incorrect"); s_gasAvailable = gasleft(); @@ -40,14 +40,14 @@ contract VRFConsumerV2PlusUpgradeableExample is Initializable, VRFConsumerBaseV2 } function topUpSubscription(uint96 amount) external { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(s_subId != 0, "sub not set"); // Approve the link transfer. LINKTOKEN.transferAndCall(address(COORDINATOR), amount, abi.encode(s_subId)); } function updateSubscription(address[] memory consumers) external { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(s_subId != 0, "subID not set"); for (uint256 i = 0; i < consumers.length; i++) { COORDINATOR.addConsumer(s_subId, consumers[i]); diff --git a/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol index 2e3aef59cd7..6599a68a96e 100644 --- a/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.4; +pragma solidity 0.8.19; import {BlockhashStoreInterface} from "../../interfaces/BlockhashStoreInterface.sol"; // solhint-disable-next-line no-unused-import @@ -648,9 +648,9 @@ contract VRFCoordinatorV2PlusUpgradedVersion is revert CoordinatorNotRegistered(newCoordinator); } (uint96 balance, uint96 nativeBalance, , address owner, address[] memory consumers) = getSubscription(subId); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(owner == msg.sender, "Not subscription owner"); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(!pendingRequestExists(subId), "Pending request exists"); V1MigrationData memory migrationData = V1MigrationData({ @@ -667,7 +667,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is // Only transfer LINK if the token is active and there is a balance. if (address(LINK) != address(0) && balance != 0) { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(LINK.transfer(address(newCoordinator), balance), "insufficient funds"); } @@ -713,7 +713,11 @@ contract VRFCoordinatorV2PlusUpgradedVersion is } for (uint256 i = 0; i < migrationData.consumers.length; i++) { - s_consumers[migrationData.consumers[i]][migrationData.subId] = ConsumerConfig({active: true, nonce: 0}); + s_consumers[migrationData.consumers[i]][migrationData.subId] = ConsumerConfig({ + active: true, + nonce: 0, + pendingReqCount: 0 + }); } s_subscriptions[migrationData.subId] = Subscription({ diff --git a/contracts/src/v0.8/vrf/dev/testhelpers/VRFMaliciousConsumerV2Plus.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFMaliciousConsumerV2Plus.sol index 9bbb5692071..cfc12102afd 100644 --- a/contracts/src/v0.8/vrf/dev/testhelpers/VRFMaliciousConsumerV2Plus.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFMaliciousConsumerV2Plus.sol @@ -45,7 +45,7 @@ contract VRFMaliciousConsumerV2Plus is VRFConsumerBaseV2Plus { } function updateSubscription(address[] memory consumers) external { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(s_subId != 0, "subID not set"); for (uint256 i = 0; i < consumers.length; i++) { s_vrfCoordinator.addConsumer(s_subId, consumers[i]); diff --git a/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusConsumerExample.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusConsumerExample.sol index 2ef4e5c021f..8063d2ea1ce 100644 --- a/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusConsumerExample.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusConsumerExample.sol @@ -29,7 +29,7 @@ contract VRFV2PlusConsumerExample is ConfirmedOwner, VRFConsumerBaseV2Plus { function getRandomness(uint256 requestId, uint256 idx) public view returns (uint256 randomWord) { Response memory resp = s_requests[requestId]; - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(resp.requestId != 0, "request ID is incorrect"); return resp.randomWords[idx]; } @@ -54,20 +54,20 @@ contract VRFV2PlusConsumerExample is ConfirmedOwner, VRFConsumerBaseV2Plus { } function topUpSubscription(uint96 amount) external { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(s_subId != 0, "sub not set"); s_linkToken.transferAndCall(address(s_vrfCoordinator), amount, abi.encode(s_subId)); } function topUpSubscriptionNative() external payable { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(s_subId != 0, "sub not set"); s_vrfCoordinatorApiV1.fundSubscriptionWithNative{value: msg.value}(s_subId); } // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(requestId == s_recentRequestId, "request ID is incorrect"); s_requests[requestId].randomWords = randomWords; s_requests[requestId].fulfilled = true; @@ -100,7 +100,7 @@ contract VRFV2PlusConsumerExample is ConfirmedOwner, VRFConsumerBaseV2Plus { } function updateSubscription(address[] memory consumers) external { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(s_subId != 0, "subID not set"); for (uint256 i = 0; i < consumers.length; i++) { s_vrfCoordinatorApiV1.addConsumer(s_subId, consumers[i]); diff --git a/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusExternalSubOwnerExample.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusExternalSubOwnerExample.sol index ed12d156f21..6b5c9f4bf23 100644 --- a/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusExternalSubOwnerExample.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusExternalSubOwnerExample.sol @@ -21,7 +21,7 @@ contract VRFV2PlusExternalSubOwnerExample is VRFConsumerBaseV2Plus { // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(requestId == s_requestId, "request ID is incorrect"); s_randomWords = randomWords; } diff --git a/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusLoadTestWithMetrics.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusLoadTestWithMetrics.sol index d937728a790..85cb7727366 100644 --- a/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusLoadTestWithMetrics.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusLoadTestWithMetrics.sol @@ -21,6 +21,8 @@ contract VRFV2PlusLoadTestWithMetrics is VRFConsumerBaseV2Plus { uint256 public s_lastRequestId; + uint32[] public s_requestBlockTimes; + struct RequestStatus { bool fulfilled; uint256[] randomWords; @@ -70,6 +72,8 @@ contract VRFV2PlusLoadTestWithMetrics is VRFConsumerBaseV2Plus { ); s_responseCount++; + + s_requestBlockTimes.push(uint32(responseTimeInBlocks)); } function requestRandomWords( @@ -116,6 +120,7 @@ contract VRFV2PlusLoadTestWithMetrics is VRFConsumerBaseV2Plus { s_fastestResponseTimeInSeconds = 999; s_requestCount = 0; s_responseCount = 0; + delete s_requestBlockTimes; } function getRequestStatus( @@ -161,4 +166,18 @@ contract VRFV2PlusLoadTestWithMetrics is VRFConsumerBaseV2Plus { return (_slowestResponseTime, _fastestResponseTime, averageInMillions); } + + function getRequestBlockTimes(uint256 offset, uint256 quantity) external view returns (uint32[] memory) { + uint256 end = offset + quantity; + if (end > s_requestBlockTimes.length) { + end = s_requestBlockTimes.length; + } + + uint32[] memory blockTimes = new uint32[](end - offset); + for (uint256 i = offset; i < end; i++) { + blockTimes[i - offset] = s_requestBlockTimes[i]; + } + + return blockTimes; + } } diff --git a/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusRevertingExample.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusRevertingExample.sol index 4e38ae39c1d..07f2e44de0b 100644 --- a/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusRevertingExample.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusRevertingExample.sol @@ -20,7 +20,7 @@ contract VRFV2PlusRevertingExample is VRFConsumerBaseV2Plus { // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256, uint256[] memory) internal pure override { - // solhint-disable-next-line custom-errors, reason-string + // solhint-disable-next-line gas-custom-errors, reason-string revert(); } @@ -34,14 +34,14 @@ contract VRFV2PlusRevertingExample is VRFConsumerBaseV2Plus { } function topUpSubscription(uint96 amount) external { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(s_subId != 0, "sub not set"); // Approve the link transfer. LINKTOKEN.transferAndCall(address(s_vrfCoordinator), amount, abi.encode(s_subId)); } function updateSubscription(address[] memory consumers) external { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(s_subId != 0, "subID not set"); for (uint256 i = 0; i < consumers.length; i++) { s_vrfCoordinator.addConsumer(s_subId, consumers[i]); diff --git a/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusSingleConsumerExample.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusSingleConsumerExample.sol index f3bf41d4f5a..b956ab0081a 100644 --- a/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusSingleConsumerExample.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusSingleConsumerExample.sol @@ -48,7 +48,7 @@ contract VRFV2PlusSingleConsumerExample is VRFConsumerBaseV2Plus { // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(requestId == s_requestId, "request ID is incorrect"); s_randomWords = randomWords; } diff --git a/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol index bc0e6531631..5025a300c28 100644 --- a/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol @@ -18,10 +18,7 @@ contract VRFV2PlusWrapperConsumerExample is VRFV2PlusWrapperConsumerBase, Confir mapping(uint256 => RequestStatus) /* requestId */ /* requestStatus */ public s_requests; - constructor( - address _link, - address _vrfV2Wrapper - ) ConfirmedOwner(msg.sender) VRFV2PlusWrapperConsumerBase(_link, _vrfV2Wrapper) {} + constructor(address _vrfV2Wrapper) ConfirmedOwner(msg.sender) VRFV2PlusWrapperConsumerBase(_vrfV2Wrapper) {} function makeRequest( uint32 _callbackGasLimit, @@ -51,7 +48,7 @@ contract VRFV2PlusWrapperConsumerExample is VRFV2PlusWrapperConsumerBase, Confir // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(s_requests[_requestId].paid > 0, "request not found"); s_requests[_requestId].fulfilled = true; s_requests[_requestId].randomWords = _randomWords; @@ -61,7 +58,7 @@ contract VRFV2PlusWrapperConsumerExample is VRFV2PlusWrapperConsumerBase, Confir function getRequestStatus( uint256 _requestId ) external view returns (uint256 paid, bool fulfilled, uint256[] memory randomWords) { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(s_requests[_requestId].paid > 0, "request not found"); RequestStatus memory request = s_requests[_requestId]; return (request.paid, request.fulfilled, request.randomWords); @@ -70,14 +67,14 @@ contract VRFV2PlusWrapperConsumerExample is VRFV2PlusWrapperConsumerBase, Confir /// @notice withdrawLink withdraws the amount specified in amount to the owner /// @param amount the amount to withdraw, in juels function withdrawLink(uint256 amount) external onlyOwner { - s_linkToken.transfer(owner(), amount); + i_linkToken.transfer(owner(), amount); } /// @notice withdrawNative withdraws the amount specified in amount to the owner /// @param amount the amount to withdraw, in wei function withdrawNative(uint256 amount) external onlyOwner { (bool success, ) = payable(owner()).call{value: amount}(""); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(success, "withdrawNative failed"); } } diff --git a/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol index 5b75bc07d6a..1389aee5f37 100644 --- a/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol @@ -13,6 +13,7 @@ contract VRFV2PlusWrapperLoadTestConsumer is VRFV2PlusWrapperConsumerBase, Confi uint256 public s_slowestFulfillment = 0; uint256 public s_fastestFulfillment = 999; uint256 public s_lastRequestId; + uint32[] public s_requestBlockTimes; // solhint-disable-next-line chainlink-solidity/prefix-storage-variables-with-s-underscore mapping(uint256 => uint256) internal requestHeights; // requestIds to block number when rand request was made @@ -32,10 +33,7 @@ contract VRFV2PlusWrapperLoadTestConsumer is VRFV2PlusWrapperConsumerBase, Confi mapping(uint256 => RequestStatus) /* requestId */ /* requestStatus */ public s_requests; - constructor( - address _link, - address _vrfV2PlusWrapper - ) ConfirmedOwner(msg.sender) VRFV2PlusWrapperConsumerBase(_link, _vrfV2PlusWrapper) {} + constructor(address _vrfV2PlusWrapper) ConfirmedOwner(msg.sender) VRFV2PlusWrapperConsumerBase(_vrfV2PlusWrapper) {} function makeRequests( uint32 _callbackGasLimit, @@ -105,7 +103,7 @@ contract VRFV2PlusWrapperLoadTestConsumer is VRFV2PlusWrapperConsumerBase, Confi // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(s_requests[_requestId].paid > 0, "request not found"); uint256 fulfilmentBlockNumber = ChainSpecificUtil._getBlockNumber(); uint256 requestDelay = fulfilmentBlockNumber - requestHeights[_requestId]; @@ -125,6 +123,8 @@ contract VRFV2PlusWrapperLoadTestConsumer is VRFV2PlusWrapperConsumerBase, Confi s_requests[_requestId].fulfilmentTimestamp = block.timestamp; s_requests[_requestId].fulfilmentBlockNumber = fulfilmentBlockNumber; + s_requestBlockTimes.push(uint32(requestDelay)); + emit WrappedRequestFulfilled(_requestId, _randomWords, s_requests[_requestId].paid); } @@ -143,7 +143,7 @@ contract VRFV2PlusWrapperLoadTestConsumer is VRFV2PlusWrapperConsumerBase, Confi uint256 fulfilmentBlockNumber ) { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(s_requests[_requestId].paid > 0, "request not found"); RequestStatus memory request = s_requests[_requestId]; return ( @@ -157,25 +157,40 @@ contract VRFV2PlusWrapperLoadTestConsumer is VRFV2PlusWrapperConsumerBase, Confi ); } + function getRequestBlockTimes(uint256 offset, uint256 quantity) external view returns (uint32[] memory) { + uint256 end = offset + quantity; + if (end > s_requestBlockTimes.length) { + end = s_requestBlockTimes.length; + } + + uint32[] memory blockTimes = new uint32[](end - offset); + for (uint256 i = offset; i < end; i++) { + blockTimes[i - offset] = s_requestBlockTimes[i]; + } + + return blockTimes; + } + function reset() external { s_averageFulfillmentInMillions = 0; // in millions for better precision s_slowestFulfillment = 0; s_fastestFulfillment = 999; s_requestCount = 0; s_responseCount = 0; + delete s_requestBlockTimes; } /// @notice withdrawLink withdraws the amount specified in amount to the owner /// @param amount the amount to withdraw, in juels function withdrawLink(uint256 amount) external onlyOwner { - s_linkToken.transfer(owner(), amount); + i_linkToken.transfer(owner(), amount); } /// @notice withdrawNative withdraws the amount specified in amount to the owner /// @param amount the amount to withdraw, in wei function withdrawNative(uint256 amount) external onlyOwner { (bool success, ) = payable(owner()).call{value: amount}(""); - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(success, "withdrawNative failed"); } diff --git a/contracts/src/v0.8/vrf/mocks/VRFCoordinatorMock.sol b/contracts/src/v0.8/vrf/mocks/VRFCoordinatorMock.sol index 6695e79b052..e192f749abc 100644 --- a/contracts/src/v0.8/vrf/mocks/VRFCoordinatorMock.sol +++ b/contracts/src/v0.8/vrf/mocks/VRFCoordinatorMock.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.0; import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; import {VRFConsumerBase} from "../../vrf/VRFConsumerBase.sol"; -// solhint-disable custom-errors +// solhint-disable gas-custom-errors contract VRFCoordinatorMock { LinkTokenInterface public LINK; diff --git a/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2Mock.sol b/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2Mock.sol index b605815f7eb..9617b76426b 100644 --- a/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2Mock.sol +++ b/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2Mock.sol @@ -7,7 +7,7 @@ import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; // solhint-disable chainlink-solidity/prefix-immutable-variables-with-i -// solhint-disable custom-errors +// solhint-disable gas-custom-errors // solhint-disable avoid-low-level-calls contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface, ConfirmedOwner { diff --git a/contracts/src/v0.8/vrf/test/BaseTest.t.sol b/contracts/src/v0.8/vrf/test/BaseTest.t.sol new file mode 100644 index 00000000000..4da698d1740 --- /dev/null +++ b/contracts/src/v0.8/vrf/test/BaseTest.t.sol @@ -0,0 +1,17 @@ +pragma solidity ^0.8.0; + +import {Test} from "forge-std/Test.sol"; + +contract BaseTest is Test { + bool private s_baseTestInitialized; + address internal constant OWNER = 0x00007e64E1fB0C487F25dd6D3601ff6aF8d32e4e; + + function setUp() public virtual { + // BaseTest.setUp is often called multiple times from tests' setUp due to inheritance. + if (s_baseTestInitialized) return; + s_baseTestInitialized = true; + + // Set msg.sender to OWNER until changePrank or stopPrank is called + vm.startPrank(OWNER); + } +} diff --git a/contracts/test/v0.8/foundry/vrf/ChainSpecificUtil.t.sol b/contracts/src/v0.8/vrf/test/ChainSpecificUtil.t.sol similarity index 94% rename from contracts/test/v0.8/foundry/vrf/ChainSpecificUtil.t.sol rename to contracts/src/v0.8/vrf/test/ChainSpecificUtil.t.sol index e0ac0036b36..efeb9027462 100644 --- a/contracts/test/v0.8/foundry/vrf/ChainSpecificUtil.t.sol +++ b/contracts/src/v0.8/vrf/test/ChainSpecificUtil.t.sol @@ -1,10 +1,11 @@ pragma solidity 0.8.6; -import "../BaseTest.t.sol"; -import {ChainSpecificUtil} from "../../../../src/v0.8/ChainSpecificUtil.sol"; -import {ArbSys} from "../../../../src/v0.8/vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; -import {ArbGasInfo} from "../../../../src/v0.8/vendor/@arbitrum/nitro-contracts/src/precompiles/ArbGasInfo.sol"; -import {OVM_GasPriceOracle} from "../../../../src/v0.8/vendor/@eth-optimism/contracts/v0.8.6/contracts/L2/predeploys/OVM_GasPriceOracle.sol"; +import "./BaseTest.t.sol"; +import {ChainSpecificUtil} from "../../ChainSpecificUtil_v0_8_6.sol"; + +import {ArbSys} from "../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; +import {ArbGasInfo} from "../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbGasInfo.sol"; +import {OVM_GasPriceOracle} from "../../vendor/@eth-optimism/contracts/v0.8.6/contracts/L2/predeploys/OVM_GasPriceOracle.sol"; contract ChainSpecificUtilTest is BaseTest { // ------------ Start Arbitrum Constants ------------ diff --git a/contracts/test/v0.8/foundry/vrf/TrustedBlockhashStore.t.sol b/contracts/src/v0.8/vrf/test/TrustedBlockhashStore.t.sol similarity index 95% rename from contracts/test/v0.8/foundry/vrf/TrustedBlockhashStore.t.sol rename to contracts/src/v0.8/vrf/test/TrustedBlockhashStore.t.sol index 4f3ea40d828..ec47f4815d9 100644 --- a/contracts/test/v0.8/foundry/vrf/TrustedBlockhashStore.t.sol +++ b/contracts/src/v0.8/vrf/test/TrustedBlockhashStore.t.sol @@ -1,7 +1,7 @@ -pragma solidity 0.8.6; +pragma solidity 0.8.19; -import "../BaseTest.t.sol"; -import {TrustedBlockhashStore} from "../../../../src/v0.8/vrf/dev/TrustedBlockhashStore.sol"; +import "./BaseTest.t.sol"; +import {TrustedBlockhashStore} from "../dev/TrustedBlockhashStore.sol"; import {console} from "forge-std/console.sol"; contract TrustedBlockhashStoreTest is BaseTest { diff --git a/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Mock.t.sol b/contracts/src/v0.8/vrf/test/VRFCoordinatorV2Mock.t.sol similarity index 96% rename from contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Mock.t.sol rename to contracts/src/v0.8/vrf/test/VRFCoordinatorV2Mock.t.sol index 6378d40167b..1716118b765 100644 --- a/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Mock.t.sol +++ b/contracts/src/v0.8/vrf/test/VRFCoordinatorV2Mock.t.sol @@ -1,11 +1,11 @@ pragma solidity 0.8.6; -import "../BaseTest.t.sol"; -import {VRF} from "../../../../src/v0.8/vrf/VRF.sol"; -import {MockLinkToken} from "../../../../src/v0.8/mocks/MockLinkToken.sol"; -import {MockV3Aggregator} from "../../../../src/v0.8/tests/MockV3Aggregator.sol"; -import {VRFCoordinatorV2Mock} from "../../../../src/v0.8/vrf/mocks/VRFCoordinatorV2Mock.sol"; -import {VRFConsumerV2} from "../../../../src/v0.8/vrf/testhelpers/VRFConsumerV2.sol"; +import "./BaseTest.t.sol"; +import {VRF} from "../VRF.sol"; +import {MockLinkToken} from "../../mocks/MockLinkToken.sol"; +import {MockV3Aggregator} from "../../tests/MockV3Aggregator.sol"; +import {VRFCoordinatorV2Mock} from "../mocks/VRFCoordinatorV2Mock.sol"; +import {VRFConsumerV2} from "../testhelpers/VRFConsumerV2.sol"; contract VRFCoordinatorV2MockTest is BaseTest { MockLinkToken internal s_linkToken; diff --git a/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Plus_Migration.t.sol b/contracts/src/v0.8/vrf/test/VRFCoordinatorV2Plus_Migration.t.sol similarity index 94% rename from contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Plus_Migration.t.sol rename to contracts/src/v0.8/vrf/test/VRFCoordinatorV2Plus_Migration.t.sol index 0c6825f8f6d..31585656b37 100644 --- a/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Plus_Migration.t.sol +++ b/contracts/src/v0.8/vrf/test/VRFCoordinatorV2Plus_Migration.t.sol @@ -1,14 +1,14 @@ -pragma solidity 0.8.6; - -import "../BaseTest.t.sol"; -import {VRFCoordinatorV2Plus_V2Example} from "../../../../src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol"; -import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol"; -import {VRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol"; -import {SubscriptionAPI} from "../../../../src/v0.8/vrf/dev/SubscriptionAPI.sol"; -import {VRFV2PlusConsumerExample} from "../../../../src/v0.8/vrf/dev/testhelpers/VRFV2PlusConsumerExample.sol"; -import {MockLinkToken} from "../../../../src/v0.8/mocks/MockLinkToken.sol"; -import {MockV3Aggregator} from "../../../../src/v0.8/tests/MockV3Aggregator.sol"; -import {VRFV2PlusMaliciousMigrator} from "../../../../src/v0.8/vrf/dev/testhelpers/VRFV2PlusMaliciousMigrator.sol"; +pragma solidity 0.8.19; + +import "./BaseTest.t.sol"; +import {VRFCoordinatorV2Plus_V2Example} from "../dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol"; +import {ExposedVRFCoordinatorV2_5} from "../dev/testhelpers/ExposedVRFCoordinatorV2_5.sol"; +import {VRFCoordinatorV2_5} from "../dev/VRFCoordinatorV2_5.sol"; +import {SubscriptionAPI} from "../dev/SubscriptionAPI.sol"; +import {VRFV2PlusConsumerExample} from "../dev/testhelpers/VRFV2PlusConsumerExample.sol"; +import {MockLinkToken} from "../../mocks/MockLinkToken.sol"; +import {MockV3Aggregator} from "../../tests/MockV3Aggregator.sol"; +import {VRFV2PlusMaliciousMigrator} from "../dev/testhelpers/VRFV2PlusMaliciousMigrator.sol"; contract VRFCoordinatorV2Plus_Migration is BaseTest { uint256 internal constant DEFAULT_LINK_FUNDING = 10 ether; // 10 LINK diff --git a/contracts/test/v0.8/foundry/vrf/VRFV2Plus.t.sol b/contracts/src/v0.8/vrf/test/VRFV2Plus.t.sol similarity index 83% rename from contracts/test/v0.8/foundry/vrf/VRFV2Plus.t.sol rename to contracts/src/v0.8/vrf/test/VRFV2Plus.t.sol index 02fd1873792..b7c2c1f882e 100644 --- a/contracts/test/v0.8/foundry/vrf/VRFV2Plus.t.sol +++ b/contracts/src/v0.8/vrf/test/VRFV2Plus.t.sol @@ -1,18 +1,19 @@ -pragma solidity 0.8.6; - -import "../BaseTest.t.sol"; -import {VRF} from "../../../../src/v0.8/vrf/VRF.sol"; -import {MockLinkToken} from "../../../../src/v0.8/mocks/MockLinkToken.sol"; -import {MockV3Aggregator} from "../../../../src/v0.8/tests/MockV3Aggregator.sol"; -import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol"; -import {VRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol"; -import {SubscriptionAPI} from "../../../../src/v0.8/vrf/dev/SubscriptionAPI.sol"; -import {BlockhashStore} from "../../../../src/v0.8/vrf/dev/BlockhashStore.sol"; -import {VRFV2PlusConsumerExample} from "../../../../src/v0.8/vrf/dev/testhelpers/VRFV2PlusConsumerExample.sol"; -import {VRFV2PlusClient} from "../../../../src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol"; +pragma solidity 0.8.19; + +import "./BaseTest.t.sol"; +import {VRF} from "../VRF.sol"; +import {MockLinkToken} from "../../mocks/MockLinkToken.sol"; +import {MockV3Aggregator} from "../../tests/MockV3Aggregator.sol"; +import {ExposedVRFCoordinatorV2_5} from "../dev/testhelpers/ExposedVRFCoordinatorV2_5.sol"; +import {VRFCoordinatorV2_5} from "../dev/VRFCoordinatorV2_5.sol"; +import {SubscriptionAPI} from "../dev/SubscriptionAPI.sol"; +import {BlockhashStore} from "../dev/BlockhashStore.sol"; +import {VRFV2PlusConsumerExample} from "../dev/testhelpers/VRFV2PlusConsumerExample.sol"; +import {VRFV2PlusClient} from "../dev/libraries/VRFV2PlusClient.sol"; +import {VRFTypes} from "../VRFTypes.sol"; import {console} from "forge-std/console.sol"; import {VmSafe} from "forge-std/Vm.sol"; -import {VRFV2PlusLoadTestWithMetrics} from "../../../../src/v0.8/vrf/dev/testhelpers/VRFV2PlusLoadTestWithMetrics.sol"; +import {VRFV2PlusLoadTestWithMetrics} from "../dev/testhelpers/VRFV2PlusLoadTestWithMetrics.sol"; import "@openzeppelin/contracts/utils/math/Math.sol"; // for Math.ceilDiv /* @@ -373,7 +374,7 @@ contract VRFV2Plus is BaseTest { function testRequestAndFulfillRandomWordsNative() public { ( VRF.Proof memory proof, - VRFCoordinatorV2_5.RequestCommitment memory rc, + VRFTypes.RequestCommitmentV2Plus memory rc, uint256 subId, uint256 requestId ) = setupSubAndRequestRandomnessNativePayment(); @@ -409,12 +410,13 @@ contract VRFV2Plus is BaseTest { // 1e15 is less than 1 percent discrepancy assertApproxEqAbs(payment, 5.138 * 1e17, 1e15); assertApproxEqAbs(nativeBalanceAfter, nativeBalanceBefore - 5.138 * 1e17, 1e15); + assertFalse(s_testCoordinator.pendingRequestExists(subId)); } function testRequestAndFulfillRandomWordsLINK() public { ( VRF.Proof memory proof, - VRFCoordinatorV2_5.RequestCommitment memory rc, + VRFTypes.RequestCommitmentV2Plus memory rc, uint256 subId, uint256 requestId ) = setupSubAndRequestRandomnessLINKPayment(); @@ -453,12 +455,13 @@ contract VRFV2Plus is BaseTest { // 1e15 is less than 1 percent discrepancy assertApproxEqAbs(payment, 8.2992 * 1e17, 1e15); assertApproxEqAbs(linkBalanceAfter, linkBalanceBefore - 8.2992 * 1e17, 1e15); + assertFalse(s_testCoordinator.pendingRequestExists(subId)); } function testRequestAndFulfillRandomWordsLINK_FallbackWeiPerUnitLinkUsed() public { ( VRF.Proof memory proof, - VRFCoordinatorV2_5.RequestCommitment memory rc, + VRFTypes.RequestCommitmentV2Plus memory rc, , uint256 requestId ) = setupSubAndRequestRandomnessLINKPayment(); @@ -478,7 +481,7 @@ contract VRFV2Plus is BaseTest { function setupSubAndRequestRandomnessLINKPayment() internal - returns (VRF.Proof memory proof, VRFCoordinatorV2_5.RequestCommitment memory rc, uint256 subId, uint256 requestId) + returns (VRF.Proof memory proof, VRFTypes.RequestCommitmentV2Plus memory rc, uint256 subId, uint256 requestId) { uint32 requestBlock = 20; vm.roll(requestBlock); @@ -508,6 +511,7 @@ contract VRFV2Plus is BaseTest { s_testConsumer.requestRandomWords(CALLBACK_GAS_LIMIT, MIN_CONFIRMATIONS, NUM_WORDS, vrfKeyHash, false); (bool fulfilled, , ) = s_testConsumer.s_requests(requestId); assertEq(fulfilled, false); + assertTrue(s_testCoordinator.pendingRequestExists(subId)); // Uncomment these console logs to see info about the request: // console.log("requestId: ", requestId); @@ -553,7 +557,7 @@ contract VRFV2Plus is BaseTest { ], zInv: 82374292458278672300647114418593830323283909625362447038989596015264004164958 }); - rc = VRFCoordinatorV2_5.RequestCommitment({ + rc = VRFTypes.RequestCommitmentV2Plus({ blockNum: requestBlock, subId: subId, callbackGasLimit: 1000000, @@ -566,7 +570,7 @@ contract VRFV2Plus is BaseTest { function setupSubAndRequestRandomnessNativePayment() internal - returns (VRF.Proof memory proof, VRFCoordinatorV2_5.RequestCommitment memory rc, uint256 subId, uint256 requestId) + returns (VRF.Proof memory proof, VRFTypes.RequestCommitmentV2Plus memory rc, uint256 subId, uint256 requestId) { uint32 requestBlock = 10; vm.roll(requestBlock); @@ -596,6 +600,7 @@ contract VRFV2Plus is BaseTest { s_testConsumer.requestRandomWords(CALLBACK_GAS_LIMIT, MIN_CONFIRMATIONS, NUM_WORDS, vrfKeyHash, true); (bool fulfilled, , ) = s_testConsumer.s_requests(requestId); assertEq(fulfilled, false); + assertTrue(s_testCoordinator.pendingRequestExists(subId)); // Uncomment these console logs to see info about the request: // console.log("requestId: ", requestId); @@ -642,7 +647,7 @@ contract VRFV2Plus is BaseTest { ], zInv: 88742453392918610091640193378775723954629905126315835248392650970979000380325 }); - rc = VRFCoordinatorV2_5.RequestCommitment({ + rc = VRFTypes.RequestCommitmentV2Plus({ blockNum: requestBlock, subId: subId, callbackGasLimit: CALLBACK_GAS_LIMIT, @@ -657,7 +662,7 @@ contract VRFV2Plus is BaseTest { function testRequestAndFulfillRandomWords_NetworkGasPriceExceedsGasLane() public { ( VRF.Proof memory proof, - VRFCoordinatorV2_5.RequestCommitment memory rc, + VRFTypes.RequestCommitmentV2Plus memory rc, , ) = setupSubAndRequestRandomnessNativePayment(); @@ -674,7 +679,7 @@ contract VRFV2Plus is BaseTest { function testRequestAndFulfillRandomWords_OnlyPremium_NativePayment() public { ( VRF.Proof memory proof, - VRFCoordinatorV2_5.RequestCommitment memory rc, + VRFTypes.RequestCommitmentV2Plus memory rc, uint256 subId, uint256 requestId ) = setupSubAndRequestRandomnessNativePayment(); @@ -715,12 +720,13 @@ contract VRFV2Plus is BaseTest { // 1e15 is less than 1 percent discrepancy assertApproxEqAbs(payment, 5.9 * 1e17, 1e15); assertApproxEqAbs(nativeBalanceAfter, nativeBalanceBefore - 5.9 * 1e17, 1e15); + assertFalse(s_testCoordinator.pendingRequestExists(subId)); } function testRequestAndFulfillRandomWords_OnlyPremium_LinkPayment() public { ( VRF.Proof memory proof, - VRFCoordinatorV2_5.RequestCommitment memory rc, + VRFTypes.RequestCommitmentV2Plus memory rc, uint256 subId, uint256 requestId ) = setupSubAndRequestRandomnessLINKPayment(); @@ -764,6 +770,7 @@ contract VRFV2Plus is BaseTest { // 1e15 is less than 1 percent discrepancy assertApproxEqAbs(payment, 9.36 * 1e17, 1e15); assertApproxEqAbs(linkBalanceAfter, linkBalanceBefore - 9.36 * 1e17, 1e15); + assertFalse(s_testCoordinator.pendingRequestExists(subId)); } function testRequestRandomWords_InvalidConsumer() public { @@ -783,6 +790,7 @@ contract VRFV2Plus is BaseTest { NUM_WORDS, 1 /* requestCount */ ); + assertFalse(s_testCoordinator.pendingRequestExists(subId)); } function testRequestRandomWords_ReAddConsumer_AssertRequestID() public { @@ -792,8 +800,7 @@ contract VRFV2Plus is BaseTest { address subOwner = makeAddr("subOwner"); changePrank(subOwner); uint256 subId = s_testCoordinator.createSubscription(); - VRFV2PlusLoadTestWithMetrics consumer = new VRFV2PlusLoadTestWithMetrics(address(s_testCoordinator)); - s_testCoordinator.addConsumer(subId, address(consumer)); + VRFV2PlusLoadTestWithMetrics consumer = createAndAddLoadTestWithMetricsConsumer(subId); uint32 requestBlock = 10; vm.roll(requestBlock); changePrank(LINK_WHALE); @@ -872,7 +879,7 @@ contract VRFV2Plus is BaseTest { ], zInv: 18898957977631212231148068121702167284572066246731769473720131179584458697812 }); - VRFCoordinatorV2_5.RequestCommitment memory rc = VRFCoordinatorV2_5.RequestCommitment({ + VRFTypes.RequestCommitmentV2Plus memory rc = VRFTypes.RequestCommitmentV2Plus({ blockNum: requestBlock, subId: subId, callbackGasLimit: CALLBACK_GAS_LIMIT, @@ -924,5 +931,169 @@ contract VRFV2Plus is BaseTest { ); assertNotEq(requestId, requestId2); assertNotEq(preSeed, preSeed2); + assertTrue(s_testCoordinator.pendingRequestExists(subId)); + } + + function testRequestRandomWords_MultipleConsumers_PendingRequestExists() public { + // 1. setup consumer and subscription + setConfig(); + registerProvingKey(); + address subOwner = makeAddr("subOwner"); + changePrank(subOwner); + uint256 subId = s_testCoordinator.createSubscription(); + VRFV2PlusLoadTestWithMetrics consumer1 = createAndAddLoadTestWithMetricsConsumer(subId); + VRFV2PlusLoadTestWithMetrics consumer2 = createAndAddLoadTestWithMetricsConsumer(subId); + uint32 requestBlock = 10; + vm.roll(requestBlock); + changePrank(LINK_WHALE); + s_testCoordinator.fundSubscriptionWithNative{value: 10 ether}(subId); + + // 2. Request random words. + changePrank(subOwner); + (uint256 requestId1, uint256 preSeed1) = s_testCoordinator.computeRequestIdExternal( + vrfKeyHash, + address(consumer1), + subId, + 1 + ); + (uint256 requestId2, uint256 preSeed2) = s_testCoordinator.computeRequestIdExternal( + vrfKeyHash, + address(consumer2), + subId, + 1 + ); + assertNotEq(requestId1, requestId2); + assertNotEq(preSeed1, preSeed2); + consumer1.requestRandomWords( + subId, + MIN_CONFIRMATIONS, + vrfKeyHash, + CALLBACK_GAS_LIMIT, + true /* nativePayment */, + NUM_WORDS, + 1 /* requestCount */ + ); + consumer2.requestRandomWords( + subId, + MIN_CONFIRMATIONS, + vrfKeyHash, + CALLBACK_GAS_LIMIT, + true /* nativePayment */, + NUM_WORDS, + 1 /* requestCount */ + ); + assertTrue(s_testCoordinator.pendingRequestExists(subId)); + + // Move on to the next block. + // Store the previous block's blockhash, and assert that it is as expected. + vm.roll(requestBlock + 1); + s_bhs.store(requestBlock); + assertEq(hex"000000000000000000000000000000000000000000000000000000000000000a", s_bhs.getBlockhash(requestBlock)); + + // 3. Fulfill the 1st request above + console.log("requestId: ", requestId1); + console.log("preSeed: ", preSeed1); + console.log("sender: ", address(consumer1)); + + // Fulfill the request. + // Proof generated via the generate-proof-v2-plus script command. Example usage: + /* + go run . generate-proof-v2-plus \ + -key-hash 0x9f2353bde94264dbc3d554a94cceba2d7d2b4fdce4304d3e09a1fea9fbeb1528 \ + -pre-seed 94043941380654896554739370173616551044559721638888689173752661912204412136884 \ + -block-hash 0x000000000000000000000000000000000000000000000000000000000000000a \ + -block-num 10 \ + -sender 0x44CAfC03154A0708F9DCf988681821f648dA74aF \ + -native-payment true + */ + VRF.Proof memory proof = VRF.Proof({ + pk: [ + 72488970228380509287422715226575535698893157273063074627791787432852706183111, + 62070622898698443831883535403436258712770888294397026493185421712108624767191 + ], + gamma: [ + 18593555375562408458806406536059989757338587469093035962641476877033456068708, + 55675218112764789548330682504442195066741636758414578491295297591596761905475 + ], + c: 56595337384472359782910435918403237878894172750128610188222417200315739516270, + s: 60666722370046279064490737533582002977678558769715798604164042022636022215663, + seed: 94043941380654896554739370173616551044559721638888689173752661912204412136884, + uWitness: 0xEdbE15fd105cfEFb9CCcbBD84403d1F62719E50d, + cGammaWitness: [ + 11752391553651713021860307604522059957920042356542944931263270793211985356642, + 14713353048309058367510422609936133400473710094544154206129568172815229277104 + ], + sHashWitness: [ + 109716108880570827107616596438987062129934448629902940427517663799192095060206, + 79378277044196229730810703755304140279837983575681427317104232794580059801930 + ], + zInv: 18898957977631212231148068121702167284572066246731769473720131179584458697812 + }); + VRFTypes.RequestCommitmentV2Plus memory rc = VRFTypes.RequestCommitmentV2Plus({ + blockNum: requestBlock, + subId: subId, + callbackGasLimit: CALLBACK_GAS_LIMIT, + numWords: NUM_WORDS, + sender: address(consumer1), + extraArgs: VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: true})) + }); + s_testCoordinator.fulfillRandomWords(proof, rc, true /* onlyPremium */); + assertTrue(s_testCoordinator.pendingRequestExists(subId)); + + //4. Fulfill the 2nd request + console.log("requestId: ", requestId2); + console.log("preSeed: ", preSeed2); + console.log("sender: ", address(consumer2)); + + // Fulfill the request. + // Proof generated via the generate-proof-v2-plus script command. Example usage: + /* + go run . generate-proof-v2-plus \ + -key-hash 0x9f2353bde94264dbc3d554a94cceba2d7d2b4fdce4304d3e09a1fea9fbeb1528 \ + -pre-seed 60086281972849674111646805013521068579710860774417505336898013292594859262126 \ + -block-hash 0x000000000000000000000000000000000000000000000000000000000000000a \ + -block-num 10 \ + -sender 0xf5a165378E120f93784395aDF1E08a437e902865 \ + -native-payment true + */ + proof = VRF.Proof({ + pk: [ + 72488970228380509287422715226575535698893157273063074627791787432852706183111, + 62070622898698443831883535403436258712770888294397026493185421712108624767191 + ], + gamma: [ + 8781676794493524976318989249067879326013864868749595045909181134740761572122, + 70144896394968351242907510966944756907625107566821127114847472296460405612124 + ], + c: 67847193668837615807355025316836592349514589069599294392546721746916067719949, + s: 114946531382736685625345450298146929067341928840493664822961336014597880904075, + seed: 60086281972849674111646805013521068579710860774417505336898013292594859262126, + uWitness: 0xe1de4fD69277D0C5516cAE4d760b1d08BC340A28, + cGammaWitness: [ + 90301582727701442026215692513959255065128476395727596945643431833363167168678, + 61501369717028493801369453424028509804064958915788808540582630993703331669978 + ], + sHashWitness: [ + 98738650825542176387169085844714248077697103572877410412808249468787326424906, + 85647963391545223707301702874240345890884970941786094239896961457539737216630 + ], + zInv: 29080001901010358083725892808339807464533563010468652346220922643802059192842 + }); + rc = VRFTypes.RequestCommitmentV2Plus({ + blockNum: requestBlock, + subId: subId, + callbackGasLimit: CALLBACK_GAS_LIMIT, + numWords: NUM_WORDS, + sender: address(consumer2), + extraArgs: VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: true})) + }); + s_testCoordinator.fulfillRandomWords(proof, rc, true /* onlyPremium */); + assertFalse(s_testCoordinator.pendingRequestExists(subId)); + } + + function createAndAddLoadTestWithMetricsConsumer(uint256 subId) internal returns (VRFV2PlusLoadTestWithMetrics) { + VRFV2PlusLoadTestWithMetrics consumer = new VRFV2PlusLoadTestWithMetrics(address(s_testCoordinator)); + s_testCoordinator.addConsumer(subId, address(consumer)); + return consumer; } } diff --git a/contracts/test/v0.8/foundry/vrf/VRFV2PlusSubscriptionAPI.t.sol b/contracts/src/v0.8/vrf/test/VRFV2PlusSubscriptionAPI.t.sol similarity index 97% rename from contracts/test/v0.8/foundry/vrf/VRFV2PlusSubscriptionAPI.t.sol rename to contracts/src/v0.8/vrf/test/VRFV2PlusSubscriptionAPI.t.sol index 9883acdbc23..4fbb44ea717 100644 --- a/contracts/test/v0.8/foundry/vrf/VRFV2PlusSubscriptionAPI.t.sol +++ b/contracts/src/v0.8/vrf/test/VRFV2PlusSubscriptionAPI.t.sol @@ -1,11 +1,11 @@ -pragma solidity 0.8.6; - -import "../BaseTest.t.sol"; -import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol"; -import {VRFV2PlusLoadTestWithMetrics} from "../../../../src/v0.8/vrf/dev/testhelpers/VRFV2PlusLoadTestWithMetrics.sol"; -import {SubscriptionAPI} from "../../../../src/v0.8/vrf/dev/SubscriptionAPI.sol"; -import {MockLinkToken} from "../../../../src/v0.8/mocks/MockLinkToken.sol"; -import {MockV3Aggregator} from "../../../../src/v0.8/tests/MockV3Aggregator.sol"; +pragma solidity 0.8.19; + +import "./BaseTest.t.sol"; +import {ExposedVRFCoordinatorV2_5} from "../dev/testhelpers/ExposedVRFCoordinatorV2_5.sol"; +import {VRFV2PlusLoadTestWithMetrics} from "../dev/testhelpers/VRFV2PlusLoadTestWithMetrics.sol"; +import {SubscriptionAPI} from "../dev/SubscriptionAPI.sol"; +import {MockLinkToken} from "../../mocks/MockLinkToken.sol"; +import {MockV3Aggregator} from "../../tests/MockV3Aggregator.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; // for Strings.toString import {VmSafe} from "forge-std/Vm.sol"; @@ -575,10 +575,10 @@ contract VRFV2PlusSubscriptionAPITest is BaseTest { } // try adding one more consumer, should revert - address consumer = makeAddr("consumer"); + address lastConsumer = makeAddr("consumer"); changePrank(subOwner); vm.expectRevert(SubscriptionAPI.TooManyConsumers.selector); - s_subscriptionAPI.addConsumer(subId, consumer); + s_subscriptionAPI.addConsumer(subId, lastConsumer); } function testAddConsumerReaddSameConsumer() public { diff --git a/contracts/test/v0.8/foundry/vrf/VRFV2PlusWrapper.t.sol b/contracts/src/v0.8/vrf/test/VRFV2PlusWrapper.t.sol similarity index 57% rename from contracts/test/v0.8/foundry/vrf/VRFV2PlusWrapper.t.sol rename to contracts/src/v0.8/vrf/test/VRFV2PlusWrapper.t.sol index 5b03b9278e7..89232f07dac 100644 --- a/contracts/test/v0.8/foundry/vrf/VRFV2PlusWrapper.t.sol +++ b/contracts/src/v0.8/vrf/test/VRFV2PlusWrapper.t.sol @@ -1,28 +1,29 @@ -pragma solidity 0.8.6; - -import "../BaseTest.t.sol"; -import {VRF} from "../../../../src/v0.8/vrf/VRF.sol"; -import {MockLinkToken} from "../../../../src/v0.8/mocks/MockLinkToken.sol"; -import {MockV3Aggregator} from "../../../../src/v0.8/tests/MockV3Aggregator.sol"; -import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol"; -import {VRFV2PlusWrapperConsumerBase} from "../../../../src/v0.8/vrf/dev/VRFV2PlusWrapperConsumerBase.sol"; -import {VRFV2PlusWrapperConsumerExample} from "../../../../src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol"; -import {VRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol"; -import {VRFV2PlusWrapper} from "../../../../src/v0.8/vrf/dev/VRFV2PlusWrapper.sol"; -import {VRFV2PlusClient} from "../../../../src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol"; -import {console} from "forge-std/console.sol"; +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {BaseTest} from "./BaseTest.t.sol"; +import {MockLinkToken} from "../../mocks/MockLinkToken.sol"; +import {MockV3Aggregator} from "../../tests/MockV3Aggregator.sol"; +import {ExposedVRFCoordinatorV2_5} from "../dev/testhelpers/ExposedVRFCoordinatorV2_5.sol"; +import {SubscriptionAPI} from "../dev/SubscriptionAPI.sol"; +import {VRFV2PlusWrapperConsumerExample} from "../dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol"; +import {VRFCoordinatorV2_5} from "../dev/VRFCoordinatorV2_5.sol"; +import {VRFConsumerBaseV2Plus} from "../dev/VRFConsumerBaseV2Plus.sol"; +import {VRFV2PlusWrapper} from "../dev/VRFV2PlusWrapper.sol"; +import {VRFV2PlusClient} from "../dev/libraries/VRFV2PlusClient.sol"; contract VRFV2PlusWrapperTest is BaseTest { address internal constant LINK_WHALE = 0xD883a6A1C22fC4AbFE938a5aDF9B2Cc31b1BF18B; - bytes32 vrfKeyHash = hex"9f2353bde94264dbc3d554a94cceba2d7d2b4fdce4304d3e09a1fea9fbeb1528"; - uint32 wrapperGasOverhead = 10_000; - uint32 coordinatorGasOverhead = 20_000; + bytes32 private vrfKeyHash = hex"9f2353bde94264dbc3d554a94cceba2d7d2b4fdce4304d3e09a1fea9fbeb1528"; + uint32 private wrapperGasOverhead = 10_000; + uint32 private coordinatorGasOverhead = 20_000; + uint256 private s_wrapperSubscriptionId; - ExposedVRFCoordinatorV2_5 s_testCoordinator; - MockLinkToken s_linkToken; - MockV3Aggregator s_linkNativeFeed; - VRFV2PlusWrapper s_wrapper; - VRFV2PlusWrapperConsumerExample s_consumer; + ExposedVRFCoordinatorV2_5 private s_testCoordinator; + MockLinkToken private s_linkToken; + MockV3Aggregator private s_linkNativeFeed; + VRFV2PlusWrapper private s_wrapper; + VRFV2PlusWrapperConsumerExample private s_consumer; function setUp() public override { BaseTest.setUp(); @@ -30,16 +31,34 @@ contract VRFV2PlusWrapperTest is BaseTest { // Fund our users. vm.roll(1); vm.deal(LINK_WHALE, 10_000 ether); - changePrank(LINK_WHALE); + vm.stopPrank(); + vm.startPrank(LINK_WHALE); // Deploy link token and link/native feed. s_linkToken = new MockLinkToken(); s_linkNativeFeed = new MockV3Aggregator(18, 500000000000000000); // .5 ETH (good for testing) - // Deploy coordinator and consumer. + // Deploy coordinator. s_testCoordinator = new ExposedVRFCoordinatorV2_5(address(0)); - s_wrapper = new VRFV2PlusWrapper(address(s_linkToken), address(s_linkNativeFeed), address(s_testCoordinator)); - s_consumer = new VRFV2PlusWrapperConsumerExample(address(s_linkToken), address(s_wrapper)); + + // Create subscription for all future wrapper contracts. + s_wrapperSubscriptionId = s_testCoordinator.createSubscription(); + + // Deploy wrapper. + s_wrapper = new VRFV2PlusWrapper( + address(s_linkToken), + address(s_linkNativeFeed), + address(s_testCoordinator), + uint256(s_wrapperSubscriptionId) + ); + assertEq(address(s_linkToken), address(s_wrapper.link())); + assertEq(address(s_linkNativeFeed), address(s_wrapper.linkNativeFeed())); + + // Add wrapper as a consumer to the wrapper's subscription. + s_testCoordinator.addConsumer(uint256(s_wrapperSubscriptionId), address(s_wrapper)); + + // Deploy consumer. + s_consumer = new VRFV2PlusWrapperConsumerExample(address(s_wrapper)); // Configure the coordinator. s_testCoordinator.setLINKAndLINKNativeFeed(address(s_linkToken), address(s_linkNativeFeed)); @@ -65,17 +84,18 @@ contract VRFV2PlusWrapperTest is BaseTest { function setConfigWrapper() internal { vm.expectEmit(false, false, false, true, address(s_wrapper)); - emit ConfigSet(wrapperGasOverhead, coordinatorGasOverhead, 0, vrfKeyHash, 10, 1, 50000000000000000, 0, 0); + emit ConfigSet(wrapperGasOverhead, coordinatorGasOverhead, 0, 0, vrfKeyHash, 10, 1, 50000000000000000, 0, 0); s_wrapper.setConfig( wrapperGasOverhead, // wrapper gas overhead coordinatorGasOverhead, // coordinator gas overhead - 0, // premium percentage + 0, // native premium percentage, + 0, // link premium percentage vrfKeyHash, // keyHash 10, // max number of words, 1, // stalenessSeconds 50000000000000000, // fallbackWeiPerUnitLink - 0, // fulfillmentFlatFeeLinkPPM - 0 // fulfillmentFlatFeeNativePPM + 0, // fulfillmentFlatFeeNativePPM + 0 // fulfillmentFlatFeeLinkDiscountPPM ); ( , @@ -84,13 +104,15 @@ contract VRFV2PlusWrapperTest is BaseTest { , uint32 _wrapperGasOverhead, uint32 _coordinatorGasOverhead, - uint8 _wrapperPremiumPercentage, + uint8 _coordinatorNativePremiumPercentage, + uint8 _coordinatorLinkPremiumPercentage, bytes32 _keyHash, uint8 _maxNumWords ) = s_wrapper.getConfig(); assertEq(_wrapperGasOverhead, wrapperGasOverhead); assertEq(_coordinatorGasOverhead, coordinatorGasOverhead); - assertEq(0, _wrapperPremiumPercentage); + assertEq(0, _coordinatorNativePremiumPercentage); + assertEq(0, _coordinatorLinkPremiumPercentage); assertEq(vrfKeyHash, _keyHash); assertEq(10, _maxNumWords); } @@ -108,18 +130,19 @@ contract VRFV2PlusWrapperTest is BaseTest { ); // IVRFV2PlusWrapper events - event LinkAndLinkNativeFeedSet(address link, address linkNativeFeed); + event LinkNativeFeedSet(address linkNativeFeed); event FulfillmentTxSizeSet(uint32 size); event ConfigSet( uint32 wrapperGasOverhead, uint32 coordinatorGasOverhead, - uint8 wrapperPremiumPercentage, + uint8 coordinatorNativePremiumPercentage, + uint8 coordinatorLinkPremiumPercentage, bytes32 keyHash, uint8 maxNumWords, uint32 stalenessSeconds, int256 fallbackWeiPerUnitLink, - uint32 fulfillmentFlatFeeLinkPPM, - uint32 fulfillmentFlatFeeNativePPM + uint32 fulfillmentFlatFeeNativePPM, + uint32 fulfillmentFlatFeeLinkDiscountPPM ); event FallbackWeiPerUnitLinkUsed(uint256 requestId, int256 fallbackWeiPerUnitLink); event Withdrawn(address indexed to, uint256 amount); @@ -130,28 +153,33 @@ contract VRFV2PlusWrapperTest is BaseTest { // VRFV2PlusWrapperConsumerBase events event LinkTokenSet(address link); - function testSetLinkAndLinkNativeFeed() public { - VRFV2PlusWrapper wrapper = new VRFV2PlusWrapper(address(0), address(0), address(s_testCoordinator)); + // SubscriptionAPI events + event SubscriptionConsumerAdded(uint256 indexed subId, address consumer); - // Set LINK and LINK/Native feed on wrapper. - vm.expectEmit(false, false, false, true, address(wrapper)); - emit LinkAndLinkNativeFeedSet(address(s_linkToken), address(s_linkNativeFeed)); - wrapper.setLinkAndLinkNativeFeed(address(s_linkToken), address(s_linkNativeFeed)); - assertEq(address(wrapper.s_link()), address(s_linkToken)); + function testVRFV2PlusWrapperZeroAddress() public { + vm.expectRevert(VRFConsumerBaseV2Plus.ZeroAddress.selector); + new VRFV2PlusWrapper(address(s_linkToken), address(s_linkNativeFeed), address(0), uint256(0)); + } - // Revert for subsequent assignment. - vm.expectRevert(VRFV2PlusWrapper.LinkAlreadySet.selector); - wrapper.setLinkAndLinkNativeFeed(address(s_linkToken), address(s_linkNativeFeed)); + function testCreationOfANewVRFV2PlusWrapper() public { + // second wrapper contract will simply add itself to the same subscription + VRFV2PlusWrapper nextWrapper = new VRFV2PlusWrapper( + address(s_linkToken), + address(s_linkNativeFeed), + address(s_testCoordinator), + s_wrapperSubscriptionId + ); + assertEq(s_wrapperSubscriptionId, nextWrapper.SUBSCRIPTION_ID()); + } - // Consumer can set LINK token. - VRFV2PlusWrapperConsumerExample consumer = new VRFV2PlusWrapperConsumerExample(address(0), address(wrapper)); - vm.expectEmit(false, false, false, true, address(consumer)); - emit LinkTokenSet(address(s_linkToken)); - consumer.setLinkToken(address(s_linkToken)); + function testVRFV2PlusWrapperWithZeroSubscriptionId() public { + vm.expectRevert(VRFV2PlusWrapper.SubscriptionIdMissing.selector); + new VRFV2PlusWrapper(address(s_linkToken), address(s_linkNativeFeed), address(s_testCoordinator), uint256(0)); + } - // Revert for subsequent assignment. - vm.expectRevert(VRFV2PlusWrapperConsumerBase.LINKAlreadySet.selector); - consumer.setLinkToken(address(s_linkToken)); + function testVRFV2PlusWrapperWithInvalidSubscriptionId() public { + vm.expectRevert(SubscriptionAPI.InvalidSubscription.selector); + new VRFV2PlusWrapper(address(s_linkToken), address(s_linkNativeFeed), address(s_testCoordinator), uint256(123456)); } function testSetFulfillmentTxSize() public { @@ -162,13 +190,18 @@ contract VRFV2PlusWrapperTest is BaseTest { assertEq(s_wrapper.s_fulfillmentTxSizeBytes(), fulfillmentTxSize); } + function testSetCoordinatorZeroAddress() public { + vm.expectRevert(VRFConsumerBaseV2Plus.ZeroAddress.selector); + s_wrapper.setCoordinator(address(0)); + } + function testRequestAndFulfillRandomWordsNativeWrapper() public { // Fund subscription. s_testCoordinator.fundSubscriptionWithNative{value: 10 ether}(s_wrapper.SUBSCRIPTION_ID()); vm.deal(address(s_consumer), 10 ether); // Get type and version. - assertEq(s_wrapper.typeAndVersion(), "VRFV2Wrapper 1.0.0"); + assertEq(s_wrapper.typeAndVersion(), "VRFV2PlusWrapper 1.0.0"); // Cannot make request while disabled. vm.expectEmit(false, false, false, true, address(s_wrapper)); @@ -235,6 +268,77 @@ contract VRFV2PlusWrapperTest is BaseTest { assertEq(address(s_wrapper).balance, 0); } + function testSetConfigFulfillmentFlatFee_LinkDiscountTooHigh() public { + // Test that setting link discount flat fee higher than native flat fee reverts + vm.expectRevert(abi.encodeWithSelector(VRFV2PlusWrapper.LinkDiscountTooHigh.selector, uint32(501), uint32(500))); + s_wrapper.setConfig( + wrapperGasOverhead, // wrapper gas overhead + coordinatorGasOverhead, // coordinator gas overhead + 0, // native premium percentage, + 0, // link premium percentage + vrfKeyHash, // keyHash + 10, // max number of words, + 1, // stalenessSeconds + 50000000000000000, // fallbackWeiPerUnitLink + 500, // fulfillmentFlatFeeNativePPM + 501 // fulfillmentFlatFeeLinkDiscountPPM + ); + } + + function testSetConfigFulfillmentFlatFee_LinkDiscountEqualsNative() public { + // Test that setting link discount flat fee equal to native flat fee does not revert + s_wrapper.setConfig( + wrapperGasOverhead, // wrapper gas overhead + coordinatorGasOverhead, // coordinator gas overhead + 0, // native premium percentage, + 0, // link premium percentage + vrfKeyHash, // keyHash + 10, // max number of words, + 1, // stalenessSeconds + 50000000000000000, // fallbackWeiPerUnitLink + 450, // fulfillmentFlatFeeNativePPM + 450 // fulfillmentFlatFeeLinkDiscountPPM + ); + } + + function testSetConfigNativePremiumPercentageInvalidPremiumPercentage() public { + // Test that setting native premium percentage higher than 155 will revert + vm.expectRevert( + abi.encodeWithSelector(VRFCoordinatorV2_5.InvalidPremiumPercentage.selector, uint8(156), uint8(155)) + ); + s_wrapper.setConfig( + wrapperGasOverhead, // wrapper gas overhead + coordinatorGasOverhead, // coordinator gas overhead + 156, // native premium percentage, + 0, // link premium percentage + vrfKeyHash, // keyHash + 10, // max number of words, + 1, // stalenessSeconds + 50000000000000000, // fallbackWeiPerUnitLink + 0, // fulfillmentFlatFeeNativePPM + 0 // fulfillmentFlatFeeLinkDiscountPPM + ); + } + + function testSetConfigLinkPremiumPercentageInvalidPremiumPercentage() public { + // Test that setting LINK premium percentage higher than 155 will revert + vm.expectRevert( + abi.encodeWithSelector(VRFCoordinatorV2_5.InvalidPremiumPercentage.selector, uint8(202), uint8(155)) + ); + s_wrapper.setConfig( + wrapperGasOverhead, // wrapper gas overhead + coordinatorGasOverhead, // coordinator gas overhead + 15, // native premium percentage, + 202, // link premium percentage + vrfKeyHash, // keyHash + 10, // max number of words, + 1, // stalenessSeconds + 50000000000000000, // fallbackWeiPerUnitLink + 0, // fulfillmentFlatFeeNativePPM + 0 // fulfillmentFlatFeeLinkDiscountPPM + ); + } + function testRequestAndFulfillRandomWordsLINKWrapper() public { // Fund subscription. s_linkToken.transferAndCall(address(s_testCoordinator), 10 ether, abi.encode(s_wrapper.SUBSCRIPTION_ID())); @@ -296,7 +400,7 @@ contract VRFV2PlusWrapperTest is BaseTest { assertEq(s_linkToken.balanceOf(address(s_wrapper)), 0); } - function testRequestRandomWordsLINKWrapper_FallbackWeiPerUnitLinkUsed() public { + function testRequestRandomWordsLINKWrapperFallbackWeiPerUnitLinkUsed() public { // Fund subscription. s_linkToken.transferAndCall(address(s_testCoordinator), 10 ether, abi.encode(s_wrapper.SUBSCRIPTION_ID())); s_linkToken.transfer(address(s_consumer), 10 ether); @@ -332,4 +436,23 @@ contract VRFV2PlusWrapperTest is BaseTest { ); s_consumer.makeRequest(callbackGasLimit, 0, 1); } + + function testRequestRandomWordsInNativeNotConfigured() public { + VRFV2PlusWrapper wrapper = new VRFV2PlusWrapper( + address(s_linkToken), + address(s_linkNativeFeed), + address(s_testCoordinator), + uint256(s_wrapperSubscriptionId) + ); + + vm.expectRevert("wrapper is not configured"); + wrapper.requestRandomWordsInNative(500_000, 0, 1, ""); + } + + function testRequestRandomWordsInNativeDisabled() public { + s_wrapper.disable(); + + vm.expectRevert("wrapper is disabled"); + s_wrapper.requestRandomWordsInNative(500_000, 0, 1, ""); + } } diff --git a/contracts/test/v0.8/foundry/vrf/VRFV2PlusWrapper_Migration.t.sol b/contracts/src/v0.8/vrf/test/VRFV2PlusWrapper_Migration.t.sol similarity index 74% rename from contracts/test/v0.8/foundry/vrf/VRFV2PlusWrapper_Migration.t.sol rename to contracts/src/v0.8/vrf/test/VRFV2PlusWrapper_Migration.t.sol index 28be25141c7..deaef4ba84e 100644 --- a/contracts/test/v0.8/foundry/vrf/VRFV2PlusWrapper_Migration.t.sol +++ b/contracts/src/v0.8/vrf/test/VRFV2PlusWrapper_Migration.t.sol @@ -1,33 +1,31 @@ -pragma solidity 0.8.6; - -import "../BaseTest.t.sol"; -import {VRF} from "../../../../src/v0.8/vrf/VRF.sol"; -import {MockLinkToken} from "../../../../src/v0.8/mocks/MockLinkToken.sol"; -import {MockV3Aggregator} from "../../../../src/v0.8/tests/MockV3Aggregator.sol"; -import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol"; -import {VRFCoordinatorV2Plus_V2Example} from "../../../../src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol"; -import {VRFV2PlusWrapperConsumerBase} from "../../../../src/v0.8/vrf/dev/VRFV2PlusWrapperConsumerBase.sol"; -import {VRFV2PlusWrapperConsumerExample} from "../../../../src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol"; -import {SubscriptionAPI} from "../../../../src/v0.8/vrf/dev/SubscriptionAPI.sol"; -import {VRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol"; -import {VRFV2PlusWrapper} from "../../../../src/v0.8/vrf/dev/VRFV2PlusWrapper.sol"; -import {VRFV2PlusClient} from "../../../../src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol"; +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {BaseTest} from "./BaseTest.t.sol"; +import {MockLinkToken} from "../../mocks/MockLinkToken.sol"; +import {MockV3Aggregator} from "../../tests/MockV3Aggregator.sol"; +import {ExposedVRFCoordinatorV2_5} from "../dev/testhelpers/ExposedVRFCoordinatorV2_5.sol"; +import {VRFCoordinatorV2Plus_V2Example} from "../dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol"; +import {VRFV2PlusWrapperConsumerExample} from "../dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol"; +import {SubscriptionAPI} from "../dev/SubscriptionAPI.sol"; +import {VRFV2PlusWrapper} from "../dev/VRFV2PlusWrapper.sol"; contract VRFV2PlusWrapper_MigrationTest is BaseTest { address internal constant LINK_WHALE = 0xD883a6A1C22fC4AbFE938a5aDF9B2Cc31b1BF18B; uint256 internal constant DEFAULT_NATIVE_FUNDING = 7 ether; // 7 ETH uint256 internal constant DEFAULT_LINK_FUNDING = 10 ether; // 10 ETH - bytes32 vrfKeyHash = hex"9f2353bde94264dbc3d554a94cceba2d7d2b4fdce4304d3e09a1fea9fbeb1528"; - uint32 wrapperGasOverhead = 10_000; - uint32 coordinatorGasOverhead = 20_000; + bytes32 private vrfKeyHash = hex"9f2353bde94264dbc3d554a94cceba2d7d2b4fdce4304d3e09a1fea9fbeb1528"; + uint32 private wrapperGasOverhead = 10_000; + uint32 private coordinatorGasOverhead = 20_000; + uint256 private s_wrapperSubscriptionId; - ExposedVRFCoordinatorV2_5 s_testCoordinator; - MockLinkToken s_linkToken; - MockV3Aggregator s_linkNativeFeed; - VRFV2PlusWrapper s_wrapper; - VRFV2PlusWrapperConsumerExample s_consumer; + ExposedVRFCoordinatorV2_5 private s_testCoordinator; + MockLinkToken private s_linkToken; + MockV3Aggregator private s_linkNativeFeed; + VRFV2PlusWrapper private s_wrapper; + VRFV2PlusWrapperConsumerExample private s_consumer; - VRFCoordinatorV2Plus_V2Example s_newCoordinator; + VRFCoordinatorV2Plus_V2Example private s_newCoordinator; event CoordinatorRegistered(address coordinatorAddress); event MigrationCompleted(address newCoordinator, uint256 subId); @@ -45,10 +43,25 @@ contract VRFV2PlusWrapper_MigrationTest is BaseTest { s_linkToken = new MockLinkToken(); s_linkNativeFeed = new MockV3Aggregator(18, 500000000000000000); // .5 ETH (good for testing) - // Deploy coordinator and consumer. + // Deploy coordinator. s_testCoordinator = new ExposedVRFCoordinatorV2_5(address(0)); - s_wrapper = new VRFV2PlusWrapper(address(s_linkToken), address(s_linkNativeFeed), address(s_testCoordinator)); - s_consumer = new VRFV2PlusWrapperConsumerExample(address(s_linkToken), address(s_wrapper)); + + // Create subscription for all future wrapper contracts. + s_wrapperSubscriptionId = s_testCoordinator.createSubscription(); + + // Deploy wrapper. + s_wrapper = new VRFV2PlusWrapper( + address(s_linkToken), + address(s_linkNativeFeed), + address(s_testCoordinator), + uint256(s_wrapperSubscriptionId) + ); + + // Add wrapper as a consumer to the wrapper's subscription. + s_testCoordinator.addConsumer(uint256(s_wrapperSubscriptionId), address(s_wrapper)); + + // Deploy consumer. + s_consumer = new VRFV2PlusWrapperConsumerExample(address(s_wrapper)); // Configure the coordinator. s_testCoordinator.setLINKAndLINKNativeFeed(address(s_linkToken), address(s_linkNativeFeed)); @@ -89,13 +102,14 @@ contract VRFV2PlusWrapper_MigrationTest is BaseTest { s_wrapper.setConfig( wrapperGasOverhead, // wrapper gas overhead coordinatorGasOverhead, // coordinator gas overhead - 0, // premium percentage + 0, // native premium percentage, + 0, // link premium percentage vrfKeyHash, // keyHash 10, // max number of words, 1, // stalenessSeconds 50000000000000000, // fallbackWeiPerUnitLink - 0, // fulfillmentFlatFeeLinkPPM - 0 // fulfillmentFlatFeeNativePPM + 0, // fulfillmentFlatFeeNativePPM + 0 // fulfillmentFlatFeeLinkDiscountPPM ); ( , @@ -104,13 +118,15 @@ contract VRFV2PlusWrapper_MigrationTest is BaseTest { , uint32 _wrapperGasOverhead, uint32 _coordinatorGasOverhead, - uint8 _wrapperPremiumPercentage, + uint8 _coordinatorNativePremiumPercentage, + uint8 _coordinatorLinkPremiumPercentage, bytes32 _keyHash, uint8 _maxNumWords ) = s_wrapper.getConfig(); assertEq(_wrapperGasOverhead, wrapperGasOverhead); assertEq(_coordinatorGasOverhead, coordinatorGasOverhead); - assertEq(0, _wrapperPremiumPercentage); + assertEq(0, _coordinatorNativePremiumPercentage); + assertEq(0, _coordinatorLinkPremiumPercentage); assertEq(vrfKeyHash, _keyHash); assertEq(10, _maxNumWords); } @@ -137,36 +153,31 @@ contract VRFV2PlusWrapper_MigrationTest is BaseTest { function testMigrateWrapperLINKPayment() public { s_linkToken.transfer(address(s_consumer), DEFAULT_LINK_FUNDING); - uint256 subID = s_wrapper.SUBSCRIPTION_ID(); + assertEq(uint256(s_wrapperSubscriptionId), uint256(s_wrapper.SUBSCRIPTION_ID())); address oldCoordinatorAddr = address(s_testCoordinator); + assertEq(address(oldCoordinatorAddr), address(s_wrapper.s_vrfCoordinator())); // Fund subscription with native and LINK payment to check // if funds are transferred to new subscription after call // migration to new coordinator - s_linkToken.transferAndCall(oldCoordinatorAddr, DEFAULT_LINK_FUNDING, abi.encode(subID)); - s_testCoordinator.fundSubscriptionWithNative{value: DEFAULT_NATIVE_FUNDING}(subID); - - // Get type and version. - assertEq(s_wrapper.typeAndVersion(), "VRFV2Wrapper 1.0.0"); + s_linkToken.transferAndCall(oldCoordinatorAddr, DEFAULT_LINK_FUNDING, abi.encode(s_wrapperSubscriptionId)); + s_testCoordinator.fundSubscriptionWithNative{value: DEFAULT_NATIVE_FUNDING}(s_wrapperSubscriptionId); // subscription exists in V1 coordinator before migration - ( uint96 balance, uint96 nativeBalance, uint64 reqCount, address owner, address[] memory consumers - ) = s_testCoordinator.getSubscription(subID); + ) = s_testCoordinator.getSubscription(s_wrapperSubscriptionId); assertEq(reqCount, 0); assertEq(balance, DEFAULT_LINK_FUNDING); assertEq(nativeBalance, DEFAULT_NATIVE_FUNDING); - assertEq(owner, address(s_wrapper)); + assertEq(owner, address(LINK_WHALE)); assertEq(consumers.length, 1); assertEq(consumers[0], address(s_wrapper)); - vm.startPrank(LINK_WHALE); - // Update wrapper to point to the new coordinator vm.expectEmit( false, // no first indexed field @@ -175,21 +186,23 @@ contract VRFV2PlusWrapper_MigrationTest is BaseTest { true // check data fields ); address newCoordinatorAddr = address(s_newCoordinator); - emit MigrationCompleted(newCoordinatorAddr, subID); + emit MigrationCompleted(newCoordinatorAddr, s_wrapperSubscriptionId); - s_wrapper.migrate(newCoordinatorAddr); + // old coordinator has to migrate wrapper's subscription to the new coordinator + s_testCoordinator.migrate(s_wrapperSubscriptionId, newCoordinatorAddr); + assertEq(address(newCoordinatorAddr), address(s_wrapper.s_vrfCoordinator())); // subscription no longer exists in v1 coordinator after migration vm.expectRevert(SubscriptionAPI.InvalidSubscription.selector); - s_testCoordinator.getSubscription(subID); + s_testCoordinator.getSubscription(s_wrapperSubscriptionId); assertEq(s_testCoordinator.s_totalBalance(), 0); assertEq(s_testCoordinator.s_totalNativeBalance(), 0); assertEq(s_linkToken.balanceOf(oldCoordinatorAddr), 0); assertEq(oldCoordinatorAddr.balance, 0); // subscription exists in v2 coordinator - (balance, nativeBalance, reqCount, owner, consumers) = s_newCoordinator.getSubscription(subID); - assertEq(owner, address(s_wrapper)); + (balance, nativeBalance, reqCount, owner, consumers) = s_newCoordinator.getSubscription(s_wrapperSubscriptionId); + assertEq(owner, address(LINK_WHALE)); assertEq(consumers.length, 1); assertEq(consumers[0], address(s_wrapper)); assertEq(reqCount, 0); @@ -202,7 +215,7 @@ contract VRFV2PlusWrapper_MigrationTest is BaseTest { // calling migrate again on V1 coordinator should fail vm.expectRevert(); - s_wrapper.migrate(newCoordinatorAddr); + s_testCoordinator.migrate(s_wrapperSubscriptionId, newCoordinatorAddr); // Request randomness from wrapper. uint32 callbackGasLimit = 1_000_000; @@ -254,17 +267,15 @@ contract VRFV2PlusWrapper_MigrationTest is BaseTest { function testMigrateWrapperNativePayment() public { vm.deal(address(s_consumer), DEFAULT_NATIVE_FUNDING); - uint256 subID = s_wrapper.SUBSCRIPTION_ID(); + assertEq(uint256(s_wrapperSubscriptionId), uint256(s_wrapper.SUBSCRIPTION_ID())); address oldCoordinatorAddr = address(s_testCoordinator); + assertEq(address(oldCoordinatorAddr), address(s_wrapper.s_vrfCoordinator())); // Fund subscription with native and LINK payment to check // if funds are transferred to new subscription after call // migration to new coordinator - s_linkToken.transferAndCall(oldCoordinatorAddr, DEFAULT_LINK_FUNDING, abi.encode(subID)); - s_testCoordinator.fundSubscriptionWithNative{value: DEFAULT_NATIVE_FUNDING}(subID); - - // Get type and version. - assertEq(s_wrapper.typeAndVersion(), "VRFV2Wrapper 1.0.0"); + s_linkToken.transferAndCall(oldCoordinatorAddr, DEFAULT_LINK_FUNDING, abi.encode(s_wrapperSubscriptionId)); + s_testCoordinator.fundSubscriptionWithNative{value: DEFAULT_NATIVE_FUNDING}(s_wrapperSubscriptionId); // subscription exists in V1 coordinator before migration ( @@ -273,16 +284,14 @@ contract VRFV2PlusWrapper_MigrationTest is BaseTest { uint64 reqCount, address owner, address[] memory consumers - ) = s_testCoordinator.getSubscription(subID); + ) = s_testCoordinator.getSubscription(s_wrapperSubscriptionId); assertEq(reqCount, 0); assertEq(balance, DEFAULT_LINK_FUNDING); assertEq(nativeBalance, DEFAULT_NATIVE_FUNDING); - assertEq(owner, address(s_wrapper)); + assertEq(owner, address(LINK_WHALE)); assertEq(consumers.length, 1); assertEq(consumers[0], address(s_wrapper)); - vm.startPrank(LINK_WHALE); - // Update wrapper to point to the new coordinator vm.expectEmit( false, // no first indexed field @@ -291,22 +300,23 @@ contract VRFV2PlusWrapper_MigrationTest is BaseTest { true // check data fields ); address newCoordinatorAddr = address(s_newCoordinator); - emit CoordinatorSet(address(s_newCoordinator)); - emit MigrationCompleted(newCoordinatorAddr, subID); + emit MigrationCompleted(newCoordinatorAddr, s_wrapperSubscriptionId); - s_wrapper.migrate(newCoordinatorAddr); + // old coordinator has to migrate wrapper's subscription to the new coordinator + s_testCoordinator.migrate(s_wrapperSubscriptionId, newCoordinatorAddr); + assertEq(address(newCoordinatorAddr), address(s_wrapper.s_vrfCoordinator())); // subscription no longer exists in v1 coordinator after migration vm.expectRevert(SubscriptionAPI.InvalidSubscription.selector); - s_testCoordinator.getSubscription(subID); + s_testCoordinator.getSubscription(s_wrapperSubscriptionId); assertEq(s_testCoordinator.s_totalBalance(), 0); assertEq(s_testCoordinator.s_totalNativeBalance(), 0); assertEq(s_linkToken.balanceOf(oldCoordinatorAddr), 0); assertEq(oldCoordinatorAddr.balance, 0); // subscription exists in v2 coordinator - (balance, nativeBalance, reqCount, owner, consumers) = s_newCoordinator.getSubscription(subID); - assertEq(owner, address(s_wrapper)); + (balance, nativeBalance, reqCount, owner, consumers) = s_newCoordinator.getSubscription(s_wrapperSubscriptionId); + assertEq(owner, address(LINK_WHALE)); assertEq(consumers.length, 1); assertEq(consumers[0], address(s_wrapper)); assertEq(reqCount, 0); @@ -319,7 +329,7 @@ contract VRFV2PlusWrapper_MigrationTest is BaseTest { // calling migrate again on V1 coordinator should fail vm.expectRevert(); - s_wrapper.migrate(newCoordinatorAddr); + s_testCoordinator.migrate(s_wrapperSubscriptionId, newCoordinatorAddr); // Request randomness from wrapper. uint32 callbackGasLimit = 1_000_000; diff --git a/contracts/src/v0.8/vrf/testhelpers/ChainSpecificUtilHelper.sol b/contracts/src/v0.8/vrf/testhelpers/ChainSpecificUtilHelper.sol index a594e02659f..16a157e3547 100644 --- a/contracts/src/v0.8/vrf/testhelpers/ChainSpecificUtilHelper.sol +++ b/contracts/src/v0.8/vrf/testhelpers/ChainSpecificUtilHelper.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../ChainSpecificUtil.sol"; +import {ChainSpecificUtil} from "../../ChainSpecificUtil_v0_8_6.sol"; /// @dev A helper contract that exposes ChainSpecificUtil methods for testing contract ChainSpecificUtilHelper { diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2LoadTestWithMetrics.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2LoadTestWithMetrics.sol index fa44b3eee30..b4d0104acee 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFV2LoadTestWithMetrics.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2LoadTestWithMetrics.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.0; import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; -import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; +import {ChainSpecificUtil} from "../../ChainSpecificUtil_v0_8_6.sol"; import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; /** diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2OwnerTestConsumer.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2OwnerTestConsumer.sol index 5961f4e5d49..8f1b275397c 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFV2OwnerTestConsumer.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2OwnerTestConsumer.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.0; import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; -import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; +import {ChainSpecificUtil} from "../../ChainSpecificUtil_v0_8_6.sol"; import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; contract VRFV2OwnerTestConsumer is VRFConsumerBaseV2, ConfirmedOwner { diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2RevertingExample.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2RevertingExample.sol index 4eccafa37ef..3d9cf30e34d 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFV2RevertingExample.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2RevertingExample.sol @@ -20,7 +20,7 @@ contract VRFV2RevertingExample is VRFConsumerBaseV2 { } function fulfillRandomWords(uint256, uint256[] memory) internal pure override { - // solhint-disable-next-line custom-errors, reason-string + // solhint-disable-next-line gas-custom-errors, reason-string revert(); } @@ -34,14 +34,14 @@ contract VRFV2RevertingExample is VRFConsumerBaseV2 { } function topUpSubscription(uint96 amount) external { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(s_subId != 0, "sub not set"); // Approve the link transfer. LINKTOKEN.transferAndCall(address(COORDINATOR), amount, abi.encode(s_subId)); } function updateSubscription(address[] memory consumers) external { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(s_subId != 0, "subID not set"); for (uint256 i = 0; i < consumers.length; i++) { COORDINATOR.addConsumer(s_subId, consumers[i]); diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperConsumerExample.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperConsumerExample.sol index 563a5b09288..924e3e4545c 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperConsumerExample.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperConsumerExample.sol @@ -33,7 +33,7 @@ contract VRFV2WrapperConsumerExample is VRFV2WrapperConsumerBase, ConfirmedOwner } function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(s_requests[_requestId].paid > 0, "request not found"); s_requests[_requestId].fulfilled = true; s_requests[_requestId].randomWords = _randomWords; @@ -43,7 +43,7 @@ contract VRFV2WrapperConsumerExample is VRFV2WrapperConsumerBase, ConfirmedOwner function getRequestStatus( uint256 _requestId ) external view returns (uint256 paid, bool fulfilled, uint256[] memory randomWords) { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(s_requests[_requestId].paid > 0, "request not found"); RequestStatus memory request = s_requests[_requestId]; return (request.paid, request.fulfilled, request.randomWords); diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperLoadTestConsumer.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperLoadTestConsumer.sol index 5a82d4b0b9d..202e3a09d51 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperLoadTestConsumer.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperLoadTestConsumer.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.6; import {VRFV2WrapperConsumerBase} from "../VRFV2WrapperConsumerBase.sol"; import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; -import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; +import {ChainSpecificUtil} from "../../ChainSpecificUtil_v0_8_6.sol"; import {VRFV2WrapperInterface} from "../interfaces/VRFV2WrapperInterface.sol"; contract VRFV2WrapperLoadTestConsumer is VRFV2WrapperConsumerBase, ConfirmedOwner { @@ -65,7 +65,7 @@ contract VRFV2WrapperLoadTestConsumer is VRFV2WrapperConsumerBase, ConfirmedOwne } function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(s_requests[_requestId].paid > 0, "request not found"); uint256 fulfilmentBlockNumber = ChainSpecificUtil._getBlockNumber(); uint256 requestDelay = fulfilmentBlockNumber - requestHeights[_requestId]; @@ -105,7 +105,7 @@ contract VRFV2WrapperLoadTestConsumer is VRFV2WrapperConsumerBase, ConfirmedOwne uint256 fulfilmentBlockNumber ) { - // solhint-disable-next-line custom-errors + // solhint-disable-next-line gas-custom-errors require(s_requests[_requestId].paid > 0, "request not found"); RequestStatus memory request = s_requests[_requestId]; return ( diff --git a/contracts/test/test-helpers/matchers.ts b/contracts/test/test-helpers/matchers.ts index 8daa673182d..1c4ee3b96e4 100644 --- a/contracts/test/test-helpers/matchers.ts +++ b/contracts/test/test-helpers/matchers.ts @@ -38,6 +38,25 @@ export async function evmRevert( } } +/** + * Check that an evm operation reverts + * + * @param action The asynchronous action to execute, which should cause an evm revert. + * @param contract The contract where the custom error is defined + * @param msg The failure message to display if the action __does not__ throw + */ +export async function evmRevertCustomError( + action: (() => Promise) | Promise, + contract: any, + msg?: string, +) { + if (msg) { + await expect(action).to.be.revertedWithCustomError(contract, msg) + } else { + await expect(action).to.be.reverted + } +} + /** * Assert that an event doesnt exist * diff --git a/contracts/test/v0.8/ChainlinkClient.test.ts b/contracts/test/v0.8/ChainlinkClient.test.ts index 20f0d08bc54..b483e890a6b 100644 --- a/contracts/test/v0.8/ChainlinkClient.test.ts +++ b/contracts/test/v0.8/ChainlinkClient.test.ts @@ -1,7 +1,7 @@ import { ethers } from 'hardhat' import { assert } from 'chai' import { Contract, ContractFactory } from 'ethers' -import { Roles, getUsers } from '../test-helpers/setup' +import { getUsers, Roles } from '../test-helpers/setup' import { convertFufillParams, decodeCCRequest, @@ -27,19 +27,19 @@ before(async () => { roles.defaultAccount, ) emptyOracleFactory = await ethers.getContractFactory( - 'src/v0.6/tests/EmptyOracle.sol:EmptyOracle', + 'src/v0.8/operatorforwarder/dev/test/testhelpers/EmptyOracle.sol:EmptyOracle', roles.defaultAccount, ) getterSetterFactory = await ethers.getContractFactory( - 'src/v0.5/tests/GetterSetter.sol:GetterSetter', + 'src/v0.8/operatorforwarder/dev/test/testhelpers/GetterSetter.sol:GetterSetter', roles.defaultAccount, ) operatorFactory = await ethers.getContractFactory( - 'src/v0.7/Operator.sol:Operator', + 'src/v0.8/operatorforwarder/dev/Operator.sol:Operator', roles.defaultAccount, ) linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', + 'src/v0.8/shared/test/helpers/LinkTokenTestHelper.sol:LinkTokenTestHelper', roles.defaultAccount, ) }) diff --git a/contracts/test/v0.8/Cron.test.ts b/contracts/test/v0.8/Cron.test.ts index 87d81e563b9..fadbb675ae2 100644 --- a/contracts/test/v0.8/Cron.test.ts +++ b/contracts/test/v0.8/Cron.test.ts @@ -62,7 +62,7 @@ describe('Cron', () => { await expect( cron.encodeCronString(input), `expected ${input} to be invalid`, - ).to.be.revertedWith('') + ).to.be.reverted } }) }) diff --git a/contracts/test/v0.8/HeartbeatRequester.test.ts b/contracts/test/v0.8/HeartbeatRequester.test.ts index 31425e29304..bb58192337d 100644 --- a/contracts/test/v0.8/HeartbeatRequester.test.ts +++ b/contracts/test/v0.8/HeartbeatRequester.test.ts @@ -102,7 +102,7 @@ describe('HeartbeatRequester', () => { requester .connect(caller1) .getAggregatorAndRequestHeartbeat(await owner.getAddress()), - ).to.be.revertedWith('HeartbeatNotPermitted()') + ).to.be.revertedWithCustomError(requester, 'HeartbeatNotPermitted') }) it('calls corresponding aggregator to request a new round', async () => { diff --git a/contracts/test/v0.8/dev/ArbitrumCrossDomainForwarder.test.ts b/contracts/test/v0.8/L2EP/ArbitrumCrossDomainForwarder.test.ts similarity index 100% rename from contracts/test/v0.8/dev/ArbitrumCrossDomainForwarder.test.ts rename to contracts/test/v0.8/L2EP/ArbitrumCrossDomainForwarder.test.ts diff --git a/contracts/test/v0.8/dev/ArbitrumCrossDomainGovernor.test.ts b/contracts/test/v0.8/L2EP/ArbitrumCrossDomainGovernor.test.ts similarity index 98% rename from contracts/test/v0.8/dev/ArbitrumCrossDomainGovernor.test.ts rename to contracts/test/v0.8/L2EP/ArbitrumCrossDomainGovernor.test.ts index 1275cc6f3fb..96e93e833ec 100644 --- a/contracts/test/v0.8/dev/ArbitrumCrossDomainGovernor.test.ts +++ b/contracts/test/v0.8/L2EP/ArbitrumCrossDomainGovernor.test.ts @@ -109,7 +109,7 @@ describe('ArbitrumCrossDomainGovernor', () => { it('should not be callable by unknown address', async () => { await expect( governor.connect(stranger).forward(greeter.address, '0x'), - ).to.be.revertedWith('Sender is not the L2 messenger') + ).to.be.revertedWith('Sender is not the L2 messenger or owner') }) it('should be callable by crossdomain messenger address / L1 owner', async () => { @@ -155,7 +155,7 @@ describe('ArbitrumCrossDomainGovernor', () => { it('should not be callable by unknown address', async () => { await expect( governor.connect(stranger).forwardDelegate(multisend.address, '0x'), - ).to.be.revertedWith('Sender is not the L2 messenger') + ).to.be.revertedWith('Sender is not the L2 messenger or owner') }) it('should be callable by crossdomain messenger address / L1 owner', async () => { diff --git a/contracts/test/v0.8/dev/ArbitrumSequencerUptimeFeed.test.ts b/contracts/test/v0.8/L2EP/ArbitrumSequencerUptimeFeed.test.ts similarity index 99% rename from contracts/test/v0.8/dev/ArbitrumSequencerUptimeFeed.test.ts rename to contracts/test/v0.8/L2EP/ArbitrumSequencerUptimeFeed.test.ts index 4d9ddefd5bf..5b101a34a31 100644 --- a/contracts/test/v0.8/dev/ArbitrumSequencerUptimeFeed.test.ts +++ b/contracts/test/v0.8/L2EP/ArbitrumSequencerUptimeFeed.test.ts @@ -184,9 +184,7 @@ describe('ArbitrumSequencerUptimeFeed', () => { tx = await arbitrumSequencerUptimeFeed .connect(l2Messenger) .updateStatus(false, staleTimestamp) - await expect(tx) - .to.not.emit(arbitrumSequencerUptimeFeed, 'AnswerUpdated') - .withArgs(1, 2 /** roundId */, timestamp) + await expect(tx).to.not.emit(arbitrumSequencerUptimeFeed, 'AnswerUpdated') await expect(tx).to.emit(arbitrumSequencerUptimeFeed, 'UpdateIgnored') }) }) diff --git a/contracts/test/v0.8/dev/ArbitrumValidator.test.ts b/contracts/test/v0.8/L2EP/ArbitrumValidator.test.ts similarity index 100% rename from contracts/test/v0.8/dev/ArbitrumValidator.test.ts rename to contracts/test/v0.8/L2EP/ArbitrumValidator.test.ts diff --git a/contracts/test/v0.8/dev/CrossDomainOwnable.test.ts b/contracts/test/v0.8/L2EP/CrossDomainOwnable.test.ts similarity index 100% rename from contracts/test/v0.8/dev/CrossDomainOwnable.test.ts rename to contracts/test/v0.8/L2EP/CrossDomainOwnable.test.ts diff --git a/contracts/test/v0.8/dev/OptimismCrossDomainForwarder.test.ts b/contracts/test/v0.8/L2EP/OptimismCrossDomainForwarder.test.ts similarity index 100% rename from contracts/test/v0.8/dev/OptimismCrossDomainForwarder.test.ts rename to contracts/test/v0.8/L2EP/OptimismCrossDomainForwarder.test.ts diff --git a/contracts/test/v0.8/dev/OptimismCrossDomainGovernor.test.ts b/contracts/test/v0.8/L2EP/OptimismCrossDomainGovernor.test.ts similarity index 98% rename from contracts/test/v0.8/dev/OptimismCrossDomainGovernor.test.ts rename to contracts/test/v0.8/L2EP/OptimismCrossDomainGovernor.test.ts index 9ea425bb995..7fbd0f9aa23 100644 --- a/contracts/test/v0.8/dev/OptimismCrossDomainGovernor.test.ts +++ b/contracts/test/v0.8/L2EP/OptimismCrossDomainGovernor.test.ts @@ -98,7 +98,7 @@ describe('OptimismCrossDomainGovernor', () => { it('should not be callable by unknown address', async () => { await expect( governor.connect(stranger).forward(greeter.address, '0x'), - ).to.be.revertedWith('Sender is not the L2 messenger') + ).to.be.revertedWith('Sender is not the L2 messenger or owner') }) it('should be callable by crossdomain messenger address / L1 owner', async () => { @@ -152,7 +152,7 @@ describe('OptimismCrossDomainGovernor', () => { it('should not be callable by unknown address', async () => { await expect( governor.connect(stranger).forwardDelegate(multisend.address, '0x'), - ).to.be.revertedWith('Sender is not the L2 messenger') + ).to.be.revertedWith('Sender is not the L2 messenger or owner') }) it('should be callable by crossdomain messenger address / L1 owner', async () => { diff --git a/contracts/test/v0.8/dev/OptimismSequencerUptimeFeed.test.ts b/contracts/test/v0.8/L2EP/OptimismSequencerUptimeFeed.test.ts similarity index 99% rename from contracts/test/v0.8/dev/OptimismSequencerUptimeFeed.test.ts rename to contracts/test/v0.8/L2EP/OptimismSequencerUptimeFeed.test.ts index 2856568793a..32e17b10770 100644 --- a/contracts/test/v0.8/dev/OptimismSequencerUptimeFeed.test.ts +++ b/contracts/test/v0.8/L2EP/OptimismSequencerUptimeFeed.test.ts @@ -195,9 +195,7 @@ describe('OptimismSequencerUptimeFeed', () => { tx = await optimismUptimeFeed .connect(l2Messenger) .updateStatus(false, staleTimestamp) - await expect(tx) - .to.not.emit(optimismUptimeFeed, 'AnswerUpdated') - .withArgs(1, 2 /** roundId */, timestamp) + await expect(tx).to.not.emit(optimismUptimeFeed, 'AnswerUpdated') await expect(tx).to.emit(optimismUptimeFeed, 'UpdateIgnored') }) }) diff --git a/contracts/test/v0.8/dev/OptimismValidator.test.ts b/contracts/test/v0.8/L2EP/OptimismValidator.test.ts similarity index 100% rename from contracts/test/v0.8/dev/OptimismValidator.test.ts rename to contracts/test/v0.8/L2EP/OptimismValidator.test.ts diff --git a/contracts/test/v0.8/dev/ScrollCrossDomainForwarder.test.ts b/contracts/test/v0.8/L2EP/ScrollCrossDomainForwarder.test.ts similarity index 100% rename from contracts/test/v0.8/dev/ScrollCrossDomainForwarder.test.ts rename to contracts/test/v0.8/L2EP/ScrollCrossDomainForwarder.test.ts diff --git a/contracts/test/v0.8/dev/ScrollCrossDomainGovernor.test.ts b/contracts/test/v0.8/L2EP/ScrollCrossDomainGovernor.test.ts similarity index 99% rename from contracts/test/v0.8/dev/ScrollCrossDomainGovernor.test.ts rename to contracts/test/v0.8/L2EP/ScrollCrossDomainGovernor.test.ts index adb78c26248..d2211145bb6 100644 --- a/contracts/test/v0.8/dev/ScrollCrossDomainGovernor.test.ts +++ b/contracts/test/v0.8/L2EP/ScrollCrossDomainGovernor.test.ts @@ -98,7 +98,7 @@ describe('ScrollCrossDomainGovernor', () => { it('should not be callable by unknown address', async () => { await expect( governor.connect(stranger).forward(greeter.address, '0x'), - ).to.be.revertedWith('Sender is not the L2 messenger') + ).to.be.revertedWith('Sender is not the L2 messenger or owner') }) it('should be callable by crossdomain messenger address / L1 owner', async () => { @@ -162,7 +162,7 @@ describe('ScrollCrossDomainGovernor', () => { it('should not be callable by unknown address', async () => { await expect( governor.connect(stranger).forwardDelegate(multisend.address, '0x'), - ).to.be.revertedWith('Sender is not the L2 messenger') + ).to.be.revertedWith('Sender is not the L2 messenger or owner') }) it('should be callable by crossdomain messenger address / L1 owner', async () => { diff --git a/contracts/test/v0.8/dev/ScrollSequencerUptimeFeed.test.ts b/contracts/test/v0.8/L2EP/ScrollSequencerUptimeFeed.test.ts similarity index 99% rename from contracts/test/v0.8/dev/ScrollSequencerUptimeFeed.test.ts rename to contracts/test/v0.8/L2EP/ScrollSequencerUptimeFeed.test.ts index 1d93497b9fa..d0fecf3b189 100644 --- a/contracts/test/v0.8/dev/ScrollSequencerUptimeFeed.test.ts +++ b/contracts/test/v0.8/L2EP/ScrollSequencerUptimeFeed.test.ts @@ -195,9 +195,7 @@ describe('ScrollSequencerUptimeFeed', () => { tx = await scrollUptimeFeed .connect(l2Messenger) .updateStatus(false, staleTimestamp) - await expect(tx) - .to.not.emit(scrollUptimeFeed, 'AnswerUpdated') - .withArgs(1, 2 /** roundId */, timestamp) + await expect(tx).to.not.emit(scrollUptimeFeed, 'AnswerUpdated') await expect(tx).to.emit(scrollUptimeFeed, 'UpdateIgnored') }) }) diff --git a/contracts/test/v0.8/dev/ScrollValidator.test.ts b/contracts/test/v0.8/L2EP/ScrollValidator.test.ts similarity index 100% rename from contracts/test/v0.8/dev/ScrollValidator.test.ts rename to contracts/test/v0.8/L2EP/ScrollValidator.test.ts diff --git a/contracts/test/v0.8/PermissionedForwardProxy.test.ts b/contracts/test/v0.8/PermissionedForwardProxy.test.ts index ef9129d7bd1..12ce63cd9b4 100644 --- a/contracts/test/v0.8/PermissionedForwardProxy.test.ts +++ b/contracts/test/v0.8/PermissionedForwardProxy.test.ts @@ -1,8 +1,8 @@ import { ethers } from 'hardhat' import { publicAbi } from '../test-helpers/helpers' -import { expect, assert } from 'chai' +import { assert, expect } from 'chai' import { Contract, ContractFactory } from 'ethers' -import { Personas, getUsers } from '../test-helpers/setup' +import { getUsers, Personas } from '../test-helpers/setup' const PERMISSION_NOT_SET = 'PermissionNotSet' @@ -129,7 +129,7 @@ describe('PermissionedForwardProxy', () => { controller .connect(personas.Carol) .forward(await personas.Eddy.getAddress(), '0x'), - ).to.be.revertedWith(PERMISSION_NOT_SET) + ).to.be.revertedWithCustomError(controller, PERMISSION_NOT_SET) }) }) diff --git a/contracts/test/v0.8/VRFD20.test.ts b/contracts/test/v0.8/VRFD20.test.ts deleted file mode 100644 index f1c1278b89a..00000000000 --- a/contracts/test/v0.8/VRFD20.test.ts +++ /dev/null @@ -1,303 +0,0 @@ -import { ethers } from 'hardhat' -import { assert, expect } from 'chai' -import { - BigNumber, - constants, - Contract, - ContractFactory, - ContractTransaction, -} from 'ethers' -import { getUsers, Personas, Roles } from '../test-helpers/setup' -import { - evmWordToAddress, - getLog, - publicAbi, - toBytes32String, - toWei, - numToBytes32, - getLogs, -} from '../test-helpers/helpers' - -let roles: Roles -let personas: Personas -let linkTokenFactory: ContractFactory -let vrfCoordinatorMockFactory: ContractFactory -let vrfD20Factory: ContractFactory - -before(async () => { - const users = await getUsers() - - roles = users.roles - personas = users.personas - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', - roles.defaultAccount, - ) - vrfCoordinatorMockFactory = await ethers.getContractFactory( - 'src/v0.8/vrf/mocks/VRFCoordinatorMock.sol:VRFCoordinatorMock', - roles.defaultAccount, - ) - vrfD20Factory = await ethers.getContractFactory( - 'src/v0.6/examples/VRFD20.sol:VRFD20', - roles.defaultAccount, - ) -}) - -describe('VRFD20', () => { - const deposit = toWei('1') - const fee = toWei('0.1') - const keyHash = toBytes32String('keyHash') - - let link: Contract - let vrfCoordinator: Contract - let vrfD20: Contract - - beforeEach(async () => { - link = await linkTokenFactory.connect(roles.defaultAccount).deploy() - vrfCoordinator = await vrfCoordinatorMockFactory - .connect(roles.defaultAccount) - .deploy(link.address) - vrfD20 = await vrfD20Factory - .connect(roles.defaultAccount) - .deploy(vrfCoordinator.address, link.address, keyHash, fee) - await link.transfer(vrfD20.address, deposit) - }) - - it('has a limited public interface [ @skip-coverage ]', () => { - publicAbi(vrfD20, [ - // Owned - 'acceptOwnership', - 'owner', - 'transferOwnership', - //VRFConsumerBase - 'rawFulfillRandomness', - // VRFD20 - 'rollDice', - 'house', - 'withdrawLINK', - 'keyHash', - 'fee', - 'setKeyHash', - 'setFee', - ]) - }) - - describe('#withdrawLINK', () => { - describe('failure', () => { - it('reverts when called by a non-owner', async () => { - await expect( - vrfD20 - .connect(roles.stranger) - .withdrawLINK(await roles.stranger.getAddress(), deposit), - ).to.be.revertedWith('Only callable by owner') - }) - - it('reverts when not enough LINK in the contract', async () => { - const withdrawAmount = deposit.mul(2) - await expect( - vrfD20 - .connect(roles.defaultAccount) - .withdrawLINK( - await roles.defaultAccount.getAddress(), - withdrawAmount, - ), - ).to.be.reverted - }) - }) - - describe('success', () => { - it('withdraws LINK', async () => { - const startingAmount = await link.balanceOf( - await roles.defaultAccount.getAddress(), - ) - const expectedAmount = BigNumber.from(startingAmount).add(deposit) - await vrfD20 - .connect(roles.defaultAccount) - .withdrawLINK(await roles.defaultAccount.getAddress(), deposit) - const actualAmount = await link.balanceOf( - await roles.defaultAccount.getAddress(), - ) - assert.equal(actualAmount.toString(), expectedAmount.toString()) - }) - }) - }) - - describe('#setKeyHash', () => { - const newHash = toBytes32String('newhash') - - describe('failure', () => { - it('reverts when called by a non-owner', async () => { - await expect( - vrfD20.connect(roles.stranger).setKeyHash(newHash), - ).to.be.revertedWith('Only callable by owner') - }) - }) - - describe('success', () => { - it('sets the key hash', async () => { - await vrfD20.setKeyHash(newHash) - const actualHash = await vrfD20.keyHash() - assert.equal(actualHash, newHash) - }) - }) - }) - - describe('#setFee', () => { - const newFee = 1234 - - describe('failure', () => { - it('reverts when called by a non-owner', async () => { - await expect( - vrfD20.connect(roles.stranger).setFee(newFee), - ).to.be.revertedWith('Only callable by owner') - }) - }) - - describe('success', () => { - it('sets the fee', async () => { - await vrfD20.setFee(newFee) - const actualFee = await vrfD20.fee() - assert.equal(actualFee.toString(), newFee.toString()) - }) - }) - }) - - describe('#house', () => { - describe('failure', () => { - it('reverts when dice not rolled', async () => { - await expect( - vrfD20.house(await personas.Nancy.getAddress()), - ).to.be.revertedWith('Dice not rolled') - }) - - it('reverts when dice roll is in progress', async () => { - await vrfD20.rollDice(await personas.Nancy.getAddress()) - await expect( - vrfD20.house(await personas.Nancy.getAddress()), - ).to.be.revertedWith('Roll in progress') - }) - }) - - describe('success', () => { - it('returns the correct house', async () => { - const randomness = 98765 - const expectedHouse = 'Martell' - const tx = await vrfD20.rollDice(await personas.Nancy.getAddress()) - const log = await getLog(tx, 3) - const eventRequestId = log?.topics?.[1] - await vrfCoordinator.callBackWithRandomness( - eventRequestId, - randomness, - vrfD20.address, - ) - const response = await vrfD20.house(await personas.Nancy.getAddress()) - assert.equal(response.toString(), expectedHouse) - }) - }) - }) - - describe('#rollDice', () => { - describe('success', () => { - let tx: ContractTransaction - beforeEach(async () => { - tx = await vrfD20.rollDice(await personas.Nancy.getAddress()) - }) - - it('emits a RandomnessRequest event from the VRFCoordinator', async () => { - const log = await getLog(tx, 2) - const topics = log?.topics - assert.equal(evmWordToAddress(topics?.[1]), vrfD20.address) - assert.equal(topics?.[2], keyHash) - assert.equal(topics?.[3], constants.HashZero) - }) - }) - - describe('failure', () => { - it('reverts when LINK balance is zero', async () => { - const vrfD202 = await vrfD20Factory - .connect(roles.defaultAccount) - .deploy(vrfCoordinator.address, link.address, keyHash, fee) - await expect( - vrfD202.rollDice(await personas.Nancy.getAddress()), - ).to.be.revertedWith('Not enough LINK to pay fee') - }) - - it('reverts when called by a non-owner', async () => { - await expect( - vrfD20 - .connect(roles.stranger) - .rollDice(await personas.Nancy.getAddress()), - ).to.be.revertedWith('Only callable by owner') - }) - - it('reverts when the roller rolls more than once', async () => { - await vrfD20.rollDice(await personas.Nancy.getAddress()) - await expect( - vrfD20.rollDice(await personas.Nancy.getAddress()), - ).to.be.revertedWith('Already rolled') - }) - }) - }) - - describe('#fulfillRandomness', () => { - const randomness = 98765 - const expectedModResult = (randomness % 20) + 1 - const expectedHouse = 'Martell' - let eventRequestId: string - beforeEach(async () => { - const tx = await vrfD20.rollDice(await personas.Nancy.getAddress()) - const log = await getLog(tx, 3) - eventRequestId = log?.topics?.[1] - }) - - describe('success', () => { - let tx: ContractTransaction - beforeEach(async () => { - tx = await vrfCoordinator.callBackWithRandomness( - eventRequestId, - randomness, - vrfD20.address, - ) - }) - - it('emits a DiceLanded event', async () => { - const log = await getLog(tx, 0) - assert.equal(log?.topics[1], eventRequestId) - assert.equal(log?.topics[2], numToBytes32(expectedModResult)) - }) - - it('sets the correct dice roll result', async () => { - const response = await vrfD20.house(await personas.Nancy.getAddress()) - assert.equal(response.toString(), expectedHouse) - }) - - it('allows someone else to roll', async () => { - const secondRandomness = 55555 - tx = await vrfD20.rollDice(await personas.Ned.getAddress()) - const log = await getLog(tx, 3) - eventRequestId = log?.topics?.[1] - tx = await vrfCoordinator.callBackWithRandomness( - eventRequestId, - secondRandomness, - vrfD20.address, - ) - }) - }) - - describe('failure', () => { - it('does not fulfill when fulfilled by the wrong VRFcoordinator', async () => { - const vrfCoordinator2 = await vrfCoordinatorMockFactory - .connect(roles.defaultAccount) - .deploy(link.address) - - const tx = await vrfCoordinator2.callBackWithRandomness( - eventRequestId, - randomness, - vrfD20.address, - ) - const logs = await getLogs(tx) - assert.equal(logs.length, 0) - }) - }) - }) -}) diff --git a/contracts/test/v0.8/automation/AutomationRegistrar2_1.test.ts b/contracts/test/v0.8/automation/AutomationRegistrar2_1.test.ts index b88911910c4..a096ee4f481 100644 --- a/contracts/test/v0.8/automation/AutomationRegistrar2_1.test.ts +++ b/contracts/test/v0.8/automation/AutomationRegistrar2_1.test.ts @@ -1,26 +1,13 @@ import { ethers } from 'hardhat' -import { assert, expect } from 'chai' -import { evmRevert } from '../../test-helpers/matchers' -import { getUsers, Personas } from '../../test-helpers/setup' -import { BigNumber, Signer } from 'ethers' -import { LinkToken__factory as LinkTokenFactory } from '../../../typechain/factories/LinkToken__factory' -import { MockV3Aggregator__factory as MockV3AggregatorFactory } from '../../../typechain/factories/MockV3Aggregator__factory' -import { UpkeepMock__factory as UpkeepMockFactory } from '../../../typechain/factories/UpkeepMock__factory' +import { assert } from 'chai' import { AutomationRegistrar2_1__factory as AutomationRegistrarFactory } from '../../../typechain/factories/AutomationRegistrar2_1__factory' -import { MockV3Aggregator } from '../../../typechain/MockV3Aggregator' -import { LinkToken } from '../../../typechain/LinkToken' -import { UpkeepMock } from '../../../typechain/UpkeepMock' -import { toWei } from '../../test-helpers/helpers' -import { IKeeperRegistryMaster as IKeeperRegistry } from '../../../typechain/IKeeperRegistryMaster' -import { AutomationRegistrar2_1 as Registrar } from '../../../typechain/AutomationRegistrar2_1' -import { deployRegistry21 } from './helpers' ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// /*********************************** REGISTRAR v2.1 IS FROZEN ************************************/ -// We are leaving the original tests enabled, however as 2.1 is still actively being deployed +// As 2.1 is still actively being deployed, we keep the tests below. describe('AutomationRegistrar2_1 - Frozen [ @skip-coverage ]', () => { it('has not changed', () => { @@ -34,1002 +21,1002 @@ describe('AutomationRegistrar2_1 - Frozen [ @skip-coverage ]', () => { ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// - -// copied from KeeperRegistryBase2_1.sol -enum Trigger { - CONDITION, - LOG, -} - -let linkTokenFactory: LinkTokenFactory -let mockV3AggregatorFactory: MockV3AggregatorFactory -let upkeepMockFactory: UpkeepMockFactory - -let personas: Personas - -before(async () => { - personas = (await getUsers()).personas - - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', - ) - mockV3AggregatorFactory = (await ethers.getContractFactory( - 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', - )) as unknown as MockV3AggregatorFactory - upkeepMockFactory = await ethers.getContractFactory('UpkeepMock') -}) - -const errorMsgs = { - onlyOwner: 'revert Only callable by owner', - onlyAdmin: 'OnlyAdminOrOwner()', - hashPayload: 'HashMismatch()', - requestNotFound: 'RequestNotFound()', -} - -describe('AutomationRegistrar2_1', () => { - const upkeepName = 'SampleUpkeep' - - const linkEth = BigNumber.from(300000000) - const gasWei = BigNumber.from(100) - const performGas = BigNumber.from(100000) - const paymentPremiumPPB = BigNumber.from(250000000) - const flatFeeMicroLink = BigNumber.from(0) - const maxAllowedAutoApprove = 5 - const trigger = '0xdeadbeef' - const offchainConfig = '0x01234567' - - const emptyBytes = '0x00' - const stalenessSeconds = BigNumber.from(43820) - const gasCeilingMultiplier = BigNumber.from(1) - const checkGasLimit = BigNumber.from(20000000) - const fallbackGasPrice = BigNumber.from(200) - const fallbackLinkPrice = BigNumber.from(200000000) - const maxCheckDataSize = BigNumber.from(10000) - const maxPerformDataSize = BigNumber.from(10000) - const maxRevertDataSize = BigNumber.from(1000) - const maxPerformGas = BigNumber.from(5000000) - const minUpkeepSpend = BigNumber.from('1000000000000000000') - const amount = BigNumber.from('5000000000000000000') - const amount1 = BigNumber.from('6000000000000000000') - const transcoder = ethers.constants.AddressZero - const upkeepManager = ethers.Wallet.createRandom().address - - // Enum values are not auto exported in ABI so have to manually declare - const autoApproveType_DISABLED = 0 - const autoApproveType_ENABLED_SENDER_ALLOWLIST = 1 - const autoApproveType_ENABLED_ALL = 2 - - let owner: Signer - let admin: Signer - let someAddress: Signer - let registrarOwner: Signer - let stranger: Signer - let requestSender: Signer - - let linkToken: LinkToken - let linkEthFeed: MockV3Aggregator - let gasPriceFeed: MockV3Aggregator - let mock: UpkeepMock - let registry: IKeeperRegistry - let registrar: Registrar - - beforeEach(async () => { - owner = personas.Default - admin = personas.Neil - someAddress = personas.Ned - registrarOwner = personas.Nelly - stranger = personas.Nancy - requestSender = personas.Norbert - - linkToken = await linkTokenFactory.connect(owner).deploy() - gasPriceFeed = await mockV3AggregatorFactory - .connect(owner) - .deploy(0, gasWei) - linkEthFeed = await mockV3AggregatorFactory - .connect(owner) - .deploy(9, linkEth) - - registry = await deployRegistry21( - owner, - 0, - linkToken.address, - linkEthFeed.address, - gasPriceFeed.address, - ) - - mock = await upkeepMockFactory.deploy() - - const registrarFactory = await ethers.getContractFactory( - 'AutomationRegistrar2_1', - ) - registrar = await registrarFactory - .connect(registrarOwner) - .deploy(linkToken.address, registry.address, minUpkeepSpend, [ - { - triggerType: Trigger.CONDITION, - autoApproveType: autoApproveType_DISABLED, - autoApproveMaxAllowed: 0, - }, - { - triggerType: Trigger.LOG, - autoApproveType: autoApproveType_DISABLED, - autoApproveMaxAllowed: 0, - }, - ]) - - await linkToken - .connect(owner) - .transfer(await requestSender.getAddress(), toWei('1000')) - - const keepers = [ - await personas.Carol.getAddress(), - await personas.Nancy.getAddress(), - await personas.Ned.getAddress(), - await personas.Neil.getAddress(), - ] - const onchainConfig = { - paymentPremiumPPB, - flatFeeMicroLink, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxCheckDataSize, - maxPerformDataSize, - maxRevertDataSize, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder, - registrars: [registrar.address], - upkeepPrivilegeManager: upkeepManager, - } - await registry - .connect(owner) - .setConfigTypeSafe(keepers, keepers, 1, onchainConfig, 1, '0x') - }) - - describe('#typeAndVersion', () => { - it('uses the correct type and version', async () => { - const typeAndVersion = await registrar.typeAndVersion() - assert.equal(typeAndVersion, 'AutomationRegistrar 2.1.0') - }) - }) - - describe('#register', () => { - it('reverts if not called by the LINK token', async () => { - await evmRevert( - registrar - .connect(someAddress) - .register( - upkeepName, - emptyBytes, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - amount, - await requestSender.getAddress(), - ), - 'OnlyLink()', - ) - }) - - it('reverts if the amount passed in data mismatches actual amount sent', async () => { - await registrar - .connect(registrarOwner) - .setTriggerConfig( - Trigger.CONDITION, - autoApproveType_ENABLED_ALL, - maxAllowedAutoApprove, - ) - - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - amount1, - await requestSender.getAddress(), - ], - ) - - await evmRevert( - linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes), - 'AmountMismatch()', - ) - }) - - it('reverts if the sender passed in data mismatches actual sender', async () => { - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - amount, - await admin.getAddress(), // Should have been requestSender.getAddress() - ], - ) - await evmRevert( - linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes), - 'SenderMismatch()', - ) - }) - - it('reverts if the admin address is 0x0000...', async () => { - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - performGas, - '0x0000000000000000000000000000000000000000', - 0, - emptyBytes, - trigger, - offchainConfig, - amount, - await requestSender.getAddress(), - ], - ) - - await evmRevert( - linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes), - 'RegistrationRequestFailed()', - ) - }) - - it('Auto Approve ON - registers an upkeep on KeeperRegistry instantly and emits both RegistrationRequested and RegistrationApproved events', async () => { - //set auto approve ON with high threshold limits - await registrar - .connect(registrarOwner) - .setTriggerConfig( - Trigger.CONDITION, - autoApproveType_ENABLED_ALL, - maxAllowedAutoApprove, - ) - - //register with auto approve ON - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - amount, - await requestSender.getAddress(), - ], - ) - const tx = await linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes) - - const [id] = await registry.getActiveUpkeepIDs(0, 1) - - //confirm if a new upkeep has been registered and the details are the same as the one just registered - const newupkeep = await registry.getUpkeep(id) - assert.equal(newupkeep.target, mock.address) - assert.equal(newupkeep.admin, await admin.getAddress()) - assert.equal(newupkeep.checkData, emptyBytes) - assert.equal(newupkeep.balance.toString(), amount.toString()) - assert.equal(newupkeep.performGas, performGas.toNumber()) - assert.equal(newupkeep.offchainConfig, offchainConfig) - - await expect(tx).to.emit(registrar, 'RegistrationRequested') - await expect(tx).to.emit(registrar, 'RegistrationApproved') - }) - - it('Auto Approve OFF - does not registers an upkeep on KeeperRegistry, emits only RegistrationRequested event', async () => { - //get upkeep count before attempting registration - const beforeCount = (await registry.getState()).state.numUpkeeps - - //set auto approve OFF, threshold limits dont matter in this case - await registrar - .connect(registrarOwner) - .setTriggerConfig( - Trigger.CONDITION, - autoApproveType_DISABLED, - maxAllowedAutoApprove, - ) - - //register with auto approve OFF - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - amount, - await requestSender.getAddress(), - ], - ) - const tx = await linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes) - const receipt = await tx.wait() - - //get upkeep count after attempting registration - const afterCount = (await registry.getState()).state.numUpkeeps - //confirm that a new upkeep has NOT been registered and upkeep count is still the same - assert.deepEqual(beforeCount, afterCount) - - //confirm that only RegistrationRequested event is emitted and RegistrationApproved event is not - await expect(tx).to.emit(registrar, 'RegistrationRequested') - await expect(tx).not.to.emit(registrar, 'RegistrationApproved') - - const hash = receipt.logs[2].topics[1] - const pendingRequest = await registrar.getPendingRequest(hash) - assert.equal(await admin.getAddress(), pendingRequest[0]) - assert.ok(amount.eq(pendingRequest[1])) - }) - - it('Auto Approve ON - Throttle max approvals - does not register an upkeep on KeeperRegistry beyond the max limit, emits only RegistrationRequested event after limit is hit', async () => { - assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 0) - - //set auto approve on, with max 1 allowed - await registrar - .connect(registrarOwner) - .setTriggerConfig(Trigger.CONDITION, autoApproveType_ENABLED_ALL, 1) - - //set auto approve on, with max 1 allowed - await registrar - .connect(registrarOwner) - .setTriggerConfig(Trigger.LOG, autoApproveType_ENABLED_ALL, 1) - - // register within threshold, new upkeep should be registered - let abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ - upkeepName, - emptyBytes, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - amount, - await requestSender.getAddress(), - ]) - await linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes) - assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 1) // 0 -> 1 - - // try registering another one, new upkeep should not be registered - abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ - upkeepName, - emptyBytes, - mock.address, - performGas.toNumber() + 1, // make unique hash - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - amount, - await requestSender.getAddress(), - ]) - await linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes) - assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 1) // Still 1 - - // register a second type of upkeep, different limit - abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ - upkeepName, - emptyBytes, - mock.address, - performGas, - await admin.getAddress(), - Trigger.LOG, - emptyBytes, - trigger, - offchainConfig, - amount, - await requestSender.getAddress(), - ]) - await linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes) - assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 2) // 1 -> 2 - - // Now set new max limit to 2. One more upkeep should get auto approved - await registrar - .connect(registrarOwner) - .setTriggerConfig(Trigger.CONDITION, autoApproveType_ENABLED_ALL, 2) - - abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ - upkeepName, - emptyBytes, - mock.address, - performGas.toNumber() + 2, // make unique hash - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - amount, - await requestSender.getAddress(), - ]) - await linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes) - assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 3) // 2 -> 3 - - // One more upkeep should not get registered - abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ - upkeepName, - emptyBytes, - mock.address, - performGas.toNumber() + 3, // make unique hash - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - amount, - await requestSender.getAddress(), - ]) - await linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes) - assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 3) // Still 3 - }) - - it('Auto Approve Sender Allowlist - sender in allowlist - registers an upkeep on KeeperRegistry instantly and emits both RegistrationRequested and RegistrationApproved events', async () => { - const senderAddress = await requestSender.getAddress() - - //set auto approve to ENABLED_SENDER_ALLOWLIST type with high threshold limits - await registrar - .connect(registrarOwner) - .setTriggerConfig( - Trigger.CONDITION, - autoApproveType_ENABLED_SENDER_ALLOWLIST, - maxAllowedAutoApprove, - ) - - // Add sender to allowlist - await registrar - .connect(registrarOwner) - .setAutoApproveAllowedSender(senderAddress, true) - - //register with auto approve ON - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - amount, - await requestSender.getAddress(), - ], - ) - const tx = await linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes) - - const [id] = await registry.getActiveUpkeepIDs(0, 1) - - //confirm if a new upkeep has been registered and the details are the same as the one just registered - const newupkeep = await registry.getUpkeep(id) - assert.equal(newupkeep.target, mock.address) - assert.equal(newupkeep.admin, await admin.getAddress()) - assert.equal(newupkeep.checkData, emptyBytes) - assert.equal(newupkeep.balance.toString(), amount.toString()) - assert.equal(newupkeep.performGas, performGas.toNumber()) - - await expect(tx).to.emit(registrar, 'RegistrationRequested') - await expect(tx).to.emit(registrar, 'RegistrationApproved') - }) - - it('Auto Approve Sender Allowlist - sender NOT in allowlist - does not registers an upkeep on KeeperRegistry, emits only RegistrationRequested event', async () => { - const beforeCount = (await registry.getState()).state.numUpkeeps - const senderAddress = await requestSender.getAddress() - - //set auto approve to ENABLED_SENDER_ALLOWLIST type with high threshold limits - await registrar - .connect(registrarOwner) - .setTriggerConfig( - Trigger.CONDITION, - autoApproveType_ENABLED_SENDER_ALLOWLIST, - maxAllowedAutoApprove, - ) - - // Explicitly remove sender from allowlist - await registrar - .connect(registrarOwner) - .setAutoApproveAllowedSender(senderAddress, false) - - //register. auto approve shouldn't happen - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - amount, - await requestSender.getAddress(), - ], - ) - const tx = await linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes) - const receipt = await tx.wait() - - //get upkeep count after attempting registration - const afterCount = (await registry.getState()).state.numUpkeeps - //confirm that a new upkeep has NOT been registered and upkeep count is still the same - assert.deepEqual(beforeCount, afterCount) - - //confirm that only RegistrationRequested event is emitted and RegistrationApproved event is not - await expect(tx).to.emit(registrar, 'RegistrationRequested') - await expect(tx).not.to.emit(registrar, 'RegistrationApproved') - - const hash = receipt.logs[2].topics[1] - const pendingRequest = await registrar.getPendingRequest(hash) - assert.equal(await admin.getAddress(), pendingRequest[0]) - assert.ok(amount.eq(pendingRequest[1])) - }) - }) - - describe('#registerUpkeep', () => { - it('reverts with empty message if amount sent is not available in LINK allowance', async () => { - await evmRevert( - registrar.connect(someAddress).registerUpkeep({ - name: upkeepName, - upkeepContract: mock.address, - gasLimit: performGas, - adminAddress: await admin.getAddress(), - triggerType: 0, - checkData: emptyBytes, - triggerConfig: trigger, - offchainConfig: emptyBytes, - amount, - encryptedEmail: emptyBytes, - }), - '', - ) - }) - - it('reverts if the amount passed in data is less than configured minimum', async () => { - await registrar - .connect(registrarOwner) - .setTriggerConfig( - Trigger.CONDITION, - autoApproveType_ENABLED_ALL, - maxAllowedAutoApprove, - ) - - // amt is one order of magnitude less than minUpkeepSpend - const amt = BigNumber.from('100000000000000000') - - await evmRevert( - registrar.connect(someAddress).registerUpkeep({ - name: upkeepName, - upkeepContract: mock.address, - gasLimit: performGas, - adminAddress: await admin.getAddress(), - triggerType: 0, - checkData: emptyBytes, - triggerConfig: trigger, - offchainConfig: emptyBytes, - amount: amt, - encryptedEmail: emptyBytes, - }), - 'InsufficientPayment()', - ) - }) - - it('Auto Approve ON - registers an upkeep on KeeperRegistry instantly and emits both RegistrationRequested and RegistrationApproved events', async () => { - //set auto approve ON with high threshold limits - await registrar - .connect(registrarOwner) - .setTriggerConfig( - Trigger.CONDITION, - autoApproveType_ENABLED_ALL, - maxAllowedAutoApprove, - ) - - await linkToken.connect(requestSender).approve(registrar.address, amount) - - const tx = await registrar.connect(requestSender).registerUpkeep({ - name: upkeepName, - upkeepContract: mock.address, - gasLimit: performGas, - adminAddress: await admin.getAddress(), - triggerType: 0, - checkData: emptyBytes, - triggerConfig: trigger, - offchainConfig, - amount, - encryptedEmail: emptyBytes, - }) - assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 1) // 0 -> 1 - - //confirm if a new upkeep has been registered and the details are the same as the one just registered - const [id] = await registry.getActiveUpkeepIDs(0, 1) - const newupkeep = await registry.getUpkeep(id) - assert.equal(newupkeep.target, mock.address) - assert.equal(newupkeep.admin, await admin.getAddress()) - assert.equal(newupkeep.checkData, emptyBytes) - assert.equal(newupkeep.balance.toString(), amount.toString()) - assert.equal(newupkeep.performGas, performGas.toNumber()) - assert.equal(newupkeep.offchainConfig, offchainConfig) - - await expect(tx).to.emit(registrar, 'RegistrationRequested') - await expect(tx).to.emit(registrar, 'RegistrationApproved') - }) - }) - - describe('#setAutoApproveAllowedSender', () => { - it('reverts if not called by the owner', async () => { - const tx = registrar - .connect(stranger) - .setAutoApproveAllowedSender(await admin.getAddress(), false) - await evmRevert(tx, 'Only callable by owner') - }) - - it('sets the allowed status correctly and emits log', async () => { - const senderAddress = await stranger.getAddress() - let tx = await registrar - .connect(registrarOwner) - .setAutoApproveAllowedSender(senderAddress, true) - await expect(tx) - .to.emit(registrar, 'AutoApproveAllowedSenderSet') - .withArgs(senderAddress, true) - - let senderAllowedStatus = await registrar - .connect(owner) - .getAutoApproveAllowedSender(senderAddress) - assert.isTrue(senderAllowedStatus) - - tx = await registrar - .connect(registrarOwner) - .setAutoApproveAllowedSender(senderAddress, false) - await expect(tx) - .to.emit(registrar, 'AutoApproveAllowedSenderSet') - .withArgs(senderAddress, false) - - senderAllowedStatus = await registrar - .connect(owner) - .getAutoApproveAllowedSender(senderAddress) - assert.isFalse(senderAllowedStatus) - }) - }) - - describe('#setTriggerConfig', () => { - it('reverts if not called by the owner', async () => { - const tx = registrar - .connect(stranger) - .setTriggerConfig(Trigger.LOG, autoApproveType_ENABLED_ALL, 100) - await evmRevert(tx, 'Only callable by owner') - }) - - it('changes the config', async () => { - const tx = await registrar - .connect(registrarOwner) - .setTriggerConfig(Trigger.LOG, autoApproveType_ENABLED_ALL, 100) - await registrar.getTriggerRegistrationDetails(Trigger.LOG) - await expect(tx) - .to.emit(registrar, 'TriggerConfigSet') - .withArgs(Trigger.LOG, autoApproveType_ENABLED_ALL, 100) - }) - }) - - describe('#approve', () => { - let hash: string - - beforeEach(async () => { - await registrar - .connect(registrarOwner) - .setTriggerConfig( - Trigger.CONDITION, - autoApproveType_DISABLED, - maxAllowedAutoApprove, - ) - - //register with auto approve OFF - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - amount, - await requestSender.getAddress(), - ], - ) - - const tx = await linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes) - const receipt = await tx.wait() - hash = receipt.logs[2].topics[1] - }) - - it('reverts if not called by the owner', async () => { - const tx = registrar - .connect(stranger) - .approve( - upkeepName, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - emptyBytes, - hash, - ) - await evmRevert(tx, 'Only callable by owner') - }) - - it('reverts if the hash does not exist', async () => { - const tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - emptyBytes, - '0x000000000000000000000000322813fd9a801c5507c9de605d63cea4f2ce6c44', - ) - await evmRevert(tx, errorMsgs.requestNotFound) - }) - - it('reverts if any member of the payload changes', async () => { - let tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - ethers.Wallet.createRandom().address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - emptyBytes, - hash, - ) - await evmRevert(tx, errorMsgs.hashPayload) - tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - 10000, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - emptyBytes, - hash, - ) - await evmRevert(tx, errorMsgs.hashPayload) - tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - performGas, - ethers.Wallet.createRandom().address, - 0, - emptyBytes, - trigger, - emptyBytes, - hash, - ) - await evmRevert(tx, errorMsgs.hashPayload) - tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - performGas, - await admin.getAddress(), - 0, - '0x1234', - trigger, - emptyBytes, - hash, - ) - await evmRevert(tx, errorMsgs.hashPayload) - }) - - it('approves an existing registration request', async () => { - const tx = await registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - hash, - ) - await expect(tx).to.emit(registrar, 'RegistrationApproved') - }) - - it('deletes the request afterwards / reverts if the request DNE', async () => { - await registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - hash, - ) - const tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - hash, - ) - await evmRevert(tx, errorMsgs.requestNotFound) - }) - }) - - describe('#cancel', () => { - let hash: string - - beforeEach(async () => { - await registrar - .connect(registrarOwner) - .setTriggerConfig( - Trigger.CONDITION, - autoApproveType_DISABLED, - maxAllowedAutoApprove, - ) - - //register with auto approve OFF - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - amount, - await requestSender.getAddress(), - ], - ) - const tx = await linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes) - const receipt = await tx.wait() - hash = receipt.logs[2].topics[1] - // submit duplicate request (increase balance) - await linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes) - }) - - it('reverts if not called by the admin / owner', async () => { - const tx = registrar.connect(stranger).cancel(hash) - await evmRevert(tx, errorMsgs.onlyAdmin) - }) - - it('reverts if the hash does not exist', async () => { - const tx = registrar - .connect(registrarOwner) - .cancel( - '0x000000000000000000000000322813fd9a801c5507c9de605d63cea4f2ce6c44', - ) - await evmRevert(tx, errorMsgs.requestNotFound) - }) - - it('refunds the total request balance to the admin address if owner cancels', async () => { - const before = await linkToken.balanceOf(await admin.getAddress()) - const tx = await registrar.connect(registrarOwner).cancel(hash) - const after = await linkToken.balanceOf(await admin.getAddress()) - assert.isTrue(after.sub(before).eq(amount.mul(BigNumber.from(2)))) - await expect(tx).to.emit(registrar, 'RegistrationRejected') - }) - - it('refunds the total request balance to the admin address if admin cancels', async () => { - const before = await linkToken.balanceOf(await admin.getAddress()) - const tx = await registrar.connect(admin).cancel(hash) - const after = await linkToken.balanceOf(await admin.getAddress()) - assert.isTrue(after.sub(before).eq(amount.mul(BigNumber.from(2)))) - await expect(tx).to.emit(registrar, 'RegistrationRejected') - }) - - it('deletes the request hash', async () => { - await registrar.connect(registrarOwner).cancel(hash) - let tx = registrar.connect(registrarOwner).cancel(hash) - await evmRevert(tx, errorMsgs.requestNotFound) - tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - emptyBytes, - hash, - ) - await evmRevert(tx, errorMsgs.requestNotFound) - }) - }) -}) +// +// // copied from KeeperRegistryBase2_1.sol +// enum Trigger { +// CONDITION, +// LOG, +// } +// +// let linkTokenFactory: LinkTokenFactory +// let mockV3AggregatorFactory: MockV3AggregatorFactory +// let upkeepMockFactory: UpkeepMockFactory +// +// let personas: Personas +// +// before(async () => { +// personas = (await getUsers()).personas +// +// linkTokenFactory = await ethers.getContractFactory( +// 'src/v0.8/shared/test/helpers/LinkTokenTestHelper.sol:LinkTokenTestHelper', +// ) +// mockV3AggregatorFactory = (await ethers.getContractFactory( +// 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', +// )) as unknown as MockV3AggregatorFactory +// upkeepMockFactory = await ethers.getContractFactory('UpkeepMock') +// }) +// +// const errorMsgs = { +// onlyOwner: 'revert Only callable by owner', +// onlyAdmin: 'OnlyAdminOrOwner()', +// hashPayload: 'HashMismatch()', +// requestNotFound: 'RequestNotFound()', +// } +// +// describe('AutomationRegistrar2_1', () => { +// const upkeepName = 'SampleUpkeep' +// +// const linkEth = BigNumber.from(300000000) +// const gasWei = BigNumber.from(100) +// const performGas = BigNumber.from(100000) +// const paymentPremiumPPB = BigNumber.from(250000000) +// const flatFeeMicroLink = BigNumber.from(0) +// const maxAllowedAutoApprove = 5 +// const trigger = '0xdeadbeef' +// const offchainConfig = '0x01234567' +// +// const emptyBytes = '0x00' +// const stalenessSeconds = BigNumber.from(43820) +// const gasCeilingMultiplier = BigNumber.from(1) +// const checkGasLimit = BigNumber.from(20000000) +// const fallbackGasPrice = BigNumber.from(200) +// const fallbackLinkPrice = BigNumber.from(200000000) +// const maxCheckDataSize = BigNumber.from(10000) +// const maxPerformDataSize = BigNumber.from(10000) +// const maxRevertDataSize = BigNumber.from(1000) +// const maxPerformGas = BigNumber.from(5000000) +// const minUpkeepSpend = BigNumber.from('1000000000000000000') +// const amount = BigNumber.from('5000000000000000000') +// const amount1 = BigNumber.from('6000000000000000000') +// const transcoder = ethers.constants.AddressZero +// const upkeepManager = ethers.Wallet.createRandom().address +// +// // Enum values are not auto exported in ABI so have to manually declare +// const autoApproveType_DISABLED = 0 +// const autoApproveType_ENABLED_SENDER_ALLOWLIST = 1 +// const autoApproveType_ENABLED_ALL = 2 +// +// let owner: Signer +// let admin: Signer +// let someAddress: Signer +// let registrarOwner: Signer +// let stranger: Signer +// let requestSender: Signer +// +// let linkToken: LinkToken +// let linkEthFeed: MockV3Aggregator +// let gasPriceFeed: MockV3Aggregator +// let mock: UpkeepMock +// let registry: IKeeperRegistry +// let registrar: Registrar +// +// beforeEach(async () => { +// owner = personas.Default +// admin = personas.Neil +// someAddress = personas.Ned +// registrarOwner = personas.Nelly +// stranger = personas.Nancy +// requestSender = personas.Norbert +// +// linkToken = await linkTokenFactory.connect(owner).deploy() +// gasPriceFeed = await mockV3AggregatorFactory +// .connect(owner) +// .deploy(0, gasWei) +// linkEthFeed = await mockV3AggregatorFactory +// .connect(owner) +// .deploy(9, linkEth) +// +// registry = await deployRegistry21( +// owner, +// 0, +// linkToken.address, +// linkEthFeed.address, +// gasPriceFeed.address, +// ) +// +// mock = await upkeepMockFactory.deploy() +// +// const registrarFactory = await ethers.getContractFactory( +// 'AutomationRegistrar2_1', +// ) +// registrar = await registrarFactory +// .connect(registrarOwner) +// .deploy(linkToken.address, registry.address, minUpkeepSpend, [ +// { +// triggerType: Trigger.CONDITION, +// autoApproveType: autoApproveType_DISABLED, +// autoApproveMaxAllowed: 0, +// }, +// { +// triggerType: Trigger.LOG, +// autoApproveType: autoApproveType_DISABLED, +// autoApproveMaxAllowed: 0, +// }, +// ]) +// +// await linkToken +// .connect(owner) +// .transfer(await requestSender.getAddress(), toWei('1000')) +// +// const keepers = [ +// await personas.Carol.getAddress(), +// await personas.Nancy.getAddress(), +// await personas.Ned.getAddress(), +// await personas.Neil.getAddress(), +// ] +// const onchainConfig = { +// paymentPremiumPPB, +// flatFeeMicroLink, +// checkGasLimit, +// stalenessSeconds, +// gasCeilingMultiplier, +// minUpkeepSpend, +// maxCheckDataSize, +// maxPerformDataSize, +// maxRevertDataSize, +// maxPerformGas, +// fallbackGasPrice, +// fallbackLinkPrice, +// transcoder, +// registrars: [registrar.address], +// upkeepPrivilegeManager: upkeepManager, +// } +// await registry +// .connect(owner) +// .setConfigTypeSafe(keepers, keepers, 1, onchainConfig, 1, '0x') +// }) +// +// describe('#typeAndVersion', () => { +// it('uses the correct type and version', async () => { +// const typeAndVersion = await registrar.typeAndVersion() +// assert.equal(typeAndVersion, 'AutomationRegistrar 2.1.0') +// }) +// }) +// +// describe('#register', () => { +// it('reverts if not called by the LINK token', async () => { +// await evmRevert( +// registrar +// .connect(someAddress) +// .register( +// upkeepName, +// emptyBytes, +// mock.address, +// performGas, +// await admin.getAddress(), +// 0, +// emptyBytes, +// trigger, +// offchainConfig, +// amount, +// await requestSender.getAddress(), +// ), +// 'OnlyLink()', +// ) +// }) +// +// it('reverts if the amount passed in data mismatches actual amount sent', async () => { +// await registrar +// .connect(registrarOwner) +// .setTriggerConfig( +// Trigger.CONDITION, +// autoApproveType_ENABLED_ALL, +// maxAllowedAutoApprove, +// ) +// +// const abiEncodedBytes = registrar.interface.encodeFunctionData( +// 'register', +// [ +// upkeepName, +// emptyBytes, +// mock.address, +// performGas, +// await admin.getAddress(), +// 0, +// emptyBytes, +// trigger, +// offchainConfig, +// amount1, +// await requestSender.getAddress(), +// ], +// ) +// +// await evmRevert( +// linkToken +// .connect(requestSender) +// .transferAndCall(registrar.address, amount, abiEncodedBytes), +// 'AmountMismatch()', +// ) +// }) +// +// it('reverts if the sender passed in data mismatches actual sender', async () => { +// const abiEncodedBytes = registrar.interface.encodeFunctionData( +// 'register', +// [ +// upkeepName, +// emptyBytes, +// mock.address, +// performGas, +// await admin.getAddress(), +// 0, +// emptyBytes, +// trigger, +// offchainConfig, +// amount, +// await admin.getAddress(), // Should have been requestSender.getAddress() +// ], +// ) +// await evmRevert( +// linkToken +// .connect(requestSender) +// .transferAndCall(registrar.address, amount, abiEncodedBytes), +// 'SenderMismatch()', +// ) +// }) +// +// it('reverts if the admin address is 0x0000...', async () => { +// const abiEncodedBytes = registrar.interface.encodeFunctionData( +// 'register', +// [ +// upkeepName, +// emptyBytes, +// mock.address, +// performGas, +// '0x0000000000000000000000000000000000000000', +// 0, +// emptyBytes, +// trigger, +// offchainConfig, +// amount, +// await requestSender.getAddress(), +// ], +// ) +// +// await evmRevert( +// linkToken +// .connect(requestSender) +// .transferAndCall(registrar.address, amount, abiEncodedBytes), +// 'RegistrationRequestFailed()', +// ) +// }) +// +// it('Auto Approve ON - registers an upkeep on KeeperRegistry instantly and emits both RegistrationRequested and RegistrationApproved events', async () => { +// //set auto approve ON with high threshold limits +// await registrar +// .connect(registrarOwner) +// .setTriggerConfig( +// Trigger.CONDITION, +// autoApproveType_ENABLED_ALL, +// maxAllowedAutoApprove, +// ) +// +// //register with auto approve ON +// const abiEncodedBytes = registrar.interface.encodeFunctionData( +// 'register', +// [ +// upkeepName, +// emptyBytes, +// mock.address, +// performGas, +// await admin.getAddress(), +// 0, +// emptyBytes, +// trigger, +// offchainConfig, +// amount, +// await requestSender.getAddress(), +// ], +// ) +// const tx = await linkToken +// .connect(requestSender) +// .transferAndCall(registrar.address, amount, abiEncodedBytes) +// +// const [id] = await registry.getActiveUpkeepIDs(0, 1) +// +// //confirm if a new upkeep has been registered and the details are the same as the one just registered +// const newupkeep = await registry.getUpkeep(id) +// assert.equal(newupkeep.target, mock.address) +// assert.equal(newupkeep.admin, await admin.getAddress()) +// assert.equal(newupkeep.checkData, emptyBytes) +// assert.equal(newupkeep.balance.toString(), amount.toString()) +// assert.equal(newupkeep.performGas, performGas.toNumber()) +// assert.equal(newupkeep.offchainConfig, offchainConfig) +// +// await expect(tx).to.emit(registrar, 'RegistrationRequested') +// await expect(tx).to.emit(registrar, 'RegistrationApproved') +// }) +// +// it('Auto Approve OFF - does not registers an upkeep on KeeperRegistry, emits only RegistrationRequested event', async () => { +// //get upkeep count before attempting registration +// const beforeCount = (await registry.getState()).state.numUpkeeps +// +// //set auto approve OFF, threshold limits dont matter in this case +// await registrar +// .connect(registrarOwner) +// .setTriggerConfig( +// Trigger.CONDITION, +// autoApproveType_DISABLED, +// maxAllowedAutoApprove, +// ) +// +// //register with auto approve OFF +// const abiEncodedBytes = registrar.interface.encodeFunctionData( +// 'register', +// [ +// upkeepName, +// emptyBytes, +// mock.address, +// performGas, +// await admin.getAddress(), +// 0, +// emptyBytes, +// trigger, +// offchainConfig, +// amount, +// await requestSender.getAddress(), +// ], +// ) +// const tx = await linkToken +// .connect(requestSender) +// .transferAndCall(registrar.address, amount, abiEncodedBytes) +// const receipt = await tx.wait() +// +// //get upkeep count after attempting registration +// const afterCount = (await registry.getState()).state.numUpkeeps +// //confirm that a new upkeep has NOT been registered and upkeep count is still the same +// assert.deepEqual(beforeCount, afterCount) +// +// //confirm that only RegistrationRequested event is emitted and RegistrationApproved event is not +// await expect(tx).to.emit(registrar, 'RegistrationRequested') +// await expect(tx).not.to.emit(registrar, 'RegistrationApproved') +// +// const hash = receipt.logs[2].topics[1] +// const pendingRequest = await registrar.getPendingRequest(hash) +// assert.equal(await admin.getAddress(), pendingRequest[0]) +// assert.ok(amount.eq(pendingRequest[1])) +// }) +// +// it('Auto Approve ON - Throttle max approvals - does not register an upkeep on KeeperRegistry beyond the max limit, emits only RegistrationRequested event after limit is hit', async () => { +// assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 0) +// +// //set auto approve on, with max 1 allowed +// await registrar +// .connect(registrarOwner) +// .setTriggerConfig(Trigger.CONDITION, autoApproveType_ENABLED_ALL, 1) +// +// //set auto approve on, with max 1 allowed +// await registrar +// .connect(registrarOwner) +// .setTriggerConfig(Trigger.LOG, autoApproveType_ENABLED_ALL, 1) +// +// // register within threshold, new upkeep should be registered +// let abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ +// upkeepName, +// emptyBytes, +// mock.address, +// performGas, +// await admin.getAddress(), +// 0, +// emptyBytes, +// trigger, +// offchainConfig, +// amount, +// await requestSender.getAddress(), +// ]) +// await linkToken +// .connect(requestSender) +// .transferAndCall(registrar.address, amount, abiEncodedBytes) +// assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 1) // 0 -> 1 +// +// // try registering another one, new upkeep should not be registered +// abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ +// upkeepName, +// emptyBytes, +// mock.address, +// performGas.toNumber() + 1, // make unique hash +// await admin.getAddress(), +// 0, +// emptyBytes, +// trigger, +// offchainConfig, +// amount, +// await requestSender.getAddress(), +// ]) +// await linkToken +// .connect(requestSender) +// .transferAndCall(registrar.address, amount, abiEncodedBytes) +// assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 1) // Still 1 +// +// // register a second type of upkeep, different limit +// abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ +// upkeepName, +// emptyBytes, +// mock.address, +// performGas, +// await admin.getAddress(), +// Trigger.LOG, +// emptyBytes, +// trigger, +// offchainConfig, +// amount, +// await requestSender.getAddress(), +// ]) +// await linkToken +// .connect(requestSender) +// .transferAndCall(registrar.address, amount, abiEncodedBytes) +// assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 2) // 1 -> 2 +// +// // Now set new max limit to 2. One more upkeep should get auto approved +// await registrar +// .connect(registrarOwner) +// .setTriggerConfig(Trigger.CONDITION, autoApproveType_ENABLED_ALL, 2) +// +// abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ +// upkeepName, +// emptyBytes, +// mock.address, +// performGas.toNumber() + 2, // make unique hash +// await admin.getAddress(), +// 0, +// emptyBytes, +// trigger, +// offchainConfig, +// amount, +// await requestSender.getAddress(), +// ]) +// await linkToken +// .connect(requestSender) +// .transferAndCall(registrar.address, amount, abiEncodedBytes) +// assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 3) // 2 -> 3 +// +// // One more upkeep should not get registered +// abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ +// upkeepName, +// emptyBytes, +// mock.address, +// performGas.toNumber() + 3, // make unique hash +// await admin.getAddress(), +// 0, +// emptyBytes, +// trigger, +// offchainConfig, +// amount, +// await requestSender.getAddress(), +// ]) +// await linkToken +// .connect(requestSender) +// .transferAndCall(registrar.address, amount, abiEncodedBytes) +// assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 3) // Still 3 +// }) +// +// it('Auto Approve Sender Allowlist - sender in allowlist - registers an upkeep on KeeperRegistry instantly and emits both RegistrationRequested and RegistrationApproved events', async () => { +// const senderAddress = await requestSender.getAddress() +// +// //set auto approve to ENABLED_SENDER_ALLOWLIST type with high threshold limits +// await registrar +// .connect(registrarOwner) +// .setTriggerConfig( +// Trigger.CONDITION, +// autoApproveType_ENABLED_SENDER_ALLOWLIST, +// maxAllowedAutoApprove, +// ) +// +// // Add sender to allowlist +// await registrar +// .connect(registrarOwner) +// .setAutoApproveAllowedSender(senderAddress, true) +// +// //register with auto approve ON +// const abiEncodedBytes = registrar.interface.encodeFunctionData( +// 'register', +// [ +// upkeepName, +// emptyBytes, +// mock.address, +// performGas, +// await admin.getAddress(), +// 0, +// emptyBytes, +// trigger, +// offchainConfig, +// amount, +// await requestSender.getAddress(), +// ], +// ) +// const tx = await linkToken +// .connect(requestSender) +// .transferAndCall(registrar.address, amount, abiEncodedBytes) +// +// const [id] = await registry.getActiveUpkeepIDs(0, 1) +// +// //confirm if a new upkeep has been registered and the details are the same as the one just registered +// const newupkeep = await registry.getUpkeep(id) +// assert.equal(newupkeep.target, mock.address) +// assert.equal(newupkeep.admin, await admin.getAddress()) +// assert.equal(newupkeep.checkData, emptyBytes) +// assert.equal(newupkeep.balance.toString(), amount.toString()) +// assert.equal(newupkeep.performGas, performGas.toNumber()) +// +// await expect(tx).to.emit(registrar, 'RegistrationRequested') +// await expect(tx).to.emit(registrar, 'RegistrationApproved') +// }) +// +// it('Auto Approve Sender Allowlist - sender NOT in allowlist - does not registers an upkeep on KeeperRegistry, emits only RegistrationRequested event', async () => { +// const beforeCount = (await registry.getState()).state.numUpkeeps +// const senderAddress = await requestSender.getAddress() +// +// //set auto approve to ENABLED_SENDER_ALLOWLIST type with high threshold limits +// await registrar +// .connect(registrarOwner) +// .setTriggerConfig( +// Trigger.CONDITION, +// autoApproveType_ENABLED_SENDER_ALLOWLIST, +// maxAllowedAutoApprove, +// ) +// +// // Explicitly remove sender from allowlist +// await registrar +// .connect(registrarOwner) +// .setAutoApproveAllowedSender(senderAddress, false) +// +// //register. auto approve shouldn't happen +// const abiEncodedBytes = registrar.interface.encodeFunctionData( +// 'register', +// [ +// upkeepName, +// emptyBytes, +// mock.address, +// performGas, +// await admin.getAddress(), +// 0, +// emptyBytes, +// trigger, +// offchainConfig, +// amount, +// await requestSender.getAddress(), +// ], +// ) +// const tx = await linkToken +// .connect(requestSender) +// .transferAndCall(registrar.address, amount, abiEncodedBytes) +// const receipt = await tx.wait() +// +// //get upkeep count after attempting registration +// const afterCount = (await registry.getState()).state.numUpkeeps +// //confirm that a new upkeep has NOT been registered and upkeep count is still the same +// assert.deepEqual(beforeCount, afterCount) +// +// //confirm that only RegistrationRequested event is emitted and RegistrationApproved event is not +// await expect(tx).to.emit(registrar, 'RegistrationRequested') +// await expect(tx).not.to.emit(registrar, 'RegistrationApproved') +// +// const hash = receipt.logs[2].topics[1] +// const pendingRequest = await registrar.getPendingRequest(hash) +// assert.equal(await admin.getAddress(), pendingRequest[0]) +// assert.ok(amount.eq(pendingRequest[1])) +// }) +// }) +// +// describe('#registerUpkeep', () => { +// it('reverts with empty message if amount sent is not available in LINK allowance', async () => { +// await evmRevert( +// registrar.connect(someAddress).registerUpkeep({ +// name: upkeepName, +// upkeepContract: mock.address, +// gasLimit: performGas, +// adminAddress: await admin.getAddress(), +// triggerType: 0, +// checkData: emptyBytes, +// triggerConfig: trigger, +// offchainConfig: emptyBytes, +// amount, +// encryptedEmail: emptyBytes, +// }), +// '', +// ) +// }) +// +// it('reverts if the amount passed in data is less than configured minimum', async () => { +// await registrar +// .connect(registrarOwner) +// .setTriggerConfig( +// Trigger.CONDITION, +// autoApproveType_ENABLED_ALL, +// maxAllowedAutoApprove, +// ) +// +// // amt is one order of magnitude less than minUpkeepSpend +// const amt = BigNumber.from('100000000000000000') +// +// await evmRevert( +// registrar.connect(someAddress).registerUpkeep({ +// name: upkeepName, +// upkeepContract: mock.address, +// gasLimit: performGas, +// adminAddress: await admin.getAddress(), +// triggerType: 0, +// checkData: emptyBytes, +// triggerConfig: trigger, +// offchainConfig: emptyBytes, +// amount: amt, +// encryptedEmail: emptyBytes, +// }), +// 'InsufficientPayment()', +// ) +// }) +// +// it('Auto Approve ON - registers an upkeep on KeeperRegistry instantly and emits both RegistrationRequested and RegistrationApproved events', async () => { +// //set auto approve ON with high threshold limits +// await registrar +// .connect(registrarOwner) +// .setTriggerConfig( +// Trigger.CONDITION, +// autoApproveType_ENABLED_ALL, +// maxAllowedAutoApprove, +// ) +// +// await linkToken.connect(requestSender).approve(registrar.address, amount) +// +// const tx = await registrar.connect(requestSender).registerUpkeep({ +// name: upkeepName, +// upkeepContract: mock.address, +// gasLimit: performGas, +// adminAddress: await admin.getAddress(), +// triggerType: 0, +// checkData: emptyBytes, +// triggerConfig: trigger, +// offchainConfig, +// amount, +// encryptedEmail: emptyBytes, +// }) +// assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 1) // 0 -> 1 +// +// //confirm if a new upkeep has been registered and the details are the same as the one just registered +// const [id] = await registry.getActiveUpkeepIDs(0, 1) +// const newupkeep = await registry.getUpkeep(id) +// assert.equal(newupkeep.target, mock.address) +// assert.equal(newupkeep.admin, await admin.getAddress()) +// assert.equal(newupkeep.checkData, emptyBytes) +// assert.equal(newupkeep.balance.toString(), amount.toString()) +// assert.equal(newupkeep.performGas, performGas.toNumber()) +// assert.equal(newupkeep.offchainConfig, offchainConfig) +// +// await expect(tx).to.emit(registrar, 'RegistrationRequested') +// await expect(tx).to.emit(registrar, 'RegistrationApproved') +// }) +// }) +// +// describe('#setAutoApproveAllowedSender', () => { +// it('reverts if not called by the owner', async () => { +// const tx = registrar +// .connect(stranger) +// .setAutoApproveAllowedSender(await admin.getAddress(), false) +// await evmRevert(tx, 'Only callable by owner') +// }) +// +// it('sets the allowed status correctly and emits log', async () => { +// const senderAddress = await stranger.getAddress() +// let tx = await registrar +// .connect(registrarOwner) +// .setAutoApproveAllowedSender(senderAddress, true) +// await expect(tx) +// .to.emit(registrar, 'AutoApproveAllowedSenderSet') +// .withArgs(senderAddress, true) +// +// let senderAllowedStatus = await registrar +// .connect(owner) +// .getAutoApproveAllowedSender(senderAddress) +// assert.isTrue(senderAllowedStatus) +// +// tx = await registrar +// .connect(registrarOwner) +// .setAutoApproveAllowedSender(senderAddress, false) +// await expect(tx) +// .to.emit(registrar, 'AutoApproveAllowedSenderSet') +// .withArgs(senderAddress, false) +// +// senderAllowedStatus = await registrar +// .connect(owner) +// .getAutoApproveAllowedSender(senderAddress) +// assert.isFalse(senderAllowedStatus) +// }) +// }) +// +// describe('#setTriggerConfig', () => { +// it('reverts if not called by the owner', async () => { +// const tx = registrar +// .connect(stranger) +// .setTriggerConfig(Trigger.LOG, autoApproveType_ENABLED_ALL, 100) +// await evmRevert(tx, 'Only callable by owner') +// }) +// +// it('changes the config', async () => { +// const tx = await registrar +// .connect(registrarOwner) +// .setTriggerConfig(Trigger.LOG, autoApproveType_ENABLED_ALL, 100) +// await registrar.getTriggerRegistrationDetails(Trigger.LOG) +// await expect(tx) +// .to.emit(registrar, 'TriggerConfigSet') +// .withArgs(Trigger.LOG, autoApproveType_ENABLED_ALL, 100) +// }) +// }) +// +// describe('#approve', () => { +// let hash: string +// +// beforeEach(async () => { +// await registrar +// .connect(registrarOwner) +// .setTriggerConfig( +// Trigger.CONDITION, +// autoApproveType_DISABLED, +// maxAllowedAutoApprove, +// ) +// +// //register with auto approve OFF +// const abiEncodedBytes = registrar.interface.encodeFunctionData( +// 'register', +// [ +// upkeepName, +// emptyBytes, +// mock.address, +// performGas, +// await admin.getAddress(), +// 0, +// emptyBytes, +// trigger, +// offchainConfig, +// amount, +// await requestSender.getAddress(), +// ], +// ) +// +// const tx = await linkToken +// .connect(requestSender) +// .transferAndCall(registrar.address, amount, abiEncodedBytes) +// const receipt = await tx.wait() +// hash = receipt.logs[2].topics[1] +// }) +// +// it('reverts if not called by the owner', async () => { +// const tx = registrar +// .connect(stranger) +// .approve( +// upkeepName, +// mock.address, +// performGas, +// await admin.getAddress(), +// 0, +// emptyBytes, +// trigger, +// emptyBytes, +// hash, +// ) +// await evmRevert(tx, 'Only callable by owner') +// }) +// +// it('reverts if the hash does not exist', async () => { +// const tx = registrar +// .connect(registrarOwner) +// .approve( +// upkeepName, +// mock.address, +// performGas, +// await admin.getAddress(), +// 0, +// emptyBytes, +// trigger, +// emptyBytes, +// '0x000000000000000000000000322813fd9a801c5507c9de605d63cea4f2ce6c44', +// ) +// await evmRevert(tx, errorMsgs.requestNotFound) +// }) +// +// it('reverts if any member of the payload changes', async () => { +// let tx = registrar +// .connect(registrarOwner) +// .approve( +// upkeepName, +// ethers.Wallet.createRandom().address, +// performGas, +// await admin.getAddress(), +// 0, +// emptyBytes, +// trigger, +// emptyBytes, +// hash, +// ) +// await evmRevert(tx, errorMsgs.hashPayload) +// tx = registrar +// .connect(registrarOwner) +// .approve( +// upkeepName, +// mock.address, +// 10000, +// await admin.getAddress(), +// 0, +// emptyBytes, +// trigger, +// emptyBytes, +// hash, +// ) +// await evmRevert(tx, errorMsgs.hashPayload) +// tx = registrar +// .connect(registrarOwner) +// .approve( +// upkeepName, +// mock.address, +// performGas, +// ethers.Wallet.createRandom().address, +// 0, +// emptyBytes, +// trigger, +// emptyBytes, +// hash, +// ) +// await evmRevert(tx, errorMsgs.hashPayload) +// tx = registrar +// .connect(registrarOwner) +// .approve( +// upkeepName, +// mock.address, +// performGas, +// await admin.getAddress(), +// 0, +// '0x1234', +// trigger, +// emptyBytes, +// hash, +// ) +// await evmRevert(tx, errorMsgs.hashPayload) +// }) +// +// it('approves an existing registration request', async () => { +// const tx = await registrar +// .connect(registrarOwner) +// .approve( +// upkeepName, +// mock.address, +// performGas, +// await admin.getAddress(), +// 0, +// emptyBytes, +// trigger, +// offchainConfig, +// hash, +// ) +// await expect(tx).to.emit(registrar, 'RegistrationApproved') +// }) +// +// it('deletes the request afterwards / reverts if the request DNE', async () => { +// await registrar +// .connect(registrarOwner) +// .approve( +// upkeepName, +// mock.address, +// performGas, +// await admin.getAddress(), +// 0, +// emptyBytes, +// trigger, +// offchainConfig, +// hash, +// ) +// const tx = registrar +// .connect(registrarOwner) +// .approve( +// upkeepName, +// mock.address, +// performGas, +// await admin.getAddress(), +// 0, +// emptyBytes, +// trigger, +// offchainConfig, +// hash, +// ) +// await evmRevert(tx, errorMsgs.requestNotFound) +// }) +// }) +// +// describe('#cancel', () => { +// let hash: string +// +// beforeEach(async () => { +// await registrar +// .connect(registrarOwner) +// .setTriggerConfig( +// Trigger.CONDITION, +// autoApproveType_DISABLED, +// maxAllowedAutoApprove, +// ) +// +// //register with auto approve OFF +// const abiEncodedBytes = registrar.interface.encodeFunctionData( +// 'register', +// [ +// upkeepName, +// emptyBytes, +// mock.address, +// performGas, +// await admin.getAddress(), +// 0, +// emptyBytes, +// trigger, +// offchainConfig, +// amount, +// await requestSender.getAddress(), +// ], +// ) +// const tx = await linkToken +// .connect(requestSender) +// .transferAndCall(registrar.address, amount, abiEncodedBytes) +// const receipt = await tx.wait() +// hash = receipt.logs[2].topics[1] +// // submit duplicate request (increase balance) +// await linkToken +// .connect(requestSender) +// .transferAndCall(registrar.address, amount, abiEncodedBytes) +// }) +// +// it('reverts if not called by the admin / owner', async () => { +// const tx = registrar.connect(stranger).cancel(hash) +// await evmRevert(tx, errorMsgs.onlyAdmin) +// }) +// +// it('reverts if the hash does not exist', async () => { +// const tx = registrar +// .connect(registrarOwner) +// .cancel( +// '0x000000000000000000000000322813fd9a801c5507c9de605d63cea4f2ce6c44', +// ) +// await evmRevert(tx, errorMsgs.requestNotFound) +// }) +// +// it('refunds the total request balance to the admin address if owner cancels', async () => { +// const before = await linkToken.balanceOf(await admin.getAddress()) +// const tx = await registrar.connect(registrarOwner).cancel(hash) +// const after = await linkToken.balanceOf(await admin.getAddress()) +// assert.isTrue(after.sub(before).eq(amount.mul(BigNumber.from(2)))) +// await expect(tx).to.emit(registrar, 'RegistrationRejected') +// }) +// +// it('refunds the total request balance to the admin address if admin cancels', async () => { +// const before = await linkToken.balanceOf(await admin.getAddress()) +// const tx = await registrar.connect(admin).cancel(hash) +// const after = await linkToken.balanceOf(await admin.getAddress()) +// assert.isTrue(after.sub(before).eq(amount.mul(BigNumber.from(2)))) +// await expect(tx).to.emit(registrar, 'RegistrationRejected') +// }) +// +// it('deletes the request hash', async () => { +// await registrar.connect(registrarOwner).cancel(hash) +// let tx = registrar.connect(registrarOwner).cancel(hash) +// await evmRevert(tx, errorMsgs.requestNotFound) +// tx = registrar +// .connect(registrarOwner) +// .approve( +// upkeepName, +// mock.address, +// performGas, +// await admin.getAddress(), +// 0, +// emptyBytes, +// trigger, +// emptyBytes, +// hash, +// ) +// await evmRevert(tx, errorMsgs.requestNotFound) +// }) +// }) +// }) diff --git a/contracts/test/v0.8/automation/AutomationRegistrar2_3.test.ts b/contracts/test/v0.8/automation/AutomationRegistrar2_3.test.ts index f9dfb408e1b..564d4e22a2c 100644 --- a/contracts/test/v0.8/automation/AutomationRegistrar2_3.test.ts +++ b/contracts/test/v0.8/automation/AutomationRegistrar2_3.test.ts @@ -1,26 +1,35 @@ import { ethers } from 'hardhat' -import { ContractFactory, Contract } from 'ethers' +import { + BigNumber, + BigNumberish, + BytesLike, + Contract, + ContractFactory, + Signer, +} from 'ethers' import { assert, expect } from 'chai' -import { evmRevert } from '../../test-helpers/matchers' +import { evmRevert, evmRevertCustomError } from '../../test-helpers/matchers' import { getUsers, Personas } from '../../test-helpers/setup' -import { BigNumber, Signer } from 'ethers' import { MockV3Aggregator__factory as MockV3AggregatorFactory } from '../../../typechain/factories/MockV3Aggregator__factory' import { UpkeepMock__factory as UpkeepMockFactory } from '../../../typechain/factories/UpkeepMock__factory' import { ChainModuleBase__factory as ChainModuleBaseFactory } from '../../../typechain/factories/ChainModuleBase__factory' import { MockV3Aggregator } from '../../../typechain/MockV3Aggregator' import { UpkeepMock } from '../../../typechain/UpkeepMock' -import { toWei } from '../../test-helpers/helpers' +import { randomAddress, toWei } from '../../test-helpers/helpers' import { ChainModuleBase } from '../../../typechain/ChainModuleBase' import { AutomationRegistrar2_3 as Registrar } from '../../../typechain/AutomationRegistrar2_3' import { deployRegistry23 } from './helpers' import { IAutomationRegistryMaster2_3 as IAutomationRegistry } from '../../../typechain' -// copied from KeeperRegistryBase2_3.sol +// copied from AutomationRegistryBase2_3.sol enum Trigger { CONDITION, LOG, } const zeroAddress = ethers.constants.AddressZero +const wrappedNativeTokenAddress = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' + +type OnChainConfig = Parameters[3] let linkTokenFactory: ContractFactory let mockV3AggregatorFactory: MockV3AggregatorFactory @@ -32,7 +41,7 @@ before(async () => { personas = (await getUsers()).personas linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', + 'src/v0.8/shared/test/helpers/LinkTokenTestHelper.sol:LinkTokenTestHelper', ) mockV3AggregatorFactory = (await ethers.getContractFactory( 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', @@ -42,9 +51,9 @@ before(async () => { const errorMsgs = { onlyOwner: 'revert Only callable by owner', - onlyAdmin: 'OnlyAdminOrOwner()', - hashPayload: 'HashMismatch()', - requestNotFound: 'RequestNotFound()', + onlyAdmin: 'OnlyAdminOrOwner', + hashPayload: 'HashMismatch', + requestNotFound: 'RequestNotFound', } describe('AutomationRegistrar2_3', () => { @@ -55,10 +64,16 @@ describe('AutomationRegistrar2_3', () => { const gasWei = BigNumber.from(100) const performGas = BigNumber.from(100000) const paymentPremiumPPB = BigNumber.from(250000000) - const flatFeeMicroLink = BigNumber.from(0) + const flatFeeMilliCents = BigNumber.from(0) const maxAllowedAutoApprove = 5 const trigger = '0xdeadbeef' const offchainConfig = '0x01234567' + const keepers = [ + randomAddress(), + randomAddress(), + randomAddress(), + randomAddress(), + ] const emptyBytes = '0x00' const stalenessSeconds = BigNumber.from(43820) @@ -71,9 +86,8 @@ describe('AutomationRegistrar2_3', () => { const maxPerformDataSize = BigNumber.from(10000) const maxRevertDataSize = BigNumber.from(1000) const maxPerformGas = BigNumber.from(5000000) - const minUpkeepSpend = BigNumber.from('1000000000000000000') + const minimumRegistrationAmount = BigNumber.from('1000000000000000000') const amount = BigNumber.from('5000000000000000000') - const amount1 = BigNumber.from('6000000000000000000') const transcoder = ethers.constants.AddressZero const upkeepManager = ethers.Wallet.createRandom().address @@ -98,6 +112,30 @@ describe('AutomationRegistrar2_3', () => { let registrar: Registrar let chainModuleBase: ChainModuleBase let chainModuleBaseFactory: ChainModuleBaseFactory + let onchainConfig: OnChainConfig + + type RegistrationParams = { + upkeepContract: string + amount: BigNumberish + adminAddress: string + gasLimit: BigNumberish + triggerType: BigNumberish + billingToken: string + name: string + encryptedEmail: BytesLike + checkData: BytesLike + triggerConfig: BytesLike + offchainConfig: BytesLike + } + + function encodeRegistrationParams(params: RegistrationParams) { + return ( + '0x' + + registrar.interface + .encodeFunctionData('registerUpkeep', [params]) + .slice(10) + ) + } beforeEach(async () => { owner = personas.Default @@ -128,6 +166,8 @@ describe('AutomationRegistrar2_3', () => { nativeUSDFeed.address, gasPriceFeed.address, zeroAddress, + 0, // onchain payout mode + wrappedNativeTokenAddress, ) mock = await upkeepMockFactory.deploy() @@ -135,9 +175,10 @@ describe('AutomationRegistrar2_3', () => { const registrarFactory = await ethers.getContractFactory( 'AutomationRegistrar2_3', ) - registrar = await registrarFactory - .connect(registrarOwner) - .deploy(linkToken.address, registry.address, minUpkeepSpend, [ + registrar = await registrarFactory.connect(registrarOwner).deploy( + linkToken.address, + registry.address, + [ { triggerType: Trigger.CONDITION, autoApproveType: autoApproveType_DISABLED, @@ -148,25 +189,20 @@ describe('AutomationRegistrar2_3', () => { autoApproveType: autoApproveType_DISABLED, autoApproveMaxAllowed: 0, }, - ]) + ], + [linkToken.address], + [minimumRegistrationAmount], + wrappedNativeTokenAddress, + ) await linkToken .connect(owner) .transfer(await requestSender.getAddress(), toWei('1000')) - const keepers = [ - await personas.Carol.getAddress(), - await personas.Nancy.getAddress(), - await personas.Ned.getAddress(), - await personas.Neil.getAddress(), - ] - const onchainConfig = { - paymentPremiumPPB, - flatFeeMicroLink, + onchainConfig = { checkGasLimit, stalenessSeconds, gasCeilingMultiplier, - minUpkeepSpend, maxCheckDataSize, maxPerformDataSize, maxRevertDataSize, @@ -181,9 +217,24 @@ describe('AutomationRegistrar2_3', () => { reorgProtectionEnabled: true, financeAdmin: await admin.getAddress(), } - await registry - .connect(owner) - .setConfigTypeSafe(keepers, keepers, 1, onchainConfig, 1, '0x', [], []) + await registry.connect(owner).setConfigTypeSafe( + keepers, + keepers, + 1, + onchainConfig, + 1, + '0x', + [linkToken.address], + [ + { + gasFeePPB: paymentPremiumPPB, + flatFeeMilliCents, + priceFeed: await registry.getLinkUSDFeedAddress(), + fallbackPrice: 200, + minSpend: minimumRegistrationAmount, + }, + ], + ) }) describe('#typeAndVersion', () => { @@ -193,110 +244,38 @@ describe('AutomationRegistrar2_3', () => { }) }) - describe('#register', () => { + describe('#onTokenTransfer', () => { it('reverts if not called by the LINK token', async () => { - await evmRevert( + await evmRevertCustomError( registrar .connect(someAddress) - .register( - upkeepName, - emptyBytes, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - amount, - await requestSender.getAddress(), - ), - 'OnlyLink()', - ) - }) - - it('reverts if the amount passed in data mismatches actual amount sent', async () => { - await registrar - .connect(registrarOwner) - .setTriggerConfig( - Trigger.CONDITION, - autoApproveType_ENABLED_ALL, - maxAllowedAutoApprove, - ) - - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - amount1, - await requestSender.getAddress(), - ], - ) - - await evmRevert( - linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes), - 'AmountMismatch()', - ) - }) - - it('reverts if the sender passed in data mismatches actual sender', async () => { - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - amount, - await admin.getAddress(), // Should have been requestSender.getAddress() - ], - ) - await evmRevert( - linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes), - 'SenderMismatch()', + .onTokenTransfer(await someAddress.getAddress(), 0, '0x'), + registrar, + 'OnlyLink', ) }) it('reverts if the admin address is 0x0000...', async () => { - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - performGas, - '0x0000000000000000000000000000000000000000', - 0, - emptyBytes, - trigger, - offchainConfig, - amount, - await requestSender.getAddress(), - ], - ) + const abiEncodedBytes = encodeRegistrationParams({ + name: upkeepName, + encryptedEmail: emptyBytes, + upkeepContract: mock.address, + gasLimit: performGas, + adminAddress: '0x0000000000000000000000000000000000000000', + checkData: emptyBytes, + triggerType: Trigger.CONDITION, + triggerConfig: trigger, + offchainConfig, + amount, + billingToken: linkToken.address, + }) - await evmRevert( + await evmRevertCustomError( linkToken .connect(requestSender) .transferAndCall(registrar.address, amount, abiEncodedBytes), - 'RegistrationRequestFailed()', + registrar, + 'InvalidAdminAddress', ) }) @@ -311,22 +290,19 @@ describe('AutomationRegistrar2_3', () => { ) //register with auto approve ON - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - amount, - await requestSender.getAddress(), - ], - ) + const abiEncodedBytes = encodeRegistrationParams({ + name: upkeepName, + encryptedEmail: emptyBytes, + upkeepContract: mock.address, + gasLimit: performGas, + adminAddress: await admin.getAddress(), + checkData: emptyBytes, + triggerType: Trigger.CONDITION, + triggerConfig: trigger, + offchainConfig, + amount, + billingToken: linkToken.address, + }) const tx = await linkToken .connect(requestSender) .transferAndCall(registrar.address, amount, abiEncodedBytes) @@ -346,6 +322,37 @@ describe('AutomationRegistrar2_3', () => { await expect(tx).to.emit(registrar, 'RegistrationApproved') }) + it('Auto Approve ON - ignores the amount passed in and uses the actual amount sent', async () => { + await registrar + .connect(registrarOwner) + .setTriggerConfig( + Trigger.CONDITION, + autoApproveType_ENABLED_ALL, + maxAllowedAutoApprove, + ) + + const abiEncodedBytes = encodeRegistrationParams({ + name: upkeepName, + encryptedEmail: emptyBytes, + upkeepContract: mock.address, + gasLimit: performGas, + adminAddress: await admin.getAddress(), + checkData: emptyBytes, + triggerType: Trigger.CONDITION, + triggerConfig: trigger, + offchainConfig, + amount: amount.mul(10), // muhahahaha 😈 + billingToken: linkToken.address, + }) + + await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + + const [id] = await registry.getActiveUpkeepIDs(0, 1) + expect(await registry.getBalance(id)).to.equal(amount) + }) + it('Auto Approve OFF - does not registers an upkeep on KeeperRegistry, emits only RegistrationRequested event', async () => { //get upkeep count before attempting registration const beforeCount = (await registry.getState()).state.numUpkeeps @@ -360,22 +367,19 @@ describe('AutomationRegistrar2_3', () => { ) //register with auto approve OFF - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - amount, - await requestSender.getAddress(), - ], - ) + const abiEncodedBytes = encodeRegistrationParams({ + name: upkeepName, + encryptedEmail: emptyBytes, + upkeepContract: mock.address, + gasLimit: performGas, + adminAddress: await admin.getAddress(), + checkData: emptyBytes, + triggerType: Trigger.CONDITION, + triggerConfig: trigger, + offchainConfig, + amount, + billingToken: linkToken.address, + }) const tx = await linkToken .connect(requestSender) .transferAndCall(registrar.address, amount, abiEncodedBytes) @@ -410,57 +414,57 @@ describe('AutomationRegistrar2_3', () => { .setTriggerConfig(Trigger.LOG, autoApproveType_ENABLED_ALL, 1) // register within threshold, new upkeep should be registered - let abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ - upkeepName, - emptyBytes, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, + let abiEncodedBytes = encodeRegistrationParams({ + name: upkeepName, + encryptedEmail: emptyBytes, + upkeepContract: mock.address, + gasLimit: performGas, + adminAddress: await admin.getAddress(), + checkData: emptyBytes, + triggerType: Trigger.CONDITION, + triggerConfig: trigger, offchainConfig, amount, - await requestSender.getAddress(), - ]) + billingToken: linkToken.address, + }) await linkToken .connect(requestSender) .transferAndCall(registrar.address, amount, abiEncodedBytes) assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 1) // 0 -> 1 // try registering another one, new upkeep should not be registered - abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ - upkeepName, - emptyBytes, - mock.address, - performGas.toNumber() + 1, // make unique hash - await admin.getAddress(), - 0, - emptyBytes, - trigger, + abiEncodedBytes = encodeRegistrationParams({ + name: upkeepName, + encryptedEmail: emptyBytes, + upkeepContract: mock.address, + gasLimit: performGas.toNumber() + 1, // make unique hash + adminAddress: await admin.getAddress(), + checkData: emptyBytes, + triggerType: Trigger.CONDITION, + triggerConfig: trigger, offchainConfig, amount, - await requestSender.getAddress(), - ]) + billingToken: linkToken.address, + }) await linkToken .connect(requestSender) .transferAndCall(registrar.address, amount, abiEncodedBytes) assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 1) // Still 1 // register a second type of upkeep, different limit - abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ - upkeepName, - emptyBytes, - mock.address, - performGas, - await admin.getAddress(), - Trigger.LOG, - emptyBytes, - trigger, + abiEncodedBytes = encodeRegistrationParams({ + name: upkeepName, + encryptedEmail: emptyBytes, + upkeepContract: mock.address, + gasLimit: performGas, // make unique hash + adminAddress: await admin.getAddress(), + checkData: emptyBytes, + triggerType: Trigger.LOG, + triggerConfig: trigger, offchainConfig, amount, - await requestSender.getAddress(), - ]) + billingToken: linkToken.address, + }) await linkToken .connect(requestSender) .transferAndCall(registrar.address, amount, abiEncodedBytes) @@ -471,38 +475,38 @@ describe('AutomationRegistrar2_3', () => { .connect(registrarOwner) .setTriggerConfig(Trigger.CONDITION, autoApproveType_ENABLED_ALL, 2) - abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ - upkeepName, - emptyBytes, - mock.address, - performGas.toNumber() + 2, // make unique hash - await admin.getAddress(), - 0, - emptyBytes, - trigger, + abiEncodedBytes = encodeRegistrationParams({ + name: upkeepName, + encryptedEmail: emptyBytes, + upkeepContract: mock.address, + gasLimit: performGas.toNumber() + 2, // make unique hash + adminAddress: await admin.getAddress(), + checkData: emptyBytes, + triggerType: Trigger.CONDITION, + triggerConfig: trigger, offchainConfig, amount, - await requestSender.getAddress(), - ]) + billingToken: linkToken.address, + }) await linkToken .connect(requestSender) .transferAndCall(registrar.address, amount, abiEncodedBytes) assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 3) // 2 -> 3 // One more upkeep should not get registered - abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ - upkeepName, - emptyBytes, - mock.address, - performGas.toNumber() + 3, // make unique hash - await admin.getAddress(), - 0, - emptyBytes, - trigger, + abiEncodedBytes = encodeRegistrationParams({ + name: upkeepName, + encryptedEmail: emptyBytes, + upkeepContract: mock.address, + gasLimit: performGas.toNumber() + 3, // make unique hash + adminAddress: await admin.getAddress(), + checkData: emptyBytes, + triggerType: Trigger.CONDITION, + triggerConfig: trigger, offchainConfig, amount, - await requestSender.getAddress(), - ]) + billingToken: linkToken.address, + }) await linkToken .connect(requestSender) .transferAndCall(registrar.address, amount, abiEncodedBytes) @@ -527,22 +531,19 @@ describe('AutomationRegistrar2_3', () => { .setAutoApproveAllowedSender(senderAddress, true) //register with auto approve ON - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - amount, - await requestSender.getAddress(), - ], - ) + const abiEncodedBytes = encodeRegistrationParams({ + name: upkeepName, + encryptedEmail: emptyBytes, + upkeepContract: mock.address, + gasLimit: performGas, + adminAddress: await admin.getAddress(), + checkData: emptyBytes, + triggerType: Trigger.CONDITION, + triggerConfig: trigger, + offchainConfig, + amount, + billingToken: linkToken.address, + }) const tx = await linkToken .connect(requestSender) .transferAndCall(registrar.address, amount, abiEncodedBytes) @@ -580,22 +581,19 @@ describe('AutomationRegistrar2_3', () => { .setAutoApproveAllowedSender(senderAddress, false) //register. auto approve shouldn't happen - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - amount, - await requestSender.getAddress(), - ], - ) + const abiEncodedBytes = encodeRegistrationParams({ + name: upkeepName, + encryptedEmail: emptyBytes, + upkeepContract: mock.address, + gasLimit: performGas, + adminAddress: await admin.getAddress(), + checkData: emptyBytes, + triggerType: Trigger.CONDITION, + triggerConfig: trigger, + offchainConfig, + amount, + billingToken: linkToken.address, + }) const tx = await linkToken .connect(requestSender) .transferAndCall(registrar.address, amount, abiEncodedBytes) @@ -625,18 +623,23 @@ describe('AutomationRegistrar2_3', () => { upkeepContract: mock.address, gasLimit: performGas, adminAddress: await admin.getAddress(), - triggerType: 0, + triggerType: Trigger.CONDITION, checkData: emptyBytes, triggerConfig: trigger, offchainConfig: emptyBytes, amount, encryptedEmail: emptyBytes, + billingToken: linkToken.address, }), '', ) }) it('reverts if the amount passed in data is less than configured minimum', async () => { + const amt = minimumRegistrationAmount.sub(1) + + await linkToken.connect(requestSender).approve(registrar.address, amt) + await registrar .connect(registrarOwner) .setTriggerConfig( @@ -645,23 +648,58 @@ describe('AutomationRegistrar2_3', () => { maxAllowedAutoApprove, ) - // amt is one order of magnitude less than minUpkeepSpend - const amt = BigNumber.from('100000000000000000') - - await evmRevert( - registrar.connect(someAddress).registerUpkeep({ + await evmRevertCustomError( + registrar.connect(requestSender).registerUpkeep({ name: upkeepName, upkeepContract: mock.address, gasLimit: performGas, adminAddress: await admin.getAddress(), - triggerType: 0, + triggerType: Trigger.CONDITION, checkData: emptyBytes, triggerConfig: trigger, offchainConfig: emptyBytes, amount: amt, encryptedEmail: emptyBytes, + billingToken: linkToken.address, + }), + registrar, + 'InsufficientPayment', + ) + }) + + it('reverts if the billing token is not supported', async () => { + await linkToken + .connect(requestSender) + .approve(registrar.address, minimumRegistrationAmount) + + await registrar + .connect(registrarOwner) + .setTriggerConfig( + Trigger.CONDITION, + autoApproveType_ENABLED_ALL, + maxAllowedAutoApprove, + ) + + await registry + .connect(owner) + .setConfigTypeSafe(keepers, keepers, 1, onchainConfig, 1, '0x', [], []) + + await evmRevertCustomError( + registrar.connect(requestSender).registerUpkeep({ + name: upkeepName, + upkeepContract: mock.address, + gasLimit: performGas, + adminAddress: await admin.getAddress(), + triggerType: Trigger.CONDITION, + checkData: emptyBytes, + triggerConfig: trigger, + offchainConfig: emptyBytes, + amount: minimumRegistrationAmount, + encryptedEmail: emptyBytes, + billingToken: linkToken.address, }), - 'InsufficientPayment()', + registrar, + 'InvalidBillingToken', ) }) @@ -682,12 +720,13 @@ describe('AutomationRegistrar2_3', () => { upkeepContract: mock.address, gasLimit: performGas, adminAddress: await admin.getAddress(), - triggerType: 0, + triggerType: Trigger.CONDITION, checkData: emptyBytes, triggerConfig: trigger, offchainConfig, amount, encryptedEmail: emptyBytes, + billingToken: linkToken.address, }) assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 1) // 0 -> 1 @@ -763,6 +802,7 @@ describe('AutomationRegistrar2_3', () => { describe('#approve', () => { let hash: string + let params: RegistrationParams beforeEach(async () => { await registrar @@ -773,23 +813,22 @@ describe('AutomationRegistrar2_3', () => { maxAllowedAutoApprove, ) + params = { + name: upkeepName, + encryptedEmail: emptyBytes, + upkeepContract: mock.address, + gasLimit: performGas, + adminAddress: await admin.getAddress(), + checkData: emptyBytes, + triggerType: Trigger.CONDITION, + triggerConfig: trigger, + offchainConfig, + amount, + billingToken: linkToken.address, + } + //register with auto approve OFF - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - amount, - await requestSender.getAddress(), - ], - ) + const abiEncodedBytes = encodeRegistrationParams(params) const tx = await linkToken .connect(requestSender) @@ -799,143 +838,146 @@ describe('AutomationRegistrar2_3', () => { }) it('reverts if not called by the owner', async () => { - const tx = registrar - .connect(stranger) - .approve( - upkeepName, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - emptyBytes, - hash, - ) + const tx = registrar.connect(stranger).approve( + { + name: upkeepName, + encryptedEmail: emptyBytes, + upkeepContract: mock.address, + gasLimit: performGas, + adminAddress: await admin.getAddress(), + checkData: emptyBytes, + triggerType: Trigger.CONDITION, + triggerConfig: trigger, + offchainConfig: emptyBytes, + amount, + billingToken: linkToken.address, + }, + hash, + ) await evmRevert(tx, 'Only callable by owner') }) it('reverts if the hash does not exist', async () => { - const tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - emptyBytes, - '0x000000000000000000000000322813fd9a801c5507c9de605d63cea4f2ce6c44', - ) - await evmRevert(tx, errorMsgs.requestNotFound) + const tx = registrar.connect(registrarOwner).approve( + { + name: upkeepName, + encryptedEmail: emptyBytes, + upkeepContract: mock.address, + gasLimit: performGas, + adminAddress: await admin.getAddress(), + checkData: emptyBytes, + triggerType: Trigger.CONDITION, + triggerConfig: trigger, + offchainConfig: emptyBytes, + amount, + billingToken: linkToken.address, + }, + '0x000000000000000000000000322813fd9a801c5507c9de605d63cea4f2ce6c44', + ) + await evmRevertCustomError(tx, registrar, errorMsgs.requestNotFound) }) it('reverts if any member of the payload changes', async () => { - let tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - ethers.Wallet.createRandom().address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - emptyBytes, - hash, - ) - await evmRevert(tx, errorMsgs.hashPayload) - tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - 10000, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - emptyBytes, - hash, - ) - await evmRevert(tx, errorMsgs.hashPayload) - tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - performGas, - ethers.Wallet.createRandom().address, - 0, - emptyBytes, - trigger, - emptyBytes, - hash, - ) - await evmRevert(tx, errorMsgs.hashPayload) - tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - performGas, - await admin.getAddress(), - 0, - '0x1234', - trigger, - emptyBytes, - hash, - ) - await evmRevert(tx, errorMsgs.hashPayload) + const invalidFields: any[] = [ + { + name: 'fake', + }, + { + encryptedEmail: '0xdeadbeef', + }, + { + upkeepContract: ethers.Wallet.createRandom().address, + }, + { + gasLimit: performGas.add(1), + }, + { + adminAddress: randomAddress(), + }, + { + checkData: '0xdeadbeef', + }, + { + triggerType: Trigger.LOG, + }, + { + triggerConfig: '0x1234', + }, + { + offchainConfig: '0xdeadbeef', + }, + { + amount: amount.add(1), + }, + { + billingToken: randomAddress(), + }, + ] + for (let i = 0; i < invalidFields.length; i++) { + const field = invalidFields[i] + const badParams = Object.assign({}, params, field) as RegistrationParams + const tx = registrar.connect(registrarOwner).approve(badParams, hash) + await expect( + tx, + `expected ${JSON.stringify(field)} to cause failure, but succeeded`, + ).to.be.revertedWithCustomError(registrar, errorMsgs.hashPayload) + } }) it('approves an existing registration request', async () => { - const tx = await registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, + const tx = await registrar.connect(registrarOwner).approve( + { + name: upkeepName, + encryptedEmail: emptyBytes, + upkeepContract: mock.address, + gasLimit: performGas, + adminAddress: await admin.getAddress(), + checkData: emptyBytes, + triggerType: Trigger.CONDITION, + triggerConfig: trigger, offchainConfig, - hash, - ) + amount, + billingToken: linkToken.address, + }, + hash, + ) await expect(tx).to.emit(registrar, 'RegistrationApproved') }) it('deletes the request afterwards / reverts if the request DNE', async () => { - await registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, + await registrar.connect(registrarOwner).approve( + { + name: upkeepName, + encryptedEmail: emptyBytes, + upkeepContract: mock.address, + gasLimit: performGas, + adminAddress: await admin.getAddress(), + checkData: emptyBytes, + triggerType: Trigger.CONDITION, + triggerConfig: trigger, offchainConfig, - hash, - ) - const tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, + amount, + billingToken: linkToken.address, + }, + hash, + ) + const tx = registrar.connect(registrarOwner).approve( + { + name: upkeepName, + encryptedEmail: emptyBytes, + upkeepContract: mock.address, + gasLimit: performGas, + adminAddress: await admin.getAddress(), + checkData: emptyBytes, + triggerType: Trigger.CONDITION, + triggerConfig: trigger, offchainConfig, - hash, - ) - await evmRevert(tx, errorMsgs.requestNotFound) + amount, + billingToken: linkToken.address, + }, + hash, + ) + await evmRevertCustomError(tx, registrar, errorMsgs.requestNotFound) }) }) @@ -952,22 +994,19 @@ describe('AutomationRegistrar2_3', () => { ) //register with auto approve OFF - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - offchainConfig, - amount, - await requestSender.getAddress(), - ], - ) + const abiEncodedBytes = encodeRegistrationParams({ + name: upkeepName, + encryptedEmail: emptyBytes, + upkeepContract: mock.address, + gasLimit: performGas, + adminAddress: await admin.getAddress(), + checkData: emptyBytes, + triggerType: Trigger.CONDITION, + triggerConfig: trigger, + offchainConfig, + amount, + billingToken: linkToken.address, + }) const tx = await linkToken .connect(requestSender) .transferAndCall(registrar.address, amount, abiEncodedBytes) @@ -981,7 +1020,7 @@ describe('AutomationRegistrar2_3', () => { it('reverts if not called by the admin / owner', async () => { const tx = registrar.connect(stranger).cancel(hash) - await evmRevert(tx, errorMsgs.onlyAdmin) + await evmRevertCustomError(tx, registrar, errorMsgs.onlyAdmin) }) it('reverts if the hash does not exist', async () => { @@ -990,7 +1029,7 @@ describe('AutomationRegistrar2_3', () => { .cancel( '0x000000000000000000000000322813fd9a801c5507c9de605d63cea4f2ce6c44', ) - await evmRevert(tx, errorMsgs.requestNotFound) + await evmRevertCustomError(tx, registrar, errorMsgs.requestNotFound) }) it('refunds the total request balance to the admin address if owner cancels', async () => { @@ -1012,21 +1051,24 @@ describe('AutomationRegistrar2_3', () => { it('deletes the request hash', async () => { await registrar.connect(registrarOwner).cancel(hash) let tx = registrar.connect(registrarOwner).cancel(hash) - await evmRevert(tx, errorMsgs.requestNotFound) - tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - performGas, - await admin.getAddress(), - 0, - emptyBytes, - trigger, - emptyBytes, - hash, - ) - await evmRevert(tx, errorMsgs.requestNotFound) + await evmRevertCustomError(tx, registrar, errorMsgs.requestNotFound) + tx = registrar.connect(registrarOwner).approve( + { + name: upkeepName, + encryptedEmail: emptyBytes, + upkeepContract: mock.address, + gasLimit: performGas, + adminAddress: await admin.getAddress(), + checkData: emptyBytes, + triggerType: Trigger.CONDITION, + triggerConfig: trigger, + offchainConfig: emptyBytes, + amount, + billingToken: linkToken.address, + }, + hash, + ) + await evmRevertCustomError(tx, registrar, errorMsgs.requestNotFound) }) }) }) diff --git a/contracts/test/v0.8/automation/AutomationRegistry2_2.test.ts b/contracts/test/v0.8/automation/AutomationRegistry2_2.test.ts index cb63c3a6344..62733bcad43 100644 --- a/contracts/test/v0.8/automation/AutomationRegistry2_2.test.ts +++ b/contracts/test/v0.8/automation/AutomationRegistry2_2.test.ts @@ -12,7 +12,7 @@ import { Signer, Wallet, } from 'ethers' -import { evmRevert } from '../../test-helpers/matchers' +import { evmRevert, evmRevertCustomError } from '../../test-helpers/matchers' import { getUsers, Personas } from '../../test-helpers/setup' import { randomAddress, toWei } from '../../test-helpers/helpers' import { StreamsLookupUpkeep__factory as StreamsLookupUpkeepFactory } from '../../../typechain/factories/StreamsLookupUpkeep__factory' @@ -415,7 +415,7 @@ describe('AutomationRegistry2_2', () => { automationUtils = await convFactory.deploy() linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', + 'src/v0.8/shared/test/helpers/LinkTokenTestHelper.sol:LinkTokenTestHelper', ) // need full path because there are two contracts with name MockV3Aggregator mockV3AggregatorFactory = (await ethers.getContractFactory( @@ -1100,16 +1100,18 @@ describe('AutomationRegistry2_2', () => { it('reverts when registry is paused', async () => { await registry.connect(owner).pause() - await evmRevert( + await evmRevertCustomError( getTransmitTx(registry, keeper1, [upkeepId]), - 'RegistryPaused()', + registry, + 'RegistryPaused', ) }) it('reverts when called by non active transmitter', async () => { - await evmRevert( + await evmRevertCustomError( getTransmitTx(registry, payee1, [upkeepId]), - 'OnlyActiveTransmitters()', + registry, + 'OnlyActiveTransmitters', ) }) @@ -1135,9 +1137,10 @@ describe('AutomationRegistry2_2', () => { performDatas, }) - await evmRevert( + await evmRevertCustomError( getTransmitTxWithReport(registry, keeper1, report), - 'InvalidReport()', + registry, + 'InvalidReport', ) }) @@ -1762,7 +1765,7 @@ describe('AutomationRegistry2_2', () => { const report = await makeLatestBlockReport([upkeepId]) const reportContext = [emptyBytes32, epochAndRound5_1, emptyBytes32] // wrong config digest const sigs = signReport(reportContext, report, signers.slice(0, f + 1)) - await evmRevert( + await evmRevertCustomError( registry .connect(keeper1) .transmit( @@ -1772,7 +1775,8 @@ describe('AutomationRegistry2_2', () => { sigs.ss, sigs.vs, ), - 'ConfigDigestMismatch()', + registry, + 'ConfigDigestMismatch', ) }) @@ -1782,7 +1786,7 @@ describe('AutomationRegistry2_2', () => { const report = await makeLatestBlockReport([upkeepId]) const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] // wrong config digest const sigs = signReport(reportContext, report, signers.slice(0, f + 2)) - await evmRevert( + await evmRevertCustomError( registry .connect(keeper1) .transmit( @@ -1792,7 +1796,8 @@ describe('AutomationRegistry2_2', () => { sigs.ss, sigs.vs, ), - 'IncorrectNumberOfSignatures()', + registry, + 'IncorrectNumberOfSignatures', ) }) @@ -1805,7 +1810,7 @@ describe('AutomationRegistry2_2', () => { new ethers.Wallet(ethers.Wallet.createRandom()), new ethers.Wallet(ethers.Wallet.createRandom()), ]) - await evmRevert( + await evmRevertCustomError( registry .connect(keeper1) .transmit( @@ -1815,7 +1820,8 @@ describe('AutomationRegistry2_2', () => { sigs.ss, sigs.vs, ), - 'OnlyActiveSigners()', + registry, + 'OnlyActiveSigners', ) }) @@ -1825,7 +1831,7 @@ describe('AutomationRegistry2_2', () => { const report = await makeLatestBlockReport([upkeepId]) const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] // wrong config digest const sigs = signReport(reportContext, report, [signer1, signer1]) - await evmRevert( + await evmRevertCustomError( registry .connect(keeper1) .transmit( @@ -1835,7 +1841,8 @@ describe('AutomationRegistry2_2', () => { sigs.ss, sigs.vs, ), - 'DuplicateSigners()', + registry, + 'DuplicateSigners', ) }) @@ -2932,36 +2939,40 @@ describe('AutomationRegistry2_2', () => { }) it('reverts if called on a non existing ID', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(admin) .withdrawFunds(upkeepId.add(1), await payee1.getAddress()), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) it('reverts if called by anyone but the admin', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(owner) .withdrawFunds(upkeepId, await payee1.getAddress()), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) it('reverts if called on an uncanceled upkeep', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(admin) .withdrawFunds(upkeepId, await payee1.getAddress()), - 'UpkeepNotCanceled()', + registry, + 'UpkeepNotCanceled', ) }) it('reverts if called with the 0 address', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(admin).withdrawFunds(upkeepId, zeroAddress), - 'InvalidRecipient()', + registry, + 'InvalidRecipient', ) }) @@ -3022,21 +3033,23 @@ describe('AutomationRegistry2_2', () => { describe('#simulatePerformUpkeep', () => { it('reverts if called by non zero address', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(await owner.getAddress()) .callStatic.simulatePerformUpkeep(upkeepId, '0x'), - 'OnlySimulatedBackend()', + registry, + 'OnlySimulatedBackend', ) }) it('reverts when registry is paused', async () => { await registry.connect(owner).pause() - await evmRevert( + await evmRevertCustomError( registry .connect(zeroAddress) .callStatic.simulatePerformUpkeep(upkeepId, '0x'), - 'RegistryPaused()', + registry, + 'RegistryPaused', ) }) @@ -3082,11 +3095,12 @@ describe('AutomationRegistry2_2', () => { describe('#checkUpkeep', () => { it('reverts if called by non zero address', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(await owner.getAddress()) .callStatic['checkUpkeep(uint256)'](upkeepId), - 'OnlySimulatedBackend()', + registry, + 'OnlySimulatedBackend', ) }) @@ -3335,9 +3349,10 @@ describe('AutomationRegistry2_2', () => { const amount = toWei('1') it('reverts if the registration does not exist', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(keeper1).addFunds(upkeepId.add(1), amount), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) @@ -3365,22 +3380,25 @@ describe('AutomationRegistry2_2', () => { it('reverts if the upkeep is canceled', async () => { await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry.connect(keeper1).addFunds(upkeepId, amount), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) }) describe('#getActiveUpkeepIDs', () => { it('reverts if startIndex is out of bounds ', async () => { - await evmRevert( + await evmRevertCustomError( registry.getActiveUpkeepIDs(numUpkeeps, 0), - 'IndexOutOfRange()', + registry, + 'IndexOutOfRange', ) - await evmRevert( + await evmRevertCustomError( registry.getActiveUpkeepIDs(numUpkeeps + 1, 0), - 'IndexOutOfRange()', + registry, + 'IndexOutOfRange', ) }) @@ -3608,11 +3626,12 @@ describe('AutomationRegistry2_2', () => { it('reverts if not called by the LINK token', async () => { const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [upkeepId]) - await evmRevert( + await evmRevertCustomError( registry .connect(keeper1) .onTokenTransfer(await keeper1.getAddress(), amount, data), - 'OnlyCallableByLINKToken()', + registry, + 'OnlyCallableByLINKToken', ) }) @@ -3637,9 +3656,10 @@ describe('AutomationRegistry2_2', () => { it('reverts if the upkeep is canceled', async () => { await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry.connect(keeper1).addFunds(upkeepId, amount), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) @@ -3710,7 +3730,7 @@ describe('AutomationRegistry2_2', () => { }) it('reverts if signers or transmitters are the zero address', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(owner) .setConfigTypeSafe( @@ -3726,10 +3746,11 @@ describe('AutomationRegistry2_2', () => { offchainVersion, offchainBytes, ), - 'InvalidSigner()', + registry, + 'InvalidSigner', ) - await evmRevert( + await evmRevertCustomError( registry .connect(owner) .setConfigTypeSafe( @@ -3745,7 +3766,8 @@ describe('AutomationRegistry2_2', () => { offchainVersion, offchainBytes, ), - 'InvalidTransmitter()', + registry, + 'InvalidTransmitter', ) }) @@ -3883,7 +3905,7 @@ describe('AutomationRegistry2_2', () => { for (let i = 0; i < 40; i++) { newKeepers.push(randomAddress()) } - await evmRevert( + await evmRevertCustomError( registry .connect(owner) .setConfigTypeSafe( @@ -3894,12 +3916,13 @@ describe('AutomationRegistry2_2', () => { offchainVersion, offchainBytes, ), - 'TooManyOracles()', + registry, + 'TooManyOracles', ) }) it('reverts if f=0', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(owner) .setConfigTypeSafe( @@ -3910,13 +3933,14 @@ describe('AutomationRegistry2_2', () => { offchainVersion, offchainBytes, ), - 'IncorrectNumberOfFaultyOracles()', + registry, + 'IncorrectNumberOfFaultyOracles', ) }) it('reverts if signers != transmitters length', async () => { const signers = [randomAddress()] - await evmRevert( + await evmRevertCustomError( registry .connect(owner) .setConfigTypeSafe( @@ -3927,13 +3951,14 @@ describe('AutomationRegistry2_2', () => { offchainVersion, offchainBytes, ), - 'IncorrectNumberOfSigners()', + registry, + 'IncorrectNumberOfSigners', ) }) it('reverts if signers <= 3f', async () => { newKeepers.pop() - await evmRevert( + await evmRevertCustomError( registry .connect(owner) .setConfigTypeSafe( @@ -3944,7 +3969,8 @@ describe('AutomationRegistry2_2', () => { offchainVersion, offchainBytes, ), - 'IncorrectNumberOfSigners()', + registry, + 'IncorrectNumberOfSigners', ) }) @@ -3955,7 +3981,7 @@ describe('AutomationRegistry2_2', () => { await personas.Eddy.getAddress(), await personas.Eddy.getAddress(), ] - await evmRevert( + await evmRevertCustomError( registry .connect(owner) .setConfigTypeSafe( @@ -3966,7 +3992,8 @@ describe('AutomationRegistry2_2', () => { offchainVersion, offchainBytes, ), - 'RepeatedSigner()', + registry, + 'RepeatedSigner', ) }) @@ -3977,7 +4004,7 @@ describe('AutomationRegistry2_2', () => { await personas.Eddy.getAddress(), await personas.Eddy.getAddress(), ] - await evmRevert( + await evmRevertCustomError( registry .connect(owner) .setConfigTypeSafe( @@ -3988,7 +4015,8 @@ describe('AutomationRegistry2_2', () => { offchainVersion, offchainBytes, ), - 'RepeatedTransmitter()', + registry, + 'RepeatedTransmitter', ) }) @@ -4109,57 +4137,62 @@ describe('AutomationRegistry2_2', () => { describe('#registerUpkeep', () => { it('reverts when registry is paused', async () => { await registry.connect(owner).pause() - await evmRevert( + await evmRevertCustomError( registry .connect(owner) [ 'registerUpkeep(address,uint32,address,bytes,bytes)' ](mock.address, performGas, await admin.getAddress(), emptyBytes, '0x'), - 'RegistryPaused()', + registry, + 'RegistryPaused', ) }) it('reverts if the target is not a contract', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(owner) [ 'registerUpkeep(address,uint32,address,bytes,bytes)' ](zeroAddress, performGas, await admin.getAddress(), emptyBytes, '0x'), - 'NotAContract()', + registry, + 'NotAContract', ) }) it('reverts if called by a non-owner', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(keeper1) [ 'registerUpkeep(address,uint32,address,bytes,bytes)' ](mock.address, performGas, await admin.getAddress(), emptyBytes, '0x'), - 'OnlyCallableByOwnerOrRegistrar()', + registry, + 'OnlyCallableByOwnerOrRegistrar', ) }) it('reverts if execute gas is too low', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(owner) [ 'registerUpkeep(address,uint32,address,bytes,bytes)' ](mock.address, 2299, await admin.getAddress(), emptyBytes, '0x'), - 'GasLimitOutsideRange()', + registry, + 'GasLimitOutsideRange', ) }) it('reverts if execute gas is too high', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(owner) [ 'registerUpkeep(address,uint32,address,bytes,bytes)' ](mock.address, 5000001, await admin.getAddress(), emptyBytes, '0x'), - 'GasLimitOutsideRange()', + registry, + 'GasLimitOutsideRange', ) }) @@ -4168,13 +4201,14 @@ describe('AutomationRegistry2_2', () => { for (let i = 0; i < 10000; i++) { longBytes += '1' } - await evmRevert( + await evmRevertCustomError( registry .connect(owner) [ 'registerUpkeep(address,uint32,address,bytes,bytes)' ](mock.address, performGas, await admin.getAddress(), longBytes, '0x'), - 'CheckDataExceedsLimit()', + registry, + 'CheckDataExceedsLimit', ) }) @@ -4231,34 +4265,38 @@ describe('AutomationRegistry2_2', () => { describe('#pauseUpkeep', () => { it('reverts if the registration does not exist', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(keeper1).pauseUpkeep(upkeepId.add(1)), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) it('reverts if the upkeep is already canceled', async () => { await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry.connect(admin).pauseUpkeep(upkeepId), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) it('reverts if the upkeep is already paused', async () => { await registry.connect(admin).pauseUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry.connect(admin).pauseUpkeep(upkeepId), - 'OnlyUnpausedUpkeep()', + registry, + 'OnlyUnpausedUpkeep', ) }) it('reverts if the caller is not the upkeep admin', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(keeper1).pauseUpkeep(upkeepId), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) @@ -4273,18 +4311,20 @@ describe('AutomationRegistry2_2', () => { describe('#unpauseUpkeep', () => { it('reverts if the registration does not exist', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(keeper1).unpauseUpkeep(upkeepId.add(1)), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) it('reverts if the upkeep is already canceled', async () => { await registry.connect(owner).cancelUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry.connect(admin).unpauseUpkeep(upkeepId), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) @@ -4297,9 +4337,10 @@ describe('AutomationRegistry2_2', () => { }) it('reverts if the upkeep is not paused', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(admin).unpauseUpkeep(upkeepId), - 'OnlyPausedUpkeep()', + registry, + 'OnlyPausedUpkeep', ) }) @@ -4310,9 +4351,10 @@ describe('AutomationRegistry2_2', () => { assert.equal(registration.paused, true) - await evmRevert( + await evmRevertCustomError( registry.connect(keeper1).unpauseUpkeep(upkeepId), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) @@ -4335,27 +4377,30 @@ describe('AutomationRegistry2_2', () => { describe('#setUpkeepCheckData', () => { it('reverts if the registration does not exist', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(keeper1) .setUpkeepCheckData(upkeepId.add(1), randomBytes), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) it('reverts if the caller is not upkeep admin', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(keeper1).setUpkeepCheckData(upkeepId, randomBytes), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) it('reverts if the upkeep is cancelled', async () => { await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry.connect(admin).setUpkeepCheckData(upkeepId, randomBytes), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) @@ -4373,9 +4418,10 @@ describe('AutomationRegistry2_2', () => { longBytes += '1' } - await evmRevert( + await evmRevertCustomError( registry.connect(admin).setUpkeepCheckData(upkeepId, longBytes), - 'CheckDataExceedsLimit()', + registry, + 'CheckDataExceedsLimit', ) }) @@ -4396,39 +4442,44 @@ describe('AutomationRegistry2_2', () => { const newGasLimit = BigNumber.from('300000') it('reverts if the registration does not exist', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(admin).setUpkeepGasLimit(upkeepId.add(1), newGasLimit), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) it('reverts if the upkeep is canceled', async () => { await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry.connect(admin).setUpkeepGasLimit(upkeepId, newGasLimit), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) it('reverts if called by anyone but the admin', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(owner).setUpkeepGasLimit(upkeepId, newGasLimit), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) it('reverts if new gas limit is out of bounds', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(admin) .setUpkeepGasLimit(upkeepId, BigNumber.from('100')), - 'GasLimitOutsideRange()', + registry, + 'GasLimitOutsideRange', ) - await evmRevert( + await evmRevertCustomError( registry .connect(admin) .setUpkeepGasLimit(upkeepId, BigNumber.from('6000000')), - 'GasLimitOutsideRange()', + registry, + 'GasLimitOutsideRange', ) }) @@ -4454,26 +4505,29 @@ describe('AutomationRegistry2_2', () => { const newConfig = '0xc0ffeec0ffee' it('reverts if the registration does not exist', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(admin) .setUpkeepOffchainConfig(upkeepId.add(1), newConfig), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) it('reverts if the upkeep is canceled', async () => { await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry.connect(admin).setUpkeepOffchainConfig(upkeepId, newConfig), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) it('reverts if called by anyone but the admin', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(owner).setUpkeepOffchainConfig(upkeepId, newConfig), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) @@ -4499,26 +4553,29 @@ describe('AutomationRegistry2_2', () => { const newConfig = '0xdeadbeef' it('reverts if the registration does not exist', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(admin) .setUpkeepTriggerConfig(upkeepId.add(1), newConfig), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) it('reverts if the upkeep is canceled', async () => { await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry.connect(admin).setUpkeepTriggerConfig(upkeepId, newConfig), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) it('reverts if called by anyone but the admin', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(owner).setUpkeepTriggerConfig(upkeepId, newConfig), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) @@ -4534,31 +4591,34 @@ describe('AutomationRegistry2_2', () => { describe('#transferUpkeepAdmin', () => { it('reverts when called by anyone but the current upkeep admin', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(payee1) .transferUpkeepAdmin(upkeepId, await payee2.getAddress()), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) it('reverts when transferring to self', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(admin) .transferUpkeepAdmin(upkeepId, await admin.getAddress()), - 'ValueNotChanged()', + registry, + 'ValueNotChanged', ) }) it('reverts when the upkeep is cancelled', async () => { await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry .connect(admin) .transferUpkeepAdmin(upkeepId, await keeper1.getAddress()), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) @@ -4620,18 +4680,20 @@ describe('AutomationRegistry2_2', () => { }) it('reverts when not called by the proposed upkeep admin', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(payee2).acceptUpkeepAdmin(upkeepId), - 'OnlyCallableByProposedAdmin()', + registry, + 'OnlyCallableByProposedAdmin', ) }) it('reverts when the upkeep is cancelled', async () => { await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry.connect(payee1).acceptUpkeepAdmin(upkeepId), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) @@ -4714,26 +4776,28 @@ describe('AutomationRegistry2_2', () => { describe('#transferPayeeship', () => { it('reverts when called by anyone but the current payee', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(payee2) .transferPayeeship( await keeper1.getAddress(), await payee2.getAddress(), ), - 'OnlyCallableByPayee()', + registry, + 'OnlyCallableByPayee', ) }) it('reverts when transferring to self', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(payee1) .transferPayeeship( await keeper1.getAddress(), await payee1.getAddress(), ), - 'ValueNotChanged()', + registry, + 'ValueNotChanged', ) }) @@ -4795,9 +4859,10 @@ describe('AutomationRegistry2_2', () => { }) it('reverts when called by anyone but the proposed payee', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(payee1).acceptPayeeship(await keeper1.getAddress()), - 'OnlyCallableByProposedPayee()', + registry, + 'OnlyCallableByProposedPayee', ) }) @@ -4841,22 +4906,24 @@ describe('AutomationRegistry2_2', () => { it('Does not allow transmits when paused', async () => { await registry.connect(owner).pause() - await evmRevert( + await evmRevertCustomError( getTransmitTx(registry, keeper1, [upkeepId]), - 'RegistryPaused()', + registry, + 'RegistryPaused', ) }) it('Does not allow creation of new upkeeps when paused', async () => { await registry.connect(owner).pause() - await evmRevert( + await evmRevertCustomError( registry .connect(owner) [ 'registerUpkeep(address,uint32,address,bytes,bytes)' ](mock.address, performGas, await admin.getAddress(), emptyBytes, '0x'), - 'RegistryPaused()', + registry, + 'RegistryPaused', ) }) }) @@ -4945,10 +5012,13 @@ describe('AutomationRegistry2_2', () => { // migration will delete the upkeep and nullify admin transfer await expect( registry.connect(payee1).acceptUpkeepAdmin(upkeepId), - ).to.be.revertedWith('UpkeepCancelled()') + ).to.be.revertedWithCustomError(registry, 'UpkeepCancelled') await expect( mgRegistry.connect(payee1).acceptUpkeepAdmin(upkeepId), - ).to.be.revertedWith('OnlyCallableByProposedAdmin()') + ).to.be.revertedWithCustomError( + mgRegistry, + 'OnlyCallableByProposedAdmin', + ) }) it('migrates a paused upkeep', async () => { @@ -5013,7 +5083,7 @@ describe('AutomationRegistry2_2', () => { registry .connect(owner) .migrateUpkeeps([upkeepId], mgRegistry.address), - ).to.be.revertedWith('OnlyCallableByAdmin()') + ).to.be.revertedWithCustomError(registry, 'OnlyCallableByAdmin') await registry .connect(admin) .migrateUpkeeps([upkeepId], mgRegistry.address) @@ -5057,20 +5127,22 @@ describe('AutomationRegistry2_2', () => { }) it('reverts with different numbers of payees than transmitters', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(owner).setPayees([...payees, randomAddress()]), - 'ParameterLengthError()', + registry, + 'ParameterLengthError', ) }) it('reverts if the payee is the zero address', async () => { await blankRegistry.connect(owner).setConfigTypeSafe(...baseConfig) // used to test initial config - await evmRevert( + await evmRevertCustomError( blankRegistry // used to test initial config .connect(owner) .setPayees([ethers.constants.AddressZero, ...payees.slice(1)]), - 'InvalidPayee()', + registry, + 'InvalidPayee', ) }) @@ -5144,9 +5216,10 @@ describe('AutomationRegistry2_2', () => { it('reverts if payee is non zero and owner tries to change payee', async () => { const newPayees = [randomAddress(), ...payees.slice(1)] - await evmRevert( + await evmRevertCustomError( registry.connect(owner).setPayees(newPayees), - 'InvalidPayee()', + registry, + 'InvalidPayee', ) }) @@ -5160,16 +5233,18 @@ describe('AutomationRegistry2_2', () => { describe('#cancelUpkeep', () => { it('reverts if the ID is not valid', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(owner).cancelUpkeep(upkeepId.add(1)), - 'CannotCancel()', + registry, + 'CannotCancel', ) }) it('reverts if called by a non-owner/non-admin', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(keeper1).cancelUpkeep(upkeepId), - 'OnlyCallableByOwnerOrAdmin()', + registry, + 'OnlyCallableByOwnerOrAdmin', ) }) @@ -5205,9 +5280,10 @@ describe('AutomationRegistry2_2', () => { it('does not revert if reverts if called multiple times', async () => { await registry.connect(owner).cancelUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry.connect(owner).cancelUpkeep(upkeepId), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) @@ -5222,9 +5298,10 @@ describe('AutomationRegistry2_2', () => { }) it('reverts with proper error', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(owner).cancelUpkeep(upkeepId), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) }) @@ -5234,9 +5311,10 @@ describe('AutomationRegistry2_2', () => { it('reverts if called again by the admin', async () => { await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry.connect(admin).cancelUpkeep(upkeepId), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) @@ -5247,9 +5325,10 @@ describe('AutomationRegistry2_2', () => { await ethers.provider.send('evm_mine', []) } - await evmRevert( + await evmRevertCustomError( registry.connect(owner).cancelUpkeep(upkeepId), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) @@ -5467,23 +5546,25 @@ describe('AutomationRegistry2_2', () => { }) it('reverts if called by anyone but the payee', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(payee2) .withdrawPayment( await keeper1.getAddress(), await nonkeeper.getAddress(), ), - 'OnlyCallableByPayee()', + registry, + 'OnlyCallableByPayee', ) }) it('reverts if called with the 0 address', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(payee2) .withdrawPayment(await keeper1.getAddress(), zeroAddress), - 'InvalidRecipient()', + registry, + 'InvalidRecipient', ) }) @@ -5634,9 +5715,10 @@ describe('AutomationRegistry2_2', () => { describe('#setUpkeepPrivilegeConfig() / #getUpkeepPrivilegeConfig()', () => { it('reverts when non manager tries to set privilege config', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(payee3).setUpkeepPrivilegeConfig(upkeepId, '0x1234'), - 'OnlyCallableByUpkeepPrivilegeManager()', + registry, + 'OnlyCallableByUpkeepPrivilegeManager', ) }) @@ -5662,9 +5744,10 @@ describe('AutomationRegistry2_2', () => { const admin = randomAddress() it('reverts when non manager tries to set privilege config', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(payee3).setAdminPrivilegeConfig(admin, '0x1234'), - 'OnlyCallableByUpkeepPrivilegeManager()', + registry, + 'OnlyCallableByUpkeepPrivilegeManager', ) }) diff --git a/contracts/test/v0.8/automation/AutomationRegistry2_3.test.ts b/contracts/test/v0.8/automation/AutomationRegistry2_3.test.ts index 60904d35b76..1036ab2ce88 100644 --- a/contracts/test/v0.8/automation/AutomationRegistry2_3.test.ts +++ b/contracts/test/v0.8/automation/AutomationRegistry2_3.test.ts @@ -12,7 +12,7 @@ import { Signer, Wallet, } from 'ethers' -import { evmRevert } from '../../test-helpers/matchers' +import { evmRevert, evmRevertCustomError } from '../../test-helpers/matchers' import { getUsers, Personas } from '../../test-helpers/setup' import { randomAddress, toWei } from '../../test-helpers/helpers' import { StreamsLookupUpkeep__factory as StreamsLookupUpkeepFactory } from '../../../typechain/factories/StreamsLookupUpkeep__factory' @@ -27,7 +27,7 @@ import { OptimismModule__factory as OptimismModuleFactory } from '../../../typec import { ILogAutomation__factory as ILogAutomationactory } from '../../../typechain/factories/ILogAutomation__factory' import { IAutomationForwarder__factory as IAutomationForwarderFactory } from '../../../typechain/factories/IAutomationForwarder__factory' import { MockArbSys__factory as MockArbSysFactory } from '../../../typechain/factories/MockArbSys__factory' -import { AutomationUtils2_3 as AutomationUtils } from '../../../typechain/AutomationUtils2_3' +import { AutomationCompatibleUtils } from '../../../typechain/AutomationCompatibleUtils' import { MockArbGasInfo } from '../../../typechain/MockArbGasInfo' import { MockOVMGasPriceOracle } from '../../../typechain/MockOVMGasPriceOracle' import { StreamsLookupUpkeep } from '../../../typechain/StreamsLookupUpkeep' @@ -50,6 +50,7 @@ import { MockContract, } from '@ethereum-waffle/mock-contract' import { deployRegistry23 } from './helpers' +import { AutomationUtils2_3 } from '../../../typechain/AutomationUtils2_3' const describeMaybe = process.env.SKIP_SLOW ? describe.skip : describe const itMaybe = process.env.SKIP_SLOW ? it.skip : it @@ -75,12 +76,13 @@ enum Trigger { } // un-exported types that must be extracted from the utils contract -type Report = Parameters[0] -type OnChainConfig = Parameters[0] -type BillingConfig = Parameters[2][0] -type LogTrigger = Parameters[0] -type ConditionalTrigger = Parameters[0] -type Log = Parameters[0] +type Report = Parameters[0] +type LogTrigger = Parameters[0] +type ConditionalTrigger = Parameters< + AutomationCompatibleUtils['_conditionalTrigger'] +>[0] +type Log = Parameters[0] +type OnChainConfig = Parameters[3] // ----------------------------------------------------------------------------------------------- @@ -109,7 +111,7 @@ const gasWei = BigNumber.from(1000000000) // 1 gwei const performGas = BigNumber.from('1000000') const paymentPremiumBase = BigNumber.from('1000000000') const paymentPremiumPPB = BigNumber.from('250000000') -const flatFeeMicroLink = BigNumber.from(0) +const flatFeeMilliCents = BigNumber.from(0) const randomBytes = '0x1234abcd' const emptyBytes = '0x' @@ -117,7 +119,7 @@ const emptyBytes32 = '0x0000000000000000000000000000000000000000000000000000000000000000' const transmitGasOverhead = 1_000_000 -const checkGasOverhead = 500_000 +const checkGasOverhead = 600_000 const stalenessSeconds = BigNumber.from(43820) const gasCeilingMultiplier = BigNumber.from(2) @@ -134,6 +136,7 @@ const f = 1 const offchainVersion = 1 const offchainBytes = '0x' const zeroAddress = ethers.constants.AddressZero +const wrappedNativeTokenAddress = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' const epochAndRound5_1 = '0x0000000000000000000000000000000000000000000000000000000000000501' @@ -174,7 +177,8 @@ let chainModuleBase: ChainModuleBase let arbitrumModule: ArbitrumModule let optimismModule: OptimismModule let streamsLookupUpkeep: StreamsLookupUpkeep -let automationUtils: AutomationUtils +let automationUtils: AutomationCompatibleUtils +let automationUtils2_3: AutomationUtils2_3 function now() { return Math.floor(Date.now() / 1000) @@ -204,23 +208,6 @@ const getTriggerType = (upkeepId: BigNumber): Trigger => { return bytes[15] as Trigger } -const encodeConfig = ( - onchainConfig: OnChainConfig, - billingTokens: string[], - billingConfigs: BillingConfig[], -) => { - return ( - '0x' + - automationUtils.interface - .encodeFunctionData('_onChainConfig', [ - onchainConfig, - billingTokens, - billingConfigs, - ]) - .slice(10) - ) -} - const encodeBlockTrigger = (conditionalTrigger: ConditionalTrigger) => { return ( '0x' + @@ -248,7 +235,9 @@ const encodeLog = (log: Log) => { const encodeReport = (report: Report) => { return ( '0x' + - automationUtils.interface.encodeFunctionData('_report', [report]).slice(10) + automationUtils2_3.interface + .encodeFunctionData('_report', [report]) + .slice(10) ) } @@ -422,19 +411,24 @@ describe('AutomationRegistry2_3', () => { let config: OnChainConfig let arbConfig: OnChainConfig let opConfig: OnChainConfig - let baseConfig: Parameters - let arbConfigParams: Parameters - let opConfigParams: Parameters + let baseConfig: Parameters + let arbConfigParams: Parameters + let opConfigParams: Parameters let upkeepManager: string before(async () => { personas = (await getUsers()).personas + const compatibleUtilsFactory = await ethers.getContractFactory( + 'AutomationCompatibleUtils', + ) + automationUtils = await compatibleUtilsFactory.deploy() + const utilsFactory = await ethers.getContractFactory('AutomationUtils2_3') - automationUtils = await utilsFactory.deploy() + automationUtils2_3 = await utilsFactory.deploy() linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', + 'src/v0.8/shared/test/helpers/LinkTokenTestHelper.sol:LinkTokenTestHelper', ) // need full path because there are two contracts with name MockV3Aggregator mockV3AggregatorFactory = (await ethers.getContractFactory( @@ -538,7 +532,7 @@ describe('AutomationRegistry2_3', () => { gasOverhead: BigNumber, gasMultiplier: BigNumber, premiumPPB: BigNumber, - flatFee: BigNumber, + flatFee: BigNumber, // in millicents l1CostWei?: BigNumber, ) => { l1CostWei = l1CostWei === undefined ? BigNumber.from(0) : l1CostWei @@ -558,9 +552,9 @@ describe('AutomationRegistry2_3', () => { .add(l1CostWei) .mul(premiumPPB) .mul(nativeUSD) - .div(linkUSD) .div(paymentPremiumBase) - .add(flatFee.mul('1000000000000')) + .add(flatFee.mul(BigNumber.from(10).pow(21))) + .div(linkUSD) return { total: gasPayment.add(premium), @@ -641,42 +635,47 @@ describe('AutomationRegistry2_3', () => { const financeAdminAddress = await financeAdmin.getAddress() for (const test of tests) { - await registry.connect(owner).setConfig( + await registry.connect(owner).setConfigTypeSafe( signerAddresses, keeperAddresses, f, - encodeConfig( - { - paymentPremiumPPB: test.premium, - flatFeeMicroLink: test.flatFee, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier: test.multiplier, - minUpkeepSpend, - maxCheckDataSize, - maxPerformDataSize, - maxRevertDataSize, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - fallbackNativePrice, - transcoder: transcoder.address, - registrars: [], - upkeepPrivilegeManager: upkeepManager, - chainModule: chainModule.address, - reorgProtectionEnabled: true, - financeAdmin: financeAdminAddress, - }, - [], - [], - ), + { + checkGasLimit, + stalenessSeconds, + gasCeilingMultiplier: test.multiplier, + maxCheckDataSize, + maxPerformDataSize, + maxRevertDataSize, + maxPerformGas, + fallbackGasPrice, + fallbackLinkPrice, + fallbackNativePrice, + transcoder: transcoder.address, + registrars: [], + upkeepPrivilegeManager: upkeepManager, + chainModule: chainModule.address, + reorgProtectionEnabled: true, + financeAdmin: financeAdminAddress, + }, offchainVersion, offchainBytes, + [linkToken.address], + [ + { + gasFeePPB: test.premium, + flatFeeMilliCents: test.flatFee, + priceFeed: linkUSDFeed.address, + fallbackPrice: fallbackLinkPrice, + minSpend: minUpkeepSpend, + }, + ], ) const conditionalPrice = await registry.getMaxPaymentForGas( + upkeepId, Trigger.CONDITION, test.gas, + linkToken.address, ) expect(conditionalPrice).to.equal( linkForGas( @@ -689,7 +688,12 @@ describe('AutomationRegistry2_3', () => { ).total, ) - const logPrice = await registry.getMaxPaymentForGas(Trigger.LOG, test.gas) + const logPrice = await registry.getMaxPaymentForGas( + upkeepId, + Trigger.LOG, + test.gas, + linkToken.address, + ) expect(logPrice).to.equal( linkForGas( BigNumber.from(test.gas), @@ -706,8 +710,9 @@ describe('AutomationRegistry2_3', () => { const verifyConsistentAccounting = async ( maxAllowedSpareChange: BigNumber, ) => { - const expectedLinkBalance = (await registry.getState()).state - .expectedLinkBalance + const expectedLinkBalance = await registry.getReserveAmount( + linkToken.address, + ) const linkTokenBalance = await linkToken.balanceOf(registry.address) const upkeepIdBalance = (await registry.getUpkeep(upkeepId)).balance let totalKeeperBalance = BigNumber.from(0) @@ -867,7 +872,7 @@ describe('AutomationRegistry2_3', () => { .connect(owner) .deploy(8, nativeUSD) const upkeepTranscoderFactory = await ethers.getContractFactory( - 'UpkeepTranscoder4_0', + 'UpkeepTranscoder5_0', ) transcoder = await upkeepTranscoderFactory.connect(owner).deploy() mockArbGasInfo = await mockArbGasInfoFactory.connect(owner).deploy() @@ -914,12 +919,9 @@ describe('AutomationRegistry2_3', () => { const financeAdminAddress = await financeAdmin.getAddress() config = { - paymentPremiumPPB, - flatFeeMicroLink, checkGasLimit, stalenessSeconds, gasCeilingMultiplier, - minUpkeepSpend, maxCheckDataSize, maxPerformDataSize, maxRevertDataSize, @@ -944,25 +946,57 @@ describe('AutomationRegistry2_3', () => { signerAddresses, keeperAddresses, f, - encodeConfig(config, [], []), + config, offchainVersion, offchainBytes, + [linkToken.address], + [ + { + gasFeePPB: paymentPremiumPPB, + flatFeeMilliCents, + priceFeed: linkUSDFeed.address, + fallbackPrice: fallbackLinkPrice, + minSpend: minUpkeepSpend, + }, + ], ] + arbConfigParams = [ signerAddresses, keeperAddresses, f, - encodeConfig(arbConfig, [], []), + arbConfig, offchainVersion, offchainBytes, + [linkToken.address], + [ + { + gasFeePPB: paymentPremiumPPB, + flatFeeMilliCents, + priceFeed: linkUSDFeed.address, + fallbackPrice: fallbackLinkPrice, + minSpend: minUpkeepSpend, + }, + ], ] + opConfigParams = [ signerAddresses, keeperAddresses, f, - encodeConfig(opConfig, [], []), + opConfig, offchainVersion, offchainBytes, + [linkToken.address], + [ + { + gasFeePPB: paymentPremiumPPB, + flatFeeMilliCents, + priceFeed: linkUSDFeed.address, + fallbackPrice: fallbackLinkPrice, + minSpend: minUpkeepSpend, + }, + ], ] const registryParams: Parameters = [ @@ -972,6 +1006,8 @@ describe('AutomationRegistry2_3', () => { nativeUSDFeed.address, gasPriceFeed.address, zeroAddress, + 0, // onchain payout mode + wrappedNativeTokenAddress, ] registry = await deployRegistry23(...registryParams) @@ -991,10 +1027,10 @@ describe('AutomationRegistry2_3', () => { await registry.getTransmitCalldataPerSignerBytesOverhead() cancellationDelay = (await registry.getCancellationDelay()).toNumber() - await registry.connect(owner).setConfig(...baseConfig) - await mgRegistry.connect(owner).setConfig(...baseConfig) - await arbRegistry.connect(owner).setConfig(...arbConfigParams) - await opRegistry.connect(owner).setConfig(...opConfigParams) + await registry.connect(owner).setConfigTypeSafe(...baseConfig) + await mgRegistry.connect(owner).setConfigTypeSafe(...baseConfig) + await arbRegistry.connect(owner).setConfigTypeSafe(...arbConfigParams) + await opRegistry.connect(owner).setConfigTypeSafe(...opConfigParams) for (const reg of [registry, arbRegistry, opRegistry, mgRegistry]) { await reg.connect(owner).setPayees(payees) await linkToken.connect(admin).approve(reg.address, toWei('1000')) @@ -1007,9 +1043,16 @@ describe('AutomationRegistry2_3', () => { .transfer(await admin.getAddress(), toWei('1000')) let tx = await registry .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') + .registerUpkeep( + mock.address, + performGas, + await admin.getAddress(), + Trigger.CONDITION, + linkToken.address, + randomBytes, + '0x', + '0x', + ) upkeepId = await getUpkeepID(tx) autoFunderUpkeep = await upkeepAutoFunderFactory @@ -1017,17 +1060,31 @@ describe('AutomationRegistry2_3', () => { .deploy(linkToken.address, registry.address) tx = await registry .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](autoFunderUpkeep.address, performGas, autoFunderUpkeep.address, randomBytes, '0x') + .registerUpkeep( + autoFunderUpkeep.address, + performGas, + autoFunderUpkeep.address, + Trigger.CONDITION, + linkToken.address, + '0x', + '0x', + '0x', + ) afUpkeepId = await getUpkeepID(tx) ltUpkeep = await deployMockContract(owner, ILogAutomationactory.abi) tx = await registry .connect(owner) - [ - 'registerUpkeep(address,uint32,address,uint8,bytes,bytes,bytes)' - ](ltUpkeep.address, performGas, await admin.getAddress(), Trigger.LOG, '0x', logTriggerConfig, emptyBytes) + .registerUpkeep( + ltUpkeep.address, + performGas, + await admin.getAddress(), + Trigger.LOG, + linkToken.address, + '0x', + logTriggerConfig, + emptyBytes, + ) logUpkeepId = await getUpkeepID(tx) await autoFunderUpkeep.setUpkeepId(afUpkeepId) @@ -1038,9 +1095,16 @@ describe('AutomationRegistry2_3', () => { tx = await registry .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](streamsLookupUpkeep.address, performGas, await admin.getAddress(), randomBytes, '0x') + .registerUpkeep( + streamsLookupUpkeep.address, + performGas, + await admin.getAddress(), + Trigger.CONDITION, + linkToken.address, + '0x', + '0x', + '0x', + ) streamsLookupUpkeepId = await getUpkeepID(tx) } @@ -1058,9 +1122,16 @@ describe('AutomationRegistry2_3', () => { await mock.setPerformGasToBurn(BigNumber.from('0')) const tx = await registry .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') + .registerUpkeep( + mock.address, + performGas, + await admin.getAddress(), + Trigger.CONDITION, + linkToken.address, + '0x', + '0x', + '0x', + ) const condUpkeepId = await getUpkeepID(tx) passingConditionalUpkeepIds.push(condUpkeepId) @@ -1073,9 +1144,16 @@ describe('AutomationRegistry2_3', () => { await mock.setPerformGasToBurn(BigNumber.from('0')) const tx = await registry .connect(owner) - [ - 'registerUpkeep(address,uint32,address,uint8,bytes,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), Trigger.LOG, '0x', logTriggerConfig, emptyBytes) + .registerUpkeep( + mock.address, + performGas, + await admin.getAddress(), + Trigger.LOG, + linkToken.address, + '0x', + logTriggerConfig, + emptyBytes, + ) const logUpkeepId = await getUpkeepID(tx) passingLogUpkeepIds.push(logUpkeepId) @@ -1088,9 +1166,16 @@ describe('AutomationRegistry2_3', () => { await mock.setPerformGasToBurn(BigNumber.from('0')) const tx = await registry .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') + .registerUpkeep( + mock.address, + performGas, + await admin.getAddress(), + Trigger.CONDITION, + linkToken.address, + '0x', + '0x', + '0x', + ) const failingUpkeepId = await getUpkeepID(tx) failingUpkeepIds.push(failingUpkeepId) } @@ -1110,16 +1195,18 @@ describe('AutomationRegistry2_3', () => { it('reverts when registry is paused', async () => { await registry.connect(owner).pause() - await evmRevert( + await evmRevertCustomError( getTransmitTx(registry, keeper1, [upkeepId]), - 'RegistryPaused()', + registry, + 'RegistryPaused', ) }) it('reverts when called by non active transmitter', async () => { - await evmRevert( + await evmRevertCustomError( getTransmitTx(registry, payee1, [upkeepId]), - 'OnlyActiveTransmitters()', + registry, + 'OnlyActiveTransmitters', ) }) @@ -1145,9 +1232,10 @@ describe('AutomationRegistry2_3', () => { performDatas, }) - await evmRevert( + await evmRevertCustomError( getTransmitTxWithReport(registry, keeper1, report), - 'InvalidReport()', + registry, + 'InvalidReport', ) }) @@ -1341,8 +1429,8 @@ describe('AutomationRegistry2_3', () => { newConfig, offchainVersion, offchainBytes, - [], - [], + baseConfig[6], + baseConfig[7], ) for (const [type, id] of tests) { @@ -1375,8 +1463,8 @@ describe('AutomationRegistry2_3', () => { newConfig, offchainVersion, offchainBytes, - [], - [], + baseConfig[6], + baseConfig[7], ) for (let i = 0; i < 256; i++) { await ethers.provider.send('evm_mine', []) @@ -1478,8 +1566,8 @@ describe('AutomationRegistry2_3', () => { newConfig, offchainVersion, offchainBytes, - [], - [], + baseConfig[6], + baseConfig[7], ) const tests: [string, BigNumber][] = [ ['conditional', upkeepId], @@ -1604,8 +1692,8 @@ describe('AutomationRegistry2_3', () => { }) it('uses actual execution price for payment and premium calculation', async () => { - // Actual multiplier is 2, but we set gasPrice to be 1x gasWei - const gasPrice = gasWei.mul(BigNumber.from('1')) + // Actual multiplier is 2, but we set gasPrice to be == gasWei + const gasPrice = gasWei await mock.setCanPerform(true) const registryPremiumBefore = (await registry.getState()).state .totalPremium @@ -1632,7 +1720,7 @@ describe('AutomationRegistry2_3', () => { gasOverhead, BigNumber.from('1'), // Not the config multiplier, but the actual gas used paymentPremiumPPB, - flatFeeMicroLink, + flatFeeMilliCents, ).total.toString(), totalPayment.toString(), ) @@ -1643,7 +1731,7 @@ describe('AutomationRegistry2_3', () => { gasOverhead, BigNumber.from('1'), // Not the config multiplier, but the actual gas used paymentPremiumPPB, - flatFeeMicroLink, + flatFeeMilliCents, ).premium.toString(), premium.toString(), ) @@ -1673,7 +1761,7 @@ describe('AutomationRegistry2_3', () => { gasOverhead, gasCeilingMultiplier, // Should be same with exisitng multiplier paymentPremiumPPB, - flatFeeMicroLink, + flatFeeMilliCents, ).total.toString(), totalPayment.toString(), ) @@ -1686,9 +1774,16 @@ describe('AutomationRegistry2_3', () => { let tx = await arbRegistry .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') + .registerUpkeep( + mock.address, + performGas, + await admin.getAddress(), + Trigger.CONDITION, + linkToken.address, + '0x', + '0x', + '0x', + ) const testUpkeepId = await getUpkeepID(tx) await arbRegistry.connect(owner).addFunds(testUpkeepId, toWei('100')) @@ -1716,7 +1811,7 @@ describe('AutomationRegistry2_3', () => { gasOverhead, gasCeilingMultiplier, paymentPremiumPPB, - flatFeeMicroLink, + flatFeeMilliCents, l1CostWeiArb, ).total.toString(), totalPayment.toString(), @@ -1725,8 +1820,10 @@ describe('AutomationRegistry2_3', () => { itMaybe('can self fund', async () => { const maxPayment = await registry.getMaxPaymentForGas( + upkeepId, Trigger.CONDITION, performGas, + linkToken.address, ) // First set auto funding amount to 0 and verify that balance is deducted upon performUpkeep @@ -1778,7 +1875,7 @@ describe('AutomationRegistry2_3', () => { const report = await makeLatestBlockReport([upkeepId]) const reportContext = [emptyBytes32, epochAndRound5_1, emptyBytes32] // wrong config digest const sigs = signReport(reportContext, report, signers.slice(0, f + 1)) - await evmRevert( + await evmRevertCustomError( registry .connect(keeper1) .transmit( @@ -1788,7 +1885,8 @@ describe('AutomationRegistry2_3', () => { sigs.ss, sigs.vs, ), - 'ConfigDigestMismatch()', + registry, + 'ConfigDigestMismatch', ) }) @@ -1798,7 +1896,7 @@ describe('AutomationRegistry2_3', () => { const report = await makeLatestBlockReport([upkeepId]) const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] // wrong config digest const sigs = signReport(reportContext, report, signers.slice(0, f + 2)) - await evmRevert( + await evmRevertCustomError( registry .connect(keeper1) .transmit( @@ -1808,7 +1906,8 @@ describe('AutomationRegistry2_3', () => { sigs.ss, sigs.vs, ), - 'IncorrectNumberOfSignatures()', + registry, + 'IncorrectNumberOfSignatures', ) }) @@ -1821,7 +1920,7 @@ describe('AutomationRegistry2_3', () => { new ethers.Wallet(ethers.Wallet.createRandom()), new ethers.Wallet(ethers.Wallet.createRandom()), ]) - await evmRevert( + await evmRevertCustomError( registry .connect(keeper1) .transmit( @@ -1831,7 +1930,8 @@ describe('AutomationRegistry2_3', () => { sigs.ss, sigs.vs, ), - 'OnlyActiveSigners()', + registry, + 'OnlyActiveSigners', ) }) @@ -1841,7 +1941,7 @@ describe('AutomationRegistry2_3', () => { const report = await makeLatestBlockReport([upkeepId]) const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] // wrong config digest const sigs = signReport(reportContext, report, [signer1, signer1]) - await evmRevert( + await evmRevertCustomError( registry .connect(keeper1) .transmit( @@ -1851,7 +1951,8 @@ describe('AutomationRegistry2_3', () => { sigs.ss, sigs.vs, ), - 'DuplicateSigners()', + registry, + 'DuplicateSigners', ) }) @@ -1865,18 +1966,19 @@ describe('AutomationRegistry2_3', () => { config, offchainVersion, offchainBytes, - [], - [], + baseConfig[6], + baseConfig[7], + ) + const tx = await registry.connect(owner).registerUpkeep( + mock.address, + maxPerformGas, // max allowed gas + await admin.getAddress(), + Trigger.CONDITION, + linkToken.address, + '0x', + '0x', + '0x', ) - const tx = await registry - .connect(owner) - ['registerUpkeep(address,uint32,address,bytes,bytes)']( - mock.address, - maxPerformGas, // max allowed gas - await admin.getAddress(), - randomBytes, - '0x', - ) const testUpkeepId = await getUpkeepID(tx) await registry.connect(admin).addFunds(testUpkeepId, toWei('100')) @@ -1912,8 +2014,8 @@ describe('AutomationRegistry2_3', () => { config, offchainVersion, offchainBytes, - [], - [], + baseConfig[6], + baseConfig[7], ) const checkBlock = await ethers.provider.getBlock('latest') @@ -2014,278 +2116,290 @@ describe('AutomationRegistry2_3', () => { }, ) - // skipping it for now as it is passing in local but failing in CI - describe.skip('Gas benchmarking conditional upkeeps [ @skip-coverage ]', function () { - const fs = [1, 10] - fs.forEach(function (newF) { - it( - 'When f=' + - newF + - ' calculates gas overhead appropriately within a margin for different scenarios', - async () => { - // Perform the upkeep once to remove non-zero storage slots and have predictable gas measurement - let tx = await getTransmitTx(registry, keeper1, [upkeepId]) - await tx.wait() - - // Different test scenarios - let longBytes = '0x' - for (let i = 0; i < maxPerformDataSize.toNumber(); i++) { - longBytes += '11' - } - const upkeepSuccessArray = [true, false] - const performGasArray = [5000, performGas] - const performDataArray = ['0x', longBytes] - const chainModuleOverheads = - await chainModuleBase.getGasOverhead() - - for (const i in upkeepSuccessArray) { - for (const j in performGasArray) { - for (const k in performDataArray) { - const upkeepSuccess = upkeepSuccessArray[i] - const performGas = performGasArray[j] - const performData = performDataArray[k] - - await mock.setCanPerform(upkeepSuccess) - await mock.setPerformGasToBurn(performGas) - await registry - .connect(owner) - .setConfigTypeSafe( - signerAddresses, - keeperAddresses, + describeMaybe( + 'Gas benchmarking conditional upkeeps [ @skip-coverage ]', + function () { + const fs = [1, 10] + fs.forEach(function (newF) { + it( + 'When f=' + + newF + + ' calculates gas overhead appropriately within a margin for different scenarios', + async () => { + // Perform the upkeep once to remove non-zero storage slots and have predictable gas measurement + let tx = await getTransmitTx(registry, keeper1, [upkeepId]) + await tx.wait() + + // Different test scenarios + let longBytes = '0x' + for (let i = 0; i < maxPerformDataSize.toNumber(); i++) { + longBytes += '11' + } + const upkeepSuccessArray = [true, false] + const performGasArray = [5000, performGas] + const performDataArray = ['0x', longBytes] + const chainModuleOverheads = + await chainModuleBase.getGasOverhead() + + for (const i in upkeepSuccessArray) { + for (const j in performGasArray) { + for (const k in performDataArray) { + const upkeepSuccess = upkeepSuccessArray[i] + const performGas = performGasArray[j] + const performData = performDataArray[k] + + await mock.setCanPerform(upkeepSuccess) + await mock.setPerformGasToBurn(performGas) + await registry + .connect(owner) + .setConfigTypeSafe( + signerAddresses, + keeperAddresses, + newF, + config, + offchainVersion, + offchainBytes, + baseConfig[6], + baseConfig[7], + ) + tx = await getTransmitTx(registry, keeper1, [upkeepId], { + numSigners: newF + 1, + performDatas: [performData], + }) + const receipt = await tx.wait() + const upkeepPerformedLogs = + parseUpkeepPerformedLogs(receipt) + // exactly 1 Upkeep Performed should be emitted + assert.equal(upkeepPerformedLogs.length, 1) + const upkeepPerformedLog = upkeepPerformedLogs[0] + + const upkeepGasUsed = upkeepPerformedLog.args.gasUsed + const chargedGasOverhead = + upkeepPerformedLog.args.gasOverhead + const actualGasOverhead = + receipt.gasUsed.sub(upkeepGasUsed) + const estimatedGasOverhead = registryConditionalOverhead + .add( + registryPerSignerGasOverhead.mul( + BigNumber.from(newF + 1), + ), + ) + .add( + registryPerPerformByteGasOverhead + .add( + chainModuleOverheads.chainModulePerByteOverhead, + ) + .mul( + BigNumber.from(performData.length / 2 - 1) + .add(registryTransmitCalldataFixedBytesOverhead) + .add( + registryTransmitCalldataPerSignerBytesOverhead.mul( + BigNumber.from(newF + 1), + ), + ), + ), + ) + .add(chainModuleOverheads.chainModuleFixedOverhead) + + assert.isTrue(upkeepGasUsed.gt(BigNumber.from('0'))) + assert.isTrue(chargedGasOverhead.gt(BigNumber.from('0'))) + assert.isTrue(actualGasOverhead.gt(BigNumber.from('0'))) + + console.log( + 'Gas Benchmarking conditional upkeeps:', + 'upkeepSuccess=', + upkeepSuccess, + 'performGas=', + performGas.toString(), + 'performData length=', + performData.length / 2 - 1, + 'sig verification ( f =', newF, - config, - offchainVersion, - offchainBytes, - [], - [], - ) - tx = await getTransmitTx(registry, keeper1, [upkeepId], { - numSigners: newF + 1, - performDatas: [performData], - }) - const receipt = await tx.wait() - const upkeepPerformedLogs = - parseUpkeepPerformedLogs(receipt) - // exactly 1 Upkeep Performed should be emitted - assert.equal(upkeepPerformedLogs.length, 1) - const upkeepPerformedLog = upkeepPerformedLogs[0] - - const upkeepGasUsed = upkeepPerformedLog.args.gasUsed - const chargedGasOverhead = - upkeepPerformedLog.args.gasOverhead - const actualGasOverhead = receipt.gasUsed.sub(upkeepGasUsed) - const estimatedGasOverhead = registryConditionalOverhead - .add( - registryPerSignerGasOverhead.mul( - BigNumber.from(newF + 1), - ), + '): estimated overhead: ', + estimatedGasOverhead.toString(), + ' charged overhead: ', + chargedGasOverhead.toString(), + ' actual overhead: ', + actualGasOverhead.toString(), + ' calculation margin over gasUsed: ', + chargedGasOverhead.sub(actualGasOverhead).toString(), + ' estimation margin over gasUsed: ', + estimatedGasOverhead.sub(actualGasOverhead).toString(), ) - .add( - registryPerPerformByteGasOverhead - .add(chainModuleOverheads.chainModulePerByteOverhead) - .mul( - BigNumber.from(performData.length / 2 - 1) - .add(registryTransmitCalldataFixedBytesOverhead) - .add( - registryTransmitCalldataPerSignerBytesOverhead.mul( - BigNumber.from(newF + 1), - ), - ), - ), + + // The actual gas overhead should be less than charged gas overhead, but not by a lot + // The charged gas overhead is controlled by ACCOUNTING_FIXED_GAS_OVERHEAD and + // ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD, and their correct values should be set to + // satisfy constraints in multiple places + assert.isTrue( + chargedGasOverhead.gt(actualGasOverhead), + 'Gas overhead calculated is too low, increase account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD) by at least ' + + actualGasOverhead.sub(chargedGasOverhead).toString(), ) - .add(chainModuleOverheads.chainModuleFixedOverhead) - - assert.isTrue(upkeepGasUsed.gt(BigNumber.from('0'))) - assert.isTrue(chargedGasOverhead.gt(BigNumber.from('0'))) - assert.isTrue(actualGasOverhead.gt(BigNumber.from('0'))) - - console.log( - 'Gas Benchmarking conditional upkeeps:', - 'upkeepSuccess=', - upkeepSuccess, - 'performGas=', - performGas.toString(), - 'performData length=', - performData.length / 2 - 1, - 'sig verification ( f =', - newF, - '): estimated overhead: ', - estimatedGasOverhead.toString(), - ' charged overhead: ', - chargedGasOverhead.toString(), - ' actual overhead: ', - actualGasOverhead.toString(), - ' calculation margin over gasUsed: ', - chargedGasOverhead.sub(actualGasOverhead).toString(), - ' estimation margin over gasUsed: ', - estimatedGasOverhead.sub(actualGasOverhead).toString(), - ) - - // The actual gas overhead should be less than charged gas overhead, but not by a lot - // The charged gas overhead is controlled by ACCOUNTING_FIXED_GAS_OVERHEAD and - // ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD, and their correct values should be set to - // satisfy constraints in multiple places - assert.isTrue( - chargedGasOverhead.gt(actualGasOverhead), - 'Gas overhead calculated is too low, increase account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD) by at least ' + - actualGasOverhead.sub(chargedGasOverhead).toString(), - ) - assert.isTrue( - chargedGasOverhead - .sub(actualGasOverhead) - .lt(gasCalculationMargin), - 'Gas overhead calculated is too high, decrease account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_SIGNER_GAS_OVERHEAD) by at least ' + + assert.isTrue( chargedGasOverhead .sub(actualGasOverhead) - .sub(gasCalculationMargin) - .toString(), - ) - - // The estimated overhead during checkUpkeep should be close to the actual overhead in transaction - // It should be greater than the actual overhead but not by a lot - // The estimated overhead is controlled by variables - // REGISTRY_CONDITIONAL_OVERHEAD, REGISTRY_LOG_OVERHEAD, REGISTRY_PER_SIGNER_GAS_OVERHEAD - // REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD - assert.isTrue( - estimatedGasOverhead.gt(actualGasOverhead), - 'Gas overhead estimated in check upkeep is too low, increase estimation gas variables (REGISTRY_CONDITIONAL_OVERHEAD/REGISTRY_LOG_OVERHEAD/REGISTRY_PER_SIGNER_GAS_OVERHEAD/REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD) by at least ' + - estimatedGasOverhead.sub(chargedGasOverhead).toString(), - ) - assert.isTrue( - estimatedGasOverhead - .sub(actualGasOverhead) - .lt(gasEstimationMargin), - 'Gas overhead estimated is too high, decrease estimation gas variables (REGISTRY_CONDITIONAL_OVERHEAD/REGISTRY_LOG_OVERHEAD/REGISTRY_PER_SIGNER_GAS_OVERHEAD/REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD) by at least ' + + .lt(gasCalculationMargin), + 'Gas overhead calculated is too high, decrease account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_SIGNER_GAS_OVERHEAD) by at least ' + + chargedGasOverhead + .sub(actualGasOverhead) + .sub(gasCalculationMargin) + .toString(), + ) + + // The estimated overhead during checkUpkeep should be close to the actual overhead in transaction + // It should be greater than the actual overhead but not by a lot + // The estimated overhead is controlled by variables + // REGISTRY_CONDITIONAL_OVERHEAD, REGISTRY_LOG_OVERHEAD, REGISTRY_PER_SIGNER_GAS_OVERHEAD + // REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD + assert.isTrue( + estimatedGasOverhead.gt(actualGasOverhead), + 'Gas overhead estimated in check upkeep is too low, increase estimation gas variables (REGISTRY_CONDITIONAL_OVERHEAD/REGISTRY_LOG_OVERHEAD/REGISTRY_PER_SIGNER_GAS_OVERHEAD/REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD) by at least ' + + estimatedGasOverhead + .sub(chargedGasOverhead) + .toString(), + ) + assert.isTrue( estimatedGasOverhead .sub(actualGasOverhead) - .sub(gasEstimationMargin) - .toString(), - ) + .lt(gasEstimationMargin), + 'Gas overhead estimated is too high, decrease estimation gas variables (REGISTRY_CONDITIONAL_OVERHEAD/REGISTRY_LOG_OVERHEAD/REGISTRY_PER_SIGNER_GAS_OVERHEAD/REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD) by at least ' + + estimatedGasOverhead + .sub(actualGasOverhead) + .sub(gasEstimationMargin) + .toString(), + ) + } } } - } - }, - ) - }) - }) + }, + ) + }) + }, + ) - describe.skip('Gas benchmarking log upkeeps [ @skip-coverage ]', function () { - const fs = [1, 10] - fs.forEach(function (newF) { - it( - 'When f=' + - newF + - ' calculates gas overhead appropriately within a margin', - async () => { - // Perform the upkeep once to remove non-zero storage slots and have predictable gas measurement - let tx = await getTransmitTx(registry, keeper1, [logUpkeepId]) - await tx.wait() - const performData = '0x' - await mock.setCanPerform(true) - await mock.setPerformGasToBurn(performGas) - await registry.setConfigTypeSafe( - signerAddresses, - keeperAddresses, - newF, - config, - offchainVersion, - offchainBytes, - [], - [], - ) - tx = await getTransmitTx(registry, keeper1, [logUpkeepId], { - numSigners: newF + 1, - performDatas: [performData], - }) - const receipt = await tx.wait() - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - // exactly 1 Upkeep Performed should be emitted - assert.equal(upkeepPerformedLogs.length, 1) - const upkeepPerformedLog = upkeepPerformedLogs[0] - const chainModuleOverheads = - await chainModuleBase.getGasOverhead() - - const upkeepGasUsed = upkeepPerformedLog.args.gasUsed - const chargedGasOverhead = upkeepPerformedLog.args.gasOverhead - const actualGasOverhead = receipt.gasUsed.sub(upkeepGasUsed) - const estimatedGasOverhead = registryLogOverhead - .add(registryPerSignerGasOverhead.mul(BigNumber.from(newF + 1))) - .add( - registryPerPerformByteGasOverhead - .add(chainModuleOverheads.chainModulePerByteOverhead) - .mul( - BigNumber.from(performData.length / 2 - 1) - .add(registryTransmitCalldataFixedBytesOverhead) - .add( - registryTransmitCalldataPerSignerBytesOverhead.mul( - BigNumber.from(newF + 1), + describeMaybe( + 'Gas benchmarking log upkeeps [ @skip-coverage ]', + function () { + const fs = [1, 10] + fs.forEach(function (newF) { + it( + 'When f=' + + newF + + ' calculates gas overhead appropriately within a margin', + async () => { + // Perform the upkeep once to remove non-zero storage slots and have predictable gas measurement + let tx = await getTransmitTx(registry, keeper1, [logUpkeepId]) + await tx.wait() + const performData = '0x' + await mock.setCanPerform(true) + await mock.setPerformGasToBurn(performGas) + await registry.setConfigTypeSafe( + signerAddresses, + keeperAddresses, + newF, + config, + offchainVersion, + offchainBytes, + baseConfig[6], + baseConfig[7], + ) + tx = await getTransmitTx(registry, keeper1, [logUpkeepId], { + numSigners: newF + 1, + performDatas: [performData], + }) + const receipt = await tx.wait() + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + // exactly 1 Upkeep Performed should be emitted + assert.equal(upkeepPerformedLogs.length, 1) + const upkeepPerformedLog = upkeepPerformedLogs[0] + const chainModuleOverheads = + await chainModuleBase.getGasOverhead() + + const upkeepGasUsed = upkeepPerformedLog.args.gasUsed + const chargedGasOverhead = upkeepPerformedLog.args.gasOverhead + const actualGasOverhead = receipt.gasUsed.sub(upkeepGasUsed) + const estimatedGasOverhead = registryLogOverhead + .add( + registryPerSignerGasOverhead.mul(BigNumber.from(newF + 1)), + ) + .add( + registryPerPerformByteGasOverhead + .add(chainModuleOverheads.chainModulePerByteOverhead) + .mul( + BigNumber.from(performData.length / 2 - 1) + .add(registryTransmitCalldataFixedBytesOverhead) + .add( + registryTransmitCalldataPerSignerBytesOverhead.mul( + BigNumber.from(newF + 1), + ), ), - ), - ), + ), + ) + .add(chainModuleOverheads.chainModuleFixedOverhead) + + assert.isTrue(upkeepGasUsed.gt(BigNumber.from('0'))) + assert.isTrue(chargedGasOverhead.gt(BigNumber.from('0'))) + assert.isTrue(actualGasOverhead.gt(BigNumber.from('0'))) + + console.log( + 'Gas Benchmarking log upkeeps:', + 'upkeepSuccess=', + true, + 'performGas=', + performGas.toString(), + 'performData length=', + performData.length / 2 - 1, + 'sig verification ( f =', + newF, + '): estimated overhead: ', + estimatedGasOverhead.toString(), + ' charged overhead: ', + chargedGasOverhead.toString(), + ' actual overhead: ', + actualGasOverhead.toString(), + ' calculation margin over gasUsed: ', + chargedGasOverhead.sub(actualGasOverhead).toString(), + ' estimation margin over gasUsed: ', + estimatedGasOverhead.sub(actualGasOverhead).toString(), ) - .add(chainModuleOverheads.chainModuleFixedOverhead) - - assert.isTrue(upkeepGasUsed.gt(BigNumber.from('0'))) - assert.isTrue(chargedGasOverhead.gt(BigNumber.from('0'))) - assert.isTrue(actualGasOverhead.gt(BigNumber.from('0'))) - - console.log( - 'Gas Benchmarking log upkeeps:', - 'upkeepSuccess=', - true, - 'performGas=', - performGas.toString(), - 'performData length=', - performData.length / 2 - 1, - 'sig verification ( f =', - newF, - '): estimated overhead: ', - estimatedGasOverhead.toString(), - ' charged overhead: ', - chargedGasOverhead.toString(), - ' actual overhead: ', - actualGasOverhead.toString(), - ' calculation margin over gasUsed: ', - chargedGasOverhead.sub(actualGasOverhead).toString(), - ' estimation margin over gasUsed: ', - estimatedGasOverhead.sub(actualGasOverhead).toString(), - ) - assert.isTrue( - chargedGasOverhead.gt(actualGasOverhead), - 'Gas overhead calculated is too low, increase account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD) by at least ' + - actualGasOverhead.sub(chargedGasOverhead).toString(), - ) - assert.isTrue( - chargedGasOverhead - .sub(actualGasOverhead) - .lt(gasCalculationMargin), - 'Gas overhead calculated is too high, decrease account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_SIGNER_GAS_OVERHEAD) by at least ' + + assert.isTrue( + chargedGasOverhead.gt(actualGasOverhead), + 'Gas overhead calculated is too low, increase account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD) by at least ' + + actualGasOverhead.sub(chargedGasOverhead).toString(), + ) + assert.isTrue( chargedGasOverhead .sub(actualGasOverhead) - .sub(gasCalculationMargin) - .toString(), - ) + .lt(gasCalculationMargin), + 'Gas overhead calculated is too high, decrease account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_SIGNER_GAS_OVERHEAD) by at least ' + + chargedGasOverhead + .sub(actualGasOverhead) + .sub(gasCalculationMargin) + .toString(), + ) - assert.isTrue( - estimatedGasOverhead.gt(actualGasOverhead), - 'Gas overhead estimated in check upkeep is too low, increase estimation gas variables (REGISTRY_CONDITIONAL_OVERHEAD/REGISTRY_LOG_OVERHEAD/REGISTRY_PER_SIGNER_GAS_OVERHEAD/REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD) by at least ' + - estimatedGasOverhead.sub(chargedGasOverhead).toString(), - ) - assert.isTrue( - estimatedGasOverhead - .sub(actualGasOverhead) - .lt(gasEstimationMargin), - 'Gas overhead estimated is too high, decrease estimation gas variables (REGISTRY_CONDITIONAL_OVERHEAD/REGISTRY_LOG_OVERHEAD/REGISTRY_PER_SIGNER_GAS_OVERHEAD/REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD) by at least ' + + assert.isTrue( + estimatedGasOverhead.gt(actualGasOverhead), + 'Gas overhead estimated in check upkeep is too low, increase estimation gas variables (REGISTRY_CONDITIONAL_OVERHEAD/REGISTRY_LOG_OVERHEAD/REGISTRY_PER_SIGNER_GAS_OVERHEAD/REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD) by at least ' + + estimatedGasOverhead.sub(chargedGasOverhead).toString(), + ) + assert.isTrue( estimatedGasOverhead .sub(actualGasOverhead) - .sub(gasEstimationMargin) - .toString(), - ) - }, - ) - }) - }) + .lt(gasEstimationMargin), + 'Gas overhead estimated is too high, decrease estimation gas variables (REGISTRY_CONDITIONAL_OVERHEAD/REGISTRY_LOG_OVERHEAD/REGISTRY_PER_SIGNER_GAS_OVERHEAD/REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD) by at least ' + + estimatedGasOverhead + .sub(actualGasOverhead) + .sub(gasEstimationMargin) + .toString(), + ) + }, + ) + }) + }, + ) }) }) @@ -2547,7 +2661,7 @@ describe('AutomationRegistry2_3', () => { }, ) - it.skip( + it( '[Conditional:' + numPassingConditionalUpkeeps + ',Log' + @@ -2681,7 +2795,7 @@ describe('AutomationRegistry2_3', () => { } } - it.skip('has enough perform gas overhead for large batches [ @skip-coverage ]', async () => { + it('has enough perform gas overhead for large batches [ @skip-coverage ]', async () => { const numUpkeeps = 20 const upkeepIds: BigNumber[] = [] let totalPerformGas = BigNumber.from('0') @@ -2689,9 +2803,16 @@ describe('AutomationRegistry2_3', () => { const mock = await upkeepMockFactory.deploy() const tx = await registry .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') + .registerUpkeep( + mock.address, + performGas, + await admin.getAddress(), + Trigger.CONDITION, + linkToken.address, + '0x', + '0x', + '0x', + ) const testUpkeepId = await getUpkeepID(tx) upkeepIds.push(testUpkeepId) @@ -2730,9 +2851,16 @@ describe('AutomationRegistry2_3', () => { const mock = await upkeepMockFactory.deploy() const tx = await arbRegistry .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') + .registerUpkeep( + mock.address, + performGas, + await admin.getAddress(), + Trigger.CONDITION, + linkToken.address, + '0x', + '0x', + '0x', + ) const testUpkeepId = await getUpkeepID(tx) upkeepIds.push(testUpkeepId) @@ -2780,7 +2908,7 @@ describe('AutomationRegistry2_3', () => { gasOverhead, gasCeilingMultiplier, paymentPremiumPPB, - flatFeeMicroLink, + flatFeeMilliCents, l1CostWeiArb .mul(upkeepCalldataWeights[i]) .div(totalCalldataWeight), @@ -2804,9 +2932,16 @@ describe('AutomationRegistry2_3', () => { // add funds to upkeep 1 and perform and withdraw some payment const tx = await registry .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), emptyBytes, emptyBytes) + .registerUpkeep( + mock.address, + performGas, + await admin.getAddress(), + Trigger.CONDITION, + linkToken.address, + '0x', + '0x', + '0x', + ) const id1 = await getUpkeepID(tx) await registry.connect(admin).addFunds(id1, toWei('5')) @@ -2828,9 +2963,16 @@ describe('AutomationRegistry2_3', () => { // add funds to upkeep 2 and perform and withdraw some payment const tx2 = await registry .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), emptyBytes, emptyBytes) + .registerUpkeep( + mock.address, + performGas, + await admin.getAddress(), + Trigger.CONDITION, + linkToken.address, + '0x', + '0x', + '0x', + ) const id2 = await getUpkeepID(tx2) await registry.connect(admin).addFunds(id2, toWei('5')) @@ -2888,9 +3030,16 @@ describe('AutomationRegistry2_3', () => { it('uses maxPerformData size in checkUpkeep but actual performDataSize in transmit', async () => { const tx = await registry .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') + .registerUpkeep( + mock.address, + performGas, + await admin.getAddress(), + Trigger.CONDITION, + linkToken.address, + '0x', + '0x', + '0x', + ) const upkeepID = await getUpkeepID(tx) await mock.setCanCheck(true) await mock.setCanPerform(true) @@ -2902,7 +3051,7 @@ describe('AutomationRegistry2_3', () => { await registry.connect(owner).addFunds(upkeepID, minBalance1) // upkeep check should return false, 2 should return true - let checkUpkeepResult = await registry + const checkUpkeepResult = await registry .connect(zeroAddress) .callStatic['checkUpkeep(uint256)'](upkeepID) assert.equal(checkUpkeepResult.upkeepNeeded, false) @@ -2934,9 +3083,16 @@ describe('AutomationRegistry2_3', () => { beforeEach(async () => { const tx = await registry .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') + .registerUpkeep( + mock.address, + performGas, + await admin.getAddress(), + Trigger.CONDITION, + linkToken.address, + '0x', + '0x', + '0x', + ) upkeepId2 = await getUpkeepID(tx) await registry.connect(admin).addFunds(upkeepId, toWei('100')) @@ -2948,36 +3104,40 @@ describe('AutomationRegistry2_3', () => { }) it('reverts if called on a non existing ID', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(admin) .withdrawFunds(upkeepId.add(1), await payee1.getAddress()), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) it('reverts if called by anyone but the admin', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(owner) .withdrawFunds(upkeepId, await payee1.getAddress()), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) it('reverts if called on an uncanceled upkeep', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(admin) .withdrawFunds(upkeepId, await payee1.getAddress()), - 'UpkeepNotCanceled()', + registry, + 'UpkeepNotCanceled', ) }) it('reverts if called with the 0 address', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(admin).withdrawFunds(upkeepId, zeroAddress), - 'InvalidRecipient()', + registry, + 'InvalidRecipient', ) }) @@ -3038,21 +3198,23 @@ describe('AutomationRegistry2_3', () => { describe('#simulatePerformUpkeep', () => { it('reverts if called by non zero address', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(await owner.getAddress()) .callStatic.simulatePerformUpkeep(upkeepId, '0x'), - 'OnlySimulatedBackend()', + registry, + 'OnlySimulatedBackend', ) }) it('reverts when registry is paused', async () => { await registry.connect(owner).pause() - await evmRevert( + await evmRevertCustomError( registry .connect(zeroAddress) .callStatic.simulatePerformUpkeep(upkeepId, '0x'), - 'RegistryPaused()', + registry, + 'RegistryPaused', ) }) @@ -3098,11 +3260,12 @@ describe('AutomationRegistry2_3', () => { describe('#checkUpkeep', () => { it('reverts if called by non zero address', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(await owner.getAddress()) .callStatic['checkUpkeep(uint256)'](upkeepId), - 'OnlySimulatedBackend()', + registry, + 'OnlySimulatedBackend', ) }) @@ -3347,56 +3510,17 @@ describe('AutomationRegistry2_3', () => { }) }) - describe('#addFunds', () => { - const amount = toWei('1') - - it('reverts if the registration does not exist', async () => { - await evmRevert( - registry.connect(keeper1).addFunds(upkeepId.add(1), amount), - 'UpkeepCancelled()', - ) - }) - - it('adds to the balance of the registration', async () => { - await registry.connect(admin).addFunds(upkeepId, amount) - const registration = await registry.getUpkeep(upkeepId) - assert.isTrue(amount.eq(registration.balance)) - }) - - it('lets anyone add funds to an upkeep not just admin', async () => { - await linkToken.connect(owner).transfer(await payee1.getAddress(), amount) - await linkToken.connect(payee1).approve(registry.address, amount) - - await registry.connect(payee1).addFunds(upkeepId, amount) - const registration = await registry.getUpkeep(upkeepId) - assert.isTrue(amount.eq(registration.balance)) - }) - - it('emits a log', async () => { - const tx = await registry.connect(admin).addFunds(upkeepId, amount) - await expect(tx) - .to.emit(registry, 'FundsAdded') - .withArgs(upkeepId, await admin.getAddress(), amount) - }) - - it('reverts if the upkeep is canceled', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( - registry.connect(keeper1).addFunds(upkeepId, amount), - 'UpkeepCancelled()', - ) - }) - }) - describe('#getActiveUpkeepIDs', () => { it('reverts if startIndex is out of bounds ', async () => { - await evmRevert( + await evmRevertCustomError( registry.getActiveUpkeepIDs(numUpkeeps, 0), - 'IndexOutOfRange()', + registry, + 'IndexOutOfRange', ) - await evmRevert( + await evmRevertCustomError( registry.getActiveUpkeepIDs(numUpkeeps + 1, 0), - 'IndexOutOfRange()', + registry, + 'IndexOutOfRange', ) }) @@ -3487,7 +3611,7 @@ describe('AutomationRegistry2_3', () => { .add(chainModuleOverheads.chainModuleFixedOverhead), gasCeilingMultiplier.mul('2'), // fallbackGasPrice is 2x gas price paymentPremiumPPB, - flatFeeMicroLink, + flatFeeMilliCents, ).total // Stale feed @@ -3502,7 +3626,12 @@ describe('AutomationRegistry2_3', () => { assert.equal( expectedFallbackMaxPayment.toString(), ( - await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) + await registry.getMaxPaymentForGas( + upkeepId, + Trigger.CONDITION, + performGas, + linkToken.address, + ) ).toString(), ) @@ -3517,7 +3646,12 @@ describe('AutomationRegistry2_3', () => { assert.equal( expectedFallbackMaxPayment.toString(), ( - await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) + await registry.getMaxPaymentForGas( + upkeepId, + Trigger.CONDITION, + performGas, + linkToken.address, + ) ).toString(), ) @@ -3532,7 +3666,12 @@ describe('AutomationRegistry2_3', () => { assert.equal( expectedFallbackMaxPayment.toString(), ( - await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) + await registry.getMaxPaymentForGas( + upkeepId, + Trigger.CONDITION, + performGas, + linkToken.address, + ) ).toString(), ) }) @@ -3560,7 +3699,7 @@ describe('AutomationRegistry2_3', () => { .add(chainModuleOverheads.chainModuleFixedOverhead), gasCeilingMultiplier.mul('2'), // fallbackLinkPrice is 1/2 link price, so multiply by 2 paymentPremiumPPB, - flatFeeMicroLink, + flatFeeMilliCents, ).total // Stale feed @@ -3575,7 +3714,12 @@ describe('AutomationRegistry2_3', () => { assert.equal( expectedFallbackMaxPayment.toString(), ( - await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) + await registry.getMaxPaymentForGas( + upkeepId, + Trigger.CONDITION, + performGas, + linkToken.address, + ) ).toString(), ) @@ -3590,7 +3734,12 @@ describe('AutomationRegistry2_3', () => { assert.equal( expectedFallbackMaxPayment.toString(), ( - await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) + await registry.getMaxPaymentForGas( + upkeepId, + Trigger.CONDITION, + performGas, + linkToken.address, + ) ).toString(), ) @@ -3605,7 +3754,12 @@ describe('AutomationRegistry2_3', () => { assert.equal( expectedFallbackMaxPayment.toString(), ( - await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) + await registry.getMaxPaymentForGas( + upkeepId, + Trigger.CONDITION, + performGas, + linkToken.address, + ) ).toString(), ) }) @@ -3618,67 +3772,10 @@ describe('AutomationRegistry2_3', () => { }) }) - describe('#onTokenTransfer', () => { - const amount = toWei('1') - - it('reverts if not called by the LINK token', async () => { - const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [upkeepId]) - - await evmRevert( - registry - .connect(keeper1) - .onTokenTransfer(await keeper1.getAddress(), amount, data), - 'OnlyCallableByLINKToken()', - ) - }) - - it('reverts if not called with more or less than 32 bytes', async () => { - const longData = ethers.utils.defaultAbiCoder.encode( - ['uint256', 'uint256'], - ['33', '34'], - ) - const shortData = '0x12345678' - - await evmRevert( - linkToken - .connect(owner) - .transferAndCall(registry.address, amount, longData), - ) - await evmRevert( - linkToken - .connect(owner) - .transferAndCall(registry.address, amount, shortData), - ) - }) - - it('reverts if the upkeep is canceled', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( - registry.connect(keeper1).addFunds(upkeepId, amount), - 'UpkeepCancelled()', - ) - }) - - it('updates the funds of the job id passed', async () => { - const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [upkeepId]) - - const before = (await registry.getUpkeep(upkeepId)).balance - await linkToken - .connect(owner) - .transferAndCall(registry.address, amount, data) - const after = (await registry.getUpkeep(upkeepId)).balance - - assert.isTrue(before.add(amount).eq(after)) - }) - }) - describeMaybe('#setConfig - onchain', async () => { - const payment = BigNumber.from(1) - const flatFee = BigNumber.from(2) const maxGas = BigNumber.from(6) const staleness = BigNumber.from(4) const ceiling = BigNumber.from(5) - const newMinUpkeepSpend = BigNumber.from(9) const newMaxCheckDataSize = BigNumber.from(10000) const newMaxPerformDataSize = BigNumber.from(10000) const newMaxRevertDataSize = BigNumber.from(10000) @@ -3692,12 +3789,9 @@ describe('AutomationRegistry2_3', () => { const financeAdminAddress = randomAddress() const newConfig: OnChainConfig = { - paymentPremiumPPB: payment, - flatFeeMicroLink: flatFee, checkGasLimit: maxGas, stalenessSeconds: staleness, gasCeilingMultiplier: ceiling, - minUpkeepSpend: newMinUpkeepSpend, maxCheckDataSize: newMaxCheckDataSize, maxPerformDataSize: newMaxPerformDataSize, maxRevertDataSize: newMaxRevertDataSize, @@ -3724,15 +3818,15 @@ describe('AutomationRegistry2_3', () => { newConfig, offchainVersion, offchainBytes, - [], - [], + baseConfig[6], + baseConfig[7], ), 'Only callable by owner', ) }) it('reverts if signers or transmitters are the zero address', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(owner) .setConfigTypeSafe( @@ -3747,13 +3841,14 @@ describe('AutomationRegistry2_3', () => { newConfig, offchainVersion, offchainBytes, - [], - [], + baseConfig[6], + baseConfig[7], ), - 'InvalidSigner()', + registry, + 'InvalidSigner', ) - await evmRevert( + await evmRevertCustomError( registry .connect(owner) .setConfigTypeSafe( @@ -3768,19 +3863,18 @@ describe('AutomationRegistry2_3', () => { newConfig, offchainVersion, offchainBytes, - [], - [], + baseConfig[6], + baseConfig[7], ), - 'InvalidTransmitter()', + registry, + 'InvalidTransmitter', ) }) it('updates the onchainConfig and configDigest', async () => { const old = await registry.getState() - const oldConfig = old.config + const oldConfig = await registry.getConfig() const oldState = old.state - assert.isTrue(paymentPremiumPPB.eq(oldConfig.paymentPremiumPPB)) - assert.isTrue(flatFeeMicroLink.eq(oldConfig.flatFeeMicroLink)) assert.isTrue(stalenessSeconds.eq(oldConfig.stalenessSeconds)) assert.isTrue(gasCeilingMultiplier.eq(oldConfig.gasCeilingMultiplier)) @@ -3800,14 +3894,8 @@ describe('AutomationRegistry2_3', () => { const updated = await registry.getState() const updatedConfig = updated.config const updatedState = updated.state - assert.equal(updatedConfig.paymentPremiumPPB, payment.toNumber()) - assert.equal(updatedConfig.flatFeeMicroLink, flatFee.toNumber()) assert.equal(updatedConfig.stalenessSeconds, staleness.toNumber()) assert.equal(updatedConfig.gasCeilingMultiplier, ceiling.toNumber()) - assert.equal( - updatedConfig.minUpkeepSpend.toString(), - newMinUpkeepSpend.toString(), - ) assert.equal( updatedConfig.maxCheckDataSize, newMaxCheckDataSize.toNumber(), @@ -3906,8 +3994,8 @@ describe('AutomationRegistry2_3', () => { config, offchainVersion, offchainBytes, - [], - [], + baseConfig[6], + baseConfig[7], ), 'Only callable by owner', ) @@ -3917,7 +4005,7 @@ describe('AutomationRegistry2_3', () => { for (let i = 0; i < 40; i++) { newKeepers.push(randomAddress()) } - await evmRevert( + await evmRevertCustomError( registry .connect(owner) .setConfigTypeSafe( @@ -3927,15 +4015,16 @@ describe('AutomationRegistry2_3', () => { config, offchainVersion, offchainBytes, - [], - [], + baseConfig[6], + baseConfig[7], ), - 'TooManyOracles()', + registry, + 'TooManyOracles', ) }) it('reverts if f=0', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(owner) .setConfigTypeSafe( @@ -3945,16 +4034,17 @@ describe('AutomationRegistry2_3', () => { config, offchainVersion, offchainBytes, - [], - [], + baseConfig[6], + baseConfig[7], ), - 'IncorrectNumberOfFaultyOracles()', + registry, + 'IncorrectNumberOfFaultyOracles', ) }) it('reverts if signers != transmitters length', async () => { const signers = [randomAddress()] - await evmRevert( + await evmRevertCustomError( registry .connect(owner) .setConfigTypeSafe( @@ -3964,16 +4054,17 @@ describe('AutomationRegistry2_3', () => { config, offchainVersion, offchainBytes, - [], - [], + baseConfig[6], + baseConfig[7], ), - 'IncorrectNumberOfSigners()', + registry, + 'IncorrectNumberOfSigners', ) }) it('reverts if signers <= 3f', async () => { newKeepers.pop() - await evmRevert( + await evmRevertCustomError( registry .connect(owner) .setConfigTypeSafe( @@ -3983,10 +4074,11 @@ describe('AutomationRegistry2_3', () => { config, offchainVersion, offchainBytes, - [], - [], + baseConfig[6], + baseConfig[7], ), - 'IncorrectNumberOfSigners()', + registry, + 'IncorrectNumberOfSigners', ) }) @@ -3997,7 +4089,7 @@ describe('AutomationRegistry2_3', () => { await personas.Eddy.getAddress(), await personas.Eddy.getAddress(), ] - await evmRevert( + await evmRevertCustomError( registry .connect(owner) .setConfigTypeSafe( @@ -4007,10 +4099,11 @@ describe('AutomationRegistry2_3', () => { config, offchainVersion, offchainBytes, - [], - [], + baseConfig[6], + baseConfig[7], ), - 'RepeatedSigner()', + registry, + 'RepeatedSigner', ) }) @@ -4021,7 +4114,7 @@ describe('AutomationRegistry2_3', () => { await personas.Eddy.getAddress(), await personas.Eddy.getAddress(), ] - await evmRevert( + await evmRevertCustomError( registry .connect(owner) .setConfigTypeSafe( @@ -4031,10 +4124,11 @@ describe('AutomationRegistry2_3', () => { config, offchainVersion, offchainBytes, - [], - [], + baseConfig[6], + baseConfig[7], ), - 'RepeatedTransmitter()', + registry, + 'RepeatedTransmitter', ) }) @@ -4154,159 +4248,40 @@ describe('AutomationRegistry2_3', () => { }) }) - describe('#registerUpkeep', () => { - it('reverts when registry is paused', async () => { - await registry.connect(owner).pause() - await evmRevert( - registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), emptyBytes, '0x'), - 'RegistryPaused()', - ) - }) - - it('reverts if the target is not a contract', async () => { - await evmRevert( - registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](zeroAddress, performGas, await admin.getAddress(), emptyBytes, '0x'), - 'NotAContract()', - ) - }) - - it('reverts if called by a non-owner', async () => { - await evmRevert( - registry - .connect(keeper1) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), emptyBytes, '0x'), - 'OnlyCallableByOwnerOrRegistrar()', - ) - }) - - it('reverts if execute gas is too low', async () => { - await evmRevert( - registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, 2299, await admin.getAddress(), emptyBytes, '0x'), - 'GasLimitOutsideRange()', - ) - }) - - it('reverts if execute gas is too high', async () => { - await evmRevert( - registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, 5000001, await admin.getAddress(), emptyBytes, '0x'), - 'GasLimitOutsideRange()', - ) - }) - - it('reverts if checkData is too long', async () => { - let longBytes = '0x' - for (let i = 0; i < 10000; i++) { - longBytes += '1' - } - await evmRevert( - registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), longBytes, '0x'), - 'CheckDataExceedsLimit()', - ) - }) - - it('creates a record of the registration', async () => { - const performGases = [100000, 500000] - const checkDatas = [emptyBytes, '0x12'] - - for (let jdx = 0; jdx < performGases.length; jdx++) { - const performGas = performGases[jdx] - for (let kdx = 0; kdx < checkDatas.length; kdx++) { - const checkData = checkDatas[kdx] - const tx = await registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), checkData, '0x') - - //confirm the upkeep details and verify emitted events - const testUpkeepId = await getUpkeepID(tx) - await expect(tx) - .to.emit(registry, 'UpkeepRegistered') - .withArgs(testUpkeepId, performGas, await admin.getAddress()) - - await expect(tx) - .to.emit(registry, 'UpkeepCheckDataSet') - .withArgs(testUpkeepId, checkData) - await expect(tx) - .to.emit(registry, 'UpkeepTriggerConfigSet') - .withArgs(testUpkeepId, '0x') - - const registration = await registry.getUpkeep(testUpkeepId) - - assert.equal(mock.address, registration.target) - assert.notEqual( - ethers.constants.AddressZero, - await registry.getForwarder(testUpkeepId), - ) - assert.equal( - performGas.toString(), - registration.performGas.toString(), - ) - assert.equal(await admin.getAddress(), registration.admin) - assert.equal(registration.balance.toNumber(), 0) - assert.equal(registration.amountSpent.toNumber(), 0) - assert.equal(registration.lastPerformedBlockNumber, 0) - assert.equal(checkData, registration.checkData) - assert.equal(registration.paused, false) - assert.equal(registration.offchainConfig, '0x') - assert(registration.maxValidBlocknumber.eq('0xffffffff')) - } - } - }) - }) - describe('#pauseUpkeep', () => { it('reverts if the registration does not exist', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(keeper1).pauseUpkeep(upkeepId.add(1)), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) it('reverts if the upkeep is already canceled', async () => { await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry.connect(admin).pauseUpkeep(upkeepId), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) it('reverts if the upkeep is already paused', async () => { await registry.connect(admin).pauseUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry.connect(admin).pauseUpkeep(upkeepId), - 'OnlyUnpausedUpkeep()', + registry, + 'OnlyUnpausedUpkeep', ) }) it('reverts if the caller is not the upkeep admin', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(keeper1).pauseUpkeep(upkeepId), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) @@ -4321,18 +4296,20 @@ describe('AutomationRegistry2_3', () => { describe('#unpauseUpkeep', () => { it('reverts if the registration does not exist', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(keeper1).unpauseUpkeep(upkeepId.add(1)), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) it('reverts if the upkeep is already canceled', async () => { await registry.connect(owner).cancelUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry.connect(admin).unpauseUpkeep(upkeepId), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) @@ -4345,9 +4322,10 @@ describe('AutomationRegistry2_3', () => { }) it('reverts if the upkeep is not paused', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(admin).unpauseUpkeep(upkeepId), - 'OnlyPausedUpkeep()', + registry, + 'OnlyPausedUpkeep', ) }) @@ -4358,9 +4336,10 @@ describe('AutomationRegistry2_3', () => { assert.equal(registration.paused, true) - await evmRevert( + await evmRevertCustomError( registry.connect(keeper1).unpauseUpkeep(upkeepId), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) @@ -4383,27 +4362,30 @@ describe('AutomationRegistry2_3', () => { describe('#setUpkeepCheckData', () => { it('reverts if the registration does not exist', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(keeper1) .setUpkeepCheckData(upkeepId.add(1), randomBytes), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) it('reverts if the caller is not upkeep admin', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(keeper1).setUpkeepCheckData(upkeepId, randomBytes), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) it('reverts if the upkeep is cancelled', async () => { await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry.connect(admin).setUpkeepCheckData(upkeepId, randomBytes), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) @@ -4421,9 +4403,10 @@ describe('AutomationRegistry2_3', () => { longBytes += '1' } - await evmRevert( + await evmRevertCustomError( registry.connect(admin).setUpkeepCheckData(upkeepId, longBytes), - 'CheckDataExceedsLimit()', + registry, + 'CheckDataExceedsLimit', ) }) @@ -4444,39 +4427,44 @@ describe('AutomationRegistry2_3', () => { const newGasLimit = BigNumber.from('300000') it('reverts if the registration does not exist', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(admin).setUpkeepGasLimit(upkeepId.add(1), newGasLimit), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) it('reverts if the upkeep is canceled', async () => { await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry.connect(admin).setUpkeepGasLimit(upkeepId, newGasLimit), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) it('reverts if called by anyone but the admin', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(owner).setUpkeepGasLimit(upkeepId, newGasLimit), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) it('reverts if new gas limit is out of bounds', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(admin) .setUpkeepGasLimit(upkeepId, BigNumber.from('100')), - 'GasLimitOutsideRange()', + registry, + 'GasLimitOutsideRange', ) - await evmRevert( + await evmRevertCustomError( registry .connect(admin) .setUpkeepGasLimit(upkeepId, BigNumber.from('6000000')), - 'GasLimitOutsideRange()', + registry, + 'GasLimitOutsideRange', ) }) @@ -4502,26 +4490,29 @@ describe('AutomationRegistry2_3', () => { const newConfig = '0xc0ffeec0ffee' it('reverts if the registration does not exist', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(admin) .setUpkeepOffchainConfig(upkeepId.add(1), newConfig), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) it('reverts if the upkeep is canceled', async () => { await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry.connect(admin).setUpkeepOffchainConfig(upkeepId, newConfig), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) it('reverts if called by anyone but the admin', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(owner).setUpkeepOffchainConfig(upkeepId, newConfig), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) @@ -4547,26 +4538,29 @@ describe('AutomationRegistry2_3', () => { const newConfig = '0xdeadbeef' it('reverts if the registration does not exist', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(admin) .setUpkeepTriggerConfig(upkeepId.add(1), newConfig), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) it('reverts if the upkeep is canceled', async () => { await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry.connect(admin).setUpkeepTriggerConfig(upkeepId, newConfig), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) it('reverts if called by anyone but the admin', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(owner).setUpkeepTriggerConfig(upkeepId, newConfig), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) @@ -4582,31 +4576,34 @@ describe('AutomationRegistry2_3', () => { describe('#transferUpkeepAdmin', () => { it('reverts when called by anyone but the current upkeep admin', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(payee1) .transferUpkeepAdmin(upkeepId, await payee2.getAddress()), - 'OnlyCallableByAdmin()', + registry, + 'OnlyCallableByAdmin', ) }) it('reverts when transferring to self', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(admin) .transferUpkeepAdmin(upkeepId, await admin.getAddress()), - 'ValueNotChanged()', + registry, + 'ValueNotChanged', ) }) it('reverts when the upkeep is cancelled', async () => { await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry .connect(admin) .transferUpkeepAdmin(upkeepId, await keeper1.getAddress()), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) @@ -4668,18 +4665,20 @@ describe('AutomationRegistry2_3', () => { }) it('reverts when not called by the proposed upkeep admin', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(payee2).acceptUpkeepAdmin(upkeepId), - 'OnlyCallableByProposedAdmin()', + registry, + 'OnlyCallableByProposedAdmin', ) }) it('reverts when the upkeep is cancelled', async () => { await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry.connect(payee1).acceptUpkeepAdmin(upkeepId), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) @@ -4700,9 +4699,10 @@ describe('AutomationRegistry2_3', () => { describe('#withdrawOwnerFunds', () => { it('can only be called by finance admin', async () => { - await evmRevert( - registry.connect(keeper1).withdrawLinkFees(zeroAddress, 1), - 'OnlyFinanceAdmin()', + await evmRevertCustomError( + registry.connect(keeper1).withdrawLink(zeroAddress, 1), + registry, + 'OnlyFinanceAdmin', ) }) @@ -4710,18 +4710,15 @@ describe('AutomationRegistry2_3', () => { await registry.connect(admin).addFunds(upkeepId, toWei('100')) const financeAdminAddress = await financeAdmin.getAddress() // Very high min spend, whole balance as cancellation fees - const minUpkeepSpend = toWei('1000') + const newMinUpkeepSpend = toWei('1000') await registry.connect(owner).setConfigTypeSafe( signerAddresses, keeperAddresses, f, { - paymentPremiumPPB, - flatFeeMicroLink, checkGasLimit, stalenessSeconds, gasCeilingMultiplier, - minUpkeepSpend, maxCheckDataSize, maxPerformDataSize, maxRevertDataSize, @@ -4738,8 +4735,16 @@ describe('AutomationRegistry2_3', () => { }, offchainVersion, offchainBytes, - [], - [], + [linkToken.address], + [ + { + gasFeePPB: paymentPremiumPPB, + flatFeeMilliCents, + priceFeed: linkUSDFeed.address, + fallbackPrice: fallbackLinkPrice, + minSpend: newMinUpkeepSpend, + }, + ], ) const upkeepBalance = (await registry.getUpkeep(upkeepId)).balance const ownerBefore = await linkToken.balanceOf(await owner.getAddress()) @@ -4753,7 +4758,7 @@ describe('AutomationRegistry2_3', () => { // Now withdraw await registry .connect(financeAdmin) - .withdrawLinkFees(await owner.getAddress(), ownerRegistryBalance) + .withdrawLink(await owner.getAddress(), ownerRegistryBalance) ownerRegistryBalance = await registry.linkAvailableForPayment() const ownerAfter = await linkToken.balanceOf(await owner.getAddress()) @@ -4768,26 +4773,28 @@ describe('AutomationRegistry2_3', () => { describe('#transferPayeeship', () => { it('reverts when called by anyone but the current payee', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(payee2) .transferPayeeship( await keeper1.getAddress(), await payee2.getAddress(), ), - 'OnlyCallableByPayee()', + registry, + 'OnlyCallableByPayee', ) }) it('reverts when transferring to self', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(payee1) .transferPayeeship( await keeper1.getAddress(), await payee1.getAddress(), ), - 'ValueNotChanged()', + registry, + 'ValueNotChanged', ) }) @@ -4849,9 +4856,10 @@ describe('AutomationRegistry2_3', () => { }) it('reverts when called by anyone but the proposed payee', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(payee1).acceptPayeeship(await keeper1.getAddress()), - 'OnlyCallableByProposedPayee()', + registry, + 'OnlyCallableByProposedPayee', ) }) @@ -4895,22 +4903,31 @@ describe('AutomationRegistry2_3', () => { it('Does not allow transmits when paused', async () => { await registry.connect(owner).pause() - await evmRevert( + await evmRevertCustomError( getTransmitTx(registry, keeper1, [upkeepId]), - 'RegistryPaused()', + registry, + 'RegistryPaused', ) }) it('Does not allow creation of new upkeeps when paused', async () => { await registry.connect(owner).pause() - await evmRevert( + await evmRevertCustomError( registry .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), emptyBytes, '0x'), - 'RegistryPaused()', + .registerUpkeep( + mock.address, + performGas, + await admin.getAddress(), + Trigger.CONDITION, + linkToken.address, + '0x', + '0x', + '0x', + ), + registry, + 'RegistryPaused', ) }) }) @@ -4936,170 +4953,6 @@ describe('AutomationRegistry2_3', () => { }) }) - describe('#migrateUpkeeps() / #receiveUpkeeps()', async () => { - context('when permissions are set', () => { - beforeEach(async () => { - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(upkeepId, toWei('100')) - await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 1) - await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 2) - }) - - it('migrates an upkeep', async () => { - const offchainBytes = '0x987654abcd' - await registry - .connect(admin) - .setUpkeepOffchainConfig(upkeepId, offchainBytes) - const reg1Upkeep = await registry.getUpkeep(upkeepId) - const forwarderAddress = await registry.getForwarder(upkeepId) - expect(reg1Upkeep.balance).to.equal(toWei('100')) - expect(reg1Upkeep.checkData).to.equal(randomBytes) - expect(forwarderAddress).to.not.equal(ethers.constants.AddressZero) - expect(reg1Upkeep.offchainConfig).to.equal(offchainBytes) - expect((await registry.getState()).state.numUpkeeps).to.equal( - numUpkeeps, - ) - const forwarder = IAutomationForwarderFactory.connect( - forwarderAddress, - owner, - ) - expect(await forwarder.getRegistry()).to.equal(registry.address) - // Set an upkeep admin transfer in progress too - await registry - .connect(admin) - .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) - - // migrate - await registry - .connect(admin) - .migrateUpkeeps([upkeepId], mgRegistry.address) - expect((await registry.getState()).state.numUpkeeps).to.equal( - numUpkeeps - 1, - ) - expect((await mgRegistry.getState()).state.numUpkeeps).to.equal(1) - expect((await registry.getUpkeep(upkeepId)).balance).to.equal(0) - expect((await registry.getUpkeep(upkeepId)).checkData).to.equal('0x') - expect((await mgRegistry.getUpkeep(upkeepId)).balance).to.equal( - toWei('100'), - ) - expect( - (await mgRegistry.getState()).state.expectedLinkBalance, - ).to.equal(toWei('100')) - expect((await mgRegistry.getUpkeep(upkeepId)).checkData).to.equal( - randomBytes, - ) - expect((await mgRegistry.getUpkeep(upkeepId)).offchainConfig).to.equal( - offchainBytes, - ) - expect(await mgRegistry.getForwarder(upkeepId)).to.equal( - forwarderAddress, - ) - // test that registry is updated on forwarder - expect(await forwarder.getRegistry()).to.equal(mgRegistry.address) - // migration will delete the upkeep and nullify admin transfer - await expect( - registry.connect(payee1).acceptUpkeepAdmin(upkeepId), - ).to.be.revertedWith('UpkeepCancelled()') - await expect( - mgRegistry.connect(payee1).acceptUpkeepAdmin(upkeepId), - ).to.be.revertedWith('OnlyCallableByProposedAdmin()') - }) - - it('migrates a paused upkeep', async () => { - expect((await registry.getUpkeep(upkeepId)).balance).to.equal( - toWei('100'), - ) - expect((await registry.getUpkeep(upkeepId)).checkData).to.equal( - randomBytes, - ) - expect((await registry.getState()).state.numUpkeeps).to.equal( - numUpkeeps, - ) - await registry.connect(admin).pauseUpkeep(upkeepId) - // verify the upkeep is paused - expect((await registry.getUpkeep(upkeepId)).paused).to.equal(true) - // migrate - await registry - .connect(admin) - .migrateUpkeeps([upkeepId], mgRegistry.address) - expect((await registry.getState()).state.numUpkeeps).to.equal( - numUpkeeps - 1, - ) - expect((await mgRegistry.getState()).state.numUpkeeps).to.equal(1) - expect((await registry.getUpkeep(upkeepId)).balance).to.equal(0) - expect((await mgRegistry.getUpkeep(upkeepId)).balance).to.equal( - toWei('100'), - ) - expect((await registry.getUpkeep(upkeepId)).checkData).to.equal('0x') - expect((await mgRegistry.getUpkeep(upkeepId)).checkData).to.equal( - randomBytes, - ) - expect( - (await mgRegistry.getState()).state.expectedLinkBalance, - ).to.equal(toWei('100')) - // verify the upkeep is still paused after migration - expect((await mgRegistry.getUpkeep(upkeepId)).paused).to.equal(true) - }) - - it('emits an event on both contracts', async () => { - expect((await registry.getUpkeep(upkeepId)).balance).to.equal( - toWei('100'), - ) - expect((await registry.getUpkeep(upkeepId)).checkData).to.equal( - randomBytes, - ) - expect((await registry.getState()).state.numUpkeeps).to.equal( - numUpkeeps, - ) - const tx = registry - .connect(admin) - .migrateUpkeeps([upkeepId], mgRegistry.address) - await expect(tx) - .to.emit(registry, 'UpkeepMigrated') - .withArgs(upkeepId, toWei('100'), mgRegistry.address) - await expect(tx) - .to.emit(mgRegistry, 'UpkeepReceived') - .withArgs(upkeepId, toWei('100'), registry.address) - }) - - it('is only migratable by the admin', async () => { - await expect( - registry - .connect(owner) - .migrateUpkeeps([upkeepId], mgRegistry.address), - ).to.be.revertedWith('OnlyCallableByAdmin()') - await registry - .connect(admin) - .migrateUpkeeps([upkeepId], mgRegistry.address) - }) - }) - - context('when permissions are not set', () => { - it('reverts', async () => { - // no permissions - await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 0) - await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 0) - await expect(registry.migrateUpkeeps([upkeepId], mgRegistry.address)).to - .be.reverted - // only outgoing permissions - await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 1) - await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 0) - await expect(registry.migrateUpkeeps([upkeepId], mgRegistry.address)).to - .be.reverted - // only incoming permissions - await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 0) - await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 2) - await expect(registry.migrateUpkeeps([upkeepId], mgRegistry.address)).to - .be.reverted - // permissions opposite direction - await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 2) - await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 1) - await expect(registry.migrateUpkeeps([upkeepId], mgRegistry.address)).to - .be.reverted - }) - }) - }) - describe('#setPayees', () => { const IGNORE_ADDRESS = '0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF' @@ -5111,20 +4964,22 @@ describe('AutomationRegistry2_3', () => { }) it('reverts with different numbers of payees than transmitters', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(owner).setPayees([...payees, randomAddress()]), - 'ParameterLengthError()', + registry, + 'ParameterLengthError', ) }) it('reverts if the payee is the zero address', async () => { - await blankRegistry.connect(owner).setConfig(...baseConfig) // used to test initial config + await blankRegistry.connect(owner).setConfigTypeSafe(...baseConfig) // used to test initial config - await evmRevert( + await evmRevertCustomError( blankRegistry // used to test initial config .connect(owner) .setPayees([ethers.constants.AddressZero, ...payees.slice(1)]), - 'InvalidPayee()', + registry, + 'InvalidPayee', ) }) @@ -5132,7 +4987,7 @@ describe('AutomationRegistry2_3', () => { 'sets the payees when exisitng payees are zero address', async () => { //Initial payees should be zero address - await blankRegistry.connect(owner).setConfig(...baseConfig) // used to test initial config + await blankRegistry.connect(owner).setConfigTypeSafe(...baseConfig) // used to test initial config for (let i = 0; i < keeperAddresses.length; i++) { const payee = ( @@ -5202,9 +5057,10 @@ describe('AutomationRegistry2_3', () => { it('reverts if payee is non zero and owner tries to change payee', async () => { const newPayees = [randomAddress(), ...payees.slice(1)] - await evmRevert( + await evmRevertCustomError( registry.connect(owner).setPayees(newPayees), - 'InvalidPayee()', + registry, + 'InvalidPayee', ) }) @@ -5218,16 +5074,18 @@ describe('AutomationRegistry2_3', () => { describe('#cancelUpkeep', () => { it('reverts if the ID is not valid', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(owner).cancelUpkeep(upkeepId.add(1)), - 'CannotCancel()', + registry, + 'CannotCancel', ) }) it('reverts if called by a non-owner/non-admin', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(keeper1).cancelUpkeep(upkeepId), - 'OnlyCallableByOwnerOrAdmin()', + registry, + 'OnlyCallableByOwnerOrAdmin', ) }) @@ -5263,14 +5121,16 @@ describe('AutomationRegistry2_3', () => { it('does not revert if reverts if called multiple times', async () => { await registry.connect(owner).cancelUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry.connect(owner).cancelUpkeep(upkeepId), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) describe('when called by the owner when the admin has just canceled', () => { // eslint-disable-next-line @typescript-eslint/no-unused-vars + // @ts-ignore let oldExpiration: BigNumber beforeEach(async () => { @@ -5280,9 +5140,10 @@ describe('AutomationRegistry2_3', () => { }) it('reverts with proper error', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(owner).cancelUpkeep(upkeepId), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) }) @@ -5292,9 +5153,10 @@ describe('AutomationRegistry2_3', () => { it('reverts if called again by the admin', async () => { await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( + await evmRevertCustomError( registry.connect(admin).cancelUpkeep(upkeepId), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) @@ -5305,9 +5167,10 @@ describe('AutomationRegistry2_3', () => { await ethers.provider.send('evm_mine', []) } - await evmRevert( + await evmRevertCustomError( registry.connect(owner).cancelUpkeep(upkeepId), - 'UpkeepCancelled()', + registry, + 'UpkeepCancelled', ) }) @@ -5360,7 +5223,7 @@ describe('AutomationRegistry2_3', () => { }) it('deducts a cancellation fee from the upkeep and adds to reserve', async () => { - const minUpkeepSpend = toWei('10') + const newMinUpkeepSpend = toWei('10') const financeAdminAddress = await financeAdmin.getAddress() await registry.connect(owner).setConfigTypeSafe( @@ -5368,12 +5231,9 @@ describe('AutomationRegistry2_3', () => { keeperAddresses, f, { - paymentPremiumPPB, - flatFeeMicroLink, checkGasLimit, stalenessSeconds, gasCeilingMultiplier, - minUpkeepSpend, maxCheckDataSize, maxPerformDataSize, maxRevertDataSize, @@ -5390,8 +5250,16 @@ describe('AutomationRegistry2_3', () => { }, offchainVersion, offchainBytes, - [], - [], + [linkToken.address], + [ + { + gasFeePPB: paymentPremiumPPB, + flatFeeMilliCents, + priceFeed: linkUSDFeed.address, + fallbackPrice: fallbackLinkPrice, + minSpend: newMinUpkeepSpend, + }, + ], ) const payee1Before = await linkToken.balanceOf( @@ -5401,7 +5269,7 @@ describe('AutomationRegistry2_3', () => { const ownerBefore = await registry.linkAvailableForPayment() const amountSpent = toWei('100').sub(upkeepBefore) - const cancellationFee = minUpkeepSpend.sub(amountSpent) + const cancellationFee = newMinUpkeepSpend.sub(amountSpent) await registry.connect(admin).cancelUpkeep(upkeepId) @@ -5421,7 +5289,7 @@ describe('AutomationRegistry2_3', () => { it('deducts up to balance as cancellation fee', async () => { // Very high min spend, should deduct whole balance as cancellation fees - const minUpkeepSpend = toWei('1000') + const newMinUpkeepSpend = toWei('1000') const financeAdminAddress = await financeAdmin.getAddress() await registry.connect(owner).setConfigTypeSafe( @@ -5429,12 +5297,9 @@ describe('AutomationRegistry2_3', () => { keeperAddresses, f, { - paymentPremiumPPB, - flatFeeMicroLink, checkGasLimit, stalenessSeconds, gasCeilingMultiplier, - minUpkeepSpend, maxCheckDataSize, maxPerformDataSize, maxRevertDataSize, @@ -5451,8 +5316,16 @@ describe('AutomationRegistry2_3', () => { }, offchainVersion, offchainBytes, - [], - [], + [linkToken.address], + [ + { + gasFeePPB: paymentPremiumPPB, + flatFeeMilliCents, + priceFeed: linkUSDFeed.address, + fallbackPrice: fallbackLinkPrice, + minSpend: newMinUpkeepSpend, + }, + ], ) const payee1Before = await linkToken.balanceOf( await payee1.getAddress(), @@ -5475,9 +5348,9 @@ describe('AutomationRegistry2_3', () => { assert.isTrue(ownerAfter.sub(ownerBefore).eq(upkeepBefore)) }) - it('does not deduct cancellation fee if more than minUpkeepSpend is spent', async () => { + it('does not deduct cancellation fee if more than minUpkeepSpendDollars is spent', async () => { // Very low min spend, already spent in one perform upkeep - const minUpkeepSpend = BigNumber.from(420) + const newMinUpkeepSpend = BigNumber.from(420) const financeAdminAddress = await financeAdmin.getAddress() await registry.connect(owner).setConfigTypeSafe( @@ -5485,12 +5358,9 @@ describe('AutomationRegistry2_3', () => { keeperAddresses, f, { - paymentPremiumPPB, - flatFeeMicroLink, checkGasLimit, stalenessSeconds, gasCeilingMultiplier, - minUpkeepSpend, maxCheckDataSize, maxPerformDataSize, maxRevertDataSize, @@ -5507,8 +5377,16 @@ describe('AutomationRegistry2_3', () => { }, offchainVersion, offchainBytes, - [], - [], + [linkToken.address], + [ + { + gasFeePPB: paymentPremiumPPB, + flatFeeMilliCents, + priceFeed: linkUSDFeed.address, + fallbackPrice: fallbackLinkPrice, + minSpend: newMinUpkeepSpend, + }, + ], ) const payee1Before = await linkToken.balanceOf( await payee1.getAddress(), @@ -5542,23 +5420,25 @@ describe('AutomationRegistry2_3', () => { }) it('reverts if called by anyone but the payee', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(payee2) .withdrawPayment( await keeper1.getAddress(), await nonkeeper.getAddress(), ), - 'OnlyCallableByPayee()', + registry, + 'OnlyCallableByPayee', ) }) it('reverts if called with the 0 address', async () => { - await evmRevert( + await evmRevertCustomError( registry .connect(payee2) .withdrawPayment(await keeper1.getAddress(), zeroAddress), - 'InvalidRecipient()', + registry, + 'InvalidRecipient', ) }) @@ -5709,9 +5589,10 @@ describe('AutomationRegistry2_3', () => { describe('#setUpkeepPrivilegeConfig() / #getUpkeepPrivilegeConfig()', () => { it('reverts when non manager tries to set privilege config', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(payee3).setUpkeepPrivilegeConfig(upkeepId, '0x1234'), - 'OnlyCallableByUpkeepPrivilegeManager()', + registry, + 'OnlyCallableByUpkeepPrivilegeManager', ) }) @@ -5737,9 +5618,10 @@ describe('AutomationRegistry2_3', () => { const admin = randomAddress() it('reverts when non manager tries to set privilege config', async () => { - await evmRevert( + await evmRevertCustomError( registry.connect(payee3).setAdminPrivilegeConfig(admin, '0x1234'), - 'OnlyCallableByUpkeepPrivilegeManager()', + registry, + 'OnlyCallableByUpkeepPrivilegeManager', ) }) @@ -5852,106 +5734,104 @@ describe('AutomationRegistry2_3', () => { assert.isTrue(k2New.lastCollected.eq(BigNumber.from(0))) }) - itMaybe( - 'maintains consistent balance information across all parties', - async () => { - // throughout transmits, withdrawals, setConfigs total claim on balances should remain less than expected balance - // some spare change can get lost but it should be less than maxAllowedSpareChange + // itMaybe( + it('maintains consistent balance information across all parties', async () => { + // throughout transmits, withdrawals, setConfigs total claim on balances should remain less than expected balance + // some spare change can get lost but it should be less than maxAllowedSpareChange - let maxAllowedSpareChange = BigNumber.from('0') - await verifyConsistentAccounting(maxAllowedSpareChange) + let maxAllowedSpareChange = BigNumber.from('0') + await verifyConsistentAccounting(maxAllowedSpareChange) - await getTransmitTx(registry, keeper1, [upkeepId]) - maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('31')) - await verifyConsistentAccounting(maxAllowedSpareChange) - - await registry - .connect(payee1) - .withdrawPayment( - await keeper1.getAddress(), - await nonkeeper.getAddress(), - ) - await verifyConsistentAccounting(maxAllowedSpareChange) - - await registry - .connect(payee2) - .withdrawPayment( - await keeper2.getAddress(), - await nonkeeper.getAddress(), - ) - await verifyConsistentAccounting(maxAllowedSpareChange) + await getTransmitTx(registry, keeper1, [upkeepId]) + maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('31')) + await verifyConsistentAccounting(maxAllowedSpareChange) - await getTransmitTx(registry, keeper1, [upkeepId]) - maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('31')) - await verifyConsistentAccounting(maxAllowedSpareChange) + await registry + .connect(payee1) + .withdrawPayment( + await keeper1.getAddress(), + await nonkeeper.getAddress(), + ) + await verifyConsistentAccounting(maxAllowedSpareChange) - await registry.connect(owner).setConfigTypeSafe( - signerAddresses.slice(2, 15), // only use 2-14th index keepers - keeperAddresses.slice(2, 15), - f, - config, - offchainVersion, - offchainBytes, - [], - [], + await registry + .connect(payee2) + .withdrawPayment( + await keeper2.getAddress(), + await nonkeeper.getAddress(), ) - await verifyConsistentAccounting(maxAllowedSpareChange) + await verifyConsistentAccounting(maxAllowedSpareChange) - await getTransmitTx(registry, keeper3, [upkeepId], { - startingSignerIndex: 2, - }) - maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('13')) - await verifyConsistentAccounting(maxAllowedSpareChange) + await getTransmitTx(registry, keeper1, [upkeepId]) + maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('31')) + await verifyConsistentAccounting(maxAllowedSpareChange) - await registry - .connect(payee1) - .withdrawPayment( - await keeper1.getAddress(), - await nonkeeper.getAddress(), - ) - await verifyConsistentAccounting(maxAllowedSpareChange) + await registry.connect(owner).setConfigTypeSafe( + signerAddresses.slice(2, 15), // only use 2-14th index keepers + keeperAddresses.slice(2, 15), + f, + config, + offchainVersion, + offchainBytes, + baseConfig[6], + baseConfig[7], + ) + await verifyConsistentAccounting(maxAllowedSpareChange) - await registry - .connect(payee3) - .withdrawPayment( - await keeper3.getAddress(), - await nonkeeper.getAddress(), - ) - await verifyConsistentAccounting(maxAllowedSpareChange) + await getTransmitTx(registry, keeper3, [upkeepId], { + startingSignerIndex: 2, + }) + maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('13')) + await verifyConsistentAccounting(maxAllowedSpareChange) - await registry.connect(owner).setConfigTypeSafe( - signerAddresses.slice(0, 4), // only use 0-3rd index keepers - keeperAddresses.slice(0, 4), - f, - config, - offchainVersion, - offchainBytes, - [], - [], + await registry + .connect(payee1) + .withdrawPayment( + await keeper1.getAddress(), + await nonkeeper.getAddress(), ) - await verifyConsistentAccounting(maxAllowedSpareChange) - await getTransmitTx(registry, keeper1, [upkeepId]) - maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('4')) - await getTransmitTx(registry, keeper3, [upkeepId]) - maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('4')) + await verifyConsistentAccounting(maxAllowedSpareChange) - await verifyConsistentAccounting(maxAllowedSpareChange) - await registry - .connect(payee5) - .withdrawPayment( - await keeper5.getAddress(), - await nonkeeper.getAddress(), - ) - await verifyConsistentAccounting(maxAllowedSpareChange) + await registry + .connect(payee3) + .withdrawPayment( + await keeper3.getAddress(), + await nonkeeper.getAddress(), + ) + await verifyConsistentAccounting(maxAllowedSpareChange) - await registry - .connect(payee1) - .withdrawPayment( - await keeper1.getAddress(), - await nonkeeper.getAddress(), - ) - await verifyConsistentAccounting(maxAllowedSpareChange) - }, - ) + await registry.connect(owner).setConfigTypeSafe( + signerAddresses.slice(0, 4), // only use 0-3rd index keepers + keeperAddresses.slice(0, 4), + f, + config, + offchainVersion, + offchainBytes, + baseConfig[6], + baseConfig[7], + ) + await verifyConsistentAccounting(maxAllowedSpareChange) + await getTransmitTx(registry, keeper1, [upkeepId]) + maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('4')) + await getTransmitTx(registry, keeper3, [upkeepId]) + maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('4')) + + await verifyConsistentAccounting(maxAllowedSpareChange) + await registry + .connect(payee5) + .withdrawPayment( + await keeper5.getAddress(), + await nonkeeper.getAddress(), + ) + await verifyConsistentAccounting(maxAllowedSpareChange) + + await registry + .connect(payee1) + .withdrawPayment( + await keeper1.getAddress(), + await nonkeeper.getAddress(), + ) + await verifyConsistentAccounting(maxAllowedSpareChange) + }) }) }) diff --git a/contracts/test/v0.8/automation/CronUpkeep.test.ts b/contracts/test/v0.8/automation/CronUpkeep.test.ts index f153345b570..9c0192e61e7 100644 --- a/contracts/test/v0.8/automation/CronUpkeep.test.ts +++ b/contracts/test/v0.8/automation/CronUpkeep.test.ts @@ -397,7 +397,10 @@ describe('CronUpkeep', () => { for (let idx = 0; idx < 5; idx++) { await createBasicCron() } - await expect(createBasicCron()).to.be.revertedWith('ExceedsMaxJobs') + await expect(createBasicCron()).to.be.revertedWithCustomError( + cron, + 'ExceedsMaxJobs', + ) }) }) @@ -453,7 +456,7 @@ describe('CronUpkeep', () => { handler2Sig, newEncodedSpec, ), - ).to.be.revertedWith(CRON_NOT_FOUND_ERR) + ).to.be.revertedWithCustomError(cron, CRON_NOT_FOUND_ERR) }) }) @@ -465,8 +468,14 @@ describe('CronUpkeep', () => { await createBasicCron() await assertJobIDsEqual([1, 2, 3, 4]) await cron.deleteCronJob(2) - await expect(cron.getCronJob(2)).to.be.revertedWith(CRON_NOT_FOUND_ERR) - await expect(cron.deleteCronJob(2)).to.be.revertedWith(CRON_NOT_FOUND_ERR) + await expect(cron.getCronJob(2)).to.be.revertedWithCustomError( + cron, + CRON_NOT_FOUND_ERR, + ) + await expect(cron.deleteCronJob(2)).to.be.revertedWithCustomError( + cron, + CRON_NOT_FOUND_ERR, + ) await assertJobIDsEqual([1, 3, 4]) await cron.deleteCronJob(1) await assertJobIDsEqual([3, 4]) @@ -484,8 +493,14 @@ describe('CronUpkeep', () => { it('reverts if trying to delete a non-existent ID', async () => { await createBasicCron() await createBasicCron() - await expect(cron.deleteCronJob(0)).to.be.revertedWith(CRON_NOT_FOUND_ERR) - await expect(cron.deleteCronJob(3)).to.be.revertedWith(CRON_NOT_FOUND_ERR) + await expect(cron.deleteCronJob(0)).to.be.revertedWithCustomError( + cron, + CRON_NOT_FOUND_ERR, + ) + await expect(cron.deleteCronJob(3)).to.be.revertedWithCustomError( + cron, + CRON_NOT_FOUND_ERR, + ) }) }) diff --git a/contracts/test/v0.8/automation/ERC20BalanceMonitor.test.ts b/contracts/test/v0.8/automation/ERC20BalanceMonitor.test.ts index afab7af5107..2d5d113abca 100644 --- a/contracts/test/v0.8/automation/ERC20BalanceMonitor.test.ts +++ b/contracts/test/v0.8/automation/ERC20BalanceMonitor.test.ts @@ -8,9 +8,9 @@ import { ERC20BalanceMonitorExposed, LinkToken } from '../../../typechain' import { BigNumber } from 'ethers' const OWNABLE_ERR = 'Only callable by owner' -const INVALID_WATCHLIST_ERR = `InvalidWatchList()` +const INVALID_WATCHLIST_ERR = `InvalidWatchList` const PAUSED_ERR = 'Pausable: paused' -const ONLY_KEEPER_ERR = `OnlyKeeperRegistry()` +const ONLY_KEEPER_ERR = `OnlyKeeperRegistry` const zeroLINK = ethers.utils.parseEther('0') const oneLINK = ethers.utils.parseEther('1') @@ -67,7 +67,7 @@ describe('ERC20BalanceMonitor', () => { owner, ) const ltFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', + 'src/v0.8/shared/test/helpers/LinkTokenTestHelper.sol:LinkTokenTestHelper', owner, ) const reFactory = await ethers.getContractFactory('ReceiveEmitter', owner) @@ -221,7 +221,7 @@ describe('ERC20BalanceMonitor', () => { }) it('Should not allow duplicates in the watchlist', async () => { - const errMsg = `DuplicateAddress("${watchAddress1}")` + const errMsg = `DuplicateAddress` const setTx = bm .connect(owner) .setWatchList( @@ -229,7 +229,9 @@ describe('ERC20BalanceMonitor', () => { [oneLINK, twoLINK, threeLINK], [twoLINK, threeLINK, fiveLINK], ) - await expect(setTx).to.be.revertedWith(errMsg) + await expect(setTx) + .to.be.revertedWithCustomError(bm, errMsg) + .withArgs(watchAddress1) }) it('Should not allow a topUpLevel les than or equal to minBalance in the watchlist', async () => { @@ -240,7 +242,10 @@ describe('ERC20BalanceMonitor', () => { [oneLINK, twoLINK, threeLINK], [zeroLINK, twoLINK, threeLINK], ) - await expect(setTx).to.be.revertedWith(INVALID_WATCHLIST_ERR) + await expect(setTx).to.be.revertedWithCustomError( + bm, + INVALID_WATCHLIST_ERR, + ) }) it('Should not allow larger than maximum watchlist size', async () => { @@ -253,7 +258,7 @@ describe('ERC20BalanceMonitor', () => { const tx = bm .connect(owner) .setWatchList(watchlist[0], watchlist[1], watchlist[2]) - await expect(tx).to.be.revertedWith(INVALID_WATCHLIST_ERR) + await expect(tx).to.be.revertedWithCustomError(bm, INVALID_WATCHLIST_ERR) }) it('Should not allow strangers to set the watchlist', async () => { @@ -265,11 +270,11 @@ describe('ERC20BalanceMonitor', () => { it('Should revert if the list lengths differ', async () => { let tx = bm.connect(owner).setWatchList([watchAddress1], [], [twoLINK]) - await expect(tx).to.be.revertedWith(INVALID_WATCHLIST_ERR) + await expect(tx).to.be.revertedWithCustomError(bm, INVALID_WATCHLIST_ERR) tx = bm.connect(owner).setWatchList([watchAddress1], [oneLINK], []) - await expect(tx).to.be.revertedWith(INVALID_WATCHLIST_ERR) + await expect(tx).to.be.revertedWithCustomError(bm, INVALID_WATCHLIST_ERR) tx = bm.connect(owner).setWatchList([], [oneLINK], [twoLINK]) - await expect(tx).to.be.revertedWith(INVALID_WATCHLIST_ERR) + await expect(tx).to.be.revertedWithCustomError(bm, INVALID_WATCHLIST_ERR) }) it('Should revert if any of the addresses are empty', async () => { @@ -280,7 +285,7 @@ describe('ERC20BalanceMonitor', () => { [oneLINK, oneLINK], [twoLINK, twoLINK], ) - await expect(tx).to.be.revertedWith(INVALID_WATCHLIST_ERR) + await expect(tx).to.be.revertedWithCustomError(bm, INVALID_WATCHLIST_ERR) }) it('Should revert if any of the top up amounts are 0', async () => { @@ -291,7 +296,7 @@ describe('ERC20BalanceMonitor', () => { [oneLINK, oneLINK], [twoLINK, zeroLINK], ) - await expect(tx).to.be.revertedWith(INVALID_WATCHLIST_ERR) + await expect(tx).to.be.revertedWithCustomError(bm, INVALID_WATCHLIST_ERR) }) }) @@ -586,9 +591,15 @@ describe('ERC20BalanceMonitor', () => { it('Should only be callable by the keeper registry contract', async () => { let performTx = bm.connect(owner).performUpkeep(validPayload) - await expect(performTx).to.be.revertedWith(ONLY_KEEPER_ERR) + await expect(performTx).to.be.revertedWithCustomError( + bm, + ONLY_KEEPER_ERR, + ) performTx = bm.connect(stranger).performUpkeep(validPayload) - await expect(performTx).to.be.revertedWith(ONLY_KEEPER_ERR) + await expect(performTx).to.be.revertedWithCustomError( + bm, + ONLY_KEEPER_ERR, + ) }) it('Should protect against running out of gas', async () => { diff --git a/contracts/test/v0.8/automation/EthBalanceMonitor.test.ts b/contracts/test/v0.8/automation/EthBalanceMonitor.test.ts index 1f7163b0ad1..edcf1b564c9 100644 --- a/contracts/test/v0.8/automation/EthBalanceMonitor.test.ts +++ b/contracts/test/v0.8/automation/EthBalanceMonitor.test.ts @@ -9,9 +9,9 @@ import { BigNumber } from 'ethers' import * as h from '../../test-helpers/helpers' const OWNABLE_ERR = 'Only callable by owner' -const INVALID_WATCHLIST_ERR = `InvalidWatchList()` +const INVALID_WATCHLIST_ERR = `InvalidWatchList` const PAUSED_ERR = 'Pausable: paused' -const ONLY_KEEPER_ERR = `OnlyKeeperRegistry()` +const ONLY_KEEPER_ERR = `OnlyKeeperRegistry` const zeroEth = ethers.utils.parseEther('0') const oneEth = ethers.utils.parseEther('1') @@ -236,7 +236,7 @@ describe('EthBalanceMonitor', () => { }) it('Should not allow duplicates in the watchlist', async () => { - const errMsg = `DuplicateAddress("${watchAddress1}")` + const errMsg = `DuplicateAddress` const setTx = bm .connect(owner) .setWatchList( @@ -244,7 +244,9 @@ describe('EthBalanceMonitor', () => { [oneEth, twoEth, threeEth], [oneEth, twoEth, threeEth], ) - await expect(setTx).to.be.revertedWith(errMsg) + await expect(setTx) + .to.be.revertedWithCustomError(bm, errMsg) + .withArgs(watchAddress1) }) it('Should not allow strangers to set the watchlist', async () => { @@ -256,11 +258,11 @@ describe('EthBalanceMonitor', () => { it('Should revert if the list lengths differ', async () => { let tx = bm.connect(owner).setWatchList([watchAddress1], [], [twoEth]) - await expect(tx).to.be.revertedWith(INVALID_WATCHLIST_ERR) + await expect(tx).to.be.revertedWithCustomError(bm, INVALID_WATCHLIST_ERR) tx = bm.connect(owner).setWatchList([watchAddress1], [oneEth], []) - await expect(tx).to.be.revertedWith(INVALID_WATCHLIST_ERR) + await expect(tx).to.be.revertedWithCustomError(bm, INVALID_WATCHLIST_ERR) tx = bm.connect(owner).setWatchList([], [oneEth], [twoEth]) - await expect(tx).to.be.revertedWith(INVALID_WATCHLIST_ERR) + await expect(tx).to.be.revertedWithCustomError(bm, INVALID_WATCHLIST_ERR) }) it('Should revert if any of the addresses are empty', async () => { @@ -271,7 +273,7 @@ describe('EthBalanceMonitor', () => { [oneEth, oneEth], [twoEth, twoEth], ) - await expect(tx).to.be.revertedWith(INVALID_WATCHLIST_ERR) + await expect(tx).to.be.revertedWithCustomError(bm, INVALID_WATCHLIST_ERR) }) it('Should revert if any of the top up amounts are 0', async () => { @@ -282,7 +284,7 @@ describe('EthBalanceMonitor', () => { [oneEth, oneEth], [twoEth, zeroEth], ) - await expect(tx).to.be.revertedWith(INVALID_WATCHLIST_ERR) + await expect(tx).to.be.revertedWithCustomError(bm, INVALID_WATCHLIST_ERR) }) }) @@ -563,9 +565,15 @@ describe('EthBalanceMonitor', () => { it('Should only be callable by the keeper registry contract', async () => { let performTx = bm.connect(owner).performUpkeep(validPayload) - await expect(performTx).to.be.revertedWith(ONLY_KEEPER_ERR) + await expect(performTx).to.be.revertedWithCustomError( + bm, + ONLY_KEEPER_ERR, + ) performTx = bm.connect(stranger).performUpkeep(validPayload) - await expect(performTx).to.be.revertedWith(ONLY_KEEPER_ERR) + await expect(performTx).to.be.revertedWithCustomError( + bm, + ONLY_KEEPER_ERR, + ) }) it('Should protect against running out of gas', async () => { diff --git a/contracts/test/v0.8/automation/IAutomationRegistryMaster2_3.test.ts b/contracts/test/v0.8/automation/IAutomationRegistryMaster2_3.test.ts new file mode 100644 index 00000000000..0a46b4805e2 --- /dev/null +++ b/contracts/test/v0.8/automation/IAutomationRegistryMaster2_3.test.ts @@ -0,0 +1,110 @@ +import fs from 'fs' +import { ethers } from 'hardhat' +import { assert } from 'chai' +import { AutomationRegistry2_3__factory as AutomationRegistryFactory } from '../../../typechain/factories/AutomationRegistry2_3__factory' +import { AutomationRegistryLogicA2_3__factory as AutomationRegistryLogicAFactory } from '../../../typechain/factories/AutomationRegistryLogicA2_3__factory' +import { AutomationRegistryLogicB2_3__factory as AutomationRegistryLogicBFactory } from '../../../typechain/factories/AutomationRegistryLogicB2_3__factory' +import { AutomationRegistryLogicC2_3__factory as AutomationRegistryLogicCFactory } from '../../../typechain/factories/AutomationRegistryLogicC2_3__factory' +import { AutomationRegistryBase2_3__factory as AutomationRegistryBaseFactory } from '../../../typechain/factories/AutomationRegistryBase2_3__factory' +import { Chainable__factory as ChainableFactory } from '../../../typechain/factories/Chainable__factory' +import { IAutomationRegistryMaster2_3__factory as IAutomationRegistryMasterFactory } from '../../../typechain/factories/IAutomationRegistryMaster2_3__factory' +import { IAutomationRegistryConsumer__factory as IAutomationRegistryConsumerFactory } from '../../../typechain/factories/IAutomationRegistryConsumer__factory' +import { MigratableKeeperRegistryInterfaceV2__factory as MigratableKeeperRegistryInterfaceV2Factory } from '../../../typechain/factories/MigratableKeeperRegistryInterfaceV2__factory' +import { OCR2Abstract__factory as OCR2AbstractFactory } from '../../../typechain/factories/OCR2Abstract__factory' +import { IAutomationV21PlusCommon__factory as IAutomationV21PlusCommonFactory } from '../../../typechain/factories/IAutomationV21PlusCommon__factory' +import { + assertSatisfiesEvents, + assertSatisfiesInterface, + entryID, +} from './helpers' + +const compositeABIs = [ + AutomationRegistryFactory.abi, + AutomationRegistryLogicAFactory.abi, + AutomationRegistryLogicBFactory.abi, + AutomationRegistryLogicCFactory.abi, +] + +/** + * @dev because the keeper master interface is a composite of several different contracts, + * it is possible that an interface could be satisfied by functions across different + * contracts, and therefore not enforceable by the compiler directly. Instead, we use this + * test to assert that the master interface satisfies the constraints of an individual interface + */ +describe('IAutomationRegistryMaster2_3', () => { + it('is up to date', async () => { + const checksum = ethers.utils.id(compositeABIs.join('')) + const knownChecksum = fs + .readFileSync( + 'src/v0.8/automation/dev/interfaces/v2_3/IAutomationRegistryMaster2_3.sol', + ) + .toString() + .slice(17, 83) // checksum located at top of file + assert.equal( + checksum, + knownChecksum, + 'master interface is out of date - regenerate using "pnpm ts-node ./scripts/generate-automation-master-interface2_3.ts"', + ) + }) + + it('is generated from composite contracts without competing definitions', async () => { + const sharedEntries = [ + ...ChainableFactory.abi, + ...AutomationRegistryBaseFactory.abi, + ] + const abiSet = new Set() + const sharedSet = new Set() + for (const entry of sharedEntries) { + sharedSet.add(entryID(entry)) + } + for (const abi of compositeABIs) { + for (const entry of abi) { + const id = entryID(entry) + if (!abiSet.has(id)) { + abiSet.add(id) + } else if (!sharedSet.has(id)) { + assert.fail( + `composite contracts contain duplicate entry: ${JSON.stringify( + entry, + )}`, + ) + } + } + } + }) + + it('satisfies the IAutomationRegistryConsumer interface', async () => { + assertSatisfiesInterface( + IAutomationRegistryMasterFactory.abi, + IAutomationRegistryConsumerFactory.abi, + ) + }) + + it('satisfies the MigratableKeeperRegistryInterfaceV2 interface', async () => { + assertSatisfiesInterface( + IAutomationRegistryMasterFactory.abi, + MigratableKeeperRegistryInterfaceV2Factory.abi, + ) + }) + + it('satisfies the OCR2Abstract interface', async () => { + assertSatisfiesInterface( + IAutomationRegistryMasterFactory.abi, + OCR2AbstractFactory.abi, + ) + }) + + it('satisfies the IAutomationV2Common interface', async () => { + assertSatisfiesInterface( + IAutomationRegistryMasterFactory.abi, + IAutomationV21PlusCommonFactory.abi, + ) + }) + + it('satisfies the IAutomationV2Common events', async () => { + assertSatisfiesEvents( + IAutomationRegistryMasterFactory.abi, + IAutomationV21PlusCommonFactory.abi, + ) + }) +}) diff --git a/contracts/test/cross-version/KeeperCompatible.test.ts b/contracts/test/v0.8/automation/KeeperCompatible.test.ts similarity index 89% rename from contracts/test/cross-version/KeeperCompatible.test.ts rename to contracts/test/v0.8/automation/KeeperCompatible.test.ts index 968ce65f208..13d1d0deff5 100644 --- a/contracts/test/cross-version/KeeperCompatible.test.ts +++ b/contracts/test/v0.8/automation/KeeperCompatible.test.ts @@ -1,10 +1,10 @@ import { ethers } from 'hardhat' import { Contract } from 'ethers' import { expect } from 'chai' -import { publicAbi } from '../test-helpers/helpers' +import { publicAbi } from '../../test-helpers/helpers' describe('KeeperCompatible', () => { - for (let version = 6; version <= 8; version++) { + for (let version = 8; version <= 8; version++) { describe(`version v0.${version}`, () => { let contract: Contract diff --git a/contracts/test/v0.8/KeeperRegistrar.test.ts b/contracts/test/v0.8/automation/KeeperRegistrar.test.ts similarity index 92% rename from contracts/test/v0.8/KeeperRegistrar.test.ts rename to contracts/test/v0.8/automation/KeeperRegistrar.test.ts index 9cef1d0204f..8aef6810109 100644 --- a/contracts/test/v0.8/KeeperRegistrar.test.ts +++ b/contracts/test/v0.8/automation/KeeperRegistrar.test.ts @@ -1,21 +1,21 @@ import { ethers } from 'hardhat' import { assert, expect } from 'chai' -import { evmRevert } from '../test-helpers/matchers' -import { getUsers, Personas } from '../test-helpers/setup' +import { evmRevert, evmRevertCustomError } from '../../test-helpers/matchers' +import { getUsers, Personas } from '../../test-helpers/setup' import { BigNumber, Signer } from 'ethers' -import { LinkToken__factory as LinkTokenFactory } from '../../typechain/factories/LinkToken__factory' +import { LinkToken__factory as LinkTokenFactory } from '../../../typechain/factories/LinkToken__factory' -import { MockV3Aggregator__factory as MockV3AggregatorFactory } from '../../typechain/factories/MockV3Aggregator__factory' -import { UpkeepMock__factory as UpkeepMockFactory } from '../../typechain/factories/UpkeepMock__factory' -import { KeeperRegistry1_2 as KeeperRegistry } from '../../typechain/KeeperRegistry1_2' -import { KeeperRegistry1_2__factory as KeeperRegistryFactory } from '../../typechain/factories/KeeperRegistry1_2__factory' -import { KeeperRegistrar } from '../../typechain/KeeperRegistrar' -import { KeeperRegistrar__factory as KeeperRegistrarFactory } from '../../typechain/factories/KeeperRegistrar__factory' +import { MockV3Aggregator__factory as MockV3AggregatorFactory } from '../../../typechain/factories/MockV3Aggregator__factory' +import { UpkeepMock__factory as UpkeepMockFactory } from '../../../typechain/factories/UpkeepMock__factory' +import { KeeperRegistry1_2 as KeeperRegistry } from '../../../typechain/KeeperRegistry1_2' +import { KeeperRegistry1_2__factory as KeeperRegistryFactory } from '../../../typechain/factories/KeeperRegistry1_2__factory' +import { KeeperRegistrar } from '../../../typechain/KeeperRegistrar' +import { KeeperRegistrar__factory as KeeperRegistrarFactory } from '../../../typechain/factories/KeeperRegistrar__factory' -import { MockV3Aggregator } from '../../typechain/MockV3Aggregator' -import { LinkToken } from '../../typechain/LinkToken' -import { UpkeepMock } from '../../typechain/UpkeepMock' -import { toWei } from '../test-helpers/helpers' +import { MockV3Aggregator } from '../../../typechain/MockV3Aggregator' +import { LinkToken } from '../../../typechain/LinkToken' +import { UpkeepMock } from '../../../typechain/UpkeepMock' +import { toWei } from '../../test-helpers/helpers' let linkTokenFactory: LinkTokenFactory let mockV3AggregatorFactory: MockV3AggregatorFactory @@ -29,7 +29,7 @@ before(async () => { personas = (await getUsers()).personas linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', + 'src/v0.8/shared/test/helpers/LinkTokenTestHelper.sol:LinkTokenTestHelper', ) mockV3AggregatorFactory = (await ethers.getContractFactory( 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', @@ -42,9 +42,9 @@ before(async () => { const errorMsgs = { onlyOwner: 'revert Only callable by owner', - onlyAdmin: 'OnlyAdminOrOwner()', - hashPayload: 'HashMismatch()', - requestNotFound: 'RequestNotFound()', + onlyAdmin: 'OnlyAdminOrOwner', + hashPayload: 'HashMismatch', + requestNotFound: 'RequestNotFound', } describe('KeeperRegistrar', () => { @@ -158,7 +158,7 @@ describe('KeeperRegistrar', () => { describe('#register', () => { it('reverts if not called by the LINK token', async () => { - await evmRevert( + await evmRevertCustomError( registrar .connect(someAddress) .register( @@ -172,7 +172,8 @@ describe('KeeperRegistrar', () => { source, await requestSender.getAddress(), ), - 'OnlyLink()', + registrar, + 'OnlyLink', ) }) @@ -201,11 +202,12 @@ describe('KeeperRegistrar', () => { ], ) - await evmRevert( + await evmRevertCustomError( linkToken .connect(requestSender) .transferAndCall(registrar.address, amount, abiEncodedBytes), - 'AmountMismatch()', + registrar, + 'AmountMismatch', ) }) @@ -224,11 +226,12 @@ describe('KeeperRegistrar', () => { await admin.getAddress(), // Should have been requestSender.getAddress() ], ) - await evmRevert( + await evmRevertCustomError( linkToken .connect(requestSender) .transferAndCall(registrar.address, amount, abiEncodedBytes), - 'SenderMismatch()', + registrar, + 'SenderMismatch', ) }) @@ -248,11 +251,12 @@ describe('KeeperRegistrar', () => { ], ) - await evmRevert( + await evmRevertCustomError( linkToken .connect(requestSender) .transferAndCall(registrar.address, amount, abiEncodedBytes), - 'RegistrationRequestFailed()', + registrar, + 'RegistrationRequestFailed', ) }) @@ -638,7 +642,7 @@ describe('KeeperRegistrar', () => { emptyBytes, '0x000000000000000000000000322813fd9a801c5507c9de605d63cea4f2ce6c44', ) - await evmRevert(tx, errorMsgs.requestNotFound) + await evmRevertCustomError(tx, registrar, errorMsgs.requestNotFound) }) it('reverts if any member of the payload changes', async () => { @@ -652,7 +656,7 @@ describe('KeeperRegistrar', () => { emptyBytes, hash, ) - await evmRevert(tx, errorMsgs.hashPayload) + await evmRevertCustomError(tx, registrar, errorMsgs.hashPayload) tx = registrar .connect(registrarOwner) .approve( @@ -663,7 +667,7 @@ describe('KeeperRegistrar', () => { emptyBytes, hash, ) - await evmRevert(tx, errorMsgs.hashPayload) + await evmRevertCustomError(tx, registrar, errorMsgs.hashPayload) tx = registrar .connect(registrarOwner) .approve( @@ -674,7 +678,7 @@ describe('KeeperRegistrar', () => { emptyBytes, hash, ) - await evmRevert(tx, errorMsgs.hashPayload) + await evmRevertCustomError(tx, registrar, errorMsgs.hashPayload) tx = registrar .connect(registrarOwner) .approve( @@ -685,7 +689,7 @@ describe('KeeperRegistrar', () => { '0x1234', hash, ) - await evmRevert(tx, errorMsgs.hashPayload) + await evmRevertCustomError(tx, registrar, errorMsgs.hashPayload) }) it('approves an existing registration request', async () => { @@ -723,7 +727,7 @@ describe('KeeperRegistrar', () => { emptyBytes, hash, ) - await evmRevert(tx, errorMsgs.requestNotFound) + await evmRevertCustomError(tx, registrar, errorMsgs.requestNotFound) }) }) @@ -768,7 +772,7 @@ describe('KeeperRegistrar', () => { it('reverts if not called by the admin / owner', async () => { const tx = registrar.connect(stranger).cancel(hash) - await evmRevert(tx, errorMsgs.onlyAdmin) + await evmRevertCustomError(tx, registrar, errorMsgs.onlyAdmin) }) it('reverts if the hash does not exist', async () => { @@ -777,7 +781,7 @@ describe('KeeperRegistrar', () => { .cancel( '0x000000000000000000000000322813fd9a801c5507c9de605d63cea4f2ce6c44', ) - await evmRevert(tx, errorMsgs.requestNotFound) + await evmRevertCustomError(tx, registrar, errorMsgs.requestNotFound) }) it('refunds the total request balance to the admin address', async () => { @@ -791,7 +795,7 @@ describe('KeeperRegistrar', () => { it('deletes the request hash', async () => { await registrar.connect(registrarOwner).cancel(hash) let tx = registrar.connect(registrarOwner).cancel(hash) - await evmRevert(tx, errorMsgs.requestNotFound) + await evmRevertCustomError(tx, registrar, errorMsgs.requestNotFound) tx = registrar .connect(registrarOwner) .approve( @@ -802,7 +806,7 @@ describe('KeeperRegistrar', () => { emptyBytes, hash, ) - await evmRevert(tx, errorMsgs.requestNotFound) + await evmRevertCustomError(tx, registrar, errorMsgs.requestNotFound) }) }) }) diff --git a/contracts/test/v0.8/automation/KeeperRegistrar2_0.test.ts b/contracts/test/v0.8/automation/KeeperRegistrar2_0.test.ts deleted file mode 100644 index 14a5c7eba2d..00000000000 --- a/contracts/test/v0.8/automation/KeeperRegistrar2_0.test.ts +++ /dev/null @@ -1,937 +0,0 @@ -import { ethers } from 'hardhat' -import { assert, expect } from 'chai' -import { evmRevert } from '../../test-helpers/matchers' -import { getUsers, Personas } from '../../test-helpers/setup' -import { BigNumber, Signer } from 'ethers' -import { LinkToken__factory as LinkTokenFactory } from '../../../typechain/factories/LinkToken__factory' - -import { MockV3Aggregator__factory as MockV3AggregatorFactory } from '../../../typechain/factories/MockV3Aggregator__factory' -import { UpkeepMock__factory as UpkeepMockFactory } from '../../../typechain/factories/UpkeepMock__factory' -import { KeeperRegistry2_0 as KeeperRegistry } from '../../../typechain/KeeperRegistry2_0' -import { KeeperRegistryLogic20 as KeeperRegistryLogic } from '../../../typechain/KeeperRegistryLogic20' -import { KeeperRegistrar20 as KeeperRegistrar } from '../../../typechain/KeeperRegistrar20' -import { KeeperRegistry2_0__factory as KeeperRegistryFactory } from '../../../typechain/factories/KeeperRegistry2_0__factory' -import { KeeperRegistryLogic2_0__factory as KeeperRegistryLogicFactory } from '../../../typechain/factories/KeeperRegistryLogic2_0__factory' -import { KeeperRegistrar2_0__factory as KeeperRegistrarFactory } from '../../../typechain/factories/KeeperRegistrar2_0__factory' - -import { MockV3Aggregator } from '../../../typechain/MockV3Aggregator' -import { LinkToken } from '../../../typechain/LinkToken' -import { UpkeepMock } from '../../../typechain/UpkeepMock' -import { toWei } from '../../test-helpers/helpers' - -let linkTokenFactory: LinkTokenFactory -let mockV3AggregatorFactory: MockV3AggregatorFactory -let keeperRegistryFactory: KeeperRegistryFactory -let keeperRegistryLogicFactory: KeeperRegistryLogicFactory -let keeperRegistrar: KeeperRegistrarFactory -let upkeepMockFactory: UpkeepMockFactory - -let personas: Personas - -before(async () => { - personas = (await getUsers()).personas - - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', - ) - mockV3AggregatorFactory = (await ethers.getContractFactory( - 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', - )) as unknown as MockV3AggregatorFactory - // @ts-ignore bug in autogen file - keeperRegistryFactory = await ethers.getContractFactory('KeeperRegistry2_0') - // @ts-ignore bug in autogen file - keeperRegistryLogicFactory = await ethers.getContractFactory( - 'KeeperRegistryLogic2_0', - ) - // @ts-ignore bug in autogen file - keeperRegistrar = await ethers.getContractFactory('KeeperRegistrar2_0') - upkeepMockFactory = await ethers.getContractFactory('UpkeepMock') -}) - -const errorMsgs = { - onlyOwner: 'revert Only callable by owner', - onlyAdmin: 'OnlyAdminOrOwner()', - hashPayload: 'HashMismatch()', - requestNotFound: 'RequestNotFound()', -} - -describe('KeeperRegistrar2_0', () => { - const upkeepName = 'SampleUpkeep' - - const linkEth = BigNumber.from(300000000) - const gasWei = BigNumber.from(100) - const executeGas = BigNumber.from(100000) - const paymentPremiumPPB = BigNumber.from(250000000) - const flatFeeMicroLink = BigNumber.from(0) - const maxAllowedAutoApprove = 5 - const offchainConfig = '0x01234567' - - const emptyBytes = '0x00' - const stalenessSeconds = BigNumber.from(43820) - const gasCeilingMultiplier = BigNumber.from(1) - const checkGasLimit = BigNumber.from(20000000) - const fallbackGasPrice = BigNumber.from(200) - const fallbackLinkPrice = BigNumber.from(200000000) - const maxCheckDataSize = BigNumber.from(10000) - const maxPerformDataSize = BigNumber.from(10000) - const maxPerformGas = BigNumber.from(5000000) - const minUpkeepSpend = BigNumber.from('1000000000000000000') - const amount = BigNumber.from('5000000000000000000') - const amount1 = BigNumber.from('6000000000000000000') - const transcoder = ethers.constants.AddressZero - - // Enum values are not auto exported in ABI so have to manually declare - const autoApproveType_DISABLED = 0 - const autoApproveType_ENABLED_SENDER_ALLOWLIST = 1 - const autoApproveType_ENABLED_ALL = 2 - - let owner: Signer - let admin: Signer - let someAddress: Signer - let registrarOwner: Signer - let stranger: Signer - let requestSender: Signer - - let linkToken: LinkToken - let linkEthFeed: MockV3Aggregator - let gasPriceFeed: MockV3Aggregator - let registry: KeeperRegistry - let registryLogic: KeeperRegistryLogic - let mock: UpkeepMock - let registrar: KeeperRegistrar - - beforeEach(async () => { - owner = personas.Default - admin = personas.Neil - someAddress = personas.Ned - registrarOwner = personas.Nelly - stranger = personas.Nancy - requestSender = personas.Norbert - - linkToken = await linkTokenFactory.connect(owner).deploy() - gasPriceFeed = await mockV3AggregatorFactory - .connect(owner) - .deploy(0, gasWei) - linkEthFeed = await mockV3AggregatorFactory - .connect(owner) - .deploy(9, linkEth) - registryLogic = await keeperRegistryLogicFactory - .connect(owner) - .deploy(0, linkToken.address, linkEthFeed.address, gasPriceFeed.address) - - registry = await keeperRegistryFactory - .connect(owner) - .deploy(registryLogic.address) - - mock = await upkeepMockFactory.deploy() - - registrar = await keeperRegistrar - .connect(registrarOwner) - .deploy( - linkToken.address, - autoApproveType_DISABLED, - BigNumber.from('0'), - registry.address, - minUpkeepSpend, - ) - - await linkToken - .connect(owner) - .transfer(await requestSender.getAddress(), toWei('1000')) - - const keepers = [ - await personas.Carol.getAddress(), - await personas.Nancy.getAddress(), - await personas.Ned.getAddress(), - await personas.Neil.getAddress(), - ] - const config = { - paymentPremiumPPB, - flatFeeMicroLink, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxCheckDataSize, - maxPerformDataSize, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder, - registrar: registrar.address, - } - const onchainConfig = ethers.utils.defaultAbiCoder.encode( - [ - 'tuple(uint32 paymentPremiumPPB,uint32 flatFeeMicroLink,uint32 checkGasLimit,uint24 stalenessSeconds\ - ,uint16 gasCeilingMultiplier,uint96 minUpkeepSpend,uint32 maxPerformGas,uint32 maxCheckDataSize,\ - uint32 maxPerformDataSize,uint256 fallbackGasPrice,uint256 fallbackLinkPrice,address transcoder,\ - address registrar)', - ], - [config], - ) - await registry - .connect(owner) - .setConfig(keepers, keepers, 1, onchainConfig, 1, '0x') - }) - - describe('#typeAndVersion', () => { - it('uses the correct type and version', async () => { - const typeAndVersion = await registrar.typeAndVersion() - assert.equal(typeAndVersion, 'KeeperRegistrar 2.0.0') - }) - }) - - describe('#register', () => { - it('reverts if not called by the LINK token', async () => { - await evmRevert( - registrar - .connect(someAddress) - .register( - upkeepName, - emptyBytes, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - offchainConfig, - amount, - await requestSender.getAddress(), - ), - 'OnlyLink()', - ) - }) - - it('reverts if the amount passed in data mismatches actual amount sent', async () => { - await registrar - .connect(registrarOwner) - .setRegistrationConfig( - autoApproveType_ENABLED_ALL, - maxAllowedAutoApprove, - registry.address, - minUpkeepSpend, - ) - - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - offchainConfig, - amount1, - await requestSender.getAddress(), - ], - ) - - await evmRevert( - linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes), - 'AmountMismatch()', - ) - }) - - it('reverts if the sender passed in data mismatches actual sender', async () => { - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - offchainConfig, - amount, - await admin.getAddress(), // Should have been requestSender.getAddress() - ], - ) - await evmRevert( - linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes), - 'SenderMismatch()', - ) - }) - - it('reverts if the admin address is 0x0000...', async () => { - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - executeGas, - '0x0000000000000000000000000000000000000000', - emptyBytes, - offchainConfig, - amount, - await requestSender.getAddress(), - ], - ) - - await evmRevert( - linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes), - 'RegistrationRequestFailed()', - ) - }) - - it('Auto Approve ON - registers an upkeep on KeeperRegistry instantly and emits both RegistrationRequested and RegistrationApproved events', async () => { - //set auto approve ON with high threshold limits - await registrar - .connect(registrarOwner) - .setRegistrationConfig( - autoApproveType_ENABLED_ALL, - maxAllowedAutoApprove, - registry.address, - minUpkeepSpend, - ) - - //register with auto approve ON - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - offchainConfig, - amount, - await requestSender.getAddress(), - ], - ) - const tx = await linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes) - - const [id] = await registry.getActiveUpkeepIDs(0, 1) - - //confirm if a new upkeep has been registered and the details are the same as the one just registered - const newupkeep = await registry.getUpkeep(id) - assert.equal(newupkeep.target, mock.address) - assert.equal(newupkeep.admin, await admin.getAddress()) - assert.equal(newupkeep.checkData, emptyBytes) - assert.equal(newupkeep.balance.toString(), amount.toString()) - assert.equal(newupkeep.executeGas, executeGas.toNumber()) - assert.equal(newupkeep.offchainConfig, offchainConfig) - - await expect(tx).to.emit(registrar, 'RegistrationRequested') - await expect(tx).to.emit(registrar, 'RegistrationApproved') - }) - - it('Auto Approve OFF - does not registers an upkeep on KeeperRegistry, emits only RegistrationRequested event', async () => { - //get upkeep count before attempting registration - const beforeCount = (await registry.getState()).state.numUpkeeps - - //set auto approve OFF, threshold limits dont matter in this case - await registrar - .connect(registrarOwner) - .setRegistrationConfig( - autoApproveType_DISABLED, - maxAllowedAutoApprove, - registry.address, - minUpkeepSpend, - ) - - //register with auto approve OFF - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - offchainConfig, - amount, - await requestSender.getAddress(), - ], - ) - const tx = await linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes) - const receipt = await tx.wait() - - //get upkeep count after attempting registration - const afterCount = (await registry.getState()).state.numUpkeeps - //confirm that a new upkeep has NOT been registered and upkeep count is still the same - assert.deepEqual(beforeCount, afterCount) - - //confirm that only RegistrationRequested event is emitted and RegistrationApproved event is not - await expect(tx).to.emit(registrar, 'RegistrationRequested') - await expect(tx).not.to.emit(registrar, 'RegistrationApproved') - - const hash = receipt.logs[2].topics[1] - const pendingRequest = await registrar.getPendingRequest(hash) - assert.equal(await admin.getAddress(), pendingRequest[0]) - assert.ok(amount.eq(pendingRequest[1])) - }) - - it('Auto Approve ON - Throttle max approvals - does not register an upkeep on KeeperRegistry beyond the max limit, emits only RegistrationRequested event after limit is hit', async () => { - assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 0) - - //set auto approve on, with max 1 allowed - await registrar.connect(registrarOwner).setRegistrationConfig( - autoApproveType_ENABLED_ALL, - 1, // maxAllowedAutoApprove - registry.address, - minUpkeepSpend, - ) - - //register within threshold, new upkeep should be registered - let abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ - upkeepName, - emptyBytes, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - offchainConfig, - amount, - await requestSender.getAddress(), - ]) - await linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes) - assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 1) // 0 -> 1 - - //try registering another one, new upkeep should not be registered - abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ - upkeepName, - emptyBytes, - mock.address, - executeGas.toNumber() + 1, // make unique hash - await admin.getAddress(), - emptyBytes, - offchainConfig, - amount, - await requestSender.getAddress(), - ]) - await linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes) - assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 1) // Still 1 - - // Now set new max limit to 2. One more upkeep should get auto approved - await registrar.connect(registrarOwner).setRegistrationConfig( - autoApproveType_ENABLED_ALL, - 2, // maxAllowedAutoApprove - registry.address, - minUpkeepSpend, - ) - abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ - upkeepName, - emptyBytes, - mock.address, - executeGas.toNumber() + 2, // make unique hash - await admin.getAddress(), - emptyBytes, - offchainConfig, - amount, - await requestSender.getAddress(), - ]) - await linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes) - assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 2) // 1 -> 2 - - // One more upkeep should not get registered - abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ - upkeepName, - emptyBytes, - mock.address, - executeGas.toNumber() + 3, // make unique hash - await admin.getAddress(), - emptyBytes, - offchainConfig, - amount, - await requestSender.getAddress(), - ]) - await linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes) - assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 2) // Still 2 - }) - - it('Auto Approve Sender Allowlist - sender in allowlist - registers an upkeep on KeeperRegistry instantly and emits both RegistrationRequested and RegistrationApproved events', async () => { - const senderAddress = await requestSender.getAddress() - - //set auto approve to ENABLED_SENDER_ALLOWLIST type with high threshold limits - await registrar - .connect(registrarOwner) - .setRegistrationConfig( - autoApproveType_ENABLED_SENDER_ALLOWLIST, - maxAllowedAutoApprove, - registry.address, - minUpkeepSpend, - ) - - // Add sender to allowlist - await registrar - .connect(registrarOwner) - .setAutoApproveAllowedSender(senderAddress, true) - - //register with auto approve ON - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - offchainConfig, - amount, - await requestSender.getAddress(), - ], - ) - const tx = await linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes) - - const [id] = await registry.getActiveUpkeepIDs(0, 1) - - //confirm if a new upkeep has been registered and the details are the same as the one just registered - const newupkeep = await registry.getUpkeep(id) - assert.equal(newupkeep.target, mock.address) - assert.equal(newupkeep.admin, await admin.getAddress()) - assert.equal(newupkeep.checkData, emptyBytes) - assert.equal(newupkeep.balance.toString(), amount.toString()) - assert.equal(newupkeep.executeGas, executeGas.toNumber()) - - await expect(tx).to.emit(registrar, 'RegistrationRequested') - await expect(tx).to.emit(registrar, 'RegistrationApproved') - }) - - it('Auto Approve Sender Allowlist - sender NOT in allowlist - does not registers an upkeep on KeeperRegistry, emits only RegistrationRequested event', async () => { - const beforeCount = (await registry.getState()).state.numUpkeeps - const senderAddress = await requestSender.getAddress() - - //set auto approve to ENABLED_SENDER_ALLOWLIST type with high threshold limits - await registrar - .connect(registrarOwner) - .setRegistrationConfig( - autoApproveType_ENABLED_SENDER_ALLOWLIST, - maxAllowedAutoApprove, - registry.address, - minUpkeepSpend, - ) - - // Explicitly remove sender from allowlist - await registrar - .connect(registrarOwner) - .setAutoApproveAllowedSender(senderAddress, false) - - //register. auto approve shouldn't happen - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - offchainConfig, - amount, - await requestSender.getAddress(), - ], - ) - const tx = await linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes) - const receipt = await tx.wait() - - //get upkeep count after attempting registration - const afterCount = (await registry.getState()).state.numUpkeeps - //confirm that a new upkeep has NOT been registered and upkeep count is still the same - assert.deepEqual(beforeCount, afterCount) - - //confirm that only RegistrationRequested event is emitted and RegistrationApproved event is not - await expect(tx).to.emit(registrar, 'RegistrationRequested') - await expect(tx).not.to.emit(registrar, 'RegistrationApproved') - - const hash = receipt.logs[2].topics[1] - const pendingRequest = await registrar.getPendingRequest(hash) - assert.equal(await admin.getAddress(), pendingRequest[0]) - assert.ok(amount.eq(pendingRequest[1])) - }) - }) - - describe('#registerUpkeep', () => { - it('reverts with empty message if amount sent is not available in LINK allowance', async () => { - await evmRevert( - registrar.connect(someAddress).registerUpkeep({ - name: upkeepName, - upkeepContract: mock.address, - gasLimit: executeGas, - adminAddress: await admin.getAddress(), - checkData: emptyBytes, - offchainConfig: emptyBytes, - amount, - encryptedEmail: emptyBytes, - }), - '', - ) - }) - - it('reverts if the amount passed in data is less than configured minimum', async () => { - await registrar - .connect(registrarOwner) - .setRegistrationConfig( - autoApproveType_ENABLED_ALL, - maxAllowedAutoApprove, - registry.address, - minUpkeepSpend, - ) - - // amt is one order of magnitude less than minUpkeepSpend - const amt = BigNumber.from('100000000000000000') - - await evmRevert( - registrar.connect(someAddress).registerUpkeep({ - name: upkeepName, - upkeepContract: mock.address, - gasLimit: executeGas, - adminAddress: await admin.getAddress(), - checkData: emptyBytes, - offchainConfig: emptyBytes, - amount: amt, - encryptedEmail: emptyBytes, - }), - 'InsufficientPayment()', - ) - }) - - it('Auto Approve ON - registers an upkeep on KeeperRegistry instantly and emits both RegistrationRequested and RegistrationApproved events', async () => { - //set auto approve ON with high threshold limits - await registrar - .connect(registrarOwner) - .setRegistrationConfig( - autoApproveType_ENABLED_ALL, - maxAllowedAutoApprove, - registry.address, - minUpkeepSpend, - ) - - await linkToken.connect(requestSender).approve(registrar.address, amount) - - const tx = await registrar.connect(requestSender).registerUpkeep({ - name: upkeepName, - upkeepContract: mock.address, - gasLimit: executeGas, - adminAddress: await admin.getAddress(), - checkData: emptyBytes, - offchainConfig, - amount, - encryptedEmail: emptyBytes, - }) - assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 1) // 0 -> 1 - - //confirm if a new upkeep has been registered and the details are the same as the one just registered - const [id] = await registry.getActiveUpkeepIDs(0, 1) - const newupkeep = await registry.getUpkeep(id) - assert.equal(newupkeep.target, mock.address) - assert.equal(newupkeep.admin, await admin.getAddress()) - assert.equal(newupkeep.checkData, emptyBytes) - assert.equal(newupkeep.balance.toString(), amount.toString()) - assert.equal(newupkeep.executeGas, executeGas.toNumber()) - assert.equal(newupkeep.offchainConfig, offchainConfig) - - await expect(tx).to.emit(registrar, 'RegistrationRequested') - await expect(tx).to.emit(registrar, 'RegistrationApproved') - }) - }) - - describe('#setAutoApproveAllowedSender', () => { - it('reverts if not called by the owner', async () => { - const tx = registrar - .connect(stranger) - .setAutoApproveAllowedSender(await admin.getAddress(), false) - await evmRevert(tx, 'Only callable by owner') - }) - - it('sets the allowed status correctly and emits log', async () => { - const senderAddress = await stranger.getAddress() - let tx = await registrar - .connect(registrarOwner) - .setAutoApproveAllowedSender(senderAddress, true) - await expect(tx) - .to.emit(registrar, 'AutoApproveAllowedSenderSet') - .withArgs(senderAddress, true) - - let senderAllowedStatus = await registrar - .connect(owner) - .getAutoApproveAllowedSender(senderAddress) - assert.isTrue(senderAllowedStatus) - - tx = await registrar - .connect(registrarOwner) - .setAutoApproveAllowedSender(senderAddress, false) - await expect(tx) - .to.emit(registrar, 'AutoApproveAllowedSenderSet') - .withArgs(senderAddress, false) - - senderAllowedStatus = await registrar - .connect(owner) - .getAutoApproveAllowedSender(senderAddress) - assert.isFalse(senderAllowedStatus) - }) - }) - - describe('#approve', () => { - let hash: string - - beforeEach(async () => { - await registrar - .connect(registrarOwner) - .setRegistrationConfig( - autoApproveType_DISABLED, - maxAllowedAutoApprove, - registry.address, - minUpkeepSpend, - ) - - //register with auto approve OFF - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - offchainConfig, - amount, - await requestSender.getAddress(), - ], - ) - - const tx = await linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes) - const receipt = await tx.wait() - hash = receipt.logs[2].topics[1] - }) - - it('reverts if not called by the owner', async () => { - const tx = registrar - .connect(stranger) - .approve( - upkeepName, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - emptyBytes, - hash, - ) - await evmRevert(tx, 'Only callable by owner') - }) - - it('reverts if the hash does not exist', async () => { - const tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - emptyBytes, - '0x000000000000000000000000322813fd9a801c5507c9de605d63cea4f2ce6c44', - ) - await evmRevert(tx, errorMsgs.requestNotFound) - }) - - it('reverts if any member of the payload changes', async () => { - let tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - ethers.Wallet.createRandom().address, - executeGas, - await admin.getAddress(), - emptyBytes, - emptyBytes, - hash, - ) - await evmRevert(tx, errorMsgs.hashPayload) - tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - 10000, - await admin.getAddress(), - emptyBytes, - emptyBytes, - hash, - ) - await evmRevert(tx, errorMsgs.hashPayload) - tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - executeGas, - ethers.Wallet.createRandom().address, - emptyBytes, - emptyBytes, - hash, - ) - await evmRevert(tx, errorMsgs.hashPayload) - tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - executeGas, - await admin.getAddress(), - '0x1234', - emptyBytes, - hash, - ) - await evmRevert(tx, errorMsgs.hashPayload) - }) - - it('approves an existing registration request', async () => { - const tx = await registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - offchainConfig, - hash, - ) - await expect(tx).to.emit(registrar, 'RegistrationApproved') - }) - - it('deletes the request afterwards / reverts if the request DNE', async () => { - await registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - offchainConfig, - hash, - ) - const tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - offchainConfig, - hash, - ) - await evmRevert(tx, errorMsgs.requestNotFound) - }) - }) - - describe('#cancel', () => { - let hash: string - - beforeEach(async () => { - await registrar - .connect(registrarOwner) - .setRegistrationConfig( - autoApproveType_DISABLED, - maxAllowedAutoApprove, - registry.address, - minUpkeepSpend, - ) - - //register with auto approve OFF - const abiEncodedBytes = registrar.interface.encodeFunctionData( - 'register', - [ - upkeepName, - emptyBytes, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - offchainConfig, - amount, - await requestSender.getAddress(), - ], - ) - const tx = await linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes) - const receipt = await tx.wait() - hash = receipt.logs[2].topics[1] - // submit duplicate request (increase balance) - await linkToken - .connect(requestSender) - .transferAndCall(registrar.address, amount, abiEncodedBytes) - }) - - it('reverts if not called by the admin / owner', async () => { - const tx = registrar.connect(stranger).cancel(hash) - await evmRevert(tx, errorMsgs.onlyAdmin) - }) - - it('reverts if the hash does not exist', async () => { - const tx = registrar - .connect(registrarOwner) - .cancel( - '0x000000000000000000000000322813fd9a801c5507c9de605d63cea4f2ce6c44', - ) - await evmRevert(tx, errorMsgs.requestNotFound) - }) - - it('refunds the total request balance to the admin address if owner cancels', async () => { - const before = await linkToken.balanceOf(await admin.getAddress()) - const tx = await registrar.connect(registrarOwner).cancel(hash) - const after = await linkToken.balanceOf(await admin.getAddress()) - assert.isTrue(after.sub(before).eq(amount.mul(BigNumber.from(2)))) - await expect(tx).to.emit(registrar, 'RegistrationRejected') - }) - - it('refunds the total request balance to the admin address if admin cancels', async () => { - const before = await linkToken.balanceOf(await admin.getAddress()) - const tx = await registrar.connect(admin).cancel(hash) - const after = await linkToken.balanceOf(await admin.getAddress()) - assert.isTrue(after.sub(before).eq(amount.mul(BigNumber.from(2)))) - await expect(tx).to.emit(registrar, 'RegistrationRejected') - }) - - it('deletes the request hash', async () => { - await registrar.connect(registrarOwner).cancel(hash) - let tx = registrar.connect(registrarOwner).cancel(hash) - await evmRevert(tx, errorMsgs.requestNotFound) - tx = registrar - .connect(registrarOwner) - .approve( - upkeepName, - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - emptyBytes, - hash, - ) - await evmRevert(tx, errorMsgs.requestNotFound) - }) - }) -}) diff --git a/contracts/test/v0.8/automation/KeeperRegistry1_2.test.ts b/contracts/test/v0.8/automation/KeeperRegistry1_2.test.ts deleted file mode 100644 index 7da13b9e266..00000000000 --- a/contracts/test/v0.8/automation/KeeperRegistry1_2.test.ts +++ /dev/null @@ -1,2228 +0,0 @@ -import { ethers } from 'hardhat' -import { assert, expect } from 'chai' -import { evmRevert } from '../../test-helpers/matchers' -import { getUsers, Personas } from '../../test-helpers/setup' -import { BigNumber, BigNumberish, Signer } from 'ethers' -import { LinkToken__factory as LinkTokenFactory } from '../../../typechain/factories/LinkToken__factory' -import { MockV3Aggregator__factory as MockV3AggregatorFactory } from '../../../typechain/factories/MockV3Aggregator__factory' -import { UpkeepMock__factory as UpkeepMockFactory } from '../../../typechain/factories/UpkeepMock__factory' -import { UpkeepReverter__factory as UpkeepReverterFactory } from '../../../typechain/factories/UpkeepReverter__factory' -import { UpkeepAutoFunder__factory as UpkeepAutoFunderFactory } from '../../../typechain/factories/UpkeepAutoFunder__factory' -import { UpkeepTranscoder__factory as UpkeepTranscoderFactory } from '../../../typechain/factories/UpkeepTranscoder__factory' -import { KeeperRegistry1_2__factory as KeeperRegistryFactory } from '../../../typechain/factories/KeeperRegistry1_2__factory' -import { KeeperRegistry1_2 as KeeperRegistry } from '../../../typechain/KeeperRegistry1_2' -import { MockV3Aggregator } from '../../../typechain/MockV3Aggregator' -import { LinkToken } from '../../../typechain/LinkToken' -import { UpkeepMock } from '../../../typechain/UpkeepMock' -import { UpkeepTranscoder } from '../../../typechain/UpkeepTranscoder' -import { toWei } from '../../test-helpers/helpers' - -////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////// - -/*********************************** REGISTRY v1.2 IS FROZEN ************************************/ - -// All tests are disabled for this contract, as we expect it to never change in the future. -// Instead, we test that the bytecode for the contract has not changed. -// If this test ever fails, you should remove it and then re-run the original test suite. - -const BYTECODE = KeeperRegistryFactory.bytecode -const BYTECODE_CHECKSUM = - '0x4a23953416a64a0fa4c943954d9a92059f862257440f2cbcf5f238314b89f416' - -describe('KeeperRegistry1_2 - Frozen [ @skip-coverage ]', () => { - it('has not changed', () => { - assert.equal(ethers.utils.id(BYTECODE), BYTECODE_CHECKSUM) - }) -}) - -////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////// - -async function getUpkeepID(tx: any) { - const receipt = await tx.wait() - return receipt.events[0].args.id -} - -function randomAddress() { - return ethers.Wallet.createRandom().address -} - -// ----------------------------------------------------------------------------------------------- -// DEV: these *should* match the perform/check gas overhead values in the contract and on the node -const PERFORM_GAS_OVERHEAD = BigNumber.from(160000) -const CHECK_GAS_OVERHEAD = BigNumber.from(170000) -// ----------------------------------------------------------------------------------------------- - -// Smart contract factories -let linkTokenFactory: LinkTokenFactory -let mockV3AggregatorFactory: MockV3AggregatorFactory -let keeperRegistryFactory: KeeperRegistryFactory -let upkeepMockFactory: UpkeepMockFactory -let upkeepReverterFactory: UpkeepReverterFactory -let upkeepAutoFunderFactory: UpkeepAutoFunderFactory -let upkeepTranscoderFactory: UpkeepTranscoderFactory -let personas: Personas - -before(async () => { - personas = (await getUsers()).personas - - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', - ) - // need full path because there are two contracts with name MockV3Aggregator - mockV3AggregatorFactory = (await ethers.getContractFactory( - 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', - )) as unknown as MockV3AggregatorFactory - // @ts-ignore bug in autogen file - keeperRegistryFactory = await ethers.getContractFactory('KeeperRegistry1_2') - upkeepMockFactory = await ethers.getContractFactory('UpkeepMock') - upkeepReverterFactory = await ethers.getContractFactory('UpkeepReverter') - upkeepAutoFunderFactory = await ethers.getContractFactory('UpkeepAutoFunder') - upkeepTranscoderFactory = await ethers.getContractFactory('UpkeepTranscoder') -}) - -describe.skip('KeeperRegistry1_2', () => { - const linkEth = BigNumber.from(300000000) - const gasWei = BigNumber.from(100) - const linkDivisibility = BigNumber.from('1000000000000000000') - const executeGas = BigNumber.from('100000') - const paymentPremiumBase = BigNumber.from('1000000000') - const paymentPremiumPPB = BigNumber.from('250000000') - const flatFeeMicroLink = BigNumber.from(0) - const blockCountPerTurn = BigNumber.from(3) - const emptyBytes = '0x00' - const randomBytes = '0x1234abcd' - const zeroAddress = ethers.constants.AddressZero - const extraGas = BigNumber.from('250000') - const registryGasOverhead = BigNumber.from('80000') - const stalenessSeconds = BigNumber.from(43820) - const gasCeilingMultiplier = BigNumber.from(1) - const checkGasLimit = BigNumber.from(20000000) - const fallbackGasPrice = BigNumber.from(200) - const fallbackLinkPrice = BigNumber.from(200000000) - const maxPerformGas = BigNumber.from(5000000) - const minUpkeepSpend = BigNumber.from(0) - - let owner: Signer - let keeper1: Signer - let keeper2: Signer - let keeper3: Signer - let nonkeeper: Signer - let admin: Signer - let payee1: Signer - let payee2: Signer - let payee3: Signer - - let linkToken: LinkToken - let linkEthFeed: MockV3Aggregator - let gasPriceFeed: MockV3Aggregator - let registry: KeeperRegistry - let registry2: KeeperRegistry - let mock: UpkeepMock - let transcoder: UpkeepTranscoder - - let id: BigNumber - let keepers: string[] - let payees: string[] - - beforeEach(async () => { - owner = personas.Default - keeper1 = personas.Carol - keeper2 = personas.Eddy - keeper3 = personas.Nancy - nonkeeper = personas.Ned - admin = personas.Neil - payee1 = personas.Nelly - payee2 = personas.Norbert - payee3 = personas.Nick - - keepers = [ - await keeper1.getAddress(), - await keeper2.getAddress(), - await keeper3.getAddress(), - ] - payees = [ - await payee1.getAddress(), - await payee2.getAddress(), - await payee3.getAddress(), - ] - - linkToken = await linkTokenFactory.connect(owner).deploy() - gasPriceFeed = await mockV3AggregatorFactory - .connect(owner) - .deploy(0, gasWei) - linkEthFeed = await mockV3AggregatorFactory - .connect(owner) - .deploy(9, linkEth) - transcoder = await upkeepTranscoderFactory.connect(owner).deploy() - registry = await keeperRegistryFactory - .connect(owner) - .deploy(linkToken.address, linkEthFeed.address, gasPriceFeed.address, { - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - registry2 = await keeperRegistryFactory - .connect(owner) - .deploy(linkToken.address, linkEthFeed.address, gasPriceFeed.address, { - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - mock = await upkeepMockFactory.deploy() - await linkToken - .connect(owner) - .transfer(await keeper1.getAddress(), toWei('1000')) - await linkToken - .connect(owner) - .transfer(await keeper2.getAddress(), toWei('1000')) - await linkToken - .connect(owner) - .transfer(await keeper3.getAddress(), toWei('1000')) - - await registry.connect(owner).setKeepers(keepers, payees) - const tx = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - randomBytes, - ) - id = await getUpkeepID(tx) - }) - - const linkForGas = ( - upkeepGasSpent: BigNumberish, - premiumPPB?: BigNumberish, - flatFee?: BigNumberish, - ) => { - premiumPPB = premiumPPB === undefined ? paymentPremiumPPB : premiumPPB - flatFee = flatFee === undefined ? flatFeeMicroLink : flatFee - const gasSpent = registryGasOverhead.add(BigNumber.from(upkeepGasSpent)) - const base = gasWei.mul(gasSpent).mul(linkDivisibility).div(linkEth) - const premium = base.mul(premiumPPB).div(paymentPremiumBase) - const flatFeeJules = BigNumber.from(flatFee).mul('1000000000000') - return base.add(premium).add(flatFeeJules) - } - - describe('#typeAndVersion', () => { - it('uses the correct type and version', async () => { - const typeAndVersion = await registry.typeAndVersion() - assert.equal(typeAndVersion, 'KeeperRegistry 1.2.0') - }) - }) - - describe('#setKeepers', () => { - const IGNORE_ADDRESS = '0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF' - it('reverts when not called by the owner', async () => { - await evmRevert( - registry.connect(keeper1).setKeepers([], []), - 'Only callable by owner', - ) - }) - - it('reverts when adding the same keeper twice', async () => { - await evmRevert( - registry - .connect(owner) - .setKeepers( - [await keeper1.getAddress(), await keeper1.getAddress()], - [await payee1.getAddress(), await payee1.getAddress()], - ), - 'DuplicateEntry()', - ) - }) - - it('reverts with different numbers of keepers/payees', async () => { - await evmRevert( - registry - .connect(owner) - .setKeepers( - [await keeper1.getAddress(), await keeper2.getAddress()], - [await payee1.getAddress()], - ), - 'ParameterLengthError()', - ) - await evmRevert( - registry - .connect(owner) - .setKeepers( - [await keeper1.getAddress()], - [await payee1.getAddress(), await payee2.getAddress()], - ), - 'ParameterLengthError()', - ) - }) - - it('reverts if the payee is the zero address', async () => { - await evmRevert( - registry - .connect(owner) - .setKeepers( - [await keeper1.getAddress(), await keeper2.getAddress()], - [ - await payee1.getAddress(), - '0x0000000000000000000000000000000000000000', - ], - ), - 'InvalidPayee()', - ) - }) - - it('emits events for every keeper added and removed', async () => { - const oldKeepers = [ - await keeper1.getAddress(), - await keeper2.getAddress(), - ] - const oldPayees = [await payee1.getAddress(), await payee2.getAddress()] - await registry.connect(owner).setKeepers(oldKeepers, oldPayees) - assert.deepEqual(oldKeepers, (await registry.getState()).keepers) - - // remove keepers - const newKeepers = [ - await keeper2.getAddress(), - await keeper3.getAddress(), - ] - const newPayees = [await payee2.getAddress(), await payee3.getAddress()] - const tx = await registry.connect(owner).setKeepers(newKeepers, newPayees) - assert.deepEqual(newKeepers, (await registry.getState()).keepers) - - await expect(tx) - .to.emit(registry, 'KeepersUpdated') - .withArgs(newKeepers, newPayees) - }) - - it('updates the keeper to inactive when removed', async () => { - await registry.connect(owner).setKeepers(keepers, payees) - await registry - .connect(owner) - .setKeepers( - [await keeper1.getAddress(), await keeper3.getAddress()], - [await payee1.getAddress(), await payee3.getAddress()], - ) - const added = await registry.getKeeperInfo(await keeper1.getAddress()) - assert.isTrue(added.active) - const removed = await registry.getKeeperInfo(await keeper2.getAddress()) - assert.isFalse(removed.active) - }) - - it('does not change the payee if IGNORE_ADDRESS is used as payee', async () => { - const oldKeepers = [ - await keeper1.getAddress(), - await keeper2.getAddress(), - ] - const oldPayees = [await payee1.getAddress(), await payee2.getAddress()] - await registry.connect(owner).setKeepers(oldKeepers, oldPayees) - assert.deepEqual(oldKeepers, (await registry.getState()).keepers) - - const newKeepers = [ - await keeper2.getAddress(), - await keeper3.getAddress(), - ] - const newPayees = [IGNORE_ADDRESS, await payee3.getAddress()] - const tx = await registry.connect(owner).setKeepers(newKeepers, newPayees) - assert.deepEqual(newKeepers, (await registry.getState()).keepers) - - const ignored = await registry.getKeeperInfo(await keeper2.getAddress()) - assert.equal(await payee2.getAddress(), ignored.payee) - assert.equal(true, ignored.active) - - await expect(tx) - .to.emit(registry, 'KeepersUpdated') - .withArgs(newKeepers, newPayees) - }) - - it('reverts if the owner changes the payee', async () => { - await registry.connect(owner).setKeepers(keepers, payees) - await evmRevert( - registry - .connect(owner) - .setKeepers(keepers, [ - await payee1.getAddress(), - await payee2.getAddress(), - await owner.getAddress(), - ]), - 'InvalidPayee()', - ) - }) - }) - - describe('#registerUpkeep', () => { - context('and the registry is paused', () => { - beforeEach(async () => { - await registry.connect(owner).pause() - }) - it('reverts', async () => { - await evmRevert( - registry - .connect(owner) - .registerUpkeep( - zeroAddress, - executeGas, - await admin.getAddress(), - emptyBytes, - ), - 'Pausable: paused', - ) - }) - }) - - it('reverts if the target is not a contract', async () => { - await evmRevert( - registry - .connect(owner) - .registerUpkeep( - zeroAddress, - executeGas, - await admin.getAddress(), - emptyBytes, - ), - 'NotAContract()', - ) - }) - - it('reverts if called by a non-owner', async () => { - await evmRevert( - registry - .connect(keeper1) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - ), - 'OnlyCallableByOwnerOrRegistrar()', - ) - }) - - it('reverts if execute gas is too low', async () => { - await evmRevert( - registry - .connect(owner) - .registerUpkeep( - mock.address, - 2299, - await admin.getAddress(), - emptyBytes, - ), - 'GasLimitOutsideRange()', - ) - }) - - it('reverts if execute gas is too high', async () => { - await evmRevert( - registry - .connect(owner) - .registerUpkeep( - mock.address, - 5000001, - await admin.getAddress(), - emptyBytes, - ), - 'GasLimitOutsideRange()', - ) - }) - - it('creates a record of the registration', async () => { - const tx = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - ) - id = await getUpkeepID(tx) - await expect(tx) - .to.emit(registry, 'UpkeepRegistered') - .withArgs(id, executeGas, await admin.getAddress()) - const registration = await registry.getUpkeep(id) - assert.equal(mock.address, registration.target) - assert.equal(0, registration.balance.toNumber()) - assert.equal(emptyBytes, registration.checkData) - assert(registration.maxValidBlocknumber.eq('0xffffffffffffffff')) - }) - }) - - describe('#addFunds', () => { - const amount = toWei('1') - - beforeEach(async () => { - await linkToken.connect(keeper1).approve(registry.address, toWei('100')) - }) - - it('reverts if the registration does not exist', async () => { - await evmRevert( - registry.connect(keeper1).addFunds(id.add(1), amount), - 'UpkeepNotActive()', - ) - }) - - it('adds to the balance of the registration', async () => { - await registry.connect(keeper1).addFunds(id, amount) - const registration = await registry.getUpkeep(id) - assert.isTrue(amount.eq(registration.balance)) - }) - - it('emits a log', async () => { - const tx = await registry.connect(keeper1).addFunds(id, amount) - await expect(tx) - .to.emit(registry, 'FundsAdded') - .withArgs(id, await keeper1.getAddress(), amount) - }) - - it('reverts if the upkeep is canceled', async () => { - await registry.connect(admin).cancelUpkeep(id) - await evmRevert( - registry.connect(keeper1).addFunds(id, amount), - 'UpkeepNotActive()', - ) - }) - }) - - describe('#setUpkeepGasLimit', () => { - const newGasLimit = BigNumber.from('500000') - - it('reverts if the registration does not exist', async () => { - await evmRevert( - registry.connect(keeper1).setUpkeepGasLimit(id.add(1), newGasLimit), - 'UpkeepNotActive()', - ) - }) - - it('reverts if the upkeep is canceled', async () => { - await registry.connect(admin).cancelUpkeep(id) - await evmRevert( - registry.connect(keeper1).setUpkeepGasLimit(id, newGasLimit), - 'UpkeepNotActive()', - ) - }) - - it('reverts if called by anyone but the admin', async () => { - await evmRevert( - registry.connect(owner).setUpkeepGasLimit(id, newGasLimit), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if new gas limit is out of bounds', async () => { - await evmRevert( - registry.connect(admin).setUpkeepGasLimit(id, BigNumber.from('100')), - 'GasLimitOutsideRange()', - ) - await evmRevert( - registry - .connect(admin) - .setUpkeepGasLimit(id, BigNumber.from('6000000')), - 'GasLimitOutsideRange()', - ) - }) - - it('updates the gas limit successfully', async () => { - const initialGasLimit = (await registry.getUpkeep(id)).executeGas - assert.equal(initialGasLimit, executeGas.toNumber()) - await registry.connect(admin).setUpkeepGasLimit(id, newGasLimit) - const updatedGasLimit = (await registry.getUpkeep(id)).executeGas - assert.equal(updatedGasLimit, newGasLimit.toNumber()) - }) - - it('emits a log', async () => { - const tx = await registry - .connect(admin) - .setUpkeepGasLimit(id, newGasLimit) - await expect(tx) - .to.emit(registry, 'UpkeepGasLimitSet') - .withArgs(id, newGasLimit) - }) - }) - - describe('#checkUpkeep', () => { - it('reverts if the upkeep is not funded', async () => { - await mock.setCanPerform(true) - await mock.setCanCheck(true) - await evmRevert( - registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress()), - 'InsufficientFunds()', - ) - }) - - context('when the registration is funded', () => { - beforeEach(async () => { - await linkToken.connect(keeper1).approve(registry.address, toWei('100')) - await registry.connect(keeper1).addFunds(id, toWei('100')) - }) - - it('reverts if executed', async () => { - await mock.setCanPerform(true) - await mock.setCanCheck(true) - await evmRevert( - registry.checkUpkeep(id, await keeper1.getAddress()), - 'OnlySimulatedBackend()', - ) - }) - - it('reverts if the specified keeper is not valid', async () => { - await mock.setCanPerform(true) - await mock.setCanCheck(true) - await evmRevert( - registry.checkUpkeep(id, await owner.getAddress()), - 'OnlySimulatedBackend()', - ) - }) - - context('and upkeep is not needed', () => { - beforeEach(async () => { - await mock.setCanCheck(false) - }) - - it('reverts', async () => { - await evmRevert( - registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress()), - 'UpkeepNotNeeded()', - ) - }) - }) - - context('and the upkeep check fails', () => { - beforeEach(async () => { - const reverter = await upkeepReverterFactory.deploy() - const tx = await registry - .connect(owner) - .registerUpkeep( - reverter.address, - 2500000, - await admin.getAddress(), - emptyBytes, - ) - id = await getUpkeepID(tx) - await linkToken - .connect(keeper1) - .approve(registry.address, toWei('100')) - await registry.connect(keeper1).addFunds(id, toWei('100')) - }) - - it('reverts', async () => { - await evmRevert( - registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress()), - 'TargetCheckReverted', - ) - }) - }) - - context('and upkeep check simulations succeeds', () => { - beforeEach(async () => { - await mock.setCanCheck(true) - await mock.setCanPerform(true) - }) - - it('returns true with pricing info if the target can execute', async () => { - const newGasMultiplier = BigNumber.from(10) - await registry.connect(owner).setConfig({ - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier: newGasMultiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - const response = await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress()) - assert.isTrue(response.gasLimit.eq(executeGas)) - assert.isTrue(response.linkEth.eq(linkEth)) - assert.isTrue( - response.adjustedGasWei.eq(gasWei.mul(newGasMultiplier)), - ) - assert.isTrue( - response.maxLinkPayment.eq( - linkForGas(executeGas.toNumber()).mul(newGasMultiplier), - ), - ) - }) - - it('has a large enough gas overhead to cover upkeeps that use all their gas [ @skip-coverage ]', async () => { - await mock.setCheckGasToBurn(checkGasLimit) - await mock.setPerformGasToBurn(executeGas) - const gas = checkGasLimit - .add(executeGas) - .add(PERFORM_GAS_OVERHEAD) - .add(CHECK_GAS_OVERHEAD) - await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress(), { - gasLimit: gas, - }) - }) - }) - }) - }) - - describe('#performUpkeep', () => { - let _lastKeeper = keeper1 - - async function getPerformPaymentAmount() { - _lastKeeper = _lastKeeper === keeper1 ? keeper2 : keeper1 - const before = ( - await registry.getKeeperInfo(await _lastKeeper.getAddress()) - ).balance - await registry.connect(_lastKeeper).performUpkeep(id, '0x') - const after = ( - await registry.getKeeperInfo(await _lastKeeper.getAddress()) - ).balance - const difference = after.sub(before) - return difference - } - - it('reverts if the registration is not funded', async () => { - await evmRevert( - registry.connect(keeper2).performUpkeep(id, '0x'), - 'InsufficientFunds()', - ) - }) - - context('and the registry is paused', () => { - beforeEach(async () => { - await registry.connect(owner).pause() - }) - - it('reverts', async () => { - await evmRevert( - registry.connect(keeper2).performUpkeep(id, '0x'), - 'Pausable: paused', - ) - }) - }) - - context('when the registration is funded', () => { - beforeEach(async () => { - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(id, toWei('100')) - }) - - it('does not revert if the target cannot execute', async () => { - const mockResponse = await mock - .connect(zeroAddress) - .callStatic.checkUpkeep('0x') - assert.isFalse(mockResponse.callable) - - await registry.connect(keeper3).performUpkeep(id, '0x') - }) - - it('returns false if the target cannot execute', async () => { - const mockResponse = await mock - .connect(zeroAddress) - .callStatic.checkUpkeep('0x') - assert.isFalse(mockResponse.callable) - - assert.isFalse( - await registry.connect(keeper1).callStatic.performUpkeep(id, '0x'), - ) - }) - - it('returns true if called', async () => { - await mock.setCanPerform(true) - - const response = await registry - .connect(keeper1) - .callStatic.performUpkeep(id, '0x') - assert.isTrue(response) - }) - - it('reverts if not enough gas supplied', async () => { - await mock.setCanPerform(true) - - await evmRevert( - registry - .connect(keeper1) - .performUpkeep(id, '0x', { gasLimit: BigNumber.from('120000') }), - ) - }) - - it('executes the data passed to the registry', async () => { - await mock.setCanPerform(true) - - const performData = '0xc0ffeec0ffee' - const tx = await registry - .connect(keeper1) - .performUpkeep(id, performData, { gasLimit: extraGas }) - const receipt = await tx.wait() - const eventLog = receipt?.events - - assert.equal(eventLog?.length, 2) - assert.equal(eventLog?.[1].event, 'UpkeepPerformed') - expect(eventLog?.[1].args?.[0]).to.equal(id) - assert.equal(eventLog?.[1].args?.[1], true) - assert.equal(eventLog?.[1].args?.[2], await keeper1.getAddress()) - assert.isNotEmpty(eventLog?.[1].args?.[3]) - assert.equal(eventLog?.[1].args?.[4], performData) - }) - - it('updates payment balances', async () => { - const keeperBefore = await registry.getKeeperInfo( - await keeper1.getAddress(), - ) - const registrationBefore = await registry.getUpkeep(id) - const keeperLinkBefore = await linkToken.balanceOf( - await keeper1.getAddress(), - ) - const registryLinkBefore = await linkToken.balanceOf(registry.address) - - // Do the thing - await registry.connect(keeper1).performUpkeep(id, '0x') - - const keeperAfter = await registry.getKeeperInfo( - await keeper1.getAddress(), - ) - const registrationAfter = await registry.getUpkeep(id) - const keeperLinkAfter = await linkToken.balanceOf( - await keeper1.getAddress(), - ) - const registryLinkAfter = await linkToken.balanceOf(registry.address) - - assert.isTrue(keeperAfter.balance.gt(keeperBefore.balance)) - assert.isTrue(registrationBefore.balance.gt(registrationAfter.balance)) - assert.isTrue(keeperLinkAfter.eq(keeperLinkBefore)) - assert.isTrue(registryLinkBefore.eq(registryLinkAfter)) - }) - - it('updates amount spent correctly', async () => { - const registrationBefore = await registry.getUpkeep(id) - const balanceBefore = registrationBefore.balance - const amountSpentBefore = registrationBefore.amountSpent - - // Do the thing - await registry.connect(keeper1).performUpkeep(id, '0x') - - const registrationAfter = await registry.getUpkeep(id) - const balanceAfter = registrationAfter.balance - const amountSpentAfter = registrationAfter.amountSpent - - assert.isTrue(balanceAfter.lt(balanceBefore)) - assert.isTrue(amountSpentAfter.gt(amountSpentBefore)) - assert.isTrue( - amountSpentAfter - .sub(amountSpentBefore) - .eq(balanceBefore.sub(balanceAfter)), - ) - }) - - it('only pays for gas used [ @skip-coverage ]', async () => { - const before = ( - await registry.getKeeperInfo(await keeper1.getAddress()) - ).balance - const tx = await registry.connect(keeper1).performUpkeep(id, '0x') - const receipt = await tx.wait() - const after = (await registry.getKeeperInfo(await keeper1.getAddress())) - .balance - - const max = linkForGas(executeGas.toNumber()) - const totalTx = linkForGas(receipt.gasUsed.toNumber()) - const difference = after.sub(before) - assert.isTrue(max.gt(totalTx)) - assert.isTrue(totalTx.gt(difference)) - assert.isTrue(linkForGas(5700).lt(difference)) // exact number is flaky - assert.isTrue(linkForGas(6000).gt(difference)) // instead test a range - }) - - it('only pays at a rate up to the gas ceiling [ @skip-coverage ]', async () => { - const multiplier = BigNumber.from(10) - const gasPrice = BigNumber.from('1000000000') // 10M x the gas feed's rate - await registry.connect(owner).setConfig({ - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier: multiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - - const before = ( - await registry.getKeeperInfo(await keeper1.getAddress()) - ).balance - const tx = await registry - .connect(keeper1) - .performUpkeep(id, '0x', { gasPrice }) - const receipt = await tx.wait() - const after = (await registry.getKeeperInfo(await keeper1.getAddress())) - .balance - - const max = linkForGas(executeGas).mul(multiplier) - const totalTx = linkForGas(receipt.gasUsed).mul(multiplier) - const difference = after.sub(before) - assert.isTrue(max.gt(totalTx)) - assert.isTrue(totalTx.gt(difference)) - assert.isTrue(linkForGas(5700).mul(multiplier).lt(difference)) - assert.isTrue(linkForGas(6000).mul(multiplier).gt(difference)) - }) - - it('only pays as much as the node spent [ @skip-coverage ]', async () => { - const multiplier = BigNumber.from(10) - const gasPrice = BigNumber.from(200) // 2X the gas feed's rate - const effectiveMultiplier = BigNumber.from(2) - await registry.connect(owner).setConfig({ - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier: multiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - - const before = ( - await registry.getKeeperInfo(await keeper1.getAddress()) - ).balance - const tx = await registry - .connect(keeper1) - .performUpkeep(id, '0x', { gasPrice }) - const receipt = await tx.wait() - const after = (await registry.getKeeperInfo(await keeper1.getAddress())) - .balance - - const max = linkForGas(executeGas.toNumber()).mul(effectiveMultiplier) - const totalTx = linkForGas(receipt.gasUsed).mul(effectiveMultiplier) - const difference = after.sub(before) - assert.isTrue(max.gt(totalTx)) - assert.isTrue(totalTx.gt(difference)) - assert.isTrue(linkForGas(5700).mul(effectiveMultiplier).lt(difference)) - assert.isTrue(linkForGas(6000).mul(effectiveMultiplier).gt(difference)) - }) - - it('pays the caller even if the target function fails', async () => { - const tx = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - ) - const id = await getUpkeepID(tx) - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(id, toWei('100')) - const keeperBalanceBefore = ( - await registry.getKeeperInfo(await keeper1.getAddress()) - ).balance - - // Do the thing - await registry.connect(keeper1).performUpkeep(id, '0x') - - const keeperBalanceAfter = ( - await registry.getKeeperInfo(await keeper1.getAddress()) - ).balance - assert.isTrue(keeperBalanceAfter.gt(keeperBalanceBefore)) - }) - - it('reverts if called by a non-keeper', async () => { - await evmRevert( - registry.connect(nonkeeper).performUpkeep(id, '0x'), - 'OnlyActiveKeepers()', - ) - }) - - it('reverts if the upkeep has been canceled', async () => { - await mock.setCanPerform(true) - - await registry.connect(owner).cancelUpkeep(id) - - await evmRevert( - registry.connect(keeper1).performUpkeep(id, '0x'), - 'UpkeepNotActive()', - ) - }) - - it('uses the fallback gas price if the feed price is stale [ @skip-coverage ]', async () => { - const normalAmount = await getPerformPaymentAmount() - const roundId = 99 - const answer = 100 - const updatedAt = 946684800 // New Years 2000 🥳 - const startedAt = 946684799 - await gasPriceFeed - .connect(owner) - .updateRoundData(roundId, answer, updatedAt, startedAt) - const amountWithStaleFeed = await getPerformPaymentAmount() - assert.isTrue(normalAmount.lt(amountWithStaleFeed)) - }) - - it('uses the fallback gas price if the feed price is non-sensical [ @skip-coverage ]', async () => { - const normalAmount = await getPerformPaymentAmount() - const roundId = 99 - const currentBlockNum = await ethers.provider.getBlockNumber() - const currentBlock = await ethers.provider.getBlock(currentBlockNum) - const updatedAt = currentBlock.timestamp - const startedAt = 946684799 - await gasPriceFeed - .connect(owner) - .updateRoundData(roundId, -100, updatedAt, startedAt) - const amountWithNegativeFeed = await getPerformPaymentAmount() - await gasPriceFeed - .connect(owner) - .updateRoundData(roundId, 0, updatedAt, startedAt) - const amountWithZeroFeed = await getPerformPaymentAmount() - assert.isTrue(normalAmount.lt(amountWithNegativeFeed)) - assert.isTrue(normalAmount.lt(amountWithZeroFeed)) - }) - - it('uses the fallback if the link price feed is stale', async () => { - const normalAmount = await getPerformPaymentAmount() - const roundId = 99 - const answer = 100 - const updatedAt = 946684800 // New Years 2000 🥳 - const startedAt = 946684799 - await linkEthFeed - .connect(owner) - .updateRoundData(roundId, answer, updatedAt, startedAt) - const amountWithStaleFeed = await getPerformPaymentAmount() - assert.isTrue(normalAmount.lt(amountWithStaleFeed)) - }) - - it('uses the fallback link price if the feed price is non-sensical [ @skip-coverage ]', async () => { - const normalAmount = await getPerformPaymentAmount() - const roundId = 99 - const currentBlockNum = await ethers.provider.getBlockNumber() - const currentBlock = await ethers.provider.getBlock(currentBlockNum) - const updatedAt = currentBlock.timestamp - const startedAt = 946684799 - await linkEthFeed - .connect(owner) - .updateRoundData(roundId, -100, updatedAt, startedAt) - const amountWithNegativeFeed = await getPerformPaymentAmount() - await linkEthFeed - .connect(owner) - .updateRoundData(roundId, 0, updatedAt, startedAt) - const amountWithZeroFeed = await getPerformPaymentAmount() - assert.isTrue(normalAmount.lt(amountWithNegativeFeed)) - assert.isTrue(normalAmount.lt(amountWithZeroFeed)) - }) - - it('reverts if the same caller calls twice in a row', async () => { - await registry.connect(keeper1).performUpkeep(id, '0x') - await evmRevert( - registry.connect(keeper1).performUpkeep(id, '0x'), - 'KeepersMustTakeTurns()', - ) - await registry.connect(keeper2).performUpkeep(id, '0x') - await evmRevert( - registry.connect(keeper2).performUpkeep(id, '0x'), - 'KeepersMustTakeTurns()', - ) - await registry.connect(keeper1).performUpkeep(id, '0x') - }) - - it('has a large enough gas overhead to cover upkeeps that use all their gas [ @skip-coverage ]', async () => { - await mock.setPerformGasToBurn(executeGas) - await mock.setCanPerform(true) - const gas = executeGas.add(PERFORM_GAS_OVERHEAD) - const performData = '0xc0ffeec0ffee' - const tx = await registry - .connect(keeper1) - .performUpkeep(id, performData, { gasLimit: gas }) - const receipt = await tx.wait() - const eventLog = receipt?.events - - assert.equal(eventLog?.length, 2) - assert.equal(eventLog?.[1].event, 'UpkeepPerformed') - expect(eventLog?.[1].args?.[0]).to.equal(id) - assert.equal(eventLog?.[1].args?.[1], true) - assert.equal(eventLog?.[1].args?.[2], await keeper1.getAddress()) - assert.isNotEmpty(eventLog?.[1].args?.[3]) - assert.equal(eventLog?.[1].args?.[4], performData) - }) - - it('can self fund', async () => { - const autoFunderUpkeep = await upkeepAutoFunderFactory - .connect(owner) - .deploy(linkToken.address, registry.address) - const tx = await registry - .connect(owner) - .registerUpkeep( - autoFunderUpkeep.address, - executeGas, - autoFunderUpkeep.address, - emptyBytes, - ) - const upkeepID = await getUpkeepID(tx) - await autoFunderUpkeep.setUpkeepId(upkeepID) - // Give enough funds for upkeep as well as to the upkeep contract - await linkToken.connect(owner).approve(registry.address, toWei('1000')) - await linkToken - .connect(owner) - .transfer(autoFunderUpkeep.address, toWei('1000')) - let maxPayment = await registry.getMaxPaymentForGas(executeGas) - - // First set auto funding amount to 0 and verify that balance is deducted upon performUpkeep - let initialBalance = toWei('100') - await registry.connect(owner).addFunds(upkeepID, initialBalance) - await autoFunderUpkeep.setAutoFundLink(0) - await autoFunderUpkeep.setIsEligible(true) - await registry.connect(keeper1).performUpkeep(upkeepID, '0x') - - let postUpkeepBalance = (await registry.getUpkeep(upkeepID)).balance - assert.isTrue(postUpkeepBalance.lt(initialBalance)) // Balance should be deducted - assert.isTrue(postUpkeepBalance.gte(initialBalance.sub(maxPayment))) // Balance should not be deducted more than maxPayment - - // Now set auto funding amount to 100 wei and verify that the balance increases - initialBalance = postUpkeepBalance - let autoTopupAmount = toWei('100') - await autoFunderUpkeep.setAutoFundLink(autoTopupAmount) - await autoFunderUpkeep.setIsEligible(true) - await registry.connect(keeper2).performUpkeep(upkeepID, '0x') - - postUpkeepBalance = (await registry.getUpkeep(upkeepID)).balance - // Balance should increase by autoTopupAmount and decrease by max maxPayment - assert.isTrue( - postUpkeepBalance.gte( - initialBalance.add(autoTopupAmount).sub(maxPayment), - ), - ) - }) - - it('can self cancel', async () => { - const autoFunderUpkeep = await upkeepAutoFunderFactory - .connect(owner) - .deploy(linkToken.address, registry.address) - const tx = await registry - .connect(owner) - .registerUpkeep( - autoFunderUpkeep.address, - executeGas, - autoFunderUpkeep.address, - emptyBytes, - ) - const upkeepID = await getUpkeepID(tx) - await autoFunderUpkeep.setUpkeepId(upkeepID) - - await linkToken.connect(owner).approve(registry.address, toWei('1000')) - await registry.connect(owner).addFunds(upkeepID, toWei('100')) - await autoFunderUpkeep.setIsEligible(true) - await autoFunderUpkeep.setShouldCancel(true) - - let registration = await registry.getUpkeep(upkeepID) - const oldExpiration = registration.maxValidBlocknumber - - // Do the thing - await registry.connect(keeper1).performUpkeep(upkeepID, '0x') - - // Verify upkeep gets cancelled - registration = await registry.getUpkeep(upkeepID) - const newExpiration = registration.maxValidBlocknumber - assert.isTrue(newExpiration.lt(oldExpiration)) - }) - }) - }) - - describe('#withdrawFunds', () => { - beforeEach(async () => { - await linkToken.connect(keeper1).approve(registry.address, toWei('100')) - await registry.connect(keeper1).addFunds(id, toWei('100')) - await registry.connect(keeper1).performUpkeep(id, '0x') - }) - - it('reverts if called by anyone but the admin', async () => { - await evmRevert( - registry - .connect(owner) - .withdrawFunds(id.add(1), await payee1.getAddress()), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if called on an uncanceled upkeep', async () => { - await evmRevert( - registry.connect(admin).withdrawFunds(id, await payee1.getAddress()), - 'UpkeepNotCanceled()', - ) - }) - - it('reverts if called with the 0 address', async () => { - await evmRevert( - registry.connect(admin).withdrawFunds(id, zeroAddress), - 'InvalidRecipient()', - ) - }) - - describe('after the registration is cancelled', () => { - beforeEach(async () => { - await registry.connect(owner).cancelUpkeep(id) - }) - - it('moves the funds out and updates the balance', async () => { - const payee1Before = await linkToken.balanceOf( - await payee1.getAddress(), - ) - const registryBefore = await linkToken.balanceOf(registry.address) - - let registration = await registry.getUpkeep(id) - let previousBalance = registration.balance - - await registry - .connect(admin) - .withdrawFunds(id, await payee1.getAddress()) - - const payee1After = await linkToken.balanceOf(await payee1.getAddress()) - const registryAfter = await linkToken.balanceOf(registry.address) - - assert.isTrue(payee1Before.add(previousBalance).eq(payee1After)) - assert.isTrue(registryBefore.sub(previousBalance).eq(registryAfter)) - - registration = await registry.getUpkeep(id) - assert.equal(0, registration.balance.toNumber()) - }) - - it('deducts cancellation fees from upkeep and gives to owner', async () => { - let minUpkeepSpend = toWei('10') - await registry.connect(owner).setConfig({ - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - - const payee1Before = await linkToken.balanceOf( - await payee1.getAddress(), - ) - let upkeepBefore = (await registry.getUpkeep(id)).balance - let ownerBefore = (await registry.getState()).state.ownerLinkBalance - assert.equal(0, ownerBefore.toNumber()) - - let amountSpent = toWei('100').sub(upkeepBefore) - let cancellationFee = minUpkeepSpend.sub(amountSpent) - - await registry - .connect(admin) - .withdrawFunds(id, await payee1.getAddress()) - - const payee1After = await linkToken.balanceOf(await payee1.getAddress()) - let upkeepAfter = (await registry.getUpkeep(id)).balance - let ownerAfter = (await registry.getState()).state.ownerLinkBalance - - // Post upkeep balance should be 0 - assert.equal(0, upkeepAfter.toNumber()) - // balance - cancellationFee should be transferred to payee - assert.isTrue( - payee1Before.add(upkeepBefore.sub(cancellationFee)).eq(payee1After), - ) - assert.isTrue(ownerAfter.eq(cancellationFee)) - }) - - it('deducts max upto balance as cancellation fees', async () => { - // Very high min spend, should deduct whole balance as cancellation fees - let minUpkeepSpend = toWei('1000') - await registry.connect(owner).setConfig({ - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - const payee1Before = await linkToken.balanceOf( - await payee1.getAddress(), - ) - let upkeepBefore = (await registry.getUpkeep(id)).balance - let ownerBefore = (await registry.getState()).state.ownerLinkBalance - assert.equal(0, ownerBefore.toNumber()) - - await registry - .connect(admin) - .withdrawFunds(id, await payee1.getAddress()) - const payee1After = await linkToken.balanceOf(await payee1.getAddress()) - let ownerAfter = (await registry.getState()).state.ownerLinkBalance - let upkeepAfter = (await registry.getUpkeep(id)).balance - - assert.equal(0, upkeepAfter.toNumber()) - // No funds should be transferred, all of upkeepBefore should be given to owner - assert.isTrue(payee1After.eq(payee1Before)) - assert.isTrue(ownerAfter.eq(upkeepBefore)) - }) - - it('does not deduct cancellation fees if enough is spent', async () => { - // Very low min spend, already spent in one upkeep - let minUpkeepSpend = BigNumber.from(420) - await registry.connect(owner).setConfig({ - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - const payee1Before = await linkToken.balanceOf( - await payee1.getAddress(), - ) - let upkeepBefore = (await registry.getUpkeep(id)).balance - let ownerBefore = (await registry.getState()).state.ownerLinkBalance - assert.equal(0, ownerBefore.toNumber()) - - await registry - .connect(admin) - .withdrawFunds(id, await payee1.getAddress()) - const payee1After = await linkToken.balanceOf(await payee1.getAddress()) - let ownerAfter = (await registry.getState()).state.ownerLinkBalance - let upkeepAfter = (await registry.getUpkeep(id)).balance - - assert.equal(0, upkeepAfter.toNumber()) - // No cancellation fees for owner - assert.equal(0, ownerAfter.toNumber()) - // Whole balance transferred to payee - assert.isTrue(payee1Before.add(upkeepBefore).eq(payee1After)) - }) - }) - }) - - describe('#withdrawOwnerFunds', () => { - it('can only be called by owner', async () => { - await evmRevert( - registry.connect(keeper1).withdrawOwnerFunds(), - 'Only callable by owner', - ) - }) - - it('withdraws the collected fees to owner', async () => { - await linkToken.connect(keeper1).approve(registry.address, toWei('100')) - await registry.connect(keeper1).addFunds(id, toWei('100')) - // Very high min spend, whole balance as cancellation fees - let minUpkeepSpend = toWei('1000') - await registry.connect(owner).setConfig({ - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - let upkeepBalance = (await registry.getUpkeep(id)).balance - const ownerBefore = await linkToken.balanceOf(await owner.getAddress()) - - await registry.connect(owner).cancelUpkeep(id) - await registry.connect(admin).withdrawFunds(id, await payee1.getAddress()) - // Transfered to owner balance on registry - let ownerRegistryBalance = (await registry.getState()).state - .ownerLinkBalance - assert.isTrue(ownerRegistryBalance.eq(upkeepBalance)) - - // Now withdraw - await registry.connect(owner).withdrawOwnerFunds() - - ownerRegistryBalance = (await registry.getState()).state.ownerLinkBalance - const ownerAfter = await linkToken.balanceOf(await owner.getAddress()) - - // Owner registry balance should be changed to 0 - assert.isTrue(ownerRegistryBalance.eq(BigNumber.from('0'))) - - // Owner should be credited with the balance - assert.isTrue(ownerBefore.add(upkeepBalance).eq(ownerAfter)) - }) - }) - - describe('#cancelUpkeep', () => { - it('reverts if the ID is not valid', async () => { - await evmRevert( - registry.connect(owner).cancelUpkeep(id.add(1)), - 'CannotCancel()', - ) - }) - - it('reverts if called by a non-owner/non-admin', async () => { - await evmRevert( - registry.connect(keeper1).cancelUpkeep(id), - 'OnlyCallableByOwnerOrAdmin()', - ) - }) - - describe('when called by the owner', async () => { - it('sets the registration to invalid immediately', async () => { - const tx = await registry.connect(owner).cancelUpkeep(id) - const receipt = await tx.wait() - const registration = await registry.getUpkeep(id) - assert.equal( - registration.maxValidBlocknumber.toNumber(), - receipt.blockNumber, - ) - }) - - it('emits an event', async () => { - const tx = await registry.connect(owner).cancelUpkeep(id) - const receipt = await tx.wait() - await expect(tx) - .to.emit(registry, 'UpkeepCanceled') - .withArgs(id, BigNumber.from(receipt.blockNumber)) - }) - - it('immediately prevents upkeep', async () => { - await registry.connect(owner).cancelUpkeep(id) - - await evmRevert( - registry.connect(keeper2).performUpkeep(id, '0x'), - 'UpkeepNotActive()', - ) - }) - - it('does not revert if reverts if called multiple times', async () => { - await registry.connect(owner).cancelUpkeep(id) - await evmRevert( - registry.connect(owner).cancelUpkeep(id), - 'CannotCancel()', - ) - }) - - describe('when called by the owner when the admin has just canceled', () => { - let oldExpiration: BigNumber - - beforeEach(async () => { - await registry.connect(admin).cancelUpkeep(id) - const registration = await registry.getUpkeep(id) - oldExpiration = registration.maxValidBlocknumber - }) - - it('allows the owner to cancel it more quickly', async () => { - await registry.connect(owner).cancelUpkeep(id) - - const registration = await registry.getUpkeep(id) - const newExpiration = registration.maxValidBlocknumber - assert.isTrue(newExpiration.lt(oldExpiration)) - }) - }) - }) - - describe('when called by the admin', async () => { - const delay = 50 - - it('sets the registration to invalid in 50 blocks', async () => { - const tx = await registry.connect(admin).cancelUpkeep(id) - const receipt = await tx.wait() - const registration = await registry.getUpkeep(id) - assert.equal( - registration.maxValidBlocknumber.toNumber(), - receipt.blockNumber + 50, - ) - }) - - it('emits an event', async () => { - const tx = await registry.connect(admin).cancelUpkeep(id) - const receipt = await tx.wait() - await expect(tx) - .to.emit(registry, 'UpkeepCanceled') - .withArgs(id, BigNumber.from(receipt.blockNumber + delay)) - }) - - // it('updates the canceled registrations list', async () => { - // let canceled = await registry.callStatic.getCanceledUpkeepList() - // assert.deepEqual([], canceled) - - // await registry.connect(admin).cancelUpkeep(id) - - // canceled = await registry.callStatic.getCanceledUpkeepList() - // assert.deepEqual([id], canceled) - // }) - - it('immediately prevents upkeep', async () => { - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(id, toWei('100')) - await registry.connect(admin).cancelUpkeep(id) - await registry.connect(keeper2).performUpkeep(id, '0x') // still works - - for (let i = 0; i < delay; i++) { - await ethers.provider.send('evm_mine', []) - } - - await evmRevert( - registry.connect(keeper2).performUpkeep(id, '0x'), - 'UpkeepNotActive()', - ) - }) - - it('reverts if called again by the admin', async () => { - await registry.connect(admin).cancelUpkeep(id) - - await evmRevert( - registry.connect(admin).cancelUpkeep(id), - 'CannotCancel()', - ) - }) - - // it('does not revert or double add the cancellation record if called by the owner immediately after', async () => { - // await registry.connect(admin).cancelUpkeep(id) - - // await registry.connect(owner).cancelUpkeep(id) - - // const canceled = await registry.callStatic.getCanceledUpkeepList() - // assert.deepEqual([id], canceled) - // }) - - it('reverts if called by the owner after the timeout', async () => { - await registry.connect(admin).cancelUpkeep(id) - - for (let i = 0; i < delay; i++) { - await ethers.provider.send('evm_mine', []) - } - - await evmRevert( - registry.connect(owner).cancelUpkeep(id), - 'CannotCancel()', - ) - }) - }) - }) - - describe('#withdrawPayment', () => { - beforeEach(async () => { - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(id, toWei('100')) - await registry.connect(keeper1).performUpkeep(id, '0x') - }) - - it('reverts if called by anyone but the payee', async () => { - await evmRevert( - registry - .connect(payee2) - .withdrawPayment( - await keeper1.getAddress(), - await nonkeeper.getAddress(), - ), - 'OnlyCallableByPayee()', - ) - }) - - it('reverts if called with the 0 address', async () => { - await evmRevert( - registry - .connect(payee2) - .withdrawPayment(await keeper1.getAddress(), zeroAddress), - 'InvalidRecipient()', - ) - }) - - it('updates the balances', async () => { - const to = await nonkeeper.getAddress() - const keeperBefore = ( - await registry.getKeeperInfo(await keeper1.getAddress()) - ).balance - const registrationBefore = (await registry.getUpkeep(id)).balance - const toLinkBefore = await linkToken.balanceOf(to) - const registryLinkBefore = await linkToken.balanceOf(registry.address) - - //// Do the thing - await registry - .connect(payee1) - .withdrawPayment(await keeper1.getAddress(), to) - - const keeperAfter = ( - await registry.getKeeperInfo(await keeper1.getAddress()) - ).balance - const registrationAfter = (await registry.getUpkeep(id)).balance - const toLinkAfter = await linkToken.balanceOf(to) - const registryLinkAfter = await linkToken.balanceOf(registry.address) - - assert.isTrue(keeperAfter.eq(BigNumber.from(0))) - assert.isTrue(registrationBefore.eq(registrationAfter)) - assert.isTrue(toLinkBefore.add(keeperBefore).eq(toLinkAfter)) - assert.isTrue(registryLinkBefore.sub(keeperBefore).eq(registryLinkAfter)) - }) - - it('emits a log announcing the withdrawal', async () => { - const balance = (await registry.getKeeperInfo(await keeper1.getAddress())) - .balance - const tx = await registry - .connect(payee1) - .withdrawPayment( - await keeper1.getAddress(), - await nonkeeper.getAddress(), - ) - await expect(tx) - .to.emit(registry, 'PaymentWithdrawn') - .withArgs( - await keeper1.getAddress(), - balance, - await nonkeeper.getAddress(), - await payee1.getAddress(), - ) - }) - }) - - describe('#transferPayeeship', () => { - it('reverts when called by anyone but the current payee', async () => { - await evmRevert( - registry - .connect(payee2) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ), - 'OnlyCallableByPayee()', - ) - }) - - it('reverts when transferring to self', async () => { - await evmRevert( - registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee1.getAddress(), - ), - 'ValueNotChanged()', - ) - }) - - it('does not change the payee', async () => { - await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - - const info = await registry.getKeeperInfo(await keeper1.getAddress()) - assert.equal(await payee1.getAddress(), info.payee) - }) - - it('emits an event announcing the new payee', async () => { - const tx = await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - await expect(tx) - .to.emit(registry, 'PayeeshipTransferRequested') - .withArgs( - await keeper1.getAddress(), - await payee1.getAddress(), - await payee2.getAddress(), - ) - }) - - it('does not emit an event when called with the same proposal', async () => { - await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - - const tx = await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - const receipt = await tx.wait() - assert.equal(0, receipt.logs.length) - }) - }) - - describe('#acceptPayeeship', () => { - beforeEach(async () => { - await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - }) - - it('reverts when called by anyone but the proposed payee', async () => { - await evmRevert( - registry.connect(payee1).acceptPayeeship(await keeper1.getAddress()), - 'OnlyCallableByProposedPayee()', - ) - }) - - it('emits an event announcing the new payee', async () => { - const tx = await registry - .connect(payee2) - .acceptPayeeship(await keeper1.getAddress()) - await expect(tx) - .to.emit(registry, 'PayeeshipTransferred') - .withArgs( - await keeper1.getAddress(), - await payee1.getAddress(), - await payee2.getAddress(), - ) - }) - - it('does change the payee', async () => { - await registry.connect(payee2).acceptPayeeship(await keeper1.getAddress()) - - const info = await registry.getKeeperInfo(await keeper1.getAddress()) - assert.equal(await payee2.getAddress(), info.payee) - }) - }) - - describe('#setConfig', () => { - const payment = BigNumber.from(1) - const flatFee = BigNumber.from(2) - const checks = BigNumber.from(3) - const staleness = BigNumber.from(4) - const ceiling = BigNumber.from(5) - const maxGas = BigNumber.from(6) - const fbGasEth = BigNumber.from(7) - const fbLinkEth = BigNumber.from(8) - - it('reverts when called by anyone but the proposed owner', async () => { - await evmRevert( - registry.connect(payee1).setConfig({ - paymentPremiumPPB: payment, - flatFeeMicroLink: flatFee, - blockCountPerTurn: checks, - checkGasLimit: maxGas, - stalenessSeconds: staleness, - gasCeilingMultiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice: fbGasEth, - fallbackLinkPrice: fbLinkEth, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }), - 'Only callable by owner', - ) - }) - - it('updates the config', async () => { - const old = (await registry.getState()).config - assert.isTrue(paymentPremiumPPB.eq(old.paymentPremiumPPB)) - assert.isTrue(flatFeeMicroLink.eq(old.flatFeeMicroLink)) - assert.isTrue(blockCountPerTurn.eq(old.blockCountPerTurn)) - assert.isTrue(stalenessSeconds.eq(old.stalenessSeconds)) - assert.isTrue(gasCeilingMultiplier.eq(old.gasCeilingMultiplier)) - - await registry.connect(owner).setConfig({ - paymentPremiumPPB: payment, - flatFeeMicroLink: flatFee, - blockCountPerTurn: checks, - checkGasLimit: maxGas, - stalenessSeconds: staleness, - gasCeilingMultiplier: ceiling, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice: fbGasEth, - fallbackLinkPrice: fbLinkEth, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - - const updated = (await registry.getState()).config - assert.equal(updated.paymentPremiumPPB, payment.toNumber()) - assert.equal(updated.flatFeeMicroLink, flatFee.toNumber()) - assert.equal(updated.blockCountPerTurn, checks.toNumber()) - assert.equal(updated.stalenessSeconds, staleness.toNumber()) - assert.equal(updated.gasCeilingMultiplier, ceiling.toNumber()) - assert.equal(updated.checkGasLimit, maxGas.toNumber()) - assert.equal(updated.fallbackGasPrice.toNumber(), fbGasEth.toNumber()) - assert.equal(updated.fallbackLinkPrice.toNumber(), fbLinkEth.toNumber()) - }) - - it('emits an event', async () => { - const tx = await registry.connect(owner).setConfig({ - paymentPremiumPPB: payment, - flatFeeMicroLink: flatFee, - blockCountPerTurn: checks, - checkGasLimit: maxGas, - stalenessSeconds: staleness, - gasCeilingMultiplier: ceiling, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice: fbGasEth, - fallbackLinkPrice: fbLinkEth, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - await expect(tx) - .to.emit(registry, 'ConfigSet') - .withArgs([ - payment, - flatFee, - checks, - maxGas, - staleness, - ceiling, - minUpkeepSpend, - maxPerformGas, - fbGasEth, - fbLinkEth, - ]) - }) - }) - - describe('#onTokenTransfer', () => { - const amount = toWei('1') - - it('reverts if not called by the LINK token', async () => { - const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [id]) - - await evmRevert( - registry - .connect(keeper1) - .onTokenTransfer(await keeper1.getAddress(), amount, data), - 'OnlyCallableByLINKToken()', - ) - }) - - it('reverts if not called with more or less than 32 bytes', async () => { - const longData = ethers.utils.defaultAbiCoder.encode( - ['uint256', 'uint256'], - ['33', '34'], - ) - const shortData = '0x12345678' - - await evmRevert( - linkToken - .connect(owner) - .transferAndCall(registry.address, amount, longData), - ) - await evmRevert( - linkToken - .connect(owner) - .transferAndCall(registry.address, amount, shortData), - ) - }) - - it('reverts if the upkeep is canceled', async () => { - await registry.connect(admin).cancelUpkeep(id) - await evmRevert( - registry.connect(keeper1).addFunds(id, amount), - 'UpkeepNotActive()', - ) - }) - - it('updates the funds of the job id passed', async () => { - const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [id]) - - const before = (await registry.getUpkeep(id)).balance - await linkToken - .connect(owner) - .transferAndCall(registry.address, amount, data) - const after = (await registry.getUpkeep(id)).balance - - assert.isTrue(before.add(amount).eq(after)) - }) - }) - - describe('#recoverFunds', () => { - const sent = toWei('7') - - beforeEach(async () => { - await linkToken.connect(keeper1).approve(registry.address, toWei('100')) - - // add funds to upkeep 1 and perform and withdraw some payment - const tx = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - ) - const id1 = await getUpkeepID(tx) - await registry.connect(keeper1).addFunds(id1, toWei('5')) - await registry.connect(keeper1).performUpkeep(id1, '0x') - await registry.connect(keeper2).performUpkeep(id1, '0x') - await registry.connect(keeper3).performUpkeep(id1, '0x') - await registry - .connect(payee1) - .withdrawPayment( - await keeper1.getAddress(), - await nonkeeper.getAddress(), - ) - - // transfer funds directly to the registry - await linkToken.connect(keeper1).transfer(registry.address, sent) - - // add funds to upkeep 2 and perform and withdraw some payment - const tx2 = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - ) - const id2 = await getUpkeepID(tx2) - await registry.connect(keeper1).addFunds(id2, toWei('5')) - await registry.connect(keeper1).performUpkeep(id2, '0x') - await registry.connect(keeper2).performUpkeep(id2, '0x') - await registry.connect(keeper3).performUpkeep(id2, '0x') - await registry - .connect(payee2) - .withdrawPayment( - await keeper2.getAddress(), - await nonkeeper.getAddress(), - ) - - // transfer funds using onTokenTransfer - const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [id2]) - await linkToken - .connect(owner) - .transferAndCall(registry.address, toWei('1'), data) - - // remove a keeper - await registry - .connect(owner) - .setKeepers( - [await keeper1.getAddress(), await keeper2.getAddress()], - [await payee1.getAddress(), await payee2.getAddress()], - ) - - // withdraw some funds - await registry.connect(owner).cancelUpkeep(id1) - await registry.connect(admin).withdrawFunds(id1, await admin.getAddress()) - }) - - it('reverts if not called by owner', async () => { - await evmRevert( - registry.connect(keeper1).recoverFunds(), - 'Only callable by owner', - ) - }) - - it('allows any funds that have been accidentally transfered to be moved', async () => { - const balanceBefore = await linkToken.balanceOf(registry.address) - - await linkToken.balanceOf(registry.address) - - await registry.connect(owner).recoverFunds() - const balanceAfter = await linkToken.balanceOf(registry.address) - assert.isTrue(balanceBefore.eq(balanceAfter.add(sent))) - }) - }) - - describe('#pause', () => { - it('reverts if called by a non-owner', async () => { - await evmRevert( - registry.connect(keeper1).pause(), - 'Only callable by owner', - ) - }) - - it('marks the contract as paused', async () => { - assert.isFalse(await registry.paused()) - - await registry.connect(owner).pause() - - assert.isTrue(await registry.paused()) - }) - }) - - describe('#unpause', () => { - beforeEach(async () => { - await registry.connect(owner).pause() - }) - - it('reverts if called by a non-owner', async () => { - await evmRevert( - registry.connect(keeper1).unpause(), - 'Only callable by owner', - ) - }) - - it('marks the contract as not paused', async () => { - assert.isTrue(await registry.paused()) - - await registry.connect(owner).unpause() - - assert.isFalse(await registry.paused()) - }) - }) - - describe('#getMaxPaymentForGas', () => { - const gasAmounts = [100000, 10000000] - const premiums = [0, 250000000] - const flatFees = [0, 1000000] - it('calculates the max fee approptiately', async () => { - for (let idx = 0; idx < gasAmounts.length; idx++) { - const gas = gasAmounts[idx] - for (let jdx = 0; jdx < premiums.length; jdx++) { - const premium = premiums[jdx] - for (let kdx = 0; kdx < flatFees.length; kdx++) { - const flatFee = flatFees[kdx] - await registry.connect(owner).setConfig({ - paymentPremiumPPB: premium, - flatFeeMicroLink: flatFee, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - const price = await registry.getMaxPaymentForGas(gas) - expect(price).to.equal(linkForGas(gas, premium, flatFee)) - } - } - } - }) - }) - - describe('#setPeerRegistryMigrationPermission() / #getPeerRegistryMigrationPermission()', () => { - const peer = randomAddress() - it('allows the owner to set the peer registries', async () => { - let permission = await registry.getPeerRegistryMigrationPermission(peer) - expect(permission).to.equal(0) - await registry.setPeerRegistryMigrationPermission(peer, 1) - permission = await registry.getPeerRegistryMigrationPermission(peer) - expect(permission).to.equal(1) - await registry.setPeerRegistryMigrationPermission(peer, 2) - permission = await registry.getPeerRegistryMigrationPermission(peer) - expect(permission).to.equal(2) - await registry.setPeerRegistryMigrationPermission(peer, 0) - permission = await registry.getPeerRegistryMigrationPermission(peer) - expect(permission).to.equal(0) - }) - it('reverts if passed an unsupported permission', async () => { - await expect( - registry.connect(admin).setPeerRegistryMigrationPermission(peer, 10), - ).to.be.reverted - }) - it('reverts if not called by the owner', async () => { - await expect( - registry.connect(admin).setPeerRegistryMigrationPermission(peer, 1), - ).to.be.revertedWith('Only callable by owner') - }) - }) - - describe('migrateUpkeeps() / #receiveUpkeeps()', async () => { - context('when permissions are set', () => { - beforeEach(async () => { - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(id, toWei('100')) - await registry.setPeerRegistryMigrationPermission(registry2.address, 1) - await registry2.setPeerRegistryMigrationPermission(registry.address, 2) - }) - - it('migrates an upkeep', async () => { - expect((await registry.getUpkeep(id)).balance).to.equal(toWei('100')) - expect((await registry.getUpkeep(id)).checkData).to.equal(randomBytes) - expect((await registry.getState()).state.numUpkeeps).to.equal(1) - // migrate - await registry.connect(admin).migrateUpkeeps([id], registry2.address) - expect((await registry.getState()).state.numUpkeeps).to.equal(0) - expect((await registry2.getState()).state.numUpkeeps).to.equal(1) - expect((await registry.getUpkeep(id)).balance).to.equal(0) - expect((await registry.getUpkeep(id)).checkData).to.equal('0x') - expect((await registry2.getUpkeep(id)).balance).to.equal(toWei('100')) - expect((await registry2.getState()).state.expectedLinkBalance).to.equal( - toWei('100'), - ) - expect((await registry2.getUpkeep(id)).checkData).to.equal(randomBytes) - }) - it('emits an event on both contracts', async () => { - expect((await registry.getUpkeep(id)).balance).to.equal(toWei('100')) - expect((await registry.getUpkeep(id)).checkData).to.equal(randomBytes) - expect((await registry.getState()).state.numUpkeeps).to.equal(1) - const tx = registry - .connect(admin) - .migrateUpkeeps([id], registry2.address) - await expect(tx) - .to.emit(registry, 'UpkeepMigrated') - .withArgs(id, toWei('100'), registry2.address) - await expect(tx) - .to.emit(registry2, 'UpkeepReceived') - .withArgs(id, toWei('100'), registry.address) - }) - it('is only migratable by the admin', async () => { - await expect( - registry.connect(owner).migrateUpkeeps([id], registry2.address), - ).to.be.revertedWith('OnlyCallableByAdmin()') - await registry.connect(admin).migrateUpkeeps([id], registry2.address) - }) - }) - - context('when permissions are not set', () => { - it('reverts', async () => { - // no permissions - await registry.setPeerRegistryMigrationPermission(registry2.address, 0) - await registry2.setPeerRegistryMigrationPermission(registry.address, 0) - await expect(registry.migrateUpkeeps([id], registry2.address)).to.be - .reverted - // only outgoing permissions - await registry.setPeerRegistryMigrationPermission(registry2.address, 1) - await registry2.setPeerRegistryMigrationPermission(registry.address, 0) - await expect(registry.migrateUpkeeps([id], registry2.address)).to.be - .reverted - // only incoming permissions - await registry.setPeerRegistryMigrationPermission(registry2.address, 0) - await registry2.setPeerRegistryMigrationPermission(registry.address, 2) - await expect(registry.migrateUpkeeps([id], registry2.address)).to.be - .reverted - // permissions opposite direction - await registry.setPeerRegistryMigrationPermission(registry2.address, 2) - await registry2.setPeerRegistryMigrationPermission(registry.address, 1) - await expect(registry.migrateUpkeeps([id], registry2.address)).to.be - .reverted - }) - }) - }) - - describe('#checkUpkeep / #performUpkeep', () => { - const performData = '0xc0ffeec0ffee' - const multiplier = BigNumber.from(10) - const flatFee = BigNumber.from('100000') //0.1 LINK - const callGasPrice = 1 - - it('uses the same minimum balance calculation [ @skip-coverage ]', async () => { - await registry.connect(owner).setConfig({ - paymentPremiumPPB, - flatFeeMicroLink: flatFee, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier: multiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - await linkToken.connect(owner).approve(registry.address, toWei('100')) - - const tx1 = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - ) - const upkeepID1 = await getUpkeepID(tx1) - const tx2 = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - ) - const upkeepID2 = await getUpkeepID(tx2) - await mock.setCanCheck(true) - await mock.setCanPerform(true) - // upkeep 1 is underfunded, 2 is funded - const minBalance1 = (await registry.getMaxPaymentForGas(executeGas)).sub( - 1, - ) - const minBalance2 = await registry.getMaxPaymentForGas(executeGas) - await registry.connect(owner).addFunds(upkeepID1, minBalance1) - await registry.connect(owner).addFunds(upkeepID2, minBalance2) - // upkeep 1 check should revert, 2 should succeed - await evmRevert( - registry - .connect(zeroAddress) - .callStatic.checkUpkeep(upkeepID1, await keeper1.getAddress(), { - gasPrice: callGasPrice, - }), - ) - await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(upkeepID2, await keeper1.getAddress(), { - gasPrice: callGasPrice, - }) - // upkeep 1 perform should revert, 2 should succeed - await evmRevert( - registry - .connect(keeper1) - .performUpkeep(upkeepID1, performData, { gasLimit: extraGas }), - 'InsufficientFunds()', - ) - await registry - .connect(keeper1) - .performUpkeep(upkeepID2, performData, { gasLimit: extraGas }) - }) - }) - - describe('#getMinBalanceForUpkeep / #checkUpkeep', () => { - it('calculates the minimum balance appropriately', async () => { - const oneWei = BigNumber.from('1') - await linkToken.connect(keeper1).approve(registry.address, toWei('100')) - await mock.setCanCheck(true) - await mock.setCanPerform(true) - const minBalance = await registry.getMinBalanceForUpkeep(id) - const tooLow = minBalance.sub(oneWei) - await registry.connect(keeper1).addFunds(id, tooLow) - await evmRevert( - registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress()), - 'InsufficientFunds()', - ) - await registry.connect(keeper1).addFunds(id, oneWei) - await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress()) - }) - }) -}) diff --git a/contracts/test/v0.8/automation/KeeperRegistry1_3.test.ts b/contracts/test/v0.8/automation/KeeperRegistry1_3.test.ts deleted file mode 100644 index 21cb1618254..00000000000 --- a/contracts/test/v0.8/automation/KeeperRegistry1_3.test.ts +++ /dev/null @@ -1,2641 +0,0 @@ -import { ethers } from 'hardhat' -import { assert, expect } from 'chai' -import { BigNumber, BigNumberish, Signer } from 'ethers' -import { evmRevert } from '../../test-helpers/matchers' -import { getUsers, Personas } from '../../test-helpers/setup' -import { toWei } from '../../test-helpers/helpers' -import { LinkToken__factory as LinkTokenFactory } from '../../../typechain/factories/LinkToken__factory' -import { MockV3Aggregator__factory as MockV3AggregatorFactory } from '../../../typechain/factories/MockV3Aggregator__factory' -import { UpkeepMock__factory as UpkeepMockFactory } from '../../../typechain/factories/UpkeepMock__factory' -import { UpkeepReverter__factory as UpkeepReverterFactory } from '../../../typechain/factories/UpkeepReverter__factory' -import { UpkeepAutoFunder__factory as UpkeepAutoFunderFactory } from '../../../typechain/factories/UpkeepAutoFunder__factory' -import { UpkeepTranscoder__factory as UpkeepTranscoderFactory } from '../../../typechain/factories/UpkeepTranscoder__factory' -import { KeeperRegistry1_3__factory as KeeperRegistryFactory } from '../../../typechain/factories/KeeperRegistry1_3__factory' -import { MockArbGasInfo__factory as MockArbGasInfoFactory } from '../../../typechain/factories/MockArbGasInfo__factory' -import { MockOVMGasPriceOracle__factory as MockOVMGasPriceOracleFactory } from '../../../typechain/factories/MockOVMGasPriceOracle__factory' -import { KeeperRegistryLogic1_3__factory as KeeperRegistryLogicFactory } from '../../../typechain/factories/KeeperRegistryLogic1_3__factory' -import { KeeperRegistry1_3 as KeeperRegistry } from '../../../typechain/KeeperRegistry1_3' -import { KeeperRegistryLogic13 as KeeperRegistryLogic } from '../../../typechain/KeeperRegistryLogic13' -import { MockV3Aggregator } from '../../../typechain/MockV3Aggregator' -import { LinkToken } from '../../../typechain/LinkToken' -import { UpkeepMock } from '../../../typechain/UpkeepMock' -import { MockArbGasInfo } from '../../../typechain/MockArbGasInfo' -import { MockOVMGasPriceOracle } from '../../../typechain/MockOVMGasPriceOracle' -import { UpkeepTranscoder } from '../../../typechain/UpkeepTranscoder' - -////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////// - -/*********************************** REGISTRY v1.3 IS FROZEN ************************************/ - -// All tests are disabled for this contract, as we expect it to never change in the future. -// Instead, we test that the bytecode for the contract has not changed. -// If this test ever fails, you should remove it and then re-run the original test suite. - -const BYTECODE = KeeperRegistryFactory.bytecode -const BYTECODE_CHECKSUM = - '0x7e831ebc4e043fc2946449e11f0d170ba5b6085b213591973c437bc5109b1582' - -describe('KeeperRegistry1_3 - Frozen [ @skip-coverage ]', () => { - it('has not changed', () => { - assert.equal(ethers.utils.id(BYTECODE), BYTECODE_CHECKSUM) - }) -}) - -////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////// - -async function getUpkeepID(tx: any) { - const receipt = await tx.wait() - return receipt.events[0].args.id -} - -function randomAddress() { - return ethers.Wallet.createRandom().address -} - -// ----------------------------------------------------------------------------------------------- -// DEV: these *should* match the perform/check gas overhead values in the contract and on the node -const PERFORM_GAS_OVERHEAD = BigNumber.from(160000) -const CHECK_GAS_OVERHEAD = BigNumber.from(362287) -// ----------------------------------------------------------------------------------------------- - -// Smart contract factories -let linkTokenFactory: LinkTokenFactory -let mockV3AggregatorFactory: MockV3AggregatorFactory -let keeperRegistryFactory: KeeperRegistryFactory -let keeperRegistryLogicFactory: KeeperRegistryLogicFactory -let upkeepMockFactory: UpkeepMockFactory -let upkeepReverterFactory: UpkeepReverterFactory -let upkeepAutoFunderFactory: UpkeepAutoFunderFactory -let upkeepTranscoderFactory: UpkeepTranscoderFactory -let mockArbGasInfoFactory: MockArbGasInfoFactory -let mockOVMGasPriceOracleFactory: MockOVMGasPriceOracleFactory -let personas: Personas - -before(async () => { - personas = (await getUsers()).personas - - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', - ) - // need full path because there are two contracts with name MockV3Aggregator - mockV3AggregatorFactory = (await ethers.getContractFactory( - 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', - )) as unknown as MockV3AggregatorFactory - // @ts-ignore bug in autogen file - keeperRegistryFactory = await ethers.getContractFactory('KeeperRegistry1_3') - // @ts-ignore bug in autogen file - keeperRegistryLogicFactory = await ethers.getContractFactory( - 'KeeperRegistryLogic1_3', - ) - upkeepMockFactory = await ethers.getContractFactory('UpkeepMock') - upkeepReverterFactory = await ethers.getContractFactory('UpkeepReverter') - upkeepAutoFunderFactory = await ethers.getContractFactory('UpkeepAutoFunder') - upkeepTranscoderFactory = await ethers.getContractFactory('UpkeepTranscoder') - mockArbGasInfoFactory = await ethers.getContractFactory('MockArbGasInfo') - mockOVMGasPriceOracleFactory = await ethers.getContractFactory( - 'MockOVMGasPriceOracle', - ) -}) - -describe.skip('KeeperRegistry1_3', () => { - const linkEth = BigNumber.from(300000000) - const gasWei = BigNumber.from(100) - const linkDivisibility = BigNumber.from('1000000000000000000') - const executeGas = BigNumber.from('100000') - const paymentPremiumBase = BigNumber.from('1000000000') - const paymentPremiumPPB = BigNumber.from('250000000') - const premiumMultiplier = BigNumber.from('1000000000') - const flatFeeMicroLink = BigNumber.from(0) - const blockCountPerTurn = BigNumber.from(3) - const emptyBytes = '0x00' - const randomBytes = '0x1234abcd' - const zeroAddress = ethers.constants.AddressZero - const extraGas = BigNumber.from('250000') - const registryGasOverhead = BigNumber.from('80000') - const stalenessSeconds = BigNumber.from(43820) - const gasCeilingMultiplier = BigNumber.from(1) - const checkGasLimit = BigNumber.from(10000000) - const fallbackGasPrice = BigNumber.from(200) - const fallbackLinkPrice = BigNumber.from(200000000) - const maxPerformGas = BigNumber.from(5000000) - const minUpkeepSpend = BigNumber.from(0) - const l1CostWeiArb = BigNumber.from(1000000) - const l1CostWeiOpt = BigNumber.from(2000000) - - let owner: Signer - let keeper1: Signer - let keeper2: Signer - let keeper3: Signer - let nonkeeper: Signer - let admin: Signer - let payee1: Signer - let payee2: Signer - let payee3: Signer - - let linkToken: LinkToken - let linkEthFeed: MockV3Aggregator - let gasPriceFeed: MockV3Aggregator - let registry: KeeperRegistry - let registryLogic: KeeperRegistryLogic - let registry2: KeeperRegistry - let registryLogic2: KeeperRegistryLogic - let mock: UpkeepMock - let transcoder: UpkeepTranscoder - let mockArbGasInfo: MockArbGasInfo - let mockOVMGasPriceOracle: MockOVMGasPriceOracle - - let id: BigNumber - let keepers: string[] - let payees: string[] - - beforeEach(async () => { - owner = personas.Default - keeper1 = personas.Carol - keeper2 = personas.Eddy - keeper3 = personas.Nancy - nonkeeper = personas.Ned - admin = personas.Neil - payee1 = personas.Nelly - payee2 = personas.Norbert - payee3 = personas.Nick - - keepers = [ - await keeper1.getAddress(), - await keeper2.getAddress(), - await keeper3.getAddress(), - ] - payees = [ - await payee1.getAddress(), - await payee2.getAddress(), - await payee3.getAddress(), - ] - - linkToken = await linkTokenFactory.connect(owner).deploy() - gasPriceFeed = await mockV3AggregatorFactory - .connect(owner) - .deploy(0, gasWei) - linkEthFeed = await mockV3AggregatorFactory - .connect(owner) - .deploy(9, linkEth) - transcoder = await upkeepTranscoderFactory.connect(owner).deploy() - mockArbGasInfo = await mockArbGasInfoFactory.connect(owner).deploy() - mockOVMGasPriceOracle = await mockOVMGasPriceOracleFactory - .connect(owner) - .deploy() - - const arbOracleCode = await ethers.provider.send('eth_getCode', [ - mockArbGasInfo.address, - ]) - await ethers.provider.send('hardhat_setCode', [ - '0x000000000000000000000000000000000000006C', - arbOracleCode, - ]) - - const optOracleCode = await ethers.provider.send('eth_getCode', [ - mockOVMGasPriceOracle.address, - ]) - await ethers.provider.send('hardhat_setCode', [ - '0x420000000000000000000000000000000000000F', - optOracleCode, - ]) - - registryLogic = await keeperRegistryLogicFactory - .connect(owner) - .deploy( - 0, - registryGasOverhead, - linkToken.address, - linkEthFeed.address, - gasPriceFeed.address, - ) - - const config = { - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - } - registry = await keeperRegistryFactory - .connect(owner) - .deploy(registryLogic.address, config) - registryLogic2 = await keeperRegistryLogicFactory - .connect(owner) - .deploy( - 0, - registryGasOverhead, - linkToken.address, - linkEthFeed.address, - gasPriceFeed.address, - ) - registry2 = await keeperRegistryFactory - .connect(owner) - .deploy(registryLogic2.address, config) - mock = await upkeepMockFactory.deploy() - await linkToken - .connect(owner) - .transfer(await keeper1.getAddress(), toWei('1000')) - await linkToken - .connect(owner) - .transfer(await keeper2.getAddress(), toWei('1000')) - await linkToken - .connect(owner) - .transfer(await keeper3.getAddress(), toWei('1000')) - - await registry.connect(owner).setKeepers(keepers, payees) - const tx = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - randomBytes, - ) - id = await getUpkeepID(tx) - }) - - const linkForGas = ( - upkeepGasSpent: BigNumberish, - premiumPPB?: BigNumberish, - flatFee?: BigNumberish, - l1CostWei?: BigNumber, - ) => { - premiumPPB = premiumPPB === undefined ? paymentPremiumPPB : premiumPPB - flatFee = flatFee === undefined ? flatFeeMicroLink : flatFee - l1CostWei = l1CostWei === undefined ? BigNumber.from(0) : l1CostWei - const gasSpent = registryGasOverhead.add(BigNumber.from(upkeepGasSpent)) - const base = gasWei.mul(gasSpent).mul(linkDivisibility).div(linkEth) - const l1Fee = l1CostWei - .mul(premiumMultiplier) - .mul(paymentPremiumBase.add(premiumPPB)) - .div(linkEth) - const premium = base.mul(premiumPPB).div(paymentPremiumBase) - const flatFeeJules = BigNumber.from(flatFee).mul('1000000000000') - return base.add(premium).add(flatFeeJules).add(l1Fee) - } - - const verifyMaxPayment = async ( - keeperRegistryLogic: KeeperRegistryLogic, - gasAmounts: number[], - premiums: number[], - flatFees: number[], - l1CostWei?: BigNumber, - ) => { - const config = { - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - } - - let registry = await keeperRegistryFactory - .connect(owner) - .deploy(keeperRegistryLogic.address, config) - - for (let idx = 0; idx < gasAmounts.length; idx++) { - const gas = gasAmounts[idx] - for (let jdx = 0; jdx < premiums.length; jdx++) { - const premium = premiums[jdx] - for (let kdx = 0; kdx < flatFees.length; kdx++) { - const flatFee = flatFees[kdx] - await registry.connect(owner).setConfig({ - paymentPremiumPPB: premium, - flatFeeMicroLink: flatFee, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - const price = await registry.getMaxPaymentForGas(gas) - expect(price).to.equal(linkForGas(gas, premium, flatFee, l1CostWei)) - } - } - } - } - - describe('#typeAndVersion', () => { - it('uses the correct type and version', async () => { - const typeAndVersion = await registry.typeAndVersion() - assert.equal(typeAndVersion, 'KeeperRegistry 1.3.0') - }) - }) - - describe('#setKeepers', () => { - const IGNORE_ADDRESS = '0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF' - it('reverts when not called by the owner', async () => { - await evmRevert( - registry.connect(keeper1).setKeepers([], []), - 'Only callable by owner', - ) - }) - - it('reverts when adding the same keeper twice', async () => { - await evmRevert( - registry - .connect(owner) - .setKeepers( - [await keeper1.getAddress(), await keeper1.getAddress()], - [await payee1.getAddress(), await payee1.getAddress()], - ), - 'DuplicateEntry()', - ) - }) - - it('reverts with different numbers of keepers/payees', async () => { - await evmRevert( - registry - .connect(owner) - .setKeepers( - [await keeper1.getAddress(), await keeper2.getAddress()], - [await payee1.getAddress()], - ), - 'ParameterLengthError()', - ) - await evmRevert( - registry - .connect(owner) - .setKeepers( - [await keeper1.getAddress()], - [await payee1.getAddress(), await payee2.getAddress()], - ), - 'ParameterLengthError()', - ) - }) - - it('reverts if the payee is the zero address', async () => { - await evmRevert( - registry - .connect(owner) - .setKeepers( - [await keeper1.getAddress(), await keeper2.getAddress()], - [ - await payee1.getAddress(), - '0x0000000000000000000000000000000000000000', - ], - ), - 'InvalidPayee()', - ) - }) - - it('emits events for every keeper added and removed', async () => { - const oldKeepers = [ - await keeper1.getAddress(), - await keeper2.getAddress(), - ] - const oldPayees = [await payee1.getAddress(), await payee2.getAddress()] - await registry.connect(owner).setKeepers(oldKeepers, oldPayees) - assert.deepEqual(oldKeepers, (await registry.getState()).keepers) - - // remove keepers - const newKeepers = [ - await keeper2.getAddress(), - await keeper3.getAddress(), - ] - const newPayees = [await payee2.getAddress(), await payee3.getAddress()] - const tx = await registry.connect(owner).setKeepers(newKeepers, newPayees) - assert.deepEqual(newKeepers, (await registry.getState()).keepers) - - await expect(tx) - .to.emit(registry, 'KeepersUpdated') - .withArgs(newKeepers, newPayees) - }) - - it('updates the keeper to inactive when removed', async () => { - await registry.connect(owner).setKeepers(keepers, payees) - await registry - .connect(owner) - .setKeepers( - [await keeper1.getAddress(), await keeper3.getAddress()], - [await payee1.getAddress(), await payee3.getAddress()], - ) - const added = await registry.getKeeperInfo(await keeper1.getAddress()) - assert.isTrue(added.active) - const removed = await registry.getKeeperInfo(await keeper2.getAddress()) - assert.isFalse(removed.active) - }) - - it('does not change the payee if IGNORE_ADDRESS is used as payee', async () => { - const oldKeepers = [ - await keeper1.getAddress(), - await keeper2.getAddress(), - ] - const oldPayees = [await payee1.getAddress(), await payee2.getAddress()] - await registry.connect(owner).setKeepers(oldKeepers, oldPayees) - assert.deepEqual(oldKeepers, (await registry.getState()).keepers) - - const newKeepers = [ - await keeper2.getAddress(), - await keeper3.getAddress(), - ] - const newPayees = [IGNORE_ADDRESS, await payee3.getAddress()] - const tx = await registry.connect(owner).setKeepers(newKeepers, newPayees) - assert.deepEqual(newKeepers, (await registry.getState()).keepers) - - const ignored = await registry.getKeeperInfo(await keeper2.getAddress()) - assert.equal(await payee2.getAddress(), ignored.payee) - assert.equal(true, ignored.active) - - await expect(tx) - .to.emit(registry, 'KeepersUpdated') - .withArgs(newKeepers, newPayees) - }) - - it('reverts if the owner changes the payee', async () => { - await registry.connect(owner).setKeepers(keepers, payees) - await evmRevert( - registry - .connect(owner) - .setKeepers(keepers, [ - await payee1.getAddress(), - await payee2.getAddress(), - await owner.getAddress(), - ]), - 'InvalidPayee()', - ) - }) - }) - - describe('#pauseUpkeep', () => { - it('reverts if the upkeep is already canceled', async () => { - await registry.connect(admin).cancelUpkeep(id) - - await evmRevert( - registry.connect(admin).pauseUpkeep(id), - 'UpkeepCancelled()', - ) - }) - - it('reverts if the upkeep is already paused', async () => { - await registry.connect(admin).pauseUpkeep(id) - - await evmRevert( - registry.connect(admin).pauseUpkeep(id), - 'OnlyUnpausedUpkeep()', - ) - }) - - it('reverts if the caller is not the upkeep admin', async () => { - await evmRevert( - registry.connect(keeper1).pauseUpkeep(id), - 'OnlyCallableByAdmin()', - ) - }) - - it('pauses the upkeep and emits an event', async () => { - const tx = await registry.connect(admin).pauseUpkeep(id) - await expect(tx).to.emit(registry, 'UpkeepPaused').withArgs(id) - - const registration = await registry.getUpkeep(id) - assert.equal(registration.paused, true) - }) - }) - - describe('#unpauseUpkeep', () => { - it('reverts if the upkeep is already canceled', async () => { - await registry.connect(owner).cancelUpkeep(id) - - await evmRevert( - registry.connect(admin).unpauseUpkeep(id), - 'UpkeepCancelled()', - ) - }) - - it('reverts if the upkeep is not paused', async () => { - await evmRevert( - registry.connect(admin).unpauseUpkeep(id), - 'OnlyPausedUpkeep()', - ) - }) - - it('reverts if the caller is not the upkeep admin', async () => { - await registry.connect(admin).pauseUpkeep(id) - - const registration = await registry.getUpkeep(id) - - assert.equal(registration.paused, true) - - await evmRevert( - registry.connect(keeper1).unpauseUpkeep(id), - 'OnlyCallableByAdmin()', - ) - }) - - it('unpauses the upkeep and emits an event', async () => { - await registry.connect(admin).pauseUpkeep(id) - - const tx = await registry.connect(admin).unpauseUpkeep(id) - - await expect(tx).to.emit(registry, 'UpkeepUnpaused').withArgs(id) - - const registration = await registry.getUpkeep(id) - assert.equal(registration.paused, false) - - const upkeepIds = await registry.getActiveUpkeepIDs(0, 0) - assert.equal(upkeepIds.length, 1) - }) - }) - - describe('#updateCheckData', () => { - it('reverts if the caller is not upkeep admin', async () => { - await evmRevert( - registry.connect(keeper1).updateCheckData(id, randomBytes), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if the upkeep is cancelled', async () => { - await registry.connect(admin).cancelUpkeep(id) - - await evmRevert( - registry.connect(admin).updateCheckData(id, randomBytes), - 'UpkeepCancelled()', - ) - }) - - it('updates the paused upkeep check data', async () => { - await registry.connect(admin).pauseUpkeep(id) - await registry.connect(admin).updateCheckData(id, randomBytes) - - const registration = await registry.getUpkeep(id) - assert.equal(randomBytes, registration.checkData) - }) - - it('updates the upkeep check data and emits an event', async () => { - const tx = await registry.connect(admin).updateCheckData(id, randomBytes) - await expect(tx) - .to.emit(registry, 'UpkeepCheckDataUpdated') - .withArgs(id, randomBytes) - - const registration = await registry.getUpkeep(id) - assert.equal(randomBytes, registration.checkData) - }) - }) - - describe('#registerUpkeep', () => { - context('and the registry is paused', () => { - beforeEach(async () => { - await registry.connect(owner).pause() - }) - it('reverts', async () => { - await evmRevert( - registry - .connect(owner) - .registerUpkeep( - zeroAddress, - executeGas, - await admin.getAddress(), - emptyBytes, - ), - 'Pausable: paused', - ) - }) - }) - - it('reverts if the target is not a contract', async () => { - await evmRevert( - registry - .connect(owner) - .registerUpkeep( - zeroAddress, - executeGas, - await admin.getAddress(), - emptyBytes, - ), - 'NotAContract()', - ) - }) - - it('reverts if called by a non-owner', async () => { - await evmRevert( - registry - .connect(keeper1) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - ), - 'OnlyCallableByOwnerOrRegistrar()', - ) - }) - - it('reverts if execute gas is too low', async () => { - await evmRevert( - registry - .connect(owner) - .registerUpkeep( - mock.address, - 2299, - await admin.getAddress(), - emptyBytes, - ), - 'GasLimitOutsideRange()', - ) - }) - - it('reverts if execute gas is too high', async () => { - await evmRevert( - registry - .connect(owner) - .registerUpkeep( - mock.address, - 5000001, - await admin.getAddress(), - emptyBytes, - ), - 'GasLimitOutsideRange()', - ) - }) - - it('creates a record of the registration', async () => { - const tx = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - ) - id = await getUpkeepID(tx) - await expect(tx) - .to.emit(registry, 'UpkeepRegistered') - .withArgs(id, executeGas, await admin.getAddress()) - const registration = await registry.getUpkeep(id) - assert.equal(mock.address, registration.target) - assert.equal(0, registration.balance.toNumber()) - assert.equal(emptyBytes, registration.checkData) - assert.equal(registration.paused, false) - assert(registration.maxValidBlocknumber.eq('0xffffffff')) - }) - }) - - describe('#addFunds', () => { - const amount = toWei('1') - - beforeEach(async () => { - await linkToken.connect(keeper1).approve(registry.address, toWei('100')) - }) - - it('reverts if the registration does not exist', async () => { - await evmRevert( - registry.connect(keeper1).addFunds(id.add(1), amount), - 'UpkeepCancelled()', - ) - }) - - it('adds to the balance of the registration', async () => { - await registry.connect(keeper1).addFunds(id, amount) - const registration = await registry.getUpkeep(id) - assert.isTrue(amount.eq(registration.balance)) - }) - - it('emits a log', async () => { - const tx = await registry.connect(keeper1).addFunds(id, amount) - await expect(tx) - .to.emit(registry, 'FundsAdded') - .withArgs(id, await keeper1.getAddress(), amount) - }) - - it('reverts if the upkeep is canceled', async () => { - await registry.connect(admin).cancelUpkeep(id) - await evmRevert( - registry.connect(keeper1).addFunds(id, amount), - 'UpkeepCancelled()', - ) - }) - }) - - describe('#setUpkeepGasLimit', () => { - const newGasLimit = BigNumber.from('500000') - - it('reverts if the registration does not exist', async () => { - await evmRevert( - registry.connect(keeper1).setUpkeepGasLimit(id.add(1), newGasLimit), - 'UpkeepCancelled()', - ) - }) - - it('reverts if the upkeep is canceled', async () => { - await registry.connect(admin).cancelUpkeep(id) - await evmRevert( - registry.connect(keeper1).setUpkeepGasLimit(id, newGasLimit), - 'UpkeepCancelled()', - ) - }) - - it('reverts if called by anyone but the admin', async () => { - await evmRevert( - registry.connect(owner).setUpkeepGasLimit(id, newGasLimit), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if new gas limit is out of bounds', async () => { - await evmRevert( - registry.connect(admin).setUpkeepGasLimit(id, BigNumber.from('100')), - 'GasLimitOutsideRange()', - ) - await evmRevert( - registry - .connect(admin) - .setUpkeepGasLimit(id, BigNumber.from('6000000')), - 'GasLimitOutsideRange()', - ) - }) - - it('updates the gas limit successfully', async () => { - const initialGasLimit = (await registry.getUpkeep(id)).executeGas - assert.equal(initialGasLimit, executeGas.toNumber()) - await registry.connect(admin).setUpkeepGasLimit(id, newGasLimit) - const updatedGasLimit = (await registry.getUpkeep(id)).executeGas - assert.equal(updatedGasLimit, newGasLimit.toNumber()) - }) - - it('emits a log', async () => { - const tx = await registry - .connect(admin) - .setUpkeepGasLimit(id, newGasLimit) - await expect(tx) - .to.emit(registry, 'UpkeepGasLimitSet') - .withArgs(id, newGasLimit) - }) - }) - - describe('#checkUpkeep', () => { - it('reverts if the upkeep is not funded', async () => { - await mock.setCanPerform(true) - await mock.setCanCheck(true) - await evmRevert( - registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress()), - 'InsufficientFunds()', - ) - }) - - context('when the registration is funded', () => { - beforeEach(async () => { - await linkToken.connect(keeper1).approve(registry.address, toWei('100')) - await registry.connect(keeper1).addFunds(id, toWei('100')) - }) - - it('reverts if executed', async () => { - await mock.setCanPerform(true) - await mock.setCanCheck(true) - await evmRevert( - registry.checkUpkeep(id, await keeper1.getAddress()), - 'OnlySimulatedBackend()', - ) - }) - - it('reverts if the specified keeper is not valid', async () => { - await mock.setCanPerform(true) - await mock.setCanCheck(true) - await evmRevert( - registry.checkUpkeep(id, await owner.getAddress()), - 'OnlySimulatedBackend()', - ) - }) - - context('and upkeep is not needed', () => { - beforeEach(async () => { - await mock.setCanCheck(false) - }) - - it('reverts', async () => { - await evmRevert( - registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress()), - 'UpkeepNotNeeded()', - ) - }) - }) - - context('and the upkeep check fails', () => { - beforeEach(async () => { - const reverter = await upkeepReverterFactory.deploy() - const tx = await registry - .connect(owner) - .registerUpkeep( - reverter.address, - 2500000, - await admin.getAddress(), - emptyBytes, - ) - id = await getUpkeepID(tx) - await linkToken - .connect(keeper1) - .approve(registry.address, toWei('100')) - await registry.connect(keeper1).addFunds(id, toWei('100')) - }) - - it('reverts', async () => { - await evmRevert( - registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress()), - 'TargetCheckReverted', - ) - }) - }) - - context('and upkeep check simulations succeeds', () => { - beforeEach(async () => { - await mock.setCanCheck(true) - await mock.setCanPerform(true) - }) - - it('reverts if the upkeep is paused', async () => { - await registry.connect(admin).pauseUpkeep(id) - - await evmRevert( - registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress()), - 'OnlyUnpausedUpkeep()', - ) - }) - - it('returns true with pricing info if the target can execute', async () => { - const newGasMultiplier = BigNumber.from(10) - await registry.connect(owner).setConfig({ - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier: newGasMultiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - const response = await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress()) - assert.isTrue(response.gasLimit.eq(executeGas)) - assert.isTrue(response.linkEth.eq(linkEth)) - assert.isTrue( - response.adjustedGasWei.eq(gasWei.mul(newGasMultiplier)), - ) - assert.isTrue( - response.maxLinkPayment.eq( - linkForGas(executeGas.toNumber()).mul(newGasMultiplier), - ), - ) - }) - - it('has a large enough gas overhead to cover upkeeps that use all their gas [ @skip-coverage ]', async () => { - await mock.setCheckGasToBurn(checkGasLimit) - const gas = checkGasLimit.add(CHECK_GAS_OVERHEAD) - await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress(), { - gasLimit: gas, - }) - }) - }) - }) - }) - - describe('#performUpkeep', () => { - let _lastKeeper = keeper1 - - async function getPerformPaymentAmount() { - _lastKeeper = _lastKeeper === keeper1 ? keeper2 : keeper1 - const before = ( - await registry.getKeeperInfo(await _lastKeeper.getAddress()) - ).balance - await registry.connect(_lastKeeper).performUpkeep(id, '0x') - const after = ( - await registry.getKeeperInfo(await _lastKeeper.getAddress()) - ).balance - const difference = after.sub(before) - return difference - } - - it('reverts if the registration is not funded', async () => { - await evmRevert( - registry.connect(keeper2).performUpkeep(id, '0x'), - 'InsufficientFunds()', - ) - }) - - context('and the registry is paused', () => { - beforeEach(async () => { - await registry.connect(owner).pause() - }) - - it('reverts', async () => { - await evmRevert( - registry.connect(keeper2).performUpkeep(id, '0x'), - 'Pausable: paused', - ) - }) - }) - - context('when the registration is funded', () => { - beforeEach(async () => { - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(id, toWei('100')) - }) - - it('does not revert if the target cannot execute', async () => { - const mockResponse = await mock - .connect(zeroAddress) - .callStatic.checkUpkeep('0x') - assert.isFalse(mockResponse.callable) - - await registry.connect(keeper3).performUpkeep(id, '0x') - }) - - it('returns false if the target cannot execute', async () => { - const mockResponse = await mock - .connect(zeroAddress) - .callStatic.checkUpkeep('0x') - assert.isFalse(mockResponse.callable) - - assert.isFalse( - await registry.connect(keeper1).callStatic.performUpkeep(id, '0x'), - ) - }) - - it('returns true if called', async () => { - await mock.setCanPerform(true) - - const response = await registry - .connect(keeper1) - .callStatic.performUpkeep(id, '0x') - assert.isTrue(response) - }) - - it('reverts if not enough gas supplied', async () => { - await mock.setCanPerform(true) - - await evmRevert( - registry - .connect(keeper1) - .performUpkeep(id, '0x', { gasLimit: BigNumber.from('120000') }), - ) - }) - - it('executes the data passed to the registry', async () => { - await mock.setCanPerform(true) - - const performData = '0xc0ffeec0ffee' - const tx = await registry - .connect(keeper1) - .performUpkeep(id, performData, { gasLimit: extraGas }) - const receipt = await tx.wait() - const eventLog = receipt?.events - - assert.equal(eventLog?.length, 2) - assert.equal(eventLog?.[1].event, 'UpkeepPerformed') - expect(eventLog?.[1].args?.[0]).to.equal(id) - assert.equal(eventLog?.[1].args?.[1], true) - assert.equal(eventLog?.[1].args?.[2], await keeper1.getAddress()) - assert.isNotEmpty(eventLog?.[1].args?.[3]) - assert.equal(eventLog?.[1].args?.[4], performData) - }) - - it('updates payment balances', async () => { - const keeperBefore = await registry.getKeeperInfo( - await keeper1.getAddress(), - ) - const registrationBefore = await registry.getUpkeep(id) - const keeperLinkBefore = await linkToken.balanceOf( - await keeper1.getAddress(), - ) - const registryLinkBefore = await linkToken.balanceOf(registry.address) - - // Do the thing - await registry.connect(keeper1).performUpkeep(id, '0x') - - const keeperAfter = await registry.getKeeperInfo( - await keeper1.getAddress(), - ) - const registrationAfter = await registry.getUpkeep(id) - const keeperLinkAfter = await linkToken.balanceOf( - await keeper1.getAddress(), - ) - const registryLinkAfter = await linkToken.balanceOf(registry.address) - - assert.isTrue(keeperAfter.balance.gt(keeperBefore.balance)) - assert.isTrue(registrationBefore.balance.gt(registrationAfter.balance)) - assert.isTrue(keeperLinkAfter.eq(keeperLinkBefore)) - assert.isTrue(registryLinkBefore.eq(registryLinkAfter)) - }) - - it('updates amount spent correctly', async () => { - const registrationBefore = await registry.getUpkeep(id) - const balanceBefore = registrationBefore.balance - const amountSpentBefore = registrationBefore.amountSpent - - // Do the thing - await registry.connect(keeper1).performUpkeep(id, '0x') - - const registrationAfter = await registry.getUpkeep(id) - const balanceAfter = registrationAfter.balance - const amountSpentAfter = registrationAfter.amountSpent - - assert.isTrue(balanceAfter.lt(balanceBefore)) - assert.isTrue(amountSpentAfter.gt(amountSpentBefore)) - assert.isTrue( - amountSpentAfter - .sub(amountSpentBefore) - .eq(balanceBefore.sub(balanceAfter)), - ) - }) - - it('only pays for gas used [ @skip-coverage ]', async () => { - const before = ( - await registry.getKeeperInfo(await keeper1.getAddress()) - ).balance - const tx = await registry.connect(keeper1).performUpkeep(id, '0x') - const receipt = await tx.wait() - const after = (await registry.getKeeperInfo(await keeper1.getAddress())) - .balance - - const max = linkForGas(executeGas.toNumber()) - const totalTx = linkForGas(receipt.gasUsed.toNumber()) - const difference = after.sub(before) - assert.isTrue(max.gt(totalTx)) - assert.isTrue(totalTx.gt(difference)) - assert.isTrue(linkForGas(5700).lt(difference)) // exact number is flaky - assert.isTrue(linkForGas(6000).gt(difference)) // instead test a range - }) - - it('only pays at a rate up to the gas ceiling [ @skip-coverage ]', async () => { - const multiplier = BigNumber.from(10) - const gasPrice = BigNumber.from('1000000000') // 10M x the gas feed's rate - await registry.connect(owner).setConfig({ - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier: multiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - - const before = ( - await registry.getKeeperInfo(await keeper1.getAddress()) - ).balance - const tx = await registry - .connect(keeper1) - .performUpkeep(id, '0x', { gasPrice }) - const receipt = await tx.wait() - const after = (await registry.getKeeperInfo(await keeper1.getAddress())) - .balance - - const max = linkForGas(executeGas).mul(multiplier) - const totalTx = linkForGas(receipt.gasUsed).mul(multiplier) - const difference = after.sub(before) - assert.isTrue(max.gt(totalTx)) - assert.isTrue(totalTx.gt(difference)) - assert.isTrue(linkForGas(5700).mul(multiplier).lt(difference)) - assert.isTrue(linkForGas(6000).mul(multiplier).gt(difference)) - }) - - it('only pays as much as the node spent [ @skip-coverage ]', async () => { - const multiplier = BigNumber.from(10) - const gasPrice = BigNumber.from(200) // 2X the gas feed's rate - const effectiveMultiplier = BigNumber.from(2) - await registry.connect(owner).setConfig({ - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier: multiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - - const before = ( - await registry.getKeeperInfo(await keeper1.getAddress()) - ).balance - const tx = await registry - .connect(keeper1) - .performUpkeep(id, '0x', { gasPrice }) - const receipt = await tx.wait() - const after = (await registry.getKeeperInfo(await keeper1.getAddress())) - .balance - - const max = linkForGas(executeGas.toNumber()).mul(effectiveMultiplier) - const totalTx = linkForGas(receipt.gasUsed).mul(effectiveMultiplier) - const difference = after.sub(before) - assert.isTrue(max.gt(totalTx)) - assert.isTrue(totalTx.gt(difference)) - assert.isTrue(linkForGas(5700).mul(effectiveMultiplier).lt(difference)) - assert.isTrue(linkForGas(6000).mul(effectiveMultiplier).gt(difference)) - }) - - it('pays the caller even if the target function fails', async () => { - const tx = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - ) - const id = await getUpkeepID(tx) - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(id, toWei('100')) - const keeperBalanceBefore = ( - await registry.getKeeperInfo(await keeper1.getAddress()) - ).balance - - // Do the thing - await registry.connect(keeper1).performUpkeep(id, '0x') - - const keeperBalanceAfter = ( - await registry.getKeeperInfo(await keeper1.getAddress()) - ).balance - assert.isTrue(keeperBalanceAfter.gt(keeperBalanceBefore)) - }) - - it('reverts if called by a non-keeper', async () => { - await evmRevert( - registry.connect(nonkeeper).performUpkeep(id, '0x'), - 'OnlyActiveKeepers()', - ) - }) - - it('reverts if the upkeep has been canceled', async () => { - await mock.setCanPerform(true) - - await registry.connect(owner).cancelUpkeep(id) - - await evmRevert( - registry.connect(keeper1).performUpkeep(id, '0x'), - 'UpkeepCancelled()', - ) - }) - - it('reverts if the upkeep is paused', async () => { - await registry.connect(admin).pauseUpkeep(id) - - await evmRevert( - registry.connect(keeper1).performUpkeep(id, '0x'), - 'OnlyUnpausedUpkeep()', - ) - }) - - it('uses the fallback gas price if the feed price is stale [ @skip-coverage ]', async () => { - const normalAmount = await getPerformPaymentAmount() - const roundId = 99 - const answer = 100 - const updatedAt = 946684800 // New Years 2000 🥳 - const startedAt = 946684799 - await gasPriceFeed - .connect(owner) - .updateRoundData(roundId, answer, updatedAt, startedAt) - const amountWithStaleFeed = await getPerformPaymentAmount() - assert.isTrue(normalAmount.lt(amountWithStaleFeed)) - }) - - it('uses the fallback gas price if the feed price is non-sensical [ @skip-coverage ]', async () => { - const normalAmount = await getPerformPaymentAmount() - const roundId = 99 - const updatedAt = Math.floor(Date.now() / 1000) - const startedAt = 946684799 - await gasPriceFeed - .connect(owner) - .updateRoundData(roundId, -100, updatedAt, startedAt) - const amountWithNegativeFeed = await getPerformPaymentAmount() - await gasPriceFeed - .connect(owner) - .updateRoundData(roundId, 0, updatedAt, startedAt) - const amountWithZeroFeed = await getPerformPaymentAmount() - assert.isTrue(normalAmount.lt(amountWithNegativeFeed)) - assert.isTrue(normalAmount.lt(amountWithZeroFeed)) - }) - - it('uses the fallback if the link price feed is stale', async () => { - const normalAmount = await getPerformPaymentAmount() - const roundId = 99 - const answer = 100 - const updatedAt = 946684800 // New Years 2000 🥳 - const startedAt = 946684799 - await linkEthFeed - .connect(owner) - .updateRoundData(roundId, answer, updatedAt, startedAt) - const amountWithStaleFeed = await getPerformPaymentAmount() - assert.isTrue(normalAmount.lt(amountWithStaleFeed)) - }) - - it('uses the fallback link price if the feed price is non-sensical [ @skip-coverage ]', async () => { - const normalAmount = await getPerformPaymentAmount() - const roundId = 99 - const updatedAt = Math.floor(Date.now() / 1000) - const startedAt = 946684799 - await linkEthFeed - .connect(owner) - .updateRoundData(roundId, -100, updatedAt, startedAt) - const amountWithNegativeFeed = await getPerformPaymentAmount() - await linkEthFeed - .connect(owner) - .updateRoundData(roundId, 0, updatedAt, startedAt) - const amountWithZeroFeed = await getPerformPaymentAmount() - assert.isTrue(normalAmount.lt(amountWithNegativeFeed)) - assert.isTrue(normalAmount.lt(amountWithZeroFeed)) - }) - - it('reverts if the same caller calls twice in a row', async () => { - await registry.connect(keeper1).performUpkeep(id, '0x') - await evmRevert( - registry.connect(keeper1).performUpkeep(id, '0x'), - 'KeepersMustTakeTurns()', - ) - await registry.connect(keeper2).performUpkeep(id, '0x') - await evmRevert( - registry.connect(keeper2).performUpkeep(id, '0x'), - 'KeepersMustTakeTurns()', - ) - await registry.connect(keeper1).performUpkeep(id, '0x') - }) - - it('has a large enough gas overhead to cover upkeeps that use all their gas [ @skip-coverage ]', async () => { - await registry.connect(admin).setUpkeepGasLimit(id, maxPerformGas) - await mock.setPerformGasToBurn(maxPerformGas) - await mock.setCanPerform(true) - const gas = maxPerformGas.add(PERFORM_GAS_OVERHEAD) - const performData = '0xc0ffeec0ffee' - const tx = await registry - .connect(keeper1) - .performUpkeep(id, performData, { gasLimit: gas }) - const receipt = await tx.wait() - const eventLog = receipt?.events - - assert.equal(eventLog?.length, 2) - assert.equal(eventLog?.[1].event, 'UpkeepPerformed') - expect(eventLog?.[1].args?.[0]).to.equal(id) - assert.equal(eventLog?.[1].args?.[1], true) - assert.equal(eventLog?.[1].args?.[2], await keeper1.getAddress()) - assert.isNotEmpty(eventLog?.[1].args?.[3]) - assert.equal(eventLog?.[1].args?.[4], performData) - }) - - it('can self fund', async () => { - const autoFunderUpkeep = await upkeepAutoFunderFactory - .connect(owner) - .deploy(linkToken.address, registry.address) - const tx = await registry - .connect(owner) - .registerUpkeep( - autoFunderUpkeep.address, - executeGas, - autoFunderUpkeep.address, - emptyBytes, - ) - const upkeepID = await getUpkeepID(tx) - await autoFunderUpkeep.setUpkeepId(upkeepID) - // Give enough funds for upkeep as well as to the upkeep contract - await linkToken.connect(owner).approve(registry.address, toWei('1000')) - await linkToken - .connect(owner) - .transfer(autoFunderUpkeep.address, toWei('1000')) - let maxPayment = await registry.getMaxPaymentForGas(executeGas) - - // First set auto funding amount to 0 and verify that balance is deducted upon performUpkeep - let initialBalance = toWei('100') - await registry.connect(owner).addFunds(upkeepID, initialBalance) - await autoFunderUpkeep.setAutoFundLink(0) - await autoFunderUpkeep.setIsEligible(true) - await registry.connect(keeper1).performUpkeep(upkeepID, '0x') - - let postUpkeepBalance = (await registry.getUpkeep(upkeepID)).balance - assert.isTrue(postUpkeepBalance.lt(initialBalance)) // Balance should be deducted - assert.isTrue(postUpkeepBalance.gte(initialBalance.sub(maxPayment))) // Balance should not be deducted more than maxPayment - - // Now set auto funding amount to 100 wei and verify that the balance increases - initialBalance = postUpkeepBalance - let autoTopupAmount = toWei('100') - await autoFunderUpkeep.setAutoFundLink(autoTopupAmount) - await autoFunderUpkeep.setIsEligible(true) - await registry.connect(keeper2).performUpkeep(upkeepID, '0x') - - postUpkeepBalance = (await registry.getUpkeep(upkeepID)).balance - // Balance should increase by autoTopupAmount and decrease by max maxPayment - assert.isTrue( - postUpkeepBalance.gte( - initialBalance.add(autoTopupAmount).sub(maxPayment), - ), - ) - }) - - it('can self cancel', async () => { - const autoFunderUpkeep = await upkeepAutoFunderFactory - .connect(owner) - .deploy(linkToken.address, registry.address) - const tx = await registry - .connect(owner) - .registerUpkeep( - autoFunderUpkeep.address, - executeGas, - autoFunderUpkeep.address, - emptyBytes, - ) - const upkeepID = await getUpkeepID(tx) - await autoFunderUpkeep.setUpkeepId(upkeepID) - - await linkToken.connect(owner).approve(registry.address, toWei('1000')) - await registry.connect(owner).addFunds(upkeepID, toWei('100')) - await autoFunderUpkeep.setIsEligible(true) - await autoFunderUpkeep.setShouldCancel(true) - - let registration = await registry.getUpkeep(upkeepID) - const oldExpiration = registration.maxValidBlocknumber - - // Do the thing - await registry.connect(keeper1).performUpkeep(upkeepID, '0x') - - // Verify upkeep gets cancelled - registration = await registry.getUpkeep(upkeepID) - const newExpiration = registration.maxValidBlocknumber - assert.isTrue(newExpiration.lt(oldExpiration)) - }) - }) - }) - - describe('#withdrawFunds', () => { - beforeEach(async () => { - await linkToken.connect(keeper1).approve(registry.address, toWei('100')) - await registry.connect(keeper1).addFunds(id, toWei('100')) - await registry.connect(keeper1).performUpkeep(id, '0x') - }) - - it('reverts if called by anyone but the admin', async () => { - await evmRevert( - registry - .connect(owner) - .withdrawFunds(id.add(1), await payee1.getAddress()), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if called on an uncanceled upkeep', async () => { - await evmRevert( - registry.connect(admin).withdrawFunds(id, await payee1.getAddress()), - 'UpkeepNotCanceled()', - ) - }) - - it('reverts if called with the 0 address', async () => { - await evmRevert( - registry.connect(admin).withdrawFunds(id, zeroAddress), - 'InvalidRecipient()', - ) - }) - - describe('after the registration is cancelled', () => { - beforeEach(async () => { - await registry.connect(owner).cancelUpkeep(id) - }) - - it('moves the funds out and updates the balance and emits an event', async () => { - const payee1Before = await linkToken.balanceOf( - await payee1.getAddress(), - ) - const registryBefore = await linkToken.balanceOf(registry.address) - - let registration = await registry.getUpkeep(id) - let previousBalance = registration.balance - - const tx = await registry - .connect(admin) - .withdrawFunds(id, await payee1.getAddress()) - await expect(tx) - .to.emit(registry, 'FundsWithdrawn') - .withArgs(id, previousBalance, await payee1.getAddress()) - - const payee1After = await linkToken.balanceOf(await payee1.getAddress()) - const registryAfter = await linkToken.balanceOf(registry.address) - - assert.isTrue(payee1Before.add(previousBalance).eq(payee1After)) - assert.isTrue(registryBefore.sub(previousBalance).eq(registryAfter)) - - registration = await registry.getUpkeep(id) - assert.equal(0, registration.balance.toNumber()) - }) - }) - }) - - describe('#withdrawOwnerFunds', () => { - it('can only be called by owner', async () => { - await evmRevert( - registry.connect(keeper1).withdrawOwnerFunds(), - 'Only callable by owner', - ) - }) - - it('withdraws the collected fees to owner', async () => { - await linkToken.connect(keeper1).approve(registry.address, toWei('100')) - await registry.connect(keeper1).addFunds(id, toWei('100')) - // Very high min spend, whole balance as cancellation fees - let minUpkeepSpend = toWei('1000') - await registry.connect(owner).setConfig({ - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - let upkeepBalance = (await registry.getUpkeep(id)).balance - const ownerBefore = await linkToken.balanceOf(await owner.getAddress()) - - await registry.connect(owner).cancelUpkeep(id) - await registry.connect(admin).withdrawFunds(id, await payee1.getAddress()) - // Transfered to owner balance on registry - let ownerRegistryBalance = (await registry.getState()).state - .ownerLinkBalance - assert.isTrue(ownerRegistryBalance.eq(upkeepBalance)) - - // Now withdraw - await registry.connect(owner).withdrawOwnerFunds() - - ownerRegistryBalance = (await registry.getState()).state.ownerLinkBalance - const ownerAfter = await linkToken.balanceOf(await owner.getAddress()) - - // Owner registry balance should be changed to 0 - assert.isTrue(ownerRegistryBalance.eq(BigNumber.from('0'))) - - // Owner should be credited with the balance - assert.isTrue(ownerBefore.add(upkeepBalance).eq(ownerAfter)) - }) - }) - - describe('#cancelUpkeep', () => { - it('reverts if the ID is not valid', async () => { - await evmRevert( - registry.connect(owner).cancelUpkeep(id.add(1)), - 'CannotCancel()', - ) - }) - - it('reverts if called by a non-owner/non-admin', async () => { - await evmRevert( - registry.connect(keeper1).cancelUpkeep(id), - 'OnlyCallableByOwnerOrAdmin()', - ) - }) - - describe('when called by the owner', async () => { - it('sets the registration to invalid immediately', async () => { - const tx = await registry.connect(owner).cancelUpkeep(id) - const receipt = await tx.wait() - const registration = await registry.getUpkeep(id) - assert.equal( - registration.maxValidBlocknumber.toNumber(), - receipt.blockNumber, - ) - }) - - it('emits an event', async () => { - const tx = await registry.connect(owner).cancelUpkeep(id) - const receipt = await tx.wait() - await expect(tx) - .to.emit(registry, 'UpkeepCanceled') - .withArgs(id, BigNumber.from(receipt.blockNumber)) - }) - - it('immediately prevents upkeep', async () => { - await registry.connect(owner).cancelUpkeep(id) - - await evmRevert( - registry.connect(keeper2).performUpkeep(id, '0x'), - 'UpkeepCancelled()', - ) - }) - - it('does not revert if reverts if called multiple times', async () => { - await registry.connect(owner).cancelUpkeep(id) - await evmRevert( - registry.connect(owner).cancelUpkeep(id), - 'CannotCancel()', - ) - }) - - describe('when called by the owner when the admin has just canceled', () => { - let oldExpiration: BigNumber - - beforeEach(async () => { - await registry.connect(admin).cancelUpkeep(id) - const registration = await registry.getUpkeep(id) - oldExpiration = registration.maxValidBlocknumber - }) - - it('allows the owner to cancel it more quickly', async () => { - await registry.connect(owner).cancelUpkeep(id) - - const registration = await registry.getUpkeep(id) - const newExpiration = registration.maxValidBlocknumber - assert.isTrue(newExpiration.lt(oldExpiration)) - }) - }) - }) - - describe('when called by the admin', async () => { - const delay = 50 - - it('reverts if called again by the admin', async () => { - await registry.connect(admin).cancelUpkeep(id) - - await evmRevert( - registry.connect(admin).cancelUpkeep(id), - 'CannotCancel()', - ) - }) - - it('reverts if called by the owner after the timeout', async () => { - await registry.connect(admin).cancelUpkeep(id) - - for (let i = 0; i < delay; i++) { - await ethers.provider.send('evm_mine', []) - } - - await evmRevert( - registry.connect(owner).cancelUpkeep(id), - 'CannotCancel()', - ) - }) - - it('sets the registration to invalid in 50 blocks', async () => { - const tx = await registry.connect(admin).cancelUpkeep(id) - const receipt = await tx.wait() - const registration = await registry.getUpkeep(id) - assert.equal( - registration.maxValidBlocknumber.toNumber(), - receipt.blockNumber + 50, - ) - }) - - it('emits an event', async () => { - const tx = await registry.connect(admin).cancelUpkeep(id) - const receipt = await tx.wait() - await expect(tx) - .to.emit(registry, 'UpkeepCanceled') - .withArgs(id, BigNumber.from(receipt.blockNumber + delay)) - }) - - it('immediately prevents upkeep', async () => { - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(id, toWei('100')) - await registry.connect(admin).cancelUpkeep(id) - await registry.connect(keeper2).performUpkeep(id, '0x') // still works - - for (let i = 0; i < delay; i++) { - await ethers.provider.send('evm_mine', []) - } - - await evmRevert( - registry.connect(keeper2).performUpkeep(id, '0x'), - 'UpkeepCancelled()', - ) - }) - - describe('when an upkeep has been performed', async () => { - beforeEach(async () => { - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(id, toWei('100')) - await registry.connect(keeper1).performUpkeep(id, '0x') - }) - - it('deducts a cancellation fee from the upkeep and gives to owner', async () => { - let minUpkeepSpend = toWei('10') - await registry.connect(owner).setConfig({ - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - - const payee1Before = await linkToken.balanceOf( - await payee1.getAddress(), - ) - let upkeepBefore = (await registry.getUpkeep(id)).balance - let ownerBefore = (await registry.getState()).state.ownerLinkBalance - assert.equal(0, ownerBefore.toNumber()) - - let amountSpent = toWei('100').sub(upkeepBefore) - let cancellationFee = minUpkeepSpend.sub(amountSpent) - - await registry.connect(admin).cancelUpkeep(id) - - const payee1After = await linkToken.balanceOf( - await payee1.getAddress(), - ) - let upkeepAfter = (await registry.getUpkeep(id)).balance - let ownerAfter = (await registry.getState()).state.ownerLinkBalance - - // post upkeep balance should be previous balance minus cancellation fee - assert.isTrue(upkeepBefore.sub(cancellationFee).eq(upkeepAfter)) - // payee balance should not change - assert.isTrue(payee1Before.eq(payee1After)) - // owner should receive the cancellation fee - assert.isTrue(ownerAfter.eq(cancellationFee)) - }) - - it('deducts up to balance as cancellation fee', async () => { - // Very high min spend, should deduct whole balance as cancellation fees - let minUpkeepSpend = toWei('1000') - await registry.connect(owner).setConfig({ - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - const payee1Before = await linkToken.balanceOf( - await payee1.getAddress(), - ) - let upkeepBefore = (await registry.getUpkeep(id)).balance - let ownerBefore = (await registry.getState()).state.ownerLinkBalance - assert.equal(0, ownerBefore.toNumber()) - - await registry.connect(admin).cancelUpkeep(id) - const payee1After = await linkToken.balanceOf( - await payee1.getAddress(), - ) - let ownerAfter = (await registry.getState()).state.ownerLinkBalance - let upkeepAfter = (await registry.getUpkeep(id)).balance - - // all upkeep balance is deducted for cancellation fee - assert.equal(0, upkeepAfter.toNumber()) - // payee balance should not change - assert.isTrue(payee1After.eq(payee1Before)) - // all upkeep balance is transferred to the owner - assert.isTrue(ownerAfter.eq(upkeepBefore)) - }) - - it('does not deduct cancellation fee if more than minUpkeepSpend is spent', async () => { - // Very low min spend, already spent in one perform upkeep - let minUpkeepSpend = BigNumber.from(420) - await registry.connect(owner).setConfig({ - paymentPremiumPPB, - flatFeeMicroLink, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - const payee1Before = await linkToken.balanceOf( - await payee1.getAddress(), - ) - let upkeepBefore = (await registry.getUpkeep(id)).balance - let ownerBefore = (await registry.getState()).state.ownerLinkBalance - assert.equal(0, ownerBefore.toNumber()) - - await registry.connect(admin).cancelUpkeep(id) - const payee1After = await linkToken.balanceOf( - await payee1.getAddress(), - ) - let ownerAfter = (await registry.getState()).state.ownerLinkBalance - let upkeepAfter = (await registry.getUpkeep(id)).balance - - // upkeep does not pay cancellation fee after cancellation because minimum upkeep spent is met - assert.isTrue(upkeepBefore.eq(upkeepAfter)) - // owner balance does not change - assert.equal(0, ownerAfter.toNumber()) - // payee balance does not change - assert.isTrue(payee1Before.eq(payee1After)) - }) - }) - }) - }) - - describe('#withdrawPayment', () => { - beforeEach(async () => { - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(id, toWei('100')) - await registry.connect(keeper1).performUpkeep(id, '0x') - }) - - it('reverts if called by anyone but the payee', async () => { - await evmRevert( - registry - .connect(payee2) - .withdrawPayment( - await keeper1.getAddress(), - await nonkeeper.getAddress(), - ), - 'OnlyCallableByPayee()', - ) - }) - - it('reverts if called with the 0 address', async () => { - await evmRevert( - registry - .connect(payee2) - .withdrawPayment(await keeper1.getAddress(), zeroAddress), - 'InvalidRecipient()', - ) - }) - - it('updates the balances', async () => { - const to = await nonkeeper.getAddress() - const keeperBefore = ( - await registry.getKeeperInfo(await keeper1.getAddress()) - ).balance - const registrationBefore = (await registry.getUpkeep(id)).balance - const toLinkBefore = await linkToken.balanceOf(to) - const registryLinkBefore = await linkToken.balanceOf(registry.address) - - //// Do the thing - await registry - .connect(payee1) - .withdrawPayment(await keeper1.getAddress(), to) - - const keeperAfter = ( - await registry.getKeeperInfo(await keeper1.getAddress()) - ).balance - const registrationAfter = (await registry.getUpkeep(id)).balance - const toLinkAfter = await linkToken.balanceOf(to) - const registryLinkAfter = await linkToken.balanceOf(registry.address) - - assert.isTrue(keeperAfter.eq(BigNumber.from(0))) - assert.isTrue(registrationBefore.eq(registrationAfter)) - assert.isTrue(toLinkBefore.add(keeperBefore).eq(toLinkAfter)) - assert.isTrue(registryLinkBefore.sub(keeperBefore).eq(registryLinkAfter)) - }) - - it('emits a log announcing the withdrawal', async () => { - const balance = (await registry.getKeeperInfo(await keeper1.getAddress())) - .balance - const tx = await registry - .connect(payee1) - .withdrawPayment( - await keeper1.getAddress(), - await nonkeeper.getAddress(), - ) - await expect(tx) - .to.emit(registry, 'PaymentWithdrawn') - .withArgs( - await keeper1.getAddress(), - balance, - await nonkeeper.getAddress(), - await payee1.getAddress(), - ) - }) - }) - - describe('#transferPayeeship', () => { - it('reverts when called by anyone but the current payee', async () => { - await evmRevert( - registry - .connect(payee2) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ), - 'OnlyCallableByPayee()', - ) - }) - - it('reverts when transferring to self', async () => { - await evmRevert( - registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee1.getAddress(), - ), - 'ValueNotChanged()', - ) - }) - - it('does not change the payee', async () => { - await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - - const info = await registry.getKeeperInfo(await keeper1.getAddress()) - assert.equal(await payee1.getAddress(), info.payee) - }) - - it('emits an event announcing the new payee', async () => { - const tx = await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - await expect(tx) - .to.emit(registry, 'PayeeshipTransferRequested') - .withArgs( - await keeper1.getAddress(), - await payee1.getAddress(), - await payee2.getAddress(), - ) - }) - - it('does not emit an event when called with the same proposal', async () => { - await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - - const tx = await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - const receipt = await tx.wait() - assert.equal(0, receipt.logs.length) - }) - }) - - describe('#acceptPayeeship', () => { - beforeEach(async () => { - await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - }) - - it('reverts when called by anyone but the proposed payee', async () => { - await evmRevert( - registry.connect(payee1).acceptPayeeship(await keeper1.getAddress()), - 'OnlyCallableByProposedPayee()', - ) - }) - - it('emits an event announcing the new payee', async () => { - const tx = await registry - .connect(payee2) - .acceptPayeeship(await keeper1.getAddress()) - await expect(tx) - .to.emit(registry, 'PayeeshipTransferred') - .withArgs( - await keeper1.getAddress(), - await payee1.getAddress(), - await payee2.getAddress(), - ) - }) - - it('does change the payee', async () => { - await registry.connect(payee2).acceptPayeeship(await keeper1.getAddress()) - - const info = await registry.getKeeperInfo(await keeper1.getAddress()) - assert.equal(await payee2.getAddress(), info.payee) - }) - }) - - describe('#transferUpkeepAdmin', () => { - beforeEach(async () => { - const tx = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - ) - id = await getUpkeepID(tx) - }) - - it('reverts when called by anyone but the current upkeep admin', async () => { - await evmRevert( - registry - .connect(payee1) - .transferUpkeepAdmin(id, await payee2.getAddress()), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts when transferring to self', async () => { - await evmRevert( - registry - .connect(admin) - .transferUpkeepAdmin(id, await admin.getAddress()), - 'ValueNotChanged()', - ) - }) - - it('reverts when the upkeep is cancelled', async () => { - await registry.connect(admin).cancelUpkeep(id) - - await evmRevert( - registry - .connect(admin) - .transferUpkeepAdmin(id, await keeper1.getAddress()), - 'UpkeepCancelled()', - ) - }) - - it('reverts when transferring to zero address', async () => { - await evmRevert( - registry - .connect(admin) - .transferUpkeepAdmin(id, ethers.constants.AddressZero), - 'InvalidRecipient()', - ) - }) - - it('does not change the upkeep admin', async () => { - await registry - .connect(admin) - .transferUpkeepAdmin(id, await payee1.getAddress()) - - const upkeep = await registry.getUpkeep(id) - assert.equal(await admin.getAddress(), upkeep.admin) - }) - - it('emits an event announcing the new upkeep admin', async () => { - const tx = await registry - .connect(admin) - .transferUpkeepAdmin(id, await payee1.getAddress()) - - await expect(tx) - .to.emit(registry, 'UpkeepAdminTransferRequested') - .withArgs(id, await admin.getAddress(), await payee1.getAddress()) - }) - - it('does not emit an event when called with the same proposed upkeep admin', async () => { - await registry - .connect(admin) - .transferUpkeepAdmin(id, await payee1.getAddress()) - - const tx = await registry - .connect(admin) - .transferUpkeepAdmin(id, await payee1.getAddress()) - const receipt = await tx.wait() - assert.equal(0, receipt.logs.length) - }) - }) - - describe('#acceptUpkeepAdmin', () => { - beforeEach(async () => { - await registry - .connect(admin) - .transferUpkeepAdmin(id, await payee1.getAddress()) - }) - - it('reverts when not called by the proposed upkeep admin', async () => { - await evmRevert( - registry.connect(payee2).acceptUpkeepAdmin(id), - 'OnlyCallableByProposedAdmin()', - ) - }) - - it('reverts when the upkeep is cancelled', async () => { - await registry.connect(admin).cancelUpkeep(id) - - await evmRevert( - registry.connect(payee1).acceptUpkeepAdmin(id), - 'UpkeepCancelled()', - ) - }) - - it('emits an event announcing the new upkeep admin', async () => { - const tx = await registry.connect(payee1).acceptUpkeepAdmin(id) - await expect(tx) - .to.emit(registry, 'UpkeepAdminTransferred') - .withArgs(id, await admin.getAddress(), await payee1.getAddress()) - }) - - it('does change the payee', async () => { - await registry.connect(payee1).acceptUpkeepAdmin(id) - - const upkeep = await registry.getUpkeep(id) - assert.equal(await payee1.getAddress(), upkeep.admin) - }) - }) - - describe('#setConfig', () => { - const payment = BigNumber.from(1) - const flatFee = BigNumber.from(2) - const checks = BigNumber.from(3) - const staleness = BigNumber.from(4) - const ceiling = BigNumber.from(5) - const maxGas = BigNumber.from(6) - const fbGasEth = BigNumber.from(7) - const fbLinkEth = BigNumber.from(8) - - it('reverts when called by anyone but the proposed owner', async () => { - await evmRevert( - registry.connect(payee1).setConfig({ - paymentPremiumPPB: payment, - flatFeeMicroLink: flatFee, - blockCountPerTurn: checks, - checkGasLimit: maxGas, - stalenessSeconds: staleness, - gasCeilingMultiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice: fbGasEth, - fallbackLinkPrice: fbLinkEth, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }), - 'Only callable by owner', - ) - }) - - it('updates the config', async () => { - const old = (await registry.getState()).config - assert.isTrue(paymentPremiumPPB.eq(old.paymentPremiumPPB)) - assert.isTrue(flatFeeMicroLink.eq(old.flatFeeMicroLink)) - assert.isTrue(blockCountPerTurn.eq(old.blockCountPerTurn)) - assert.isTrue(stalenessSeconds.eq(old.stalenessSeconds)) - assert.isTrue(gasCeilingMultiplier.eq(old.gasCeilingMultiplier)) - - await registry.connect(owner).setConfig({ - paymentPremiumPPB: payment, - flatFeeMicroLink: flatFee, - blockCountPerTurn: checks, - checkGasLimit: maxGas, - stalenessSeconds: staleness, - gasCeilingMultiplier: ceiling, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice: fbGasEth, - fallbackLinkPrice: fbLinkEth, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - - const updated = (await registry.getState()).config - assert.equal(updated.paymentPremiumPPB, payment.toNumber()) - assert.equal(updated.flatFeeMicroLink, flatFee.toNumber()) - assert.equal(updated.blockCountPerTurn, checks.toNumber()) - assert.equal(updated.stalenessSeconds, staleness.toNumber()) - assert.equal(updated.gasCeilingMultiplier, ceiling.toNumber()) - assert.equal(updated.checkGasLimit, maxGas.toNumber()) - assert.equal(updated.fallbackGasPrice.toNumber(), fbGasEth.toNumber()) - assert.equal(updated.fallbackLinkPrice.toNumber(), fbLinkEth.toNumber()) - }) - - it('emits an event', async () => { - const tx = await registry.connect(owner).setConfig({ - paymentPremiumPPB: payment, - flatFeeMicroLink: flatFee, - blockCountPerTurn: checks, - checkGasLimit: maxGas, - stalenessSeconds: staleness, - gasCeilingMultiplier: ceiling, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice: fbGasEth, - fallbackLinkPrice: fbLinkEth, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - await expect(tx) - .to.emit(registry, 'ConfigSet') - .withArgs([ - payment, - flatFee, - checks, - maxGas, - staleness, - ceiling, - minUpkeepSpend, - maxPerformGas, - fbGasEth, - fbLinkEth, - ]) - }) - }) - - describe('#onTokenTransfer', () => { - const amount = toWei('1') - - it('reverts if not called by the LINK token', async () => { - const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [id]) - - await evmRevert( - registry - .connect(keeper1) - .onTokenTransfer(await keeper1.getAddress(), amount, data), - 'OnlyCallableByLINKToken()', - ) - }) - - it('reverts if not called with more or less than 32 bytes', async () => { - const longData = ethers.utils.defaultAbiCoder.encode( - ['uint256', 'uint256'], - ['33', '34'], - ) - const shortData = '0x12345678' - - await evmRevert( - linkToken - .connect(owner) - .transferAndCall(registry.address, amount, longData), - ) - await evmRevert( - linkToken - .connect(owner) - .transferAndCall(registry.address, amount, shortData), - ) - }) - - it('reverts if the upkeep is canceled', async () => { - await registry.connect(admin).cancelUpkeep(id) - await evmRevert( - registry.connect(keeper1).addFunds(id, amount), - 'UpkeepCancelled()', - ) - }) - - it('updates the funds of the job id passed', async () => { - const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [id]) - - const before = (await registry.getUpkeep(id)).balance - await linkToken - .connect(owner) - .transferAndCall(registry.address, amount, data) - const after = (await registry.getUpkeep(id)).balance - - assert.isTrue(before.add(amount).eq(after)) - }) - }) - - describe('#recoverFunds', () => { - const sent = toWei('7') - - beforeEach(async () => { - await linkToken.connect(keeper1).approve(registry.address, toWei('100')) - - // add funds to upkeep 1 and perform and withdraw some payment - const tx = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - ) - const id1 = await getUpkeepID(tx) - await registry.connect(keeper1).addFunds(id1, toWei('5')) - await registry.connect(keeper1).performUpkeep(id1, '0x') - await registry.connect(keeper2).performUpkeep(id1, '0x') - await registry.connect(keeper3).performUpkeep(id1, '0x') - await registry - .connect(payee1) - .withdrawPayment( - await keeper1.getAddress(), - await nonkeeper.getAddress(), - ) - - // transfer funds directly to the registry - await linkToken.connect(keeper1).transfer(registry.address, sent) - - // add funds to upkeep 2 and perform and withdraw some payment - const tx2 = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - ) - const id2 = await getUpkeepID(tx2) - await registry.connect(keeper1).addFunds(id2, toWei('5')) - await registry.connect(keeper1).performUpkeep(id2, '0x') - await registry.connect(keeper2).performUpkeep(id2, '0x') - await registry.connect(keeper3).performUpkeep(id2, '0x') - await registry - .connect(payee2) - .withdrawPayment( - await keeper2.getAddress(), - await nonkeeper.getAddress(), - ) - - // transfer funds using onTokenTransfer - const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [id2]) - await linkToken - .connect(owner) - .transferAndCall(registry.address, toWei('1'), data) - - // remove a keeper - await registry - .connect(owner) - .setKeepers( - [await keeper1.getAddress(), await keeper2.getAddress()], - [await payee1.getAddress(), await payee2.getAddress()], - ) - - // withdraw some funds - await registry.connect(owner).cancelUpkeep(id1) - await registry.connect(admin).withdrawFunds(id1, await admin.getAddress()) - }) - - it('reverts if not called by owner', async () => { - await evmRevert( - registry.connect(keeper1).recoverFunds(), - 'Only callable by owner', - ) - }) - - it('allows any funds that have been accidentally transfered to be moved', async () => { - const balanceBefore = await linkToken.balanceOf(registry.address) - - await linkToken.balanceOf(registry.address) - - await registry.connect(owner).recoverFunds() - const balanceAfter = await linkToken.balanceOf(registry.address) - assert.isTrue(balanceBefore.eq(balanceAfter.add(sent))) - }) - }) - - describe('#pause', () => { - it('reverts if called by a non-owner', async () => { - await evmRevert( - registry.connect(keeper1).pause(), - 'Only callable by owner', - ) - }) - - it('marks the contract as paused', async () => { - assert.isFalse(await registry.paused()) - - await registry.connect(owner).pause() - - assert.isTrue(await registry.paused()) - }) - }) - - describe('#unpause', () => { - beforeEach(async () => { - await registry.connect(owner).pause() - }) - - it('reverts if called by a non-owner', async () => { - await evmRevert( - registry.connect(keeper1).unpause(), - 'Only callable by owner', - ) - }) - - it('marks the contract as not paused', async () => { - assert.isTrue(await registry.paused()) - - await registry.connect(owner).unpause() - - assert.isFalse(await registry.paused()) - }) - }) - - describe('#getMaxPaymentForGas', () => { - const gasAmounts = [100000, 10000000] - const premiums = [0, 250000000] - const flatFees = [0, 1000000] - it('calculates the max fee appropriately', async () => { - const registryLogicL1 = await keeperRegistryLogicFactory - .connect(owner) - .deploy( - 0, - registryGasOverhead, - linkToken.address, - linkEthFeed.address, - gasPriceFeed.address, - ) - await verifyMaxPayment(registryLogicL1, gasAmounts, premiums, flatFees) - }) - - it('calculates the max fee appropriately for Arbitrum', async () => { - const registryLogicArb = await keeperRegistryLogicFactory - .connect(owner) - .deploy( - 1, - registryGasOverhead, - linkToken.address, - linkEthFeed.address, - gasPriceFeed.address, - ) - await verifyMaxPayment( - registryLogicArb, - gasAmounts, - premiums, - flatFees, - l1CostWeiArb, - ) - }) - - it('calculates the max fee appropriately for Optimism', async () => { - const registryLogicOpt = await keeperRegistryLogicFactory - .connect(owner) - .deploy( - 2, - registryGasOverhead, - linkToken.address, - linkEthFeed.address, - gasPriceFeed.address, - ) - await verifyMaxPayment( - registryLogicOpt, - gasAmounts, - premiums, - flatFees, - l1CostWeiOpt, - ) - }) - }) - - describe('#setPeerRegistryMigrationPermission() / #getPeerRegistryMigrationPermission()', () => { - const peer = randomAddress() - it('allows the owner to set the peer registries', async () => { - let permission = await registry.getPeerRegistryMigrationPermission(peer) - expect(permission).to.equal(0) - await registry.setPeerRegistryMigrationPermission(peer, 1) - permission = await registry.getPeerRegistryMigrationPermission(peer) - expect(permission).to.equal(1) - await registry.setPeerRegistryMigrationPermission(peer, 2) - permission = await registry.getPeerRegistryMigrationPermission(peer) - expect(permission).to.equal(2) - await registry.setPeerRegistryMigrationPermission(peer, 0) - permission = await registry.getPeerRegistryMigrationPermission(peer) - expect(permission).to.equal(0) - }) - it('reverts if passed an unsupported permission', async () => { - await expect( - registry.connect(admin).setPeerRegistryMigrationPermission(peer, 10), - ).to.be.reverted - }) - it('reverts if not called by the owner', async () => { - await expect( - registry.connect(admin).setPeerRegistryMigrationPermission(peer, 1), - ).to.be.revertedWith('Only callable by owner') - }) - }) - - describe('migrateUpkeeps() / #receiveUpkeeps()', async () => { - context('when permissions are set', () => { - beforeEach(async () => { - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(id, toWei('100')) - await registry.setPeerRegistryMigrationPermission(registry2.address, 1) - await registry2.setPeerRegistryMigrationPermission(registry.address, 2) - }) - - it('migrates an upkeep', async () => { - expect((await registry.getUpkeep(id)).balance).to.equal(toWei('100')) - expect((await registry.getUpkeep(id)).checkData).to.equal(randomBytes) - expect((await registry.getState()).state.numUpkeeps).to.equal(1) - await registry - .connect(admin) - .transferUpkeepAdmin(id, await payee1.getAddress()) - - // migrate - await registry.connect(admin).migrateUpkeeps([id], registry2.address) - expect((await registry.getState()).state.numUpkeeps).to.equal(0) - expect((await registry2.getState()).state.numUpkeeps).to.equal(1) - expect((await registry.getUpkeep(id)).balance).to.equal(0) - expect((await registry.getUpkeep(id)).checkData).to.equal('0x') - expect((await registry2.getUpkeep(id)).balance).to.equal(toWei('100')) - expect((await registry2.getState()).state.expectedLinkBalance).to.equal( - toWei('100'), - ) - expect((await registry2.getUpkeep(id)).checkData).to.equal(randomBytes) - // migration will delete the upkeep and nullify admin transfer - await expect( - registry.connect(payee1).acceptUpkeepAdmin(id), - ).to.be.revertedWith('UpkeepCancelled()') - await expect( - registry2.connect(payee1).acceptUpkeepAdmin(id), - ).to.be.revertedWith('OnlyCallableByProposedAdmin()') - }) - - it('migrates a paused upkeep', async () => { - expect((await registry.getUpkeep(id)).balance).to.equal(toWei('100')) - expect((await registry.getUpkeep(id)).checkData).to.equal(randomBytes) - expect((await registry.getState()).state.numUpkeeps).to.equal(1) - await registry.connect(admin).pauseUpkeep(id) - // verify the upkeep is paused - expect((await registry.getUpkeep(id)).paused).to.equal(true) - // migrate - await registry.connect(admin).migrateUpkeeps([id], registry2.address) - expect((await registry.getState()).state.numUpkeeps).to.equal(0) - expect((await registry2.getState()).state.numUpkeeps).to.equal(1) - expect((await registry.getUpkeep(id)).balance).to.equal(0) - expect((await registry2.getUpkeep(id)).balance).to.equal(toWei('100')) - expect((await registry.getUpkeep(id)).checkData).to.equal('0x') - expect((await registry2.getUpkeep(id)).checkData).to.equal(randomBytes) - expect((await registry2.getState()).state.expectedLinkBalance).to.equal( - toWei('100'), - ) - // verify the upkeep is still paused after migration - expect((await registry2.getUpkeep(id)).paused).to.equal(true) - }) - - it('emits an event on both contracts', async () => { - expect((await registry.getUpkeep(id)).balance).to.equal(toWei('100')) - expect((await registry.getUpkeep(id)).checkData).to.equal(randomBytes) - expect((await registry.getState()).state.numUpkeeps).to.equal(1) - const tx = registry - .connect(admin) - .migrateUpkeeps([id], registry2.address) - await expect(tx) - .to.emit(registry, 'UpkeepMigrated') - .withArgs(id, toWei('100'), registry2.address) - await expect(tx) - .to.emit(registry2, 'UpkeepReceived') - .withArgs(id, toWei('100'), registry.address) - }) - it('is only migratable by the admin', async () => { - await expect( - registry.connect(owner).migrateUpkeeps([id], registry2.address), - ).to.be.revertedWith('OnlyCallableByAdmin()') - await registry.connect(admin).migrateUpkeeps([id], registry2.address) - }) - }) - - context('when permissions are not set', () => { - it('reverts', async () => { - // no permissions - await registry.setPeerRegistryMigrationPermission(registry2.address, 0) - await registry2.setPeerRegistryMigrationPermission(registry.address, 0) - await expect(registry.migrateUpkeeps([id], registry2.address)).to.be - .reverted - // only outgoing permissions - await registry.setPeerRegistryMigrationPermission(registry2.address, 1) - await registry2.setPeerRegistryMigrationPermission(registry.address, 0) - await expect(registry.migrateUpkeeps([id], registry2.address)).to.be - .reverted - // only incoming permissions - await registry.setPeerRegistryMigrationPermission(registry2.address, 0) - await registry2.setPeerRegistryMigrationPermission(registry.address, 2) - await expect(registry.migrateUpkeeps([id], registry2.address)).to.be - .reverted - // permissions opposite direction - await registry.setPeerRegistryMigrationPermission(registry2.address, 2) - await registry2.setPeerRegistryMigrationPermission(registry.address, 1) - await expect(registry.migrateUpkeeps([id], registry2.address)).to.be - .reverted - }) - }) - }) - - describe('#checkUpkeep / #performUpkeep', () => { - const performData = '0xc0ffeec0ffee' - const multiplier = BigNumber.from(10) - const flatFee = BigNumber.from('100000') //0.1 LINK - const callGasPrice = 1 - - it('uses the same minimum balance calculation [ @skip-coverage ]', async () => { - await registry.connect(owner).setConfig({ - paymentPremiumPPB, - flatFeeMicroLink: flatFee, - blockCountPerTurn, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier: multiplier, - minUpkeepSpend, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }) - await linkToken.connect(owner).approve(registry.address, toWei('100')) - - const tx1 = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - ) - const upkeepID1 = await getUpkeepID(tx1) - const tx2 = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - ) - const upkeepID2 = await getUpkeepID(tx2) - await mock.setCanCheck(true) - await mock.setCanPerform(true) - // upkeep 1 is underfunded, 2 is funded - const minBalance1 = (await registry.getMaxPaymentForGas(executeGas)).sub( - 1, - ) - const minBalance2 = await registry.getMaxPaymentForGas(executeGas) - await registry.connect(owner).addFunds(upkeepID1, minBalance1) - await registry.connect(owner).addFunds(upkeepID2, minBalance2) - // upkeep 1 check should revert, 2 should succeed - await evmRevert( - registry - .connect(zeroAddress) - .callStatic.checkUpkeep(upkeepID1, await keeper1.getAddress(), { - gasPrice: callGasPrice, - }), - ) - await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(upkeepID2, await keeper1.getAddress(), { - gasPrice: callGasPrice, - }) - // upkeep 1 perform should revert, 2 should succeed - await evmRevert( - registry - .connect(keeper1) - .performUpkeep(upkeepID1, performData, { gasLimit: extraGas }), - 'InsufficientFunds()', - ) - await registry - .connect(keeper1) - .performUpkeep(upkeepID2, performData, { gasLimit: extraGas }) - }) - }) - - describe('#getMinBalanceForUpkeep / #checkUpkeep', () => { - it('calculates the minimum balance appropriately', async () => { - const oneWei = BigNumber.from('1') - await linkToken.connect(keeper1).approve(registry.address, toWei('100')) - await mock.setCanCheck(true) - await mock.setCanPerform(true) - const minBalance = await registry.getMinBalanceForUpkeep(id) - const tooLow = minBalance.sub(oneWei) - await registry.connect(keeper1).addFunds(id, tooLow) - await evmRevert( - registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress()), - 'InsufficientFunds()', - ) - await registry.connect(keeper1).addFunds(id, oneWei) - await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(id, await keeper1.getAddress()) - }) - }) -}) diff --git a/contracts/test/v0.8/automation/KeeperRegistry2_0.test.ts b/contracts/test/v0.8/automation/KeeperRegistry2_0.test.ts deleted file mode 100644 index 9886e84854b..00000000000 --- a/contracts/test/v0.8/automation/KeeperRegistry2_0.test.ts +++ /dev/null @@ -1,4802 +0,0 @@ -import { ethers } from 'hardhat' -import { assert, expect } from 'chai' -import { BigNumber, Signer, Wallet } from 'ethers' -import { evmRevert } from '../../test-helpers/matchers' -import { getUsers, Personas } from '../../test-helpers/setup' -import { toWei } from '../../test-helpers/helpers' -import { LinkToken__factory as LinkTokenFactory } from '../../../typechain/factories/LinkToken__factory' -import { MockV3Aggregator__factory as MockV3AggregatorFactory } from '../../../typechain/factories/MockV3Aggregator__factory' -import { UpkeepMock__factory as UpkeepMockFactory } from '../../../typechain/factories/UpkeepMock__factory' -import { UpkeepAutoFunder__factory as UpkeepAutoFunderFactory } from '../../../typechain/factories/UpkeepAutoFunder__factory' -import { UpkeepTranscoder__factory as UpkeepTranscoderFactory } from '../../../typechain/factories/UpkeepTranscoder__factory' -import { KeeperRegistry2_0__factory as KeeperRegistryFactory } from '../../../typechain/factories/KeeperRegistry2_0__factory' -import { MockArbGasInfo__factory as MockArbGasInfoFactory } from '../../../typechain/factories/MockArbGasInfo__factory' -import { MockOVMGasPriceOracle__factory as MockOVMGasPriceOracleFactory } from '../../../typechain/factories/MockOVMGasPriceOracle__factory' -import { KeeperRegistryLogic2_0__factory as KeeperRegistryLogicFactory } from '../../../typechain/factories/KeeperRegistryLogic2_0__factory' -import { MockArbSys__factory as MockArbSysFactory } from '../../../typechain/factories/MockArbSys__factory' -import { KeeperRegistry2_0 as KeeperRegistry } from '../../../typechain/KeeperRegistry2_0' -import { KeeperRegistryLogic20 as KeeperRegistryLogic } from '../../../typechain/KeeperRegistryLogic20' -import { MockV3Aggregator } from '../../../typechain/MockV3Aggregator' -import { LinkToken } from '../../../typechain/LinkToken' -import { UpkeepMock } from '../../../typechain/UpkeepMock' -import { MockArbGasInfo } from '../../../typechain/MockArbGasInfo' -import { MockOVMGasPriceOracle } from '../../../typechain/MockOVMGasPriceOracle' -import { UpkeepTranscoder } from '../../../typechain/UpkeepTranscoder' - -////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////// - -/*********************************** REGISTRY v2.0 IS FROZEN ************************************/ - -// All tests are disabled for this contract, as we expect it to never change in the future. -// Instead, we test that the bytecode for the contract has not changed. -// If this test ever fails, you should remove it and then re-run the original test suite. - -const BYTECODE = KeeperRegistryFactory.bytecode -const BYTECODE_CHECKSUM = - '0x60660453a335cdcd42b5aa64e58a8c04517e8a8645d2618b51a7552df6e2973b' - -describe('KeeperRegistry2_0 - Frozen [ @skip-coverage ]', () => { - it('has not changed', () => { - assert.equal(ethers.utils.id(BYTECODE), BYTECODE_CHECKSUM) - }) -}) - -////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////////////////////////// - -// copied from AutomationRegistryInterface2_0.sol -enum UpkeepFailureReason { - NONE, - UPKEEP_CANCELLED, - UPKEEP_PAUSED, - TARGET_CHECK_REVERTED, - UPKEEP_NOT_NEEDED, - PERFORM_DATA_EXCEEDS_LIMIT, - INSUFFICIENT_BALANCE, -} - -// copied from AutomationRegistryInterface2_0.sol -enum Mode { - DEFAULT, - ARBITRUM, - OPTIMISM, -} - -async function getUpkeepID(tx: any) { - const receipt = await tx.wait() - return receipt.events[0].args.id -} - -function randomAddress() { - return ethers.Wallet.createRandom().address -} - -// ----------------------------------------------------------------------------------------------- -// These are the gas overheads that off chain systems should provide to check upkeep / transmit -// These overheads are not actually charged for -const transmitGasOverhead = BigNumber.from(800000) -const checkGasOverhead = BigNumber.from(400000) - -// These values should match the constants declared in registry -const registryGasOverhead = BigNumber.from(70_000) -const registryPerSignerGasOverhead = BigNumber.from(7500) -const registryPerPerformByteGasOverhead = BigNumber.from(20) -const cancellationDelay = 50 - -// This is the margin for gas that we test for. Gas charged should always be greater -// than total gas used in tx but should not increase beyond this margin -const gasCalculationMargin = BigNumber.from(4000) -// ----------------------------------------------------------------------------------------------- - -// Smart contract factories -let linkTokenFactory: LinkTokenFactory -let mockV3AggregatorFactory: MockV3AggregatorFactory -let keeperRegistryFactory: KeeperRegistryFactory -let keeperRegistryLogicFactory: KeeperRegistryLogicFactory -let upkeepMockFactory: UpkeepMockFactory -let upkeepAutoFunderFactory: UpkeepAutoFunderFactory -let upkeepTranscoderFactory: UpkeepTranscoderFactory -let mockArbGasInfoFactory: MockArbGasInfoFactory -let mockOVMGasPriceOracleFactory: MockOVMGasPriceOracleFactory -let personas: Personas - -const encodeConfig = (config: any) => { - return ethers.utils.defaultAbiCoder.encode( - [ - 'tuple(uint32 paymentPremiumPPB,uint32 flatFeeMicroLink,uint32 checkGasLimit,uint24 stalenessSeconds\ - ,uint16 gasCeilingMultiplier,uint96 minUpkeepSpend,uint32 maxPerformGas,uint32 maxCheckDataSize,\ - uint32 maxPerformDataSize,uint256 fallbackGasPrice,uint256 fallbackLinkPrice,address transcoder,\ - address registrar)', - ], - [config], - ) -} - -const linkEth = BigNumber.from(5000000000000000) // 1 Link = 0.005 Eth -const gasWei = BigNumber.from(1000000000) // 1 gwei -const encodeReport = ( - upkeeps: any, - gasWeiReport = gasWei, - linkEthReport = linkEth, -) => { - const upkeepIds = upkeeps.map((u: any) => u.Id) - const performDataTuples = upkeeps.map((u: any) => [ - u.checkBlockNum, - u.checkBlockHash, - u.performData, - ]) - return ethers.utils.defaultAbiCoder.encode( - ['uint256', 'uint256', 'uint256[]', 'tuple(uint32,bytes32,bytes)[]'], - [gasWeiReport, linkEthReport, upkeepIds, performDataTuples], - ) -} - -const encodeLatestBlockReport = async (upkeeps: any) => { - const latestBlock = await ethers.provider.getBlock('latest') - for (let i = 0; i < upkeeps.length; i++) { - upkeeps[i].checkBlockNum = latestBlock.number - upkeeps[i].checkBlockHash = latestBlock.hash - upkeeps[i].performData = '0x' - } - return encodeReport(upkeeps) -} - -const signReport = ( - reportContext: string[], - report: any, - signers: Wallet[], -) => { - const reportDigest = ethers.utils.keccak256(report) - const packedArgs = ethers.utils.solidityPack( - ['bytes32', 'bytes32[3]'], - [reportDigest, reportContext], - ) - const packedDigest = ethers.utils.keccak256(packedArgs) - - const signatures = [] - for (const signer of signers) { - signatures.push(signer._signingKey().signDigest(packedDigest)) - } - const vs = signatures.map((i) => '0' + (i.v - 27).toString(16)).join('') - return { - vs: '0x' + vs.padEnd(64, '0'), - rs: signatures.map((i) => i.r), - ss: signatures.map((i) => i.s), - } -} - -const parseUpkeepPerformedLogs = (receipt: any) => { - const upkeepPerformedABI = [ - 'event UpkeepPerformed(uint256 indexed id,bool indexed success, \ - uint32 checkBlockNumber,uint256 gasUsed,uint256 gasOverhead,uint96 totalPayment)', - ] - const iface = new ethers.utils.Interface(upkeepPerformedABI) - - const parsedLogs = [] - for (let i = 0; i < receipt.logs.length; i++) { - const log = receipt.logs[i] - try { - parsedLogs.push(iface.parseLog(log)) - } catch (e) { - // ignore log - } - } - return parsedLogs -} - -const parseReorgedUpkeepReportLogs = (receipt: any) => { - const logABI = [' event ReorgedUpkeepReport(uint256 indexed id)'] - const iface = new ethers.utils.Interface(logABI) - - const parsedLogs = [] - for (let i = 0; i < receipt.logs.length; i++) { - const log = receipt.logs[i] - try { - parsedLogs.push(iface.parseLog(log)) - } catch (e) { - // ignore log - } - } - return parsedLogs -} - -const parseStaleUpkeepReportLogs = (receipt: any) => { - const logABI = [' event StaleUpkeepReport(uint256 indexed id)'] - const iface = new ethers.utils.Interface(logABI) - - const parsedLogs = [] - for (let i = 0; i < receipt.logs.length; i++) { - const log = receipt.logs[i] - try { - parsedLogs.push(iface.parseLog(log)) - } catch (e) { - // ignore log - } - } - return parsedLogs -} - -const parseInsufficientFundsUpkeepReportLogs = (receipt: any) => { - const logABI = [' event InsufficientFundsUpkeepReport(uint256 indexed id)'] - const iface = new ethers.utils.Interface(logABI) - - const parsedLogs = [] - for (let i = 0; i < receipt.logs.length; i++) { - const log = receipt.logs[i] - try { - parsedLogs.push(iface.parseLog(log)) - } catch (e) { - // ignore log - } - } - return parsedLogs -} - -const parseCancelledUpkeepReportLogs = (receipt: any) => { - const logABI = [' event CancelledUpkeepReport(uint256 indexed id)'] - const iface = new ethers.utils.Interface(logABI) - - const parsedLogs = [] - for (let i = 0; i < receipt.logs.length; i++) { - const log = receipt.logs[i] - try { - parsedLogs.push(iface.parseLog(log)) - } catch (e) { - // ignore log - } - } - return parsedLogs -} - -before(async () => { - personas = (await getUsers()).personas - - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', - ) - // need full path because there are two contracts with name MockV3Aggregator - mockV3AggregatorFactory = (await ethers.getContractFactory( - 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', - )) as unknown as MockV3AggregatorFactory - keeperRegistryFactory = (await ethers.getContractFactory( - 'KeeperRegistry2_0', - )) as unknown as KeeperRegistryFactory // bug in typechain requires force casting - keeperRegistryLogicFactory = (await ethers.getContractFactory( - 'KeeperRegistryLogic2_0', - )) as unknown as KeeperRegistryLogicFactory // bug in typechain requires force casting - upkeepMockFactory = await ethers.getContractFactory('UpkeepMock') - upkeepAutoFunderFactory = await ethers.getContractFactory('UpkeepAutoFunder') - upkeepTranscoderFactory = await ethers.getContractFactory('UpkeepTranscoder') - mockArbGasInfoFactory = await ethers.getContractFactory('MockArbGasInfo') - mockOVMGasPriceOracleFactory = await ethers.getContractFactory( - 'MockOVMGasPriceOracle', - ) -}) - -describe.skip('KeeperRegistry2_0', () => { - const linkDivisibility = BigNumber.from('1000000000000000000') - const executeGas = BigNumber.from('1000000') - const paymentPremiumBase = BigNumber.from('1000000000') - const paymentPremiumPPB = BigNumber.from('250000000') - const flatFeeMicroLink = BigNumber.from(0) - - const randomBytes = '0x1234abcd' - const emptyBytes = '0x' - const emptyBytes32 = - '0x0000000000000000000000000000000000000000000000000000000000000000' - - const stalenessSeconds = BigNumber.from(43820) - const gasCeilingMultiplier = BigNumber.from(2) - const checkGasLimit = BigNumber.from(10000000) - const fallbackGasPrice = gasWei.mul(BigNumber.from('2')) - const fallbackLinkPrice = linkEth.div(BigNumber.from('2')) - const maxCheckDataSize = BigNumber.from(1000) - const maxPerformDataSize = BigNumber.from(1000) - const maxPerformGas = BigNumber.from(5000000) - const minUpkeepSpend = BigNumber.from(0) - const f = 1 - const offchainVersion = 1 - const offchainBytes = '0x' - const zeroAddress = ethers.constants.AddressZero - const epochAndRound5_1 = - '0x0000000000000000000000000000000000000000000000000000000000000501' - - let owner: Signer - let keeper1: Signer - let keeper2: Signer - let keeper3: Signer - let keeper4: Signer - let keeper5: Signer - let nonkeeper: Signer - let signer1: Wallet - let signer2: Wallet - let signer3: Wallet - let signer4: Wallet - let signer5: Wallet - let admin: Signer - let payee1: Signer - let payee2: Signer - let payee3: Signer - let payee4: Signer - let payee5: Signer - - let linkToken: LinkToken - let linkEthFeed: MockV3Aggregator - let gasPriceFeed: MockV3Aggregator - let registry: KeeperRegistry - let registryLogic: KeeperRegistryLogic - let mock: UpkeepMock - let transcoder: UpkeepTranscoder - let mockArbGasInfo: MockArbGasInfo - let mockOVMGasPriceOracle: MockOVMGasPriceOracle - - let upkeepId: BigNumber - let keeperAddresses: string[] - let payees: string[] - let signers: Wallet[] - let signerAddresses: string[] - let config: any - - const linkForGas = ( - upkeepGasSpent: BigNumber, - gasOverhead: BigNumber, - gasMultiplier: BigNumber, - premiumPPB: BigNumber, - flatFee: BigNumber, - l1CostWei?: BigNumber, - numUpkeepsBatch?: BigNumber, - ) => { - l1CostWei = l1CostWei === undefined ? BigNumber.from(0) : l1CostWei - numUpkeepsBatch = - numUpkeepsBatch === undefined ? BigNumber.from(1) : numUpkeepsBatch - - const gasSpent = gasOverhead.add(BigNumber.from(upkeepGasSpent)) - const base = gasWei - .mul(gasMultiplier) - .mul(gasSpent) - .mul(linkDivisibility) - .div(linkEth) - const l1Fee = l1CostWei - .mul(gasMultiplier) - .div(numUpkeepsBatch) - .mul(linkDivisibility) - .div(linkEth) - const gasPayment = base.add(l1Fee) - - const premium = gasWei - .mul(gasMultiplier) - .mul(upkeepGasSpent) - .add(l1CostWei.mul(gasMultiplier).div(numUpkeepsBatch)) - .mul(linkDivisibility) - .div(linkEth) - .mul(premiumPPB) - .div(paymentPremiumBase) - .add(BigNumber.from(flatFee).mul('1000000000000')) - - return { - total: gasPayment.add(premium), - gasPaymemnt: gasPayment, - premium, - } - } - - const verifyMaxPayment = async ( - mode: number, - multipliers: BigNumber[], - gasAmounts: number[], - premiums: number[], - flatFees: number[], - l1CostWei?: BigNumber, - ) => { - const config = { - paymentPremiumPPB, - flatFeeMicroLink, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxCheckDataSize, - maxPerformDataSize, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - } - - // Deploy a new registry since we change payment model - const registryLogic = await keeperRegistryLogicFactory - .connect(owner) - .deploy( - mode, - linkToken.address, - linkEthFeed.address, - gasPriceFeed.address, - ) - // Deploy a new registry since we change payment model - const registry = await keeperRegistryFactory - .connect(owner) - .deploy(registryLogic.address) - await registry - .connect(owner) - .setConfig( - signerAddresses, - keeperAddresses, - f, - encodeConfig(config), - offchainVersion, - offchainBytes, - ) - - const fPlusOne = BigNumber.from(f + 1) - const totalGasOverhead = registryGasOverhead - .add(registryPerSignerGasOverhead.mul(fPlusOne)) - .add(registryPerPerformByteGasOverhead.mul(maxPerformDataSize)) - - for (let idx = 0; idx < gasAmounts.length; idx++) { - const gas = gasAmounts[idx] - for (let jdx = 0; jdx < premiums.length; jdx++) { - const premium = premiums[jdx] - for (let kdx = 0; kdx < flatFees.length; kdx++) { - const flatFee = flatFees[kdx] - for (let ldx = 0; ldx < multipliers.length; ldx++) { - const multiplier = multipliers[ldx] - - await registry.connect(owner).setConfig( - signerAddresses, - keeperAddresses, - f, - encodeConfig({ - paymentPremiumPPB: premium, - flatFeeMicroLink: flatFee, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier: multiplier, - minUpkeepSpend, - maxCheckDataSize, - maxPerformDataSize, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }), - offchainVersion, - offchainBytes, - ) - - const price = await registry.getMaxPaymentForGas(gas) - expect(price).to.equal( - linkForGas( - BigNumber.from(gas), - totalGasOverhead, - multiplier, - BigNumber.from(premium), - BigNumber.from(flatFee), - l1CostWei, - ).total, - ) - } - } - } - } - } - - const getTransmitTx = async ( - registry: KeeperRegistry, - transmitter: any, - upkeepIds: any, - numSigners: any, - extraParams?: any, - performData?: any, - checkBlockNum?: any, - checkBlockHash?: any, - ) => { - const latestBlock = await ethers.provider.getBlock('latest') - const configDigest = (await registry.getState()).state.latestConfigDigest - - const upkeeps = [] - for (let i = 0; i < upkeepIds.length; i++) { - upkeeps.push({ - Id: upkeepIds[i], - checkBlockNum: checkBlockNum ? checkBlockNum : latestBlock.number, - checkBlockHash: checkBlockHash ? checkBlockHash : latestBlock.hash, - performData: performData ? performData : '0x', - }) - } - - const report = encodeReport(upkeeps) - const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] - const sigs = signReport(reportContext, report, signers.slice(0, numSigners)) - - return registry - .connect(transmitter) - .transmit( - [configDigest, epochAndRound5_1, emptyBytes32], - report, - sigs.rs, - sigs.ss, - sigs.vs, - { gasLimit: extraParams?.gasLimit, gasPrice: extraParams?.gasPrice }, - ) - } - - const getTransmitTxWithReport = async ( - registry: KeeperRegistry, - transmitter: any, - report: any, - numSigners: any, - ) => { - const configDigest = (await registry.getState()).state.latestConfigDigest - const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] - const sigs = signReport(reportContext, report, signers.slice(0, numSigners)) - - return registry - .connect(transmitter) - .transmit( - [configDigest, epochAndRound5_1, emptyBytes32], - report, - sigs.rs, - sigs.ss, - sigs.vs, - ) - } - - beforeEach(async () => { - // Deploys a registry, setups of initial configuration - // Registers an upkeep which is unfunded to start with - owner = personas.Default - keeper1 = personas.Carol - keeper2 = personas.Eddy - keeper3 = personas.Nancy - keeper4 = personas.Norbert - keeper5 = personas.Nick - nonkeeper = personas.Ned - admin = personas.Neil - payee1 = personas.Nelly - payee2 = personas.Norbert - payee3 = personas.Nick - payee4 = personas.Eddy - payee5 = personas.Carol - // signers - signer1 = new ethers.Wallet( - '0x7777777000000000000000000000000000000000000000000000000000000001', - ) - signer2 = new ethers.Wallet( - '0x7777777000000000000000000000000000000000000000000000000000000002', - ) - signer3 = new ethers.Wallet( - '0x7777777000000000000000000000000000000000000000000000000000000003', - ) - signer4 = new ethers.Wallet( - '0x7777777000000000000000000000000000000000000000000000000000000004', - ) - signer5 = new ethers.Wallet( - '0x7777777000000000000000000000000000000000000000000000000000000005', - ) - - keeperAddresses = [ - await keeper1.getAddress(), - await keeper2.getAddress(), - await keeper3.getAddress(), - await keeper4.getAddress(), - await keeper5.getAddress(), - ] - payees = [ - await payee1.getAddress(), - await payee2.getAddress(), - await payee3.getAddress(), - await payee4.getAddress(), - await payee5.getAddress(), - ] - signers = [signer1, signer2, signer3, signer4, signer5] - - // We append 26 random addresses to keepers, payees and signers to get a system of 31 oracles - // This allows f value of 1 - 10 - for (let i = 0; i < 26; i++) { - keeperAddresses.push(randomAddress()) - payees.push(randomAddress()) - signers.push(ethers.Wallet.createRandom()) - } - signerAddresses = [] - for (const signer of signers) { - signerAddresses.push(await signer.getAddress()) - } - - linkToken = await linkTokenFactory.connect(owner).deploy() - gasPriceFeed = await mockV3AggregatorFactory - .connect(owner) - .deploy(0, gasWei) - linkEthFeed = await mockV3AggregatorFactory - .connect(owner) - .deploy(9, linkEth) - transcoder = await upkeepTranscoderFactory.connect(owner).deploy() - mockArbGasInfo = await mockArbGasInfoFactory.connect(owner).deploy() - mockOVMGasPriceOracle = await mockOVMGasPriceOracleFactory - .connect(owner) - .deploy() - - const arbOracleCode = await ethers.provider.send('eth_getCode', [ - mockArbGasInfo.address, - ]) - await ethers.provider.send('hardhat_setCode', [ - '0x000000000000000000000000000000000000006C', - arbOracleCode, - ]) - - const optOracleCode = await ethers.provider.send('eth_getCode', [ - mockOVMGasPriceOracle.address, - ]) - await ethers.provider.send('hardhat_setCode', [ - '0x420000000000000000000000000000000000000F', - optOracleCode, - ]) - - const mockArbSys = await new MockArbSysFactory(owner).deploy() - const arbSysCode = await ethers.provider.send('eth_getCode', [ - mockArbSys.address, - ]) - await ethers.provider.send('hardhat_setCode', [ - '0x0000000000000000000000000000000000000064', - arbSysCode, - ]) - - registryLogic = await keeperRegistryLogicFactory - .connect(owner) - .deploy( - Mode.DEFAULT, - linkToken.address, - linkEthFeed.address, - gasPriceFeed.address, - ) - - config = { - paymentPremiumPPB, - flatFeeMicroLink, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxCheckDataSize, - maxPerformDataSize, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - } - registry = await keeperRegistryFactory - .connect(owner) - .deploy(registryLogic.address) - - await registry - .connect(owner) - .setConfig( - signerAddresses, - keeperAddresses, - f, - encodeConfig(config), - offchainVersion, - offchainBytes, - ) - await registry.connect(owner).setPayees(payees) - - mock = await upkeepMockFactory.deploy() - await linkToken - .connect(owner) - .transfer(await admin.getAddress(), toWei('1000')) - await linkToken.connect(admin).approve(registry.address, toWei('1000')) - await linkToken.connect(owner).approve(registry.address, toWei('1000')) - - const tx = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - randomBytes, - emptyBytes, - ) - upkeepId = await getUpkeepID(tx) - }) - - describe('#transmit', () => { - const fArray = [1, 5, 10] - - it('reverts when registry is paused', async () => { - await registry.connect(owner).pause() - await evmRevert( - getTransmitTx(registry, keeper1, [upkeepId.toString()], f + 1), - 'RegistryPaused()', - ) - }) - - it('reverts when called by non active transmitter', async () => { - await evmRevert( - getTransmitTx(registry, payee1, [upkeepId.toString()], f + 1), - 'OnlyActiveTransmitters()', - ) - }) - - it('reverts when upkeeps and performData length mismatches', async () => { - const upkeepIds = [] - const performDataTuples = [] - const latestBlock = await ethers.provider.getBlock('latest') - - upkeepIds.push(upkeepId) - performDataTuples.push([latestBlock.number + 1, latestBlock.hash, '0x']) - // Push an extra perform data - performDataTuples.push([latestBlock.number + 1, latestBlock.hash, '0x']) - - const report = ethers.utils.defaultAbiCoder.encode( - ['uint256', 'uint256', 'uint256[]', 'tuple(uint32,bytes32,bytes)[]'], - [0, 0, upkeepIds, performDataTuples], - ) - - await evmRevert( - getTransmitTxWithReport(registry, keeper1, report, f + 1), - 'InvalidReport()', - ) - }) - - it('reverts when wrappedPerformData is incorrectly encoded', async () => { - const upkeepIds = [] - const wrappedPerformDatas = [] - const latestBlock = await ethers.provider.getBlock('latest') - - upkeepIds.push(upkeepId) - wrappedPerformDatas.push( - ethers.utils.defaultAbiCoder.encode( - ['tuple(uint32,bytes32)'], // missing performData - [[latestBlock.number + 1, latestBlock.hash]], - ), - ) - - const report = ethers.utils.defaultAbiCoder.encode( - ['uint256[]', 'bytes[]'], - [upkeepIds, wrappedPerformDatas], - ) - - await evmRevert(getTransmitTxWithReport(registry, keeper1, report, f + 1)) - }) - - it('returns early when no upkeeps are included in report', async () => { - const upkeepIds: string[] = [] - const wrappedPerformDatas: string[] = [] - const report = ethers.utils.defaultAbiCoder.encode( - ['uint256', 'uint256', 'uint256[]', 'bytes[]'], - [0, 0, upkeepIds, wrappedPerformDatas], - ) - - await getTransmitTxWithReport(registry, keeper1, report, f + 1) - }) - - it('returns early when invalid upkeepIds are included in report', async () => { - const tx = await getTransmitTx( - registry, - keeper1, - [upkeepId.add(BigNumber.from('1')).toString()], - f + 1, - ) - - const receipt = await tx.wait() - const cancelledUpkeepReportLogs = parseCancelledUpkeepReportLogs(receipt) - // exactly 1 CancelledUpkeepReport log should be emitted - assert.equal(cancelledUpkeepReportLogs.length, 1) - }) - - it('reverts when duplicated upkeepIds are included in report', async () => { - // Fund the upkeep so that pre-checks pass - await registry.connect(admin).addFunds(upkeepId, toWei('100')) - await evmRevert( - getTransmitTx( - registry, - keeper1, - [upkeepId.toString(), upkeepId.toString()], - f + 1, - ), - 'InvalidReport()', - ) - }) - - it('returns early when upkeep has insufficient funds', async () => { - const tx = await getTransmitTx( - registry, - keeper1, - [upkeepId.toString()], - f + 1, - ) - - const receipt = await tx.wait() - const insufficientFundsUpkeepReportLogs = - parseInsufficientFundsUpkeepReportLogs(receipt) - // exactly 1 InsufficientFundsUpkeepReportLogs log should be emitted - assert.equal(insufficientFundsUpkeepReportLogs.length, 1) - }) - - context('When the upkeep is funded', async () => { - beforeEach(async () => { - // Fund the upkeep - await registry.connect(admin).addFunds(upkeepId, toWei('100')) - }) - - it('returns early when check block number is less than last perform', async () => { - // First perform an upkeep to put last perform block number on upkeep state - - const tx = await getTransmitTx( - registry, - keeper1, - [upkeepId.toString()], - f + 1, - ) - await tx.wait() - - const lastPerformBlockNumber = (await registry.getUpkeep(upkeepId)) - .lastPerformBlockNumber - const lastPerformBlock = await ethers.provider.getBlock( - lastPerformBlockNumber, - ) - assert.equal( - lastPerformBlockNumber.toString(), - tx.blockNumber?.toString(), - ) - - // Try to transmit a report which has checkBlockNumber = lastPerformBlockNumber-1, should result in stale report - const transmitTx = await getTransmitTx( - registry, - keeper1, - [upkeepId.toString()], - f + 1, - {}, - '0x', - lastPerformBlock.number - 1, - lastPerformBlock.parentHash, - ) - - const receipt = await transmitTx.wait() - const staleUpkeepReportLogs = parseStaleUpkeepReportLogs(receipt) - // exactly 1 StaleUpkeepReportLogs log should be emitted - assert.equal(staleUpkeepReportLogs.length, 1) - }) - - it('returns early when check block hash does not match', async () => { - await registry.connect(admin).addFunds(upkeepId, toWei('100')) - const latestBlock = await ethers.provider.getBlock('latest') - // Try to transmit a report which has incorrect checkBlockHash - const tx = await getTransmitTx( - registry, - keeper1, - [upkeepId.toString()], - f + 1, - {}, - '0x', - latestBlock.number - 1, - latestBlock.hash, - ) // should be latestBlock.parentHash - - const receipt = await tx.wait() - const reorgedUpkeepReportLogs = parseReorgedUpkeepReportLogs(receipt) - // exactly 1 ReorgedUpkeepReportLogs log should be emitted - assert.equal(reorgedUpkeepReportLogs.length, 1) - }) - - it('returns early when check block number is older than 256 blocks', async () => { - const latestBlockReport = await encodeLatestBlockReport([ - { Id: upkeepId.toString() }, - ]) - - for (let i = 0; i < 256; i++) { - await ethers.provider.send('evm_mine', []) - } - - // Try to transmit a report which is older than 256 blocks so block hash cannot be matched - const tx = await registry - .connect(keeper1) - .transmit( - [emptyBytes32, emptyBytes32, emptyBytes32], - latestBlockReport, - [], - [], - emptyBytes32, - ) - - const receipt = await tx.wait() - const reorgedUpkeepReportLogs = parseReorgedUpkeepReportLogs(receipt) - // exactly 1 ReorgedUpkeepReportLogs log should be emitted - assert.equal(reorgedUpkeepReportLogs.length, 1) - }) - - it('returns early when upkeep is cancelled and cancellation delay has gone', async () => { - const latestBlockReport = await encodeLatestBlockReport([ - { Id: upkeepId.toString() }, - ]) - await registry.connect(admin).cancelUpkeep(upkeepId) - - for (let i = 0; i < cancellationDelay; i++) { - await ethers.provider.send('evm_mine', []) - } - - const tx = await getTransmitTxWithReport( - registry, - keeper1, - latestBlockReport, - f + 1, - ) - - const receipt = await tx.wait() - const cancelledUpkeepReportLogs = - parseCancelledUpkeepReportLogs(receipt) - // exactly 1 CancelledUpkeepReport log should be emitted - assert.equal(cancelledUpkeepReportLogs.length, 1) - }) - - it('does not revert if the target cannot execute', async () => { - mock.setCanPerform(false) - const tx = await getTransmitTx( - registry, - keeper1, - [upkeepId.toString()], - f + 1, - ) - - const receipt = await tx.wait() - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - // exactly 1 Upkeep Performed should be emitted - assert.equal(upkeepPerformedLogs.length, 1) - const upkeepPerformedLog = upkeepPerformedLogs[0] - - const success = upkeepPerformedLog.args.success - assert.equal(success, false) - }) - - it('reverts if not enough gas supplied', async () => { - mock.setPerformGasToBurn(executeGas) - await evmRevert( - getTransmitTx(registry, keeper1, [upkeepId.toString()], f + 1, { - gasLimit: executeGas, - }), - ) - }) - - it('executes the data passed to the registry', async () => { - mock.setCanPerform(true) - - const tx = await getTransmitTx( - registry, - keeper1, - [upkeepId.toString()], - f + 1, - {}, - randomBytes, - ) - const receipt = await tx.wait() - - const upkeepPerformedWithABI = [ - 'event UpkeepPerformedWith(bytes upkeepData)', - ] - const iface = new ethers.utils.Interface(upkeepPerformedWithABI) - const parsedLogs = [] - for (let i = 0; i < receipt.logs.length; i++) { - const log = receipt.logs[i] - try { - parsedLogs.push(iface.parseLog(log)) - } catch (e) { - // ignore log - } - } - assert.equal(parsedLogs.length, 1) - assert.equal(parsedLogs[0].args.upkeepData, randomBytes) - }) - - it('uses actual execution price for payment and premium calculation', async () => { - // Actual multiplier is 2, but we set gasPrice to be 1x gasWei - const gasPrice = gasWei.mul(BigNumber.from('1')) - mock.setCanPerform(true) - const registryPremiumBefore = (await registry.getState()).state - .totalPremium - const tx = await getTransmitTx( - registry, - keeper1, - [upkeepId.toString()], - f + 1, - { gasPrice }, - ) - const receipt = await tx.wait() - const registryPremiumAfter = (await registry.getState()).state - .totalPremium - const premium = registryPremiumAfter.sub(registryPremiumBefore) - - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - // exactly 1 Upkeep Performed should be emitted - assert.equal(upkeepPerformedLogs.length, 1) - const upkeepPerformedLog = upkeepPerformedLogs[0] - - const gasUsed = upkeepPerformedLog.args.gasUsed - const gasOverhead = upkeepPerformedLog.args.gasOverhead - const totalPayment = upkeepPerformedLog.args.totalPayment - - assert.equal( - linkForGas( - gasUsed, - gasOverhead, - BigNumber.from('1'), // Not the config multiplier, but the actual gas used - paymentPremiumPPB, - flatFeeMicroLink, - ).total.toString(), - totalPayment.toString(), - ) - - assert.equal( - linkForGas( - gasUsed, - gasOverhead, - BigNumber.from('1'), // Not the config multiplier, but the actual gas used - paymentPremiumPPB, - flatFeeMicroLink, - ).premium.toString(), - premium.toString(), - ) - }) - - it('only pays at a rate up to the gas ceiling [ @skip-coverage ]', async () => { - // Actual multiplier is 2, but we set gasPrice to be 10x - const gasPrice = gasWei.mul(BigNumber.from('10')) - mock.setCanPerform(true) - - const tx = await getTransmitTx( - registry, - keeper1, - [upkeepId.toString()], - f + 1, - { gasPrice }, - ) - const receipt = await tx.wait() - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - // exactly 1 Upkeep Performed should be emitted - assert.equal(upkeepPerformedLogs.length, 1) - const upkeepPerformedLog = upkeepPerformedLogs[0] - - const gasUsed = upkeepPerformedLog.args.gasUsed - const gasOverhead = upkeepPerformedLog.args.gasOverhead - const totalPayment = upkeepPerformedLog.args.totalPayment - - assert.equal( - linkForGas( - gasUsed, - gasOverhead, - gasCeilingMultiplier, // Should be same with exisitng multiplier - paymentPremiumPPB, - flatFeeMicroLink, - ).total.toString(), - totalPayment.toString(), - ) - }) - - it('correctly accounts for l1 payment', async () => { - mock.setCanPerform(true) - // Same as MockArbGasInfo.sol - const l1CostWeiArb = BigNumber.from(1000000) - - // Deploy a new registry since we change payment model - const registryLogic = await keeperRegistryLogicFactory - .connect(owner) - .deploy( - Mode.ARBITRUM, - linkToken.address, - linkEthFeed.address, - gasPriceFeed.address, - ) - // Deploy a new registry since we change payment model - const registry = await keeperRegistryFactory - .connect(owner) - .deploy(registryLogic.address) - await registry - .connect(owner) - .setConfig( - signerAddresses, - keeperAddresses, - f, - encodeConfig(config), - offchainVersion, - offchainBytes, - ) - let tx = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - randomBytes, - emptyBytes, - ) - upkeepId = await getUpkeepID(tx) - await linkToken.connect(owner).approve(registry.address, toWei('1000')) - await registry.connect(owner).addFunds(upkeepId, toWei('100')) - - // Do the thing - tx = await getTransmitTx( - registry, - keeper1, - [upkeepId.toString()], - f + 1, - { gasPrice: gasWei.mul('5') }, // High gas price so that it gets capped - ) - const receipt = await tx.wait() - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - // exactly 1 Upkeep Performed should be emitted - assert.equal(upkeepPerformedLogs.length, 1) - const upkeepPerformedLog = upkeepPerformedLogs[0] - - const gasUsed = upkeepPerformedLog.args.gasUsed - const gasOverhead = upkeepPerformedLog.args.gasOverhead - const totalPayment = upkeepPerformedLog.args.totalPayment - - assert.equal( - linkForGas( - gasUsed, - gasOverhead, - gasCeilingMultiplier, - paymentPremiumPPB, - flatFeeMicroLink, - l1CostWeiArb.div(gasCeilingMultiplier), // Dividing by gasCeilingMultiplier as it gets multiplied later - ).total.toString(), - totalPayment.toString(), - ) - }) - - it('can self fund', async () => { - const autoFunderUpkeep = await upkeepAutoFunderFactory - .connect(owner) - .deploy(linkToken.address, registry.address) - const tx = await registry - .connect(owner) - .registerUpkeep( - autoFunderUpkeep.address, - executeGas, - autoFunderUpkeep.address, - randomBytes, - emptyBytes, - ) - upkeepId = await getUpkeepID(tx) - - await autoFunderUpkeep.setUpkeepId(upkeepId) - // Give enough funds for upkeep as well as to the upkeep contract - await linkToken - .connect(owner) - .transfer(autoFunderUpkeep.address, toWei('1000')) - const maxPayment = await registry.getMaxPaymentForGas(executeGas) - - // First set auto funding amount to 0 and verify that balance is deducted upon performUpkeep - let initialBalance = toWei('100') - await registry.connect(owner).addFunds(upkeepId, initialBalance) - await autoFunderUpkeep.setAutoFundLink(0) - await autoFunderUpkeep.setIsEligible(true) - await getTransmitTx(registry, keeper1, [upkeepId.toString()], f + 1) - - let postUpkeepBalance = (await registry.getUpkeep(upkeepId)).balance - assert.isTrue(postUpkeepBalance.lt(initialBalance)) // Balance should be deducted - assert.isTrue(postUpkeepBalance.gte(initialBalance.sub(maxPayment))) // Balance should not be deducted more than maxPayment - - // Now set auto funding amount to 100 wei and verify that the balance increases - initialBalance = postUpkeepBalance - const autoTopupAmount = toWei('100') - await autoFunderUpkeep.setAutoFundLink(autoTopupAmount) - await autoFunderUpkeep.setIsEligible(true) - await getTransmitTx(registry, keeper1, [upkeepId.toString()], f + 1) - - postUpkeepBalance = (await registry.getUpkeep(upkeepId)).balance - // Balance should increase by autoTopupAmount and decrease by max maxPayment - assert.isTrue( - postUpkeepBalance.gte( - initialBalance.add(autoTopupAmount).sub(maxPayment), - ), - ) - }) - - it('can self cancel', async () => { - const autoFunderUpkeep = await upkeepAutoFunderFactory - .connect(owner) - .deploy(linkToken.address, registry.address) - const tx = await registry - .connect(owner) - .registerUpkeep( - autoFunderUpkeep.address, - executeGas, - autoFunderUpkeep.address, - randomBytes, - emptyBytes, - ) - upkeepId = await getUpkeepID(tx) - - await autoFunderUpkeep.setUpkeepId(upkeepId) - await registry.connect(owner).addFunds(upkeepId, toWei('100')) - - await autoFunderUpkeep.setIsEligible(true) - await autoFunderUpkeep.setShouldCancel(true) - - let registration = await registry.getUpkeep(upkeepId) - const oldExpiration = registration.maxValidBlocknumber - - // Do the thing - await getTransmitTx(registry, keeper1, [upkeepId.toString()], f + 1) - - // Verify upkeep gets cancelled - registration = await registry.getUpkeep(upkeepId) - const newExpiration = registration.maxValidBlocknumber - assert.isTrue(newExpiration.lt(oldExpiration)) - }) - - it('reverts when configDigest mismatches', async () => { - const report = await encodeLatestBlockReport([ - { - Id: upkeepId.toString(), - }, - ]) - const reportContext = [emptyBytes32, epochAndRound5_1, emptyBytes32] // wrong config digest - const sigs = signReport(reportContext, report, signers.slice(0, f + 1)) - await evmRevert( - registry - .connect(keeper1) - .transmit( - [reportContext[0], reportContext[1], reportContext[2]], - report, - sigs.rs, - sigs.ss, - sigs.vs, - ), - 'ConfigDigestMismatch()', - ) - }) - - it('reverts with incorrect number of signatures', async () => { - const configDigest = (await registry.getState()).state - .latestConfigDigest - const report = await encodeLatestBlockReport([ - { - Id: upkeepId.toString(), - }, - ]) - const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] // wrong config digest - const sigs = signReport(reportContext, report, signers.slice(0, f + 2)) - await evmRevert( - registry - .connect(keeper1) - .transmit( - [reportContext[0], reportContext[1], reportContext[2]], - report, - sigs.rs, - sigs.ss, - sigs.vs, - ), - 'IncorrectNumberOfSignatures()', - ) - }) - - it('reverts with invalid signature for inactive signers', async () => { - const configDigest = (await registry.getState()).state - .latestConfigDigest - const report = await encodeLatestBlockReport([ - { - Id: upkeepId.toString(), - }, - ]) - const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] // wrong config digest - const sigs = signReport(reportContext, report, [ - new ethers.Wallet(ethers.Wallet.createRandom()), - new ethers.Wallet(ethers.Wallet.createRandom()), - ]) - await evmRevert( - registry - .connect(keeper1) - .transmit( - [reportContext[0], reportContext[1], reportContext[2]], - report, - sigs.rs, - sigs.ss, - sigs.vs, - ), - 'OnlyActiveSigners()', - ) - }) - - it('reverts with invalid signature for duplicated signers', async () => { - const configDigest = (await registry.getState()).state - .latestConfigDigest - const report = await encodeLatestBlockReport([ - { - Id: upkeepId.toString(), - }, - ]) - const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] // wrong config digest - const sigs = signReport(reportContext, report, [signer1, signer1]) - await evmRevert( - registry - .connect(keeper1) - .transmit( - [reportContext[0], reportContext[1], reportContext[2]], - report, - sigs.rs, - sigs.ss, - sigs.vs, - ), - 'DuplicateSigners()', - ) - }) - - it('has a large enough gas overhead to cover upkeep that use all its gas [ @skip-coverage ]', async () => { - await registry.connect(owner).setConfig( - signerAddresses, - keeperAddresses, - 10, // maximise f to maximise overhead - encodeConfig(config), - offchainVersion, - offchainBytes, - ) - const tx = await registry.connect(owner).registerUpkeep( - mock.address, - maxPerformGas, // max allowed gas - await admin.getAddress(), - randomBytes, - emptyBytes, - ) - upkeepId = await getUpkeepID(tx) - await registry.connect(admin).addFunds(upkeepId, toWei('100')) - - let performData = '0x' - for (let i = 0; i < maxPerformDataSize.toNumber(); i++) { - performData += '11' - } // max allowed performData - - mock.setCanPerform(true) - mock.setPerformGasToBurn(maxPerformGas) - - await getTransmitTx( - registry, - keeper1, - [upkeepId.toString()], - 11, - { gasLimit: maxPerformGas.add(transmitGasOverhead) }, - performData, - ) // Should not revert - }) - - it('performs upkeep, deducts payment, updates lastPerformBlockNumber and emits events', async () => { - for (const i in fArray) { - const newF = fArray[i] - await registry - .connect(owner) - .setConfig( - signerAddresses, - keeperAddresses, - newF, - encodeConfig(config), - offchainVersion, - offchainBytes, - ) - mock.setCanPerform(true) - const checkBlock = await ethers.provider.getBlock('latest') - - const keeperBefore = await registry.getTransmitterInfo( - await keeper1.getAddress(), - ) - const registrationBefore = await registry.getUpkeep(upkeepId) - const registryPremiumBefore = (await registry.getState()).state - .totalPremium - const keeperLinkBefore = await linkToken.balanceOf( - await keeper1.getAddress(), - ) - const registryLinkBefore = await linkToken.balanceOf(registry.address) - - // Do the thing - const tx = await getTransmitTx( - registry, - keeper1, - [upkeepId.toString()], - newF + 1, - {}, - '0x', - checkBlock.number - 1, - checkBlock.parentHash, - ) - - const receipt = await tx.wait() - - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - // exactly 1 Upkeep Performed should be emitted - assert.equal(upkeepPerformedLogs.length, 1) - const upkeepPerformedLog = upkeepPerformedLogs[0] - - const id = upkeepPerformedLog.args.id - const success = upkeepPerformedLog.args.success - const checkBlockNumber = upkeepPerformedLog.args.checkBlockNumber - const gasUsed = upkeepPerformedLog.args.gasUsed - const gasOverhead = upkeepPerformedLog.args.gasOverhead - const totalPayment = upkeepPerformedLog.args.totalPayment - - assert.equal(id.toString(), upkeepId.toString()) - assert.equal(success, true) - assert.equal( - checkBlockNumber.toString(), - (checkBlock.number - 1).toString(), - ) - assert.isTrue(gasUsed.gt(BigNumber.from('0'))) - assert.isTrue(gasOverhead.gt(BigNumber.from('0'))) - assert.isTrue(totalPayment.gt(BigNumber.from('0'))) - - const keeperAfter = await registry.getTransmitterInfo( - await keeper1.getAddress(), - ) - const registrationAfter = await registry.getUpkeep(upkeepId) - const keeperLinkAfter = await linkToken.balanceOf( - await keeper1.getAddress(), - ) - const registryLinkAfter = await linkToken.balanceOf(registry.address) - const registryPremiumAfter = (await registry.getState()).state - .totalPremium - const premium = registryPremiumAfter.sub(registryPremiumBefore) - // Keeper payment is gasPayment + premium / num keepers - const keeperPayment = totalPayment - .sub(premium) - .add(premium.div(BigNumber.from(keeperAddresses.length))) - - assert.equal( - keeperAfter.balance.sub(keeperPayment).toString(), - keeperBefore.balance.toString(), - ) - assert.equal( - registrationBefore.balance.sub(totalPayment).toString(), - registrationAfter.balance.toString(), - ) - assert.isTrue(keeperLinkAfter.eq(keeperLinkBefore)) - assert.isTrue(registryLinkBefore.eq(registryLinkAfter)) - - // Amount spent should be updated correctly - assert.equal( - registrationAfter.amountSpent.sub(totalPayment).toString(), - registrationBefore.amountSpent.toString(), - ) - assert.isTrue( - registrationAfter.amountSpent - .sub(registrationBefore.amountSpent) - .eq(registrationBefore.balance.sub(registrationAfter.balance)), - ) - // Last perform block number should be updated - assert.equal( - registrationAfter.lastPerformBlockNumber.toString(), - tx.blockNumber?.toString(), - ) - - // Latest epoch should be 5 - assert.equal((await registry.getState()).state.latestEpoch, 5) - } - }) - - it('calculates gas overhead appropriately within a margin for different scenarios [ @skip-coverage ]', async () => { - // Perform the upkeep once to remove non-zero storage slots and have predictable gas measurement - - let tx = await getTransmitTx( - registry, - keeper1, - [upkeepId.toString()], - f + 1, - ) - - await tx.wait() - - // Different test scenarios - let longBytes = '0x' - for (let i = 0; i < maxPerformDataSize.toNumber(); i++) { - longBytes += '11' - } - const upkeepSuccessArray = [true, false] - const performGasArray = [5000, 100000, executeGas] - const performDataArray = ['0x', randomBytes, longBytes] - - for (const i in upkeepSuccessArray) { - for (const j in performGasArray) { - for (const k in performDataArray) { - for (const l in fArray) { - const upkeepSuccess = upkeepSuccessArray[i] - const performGas = performGasArray[j] - const performData = performDataArray[k] - const newF = fArray[l] - - mock.setCanPerform(upkeepSuccess) - mock.setPerformGasToBurn(performGas) - await registry - .connect(owner) - .setConfig( - signerAddresses, - keeperAddresses, - newF, - encodeConfig(config), - offchainVersion, - offchainBytes, - ) - tx = await getTransmitTx( - registry, - keeper1, - [upkeepId.toString()], - newF + 1, - {}, - performData, - ) - const receipt = await tx.wait() - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - // exactly 1 Upkeep Performed should be emitted - assert.equal(upkeepPerformedLogs.length, 1) - const upkeepPerformedLog = upkeepPerformedLogs[0] - - const upkeepGasUsed = upkeepPerformedLog.args.gasUsed - const chargedGasOverhead = upkeepPerformedLog.args.gasOverhead - const actualGasOverhead = receipt.gasUsed.sub(upkeepGasUsed) - - assert.isTrue(upkeepGasUsed.gt(BigNumber.from('0'))) - assert.isTrue(chargedGasOverhead.gt(BigNumber.from('0'))) - - if (i == '0' && j == '0' && k == '0') { - console.log( - 'Gas Benchmarking - sig verification ( f =', - newF, - '): calculated overhead: ', - chargedGasOverhead.toString(), - ' actual overhead: ', - actualGasOverhead.toString(), - ' margin over gasUsed: ', - chargedGasOverhead.sub(actualGasOverhead).toString(), - ) - } - - // Overhead should not get capped - const gasOverheadCap = registryGasOverhead - .add( - registryPerSignerGasOverhead.mul(BigNumber.from(newF + 1)), - ) - .add( - BigNumber.from( - registryPerPerformByteGasOverhead.toNumber() * - performData.length, - ), - ) - const gasCapMinusOverhead = - gasOverheadCap.sub(chargedGasOverhead) - assert.isTrue( - gasCapMinusOverhead.gt(BigNumber.from(0)), - 'Gas overhead got capped. Verify gas overhead variables in test match those in the registry. To not have the overheads capped increase REGISTRY_GAS_OVERHEAD by atleast ' + - gasCapMinusOverhead.toString(), - ) - // total gas charged should be greater than tx gas but within gasCalculationMargin - assert.isTrue( - chargedGasOverhead.gt(actualGasOverhead), - 'Gas overhead calculated is too low, increase account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_SIGNER_GAS_OVERHEAD) by atleast ' + - actualGasOverhead.sub(chargedGasOverhead).toString(), - ) - - assert.isTrue( - chargedGasOverhead - .sub(actualGasOverhead) - .lt(BigNumber.from(gasCalculationMargin)), - ), - 'Gas overhead calculated is too high, decrease account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_SIGNER_GAS_OVERHEAD) by atleast ' + - chargedGasOverhead - .sub(chargedGasOverhead) - .sub(BigNumber.from(gasCalculationMargin)) - .toString() - } - } - } - } - }) - }) - - describe('When upkeeps are batched', () => { - const numPassingUpkeepsArray = [1, 2, 10] - const numFailingUpkeepsArray = [0, 1, 3] - - numPassingUpkeepsArray.forEach(function (numPassingUpkeeps) { - numFailingUpkeepsArray.forEach(function (numFailingUpkeeps) { - describe( - 'passing upkeeps ' + - numPassingUpkeeps.toString() + - ', failing upkeeps ' + - numFailingUpkeeps.toString(), - () => { - let passingUpkeepIds: string[] - let failingUpkeepIds: string[] - - beforeEach(async () => { - passingUpkeepIds = [] - failingUpkeepIds = [] - for (let i = 0; i < numPassingUpkeeps; i++) { - mock = await upkeepMockFactory.deploy() - const tx = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - randomBytes, - emptyBytes, - ) - upkeepId = await getUpkeepID(tx) - passingUpkeepIds.push(upkeepId.toString()) - - // Add funds to passing upkeeps - await registry.connect(admin).addFunds(upkeepId, toWei('100')) - } - for (let i = 0; i < numFailingUpkeeps; i++) { - mock = await upkeepMockFactory.deploy() - const tx = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - randomBytes, - emptyBytes, - ) - upkeepId = await getUpkeepID(tx) - failingUpkeepIds.push(upkeepId.toString()) - } - }) - - it('performs successful upkeeps and does not change failing upkeeps', async () => { - const keeperBefore = await registry.getTransmitterInfo( - await keeper1.getAddress(), - ) - const keeperLinkBefore = await linkToken.balanceOf( - await keeper1.getAddress(), - ) - const registryLinkBefore = await linkToken.balanceOf( - registry.address, - ) - const registryPremiumBefore = (await registry.getState()).state - .totalPremium - const registrationPassingBefore = await Promise.all( - passingUpkeepIds.map(async (id) => { - const reg = await registry.getUpkeep(BigNumber.from(id)) - assert.equal(reg.lastPerformBlockNumber.toString(), '0') - return reg - }), - ) - const registrationFailingBefore = await await Promise.all( - failingUpkeepIds.map(async (id) => { - const reg = await registry.getUpkeep(BigNumber.from(id)) - assert.equal(reg.lastPerformBlockNumber.toString(), '0') - return reg - }), - ) - - const tx = await getTransmitTx( - registry, - keeper1, - passingUpkeepIds.concat(failingUpkeepIds), - f + 1, - ) - - const receipt = await tx.wait() - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - // exactly numPassingUpkeeps Upkeep Performed should be emitted - assert.equal(upkeepPerformedLogs.length, numPassingUpkeeps) - const insufficientFundsLogs = - parseInsufficientFundsUpkeepReportLogs(receipt) - // exactly numFailingUpkeeps Upkeep Performed should be emitted - assert.equal(insufficientFundsLogs.length, numFailingUpkeeps) - - const keeperAfter = await registry.getTransmitterInfo( - await keeper1.getAddress(), - ) - const keeperLinkAfter = await linkToken.balanceOf( - await keeper1.getAddress(), - ) - const registryLinkAfter = await linkToken.balanceOf( - registry.address, - ) - const registrationPassingAfter = await Promise.all( - passingUpkeepIds.map(async (id) => { - return await registry.getUpkeep(BigNumber.from(id)) - }), - ) - const registrationFailingAfter = await await Promise.all( - failingUpkeepIds.map(async (id) => { - return await registry.getUpkeep(BigNumber.from(id)) - }), - ) - const registryPremiumAfter = (await registry.getState()).state - .totalPremium - const premium = registryPremiumAfter.sub(registryPremiumBefore) - - let netPayment = BigNumber.from('0') - for (let i = 0; i < numPassingUpkeeps; i++) { - const id = upkeepPerformedLogs[i].args.id - const gasUsed = upkeepPerformedLogs[i].args.gasUsed - const gasOverhead = upkeepPerformedLogs[i].args.gasOverhead - const totalPayment = upkeepPerformedLogs[i].args.totalPayment - - assert.equal(id.toString(), passingUpkeepIds[i]) - assert.isTrue(gasUsed.gt(BigNumber.from('0'))) - assert.isTrue(gasOverhead.gt(BigNumber.from('0'))) - assert.isTrue(totalPayment.gt(BigNumber.from('0'))) - - // Balance should be deducted - assert.equal( - registrationPassingBefore[i].balance - .sub(totalPayment) - .toString(), - registrationPassingAfter[i].balance.toString(), - ) - - // Amount spent should be updated correctly - assert.equal( - registrationPassingAfter[i].amountSpent - .sub(totalPayment) - .toString(), - registrationPassingBefore[i].amountSpent.toString(), - ) - - // Last perform block number should be updated - assert.equal( - registrationPassingAfter[ - i - ].lastPerformBlockNumber.toString(), - tx.blockNumber?.toString(), - ) - - netPayment = netPayment.add(totalPayment) - } - - for (let i = 0; i < numFailingUpkeeps; i++) { - // InsufficientFunds log should be emitted - const id = insufficientFundsLogs[i].args.id - assert.equal(id.toString(), failingUpkeepIds[i]) - - // Balance and amount spent should be same - assert.equal( - registrationFailingBefore[i].balance.toString(), - registrationFailingAfter[i].balance.toString(), - ) - assert.equal( - registrationFailingBefore[i].amountSpent.toString(), - registrationFailingAfter[i].amountSpent.toString(), - ) - - // Last perform block number should not be updated - assert.equal( - registrationFailingAfter[ - i - ].lastPerformBlockNumber.toString(), - '0', - ) - } - - // Keeper payment is gasPayment + premium / num keepers - const keeperPayment = netPayment - .sub(premium) - .add(premium.div(BigNumber.from(keeperAddresses.length))) - - // Keeper should be paid net payment for all passed upkeeps - assert.equal( - keeperAfter.balance.sub(keeperPayment).toString(), - keeperBefore.balance.toString(), - ) - - assert.isTrue(keeperLinkAfter.eq(keeperLinkBefore)) - assert.isTrue(registryLinkBefore.eq(registryLinkAfter)) - }) - - it('splits gas overhead appropriately among performed upkeeps [ @skip-coverage ]', async () => { - // Perform the upkeeps once to remove non-zero storage slots and have predictable gas measurement - let tx = await getTransmitTx( - registry, - keeper1, - passingUpkeepIds.concat(failingUpkeepIds), - f + 1, - ) - - await tx.wait() - - // Do the actual thing - - tx = await getTransmitTx( - registry, - keeper1, - passingUpkeepIds.concat(failingUpkeepIds), - f + 1, - ) - - const receipt = await tx.wait() - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - // exactly numPassingUpkeeps Upkeep Performed should be emitted - assert.equal(upkeepPerformedLogs.length, numPassingUpkeeps) - - const gasOverheadCap = registryGasOverhead.add( - registryPerSignerGasOverhead.mul(BigNumber.from(f + 1)), - ) - - const overheadCanGetCapped = - numPassingUpkeeps == 1 && numFailingUpkeeps > 0 - // Should only happen with 1 successful upkeep and some failing upkeeps. - // With 2 successful upkeeps and upto 3 failing upkeeps, overhead should be small enough to not get capped - let netGasUsedPlusOverhead = BigNumber.from('0') - - for (let i = 0; i < numPassingUpkeeps; i++) { - const gasUsed = upkeepPerformedLogs[i].args.gasUsed - const gasOverhead = upkeepPerformedLogs[i].args.gasOverhead - - assert.isTrue(gasUsed.gt(BigNumber.from('0'))) - assert.isTrue(gasOverhead.gt(BigNumber.from('0'))) - - // Overhead should not exceed capped - assert.isTrue(gasOverhead.lte(gasOverheadCap)) - - // Overhead should be same for every upkeep since they have equal performData, hence same caps - assert.isTrue( - gasOverhead.eq(upkeepPerformedLogs[0].args.gasOverhead), - ) - - netGasUsedPlusOverhead = netGasUsedPlusOverhead - .add(gasUsed) - .add(gasOverhead) - } - - const overheadsGotCapped = - upkeepPerformedLogs[0].args.gasOverhead.eq(gasOverheadCap) - // Should only get capped in certain scenarios - if (overheadsGotCapped) { - assert.isTrue( - overheadCanGetCapped, - 'Gas overhead got capped. Verify gas overhead variables in test match those in the registry. To not have the overheads capped increase REGISTRY_GAS_OVERHEAD', - ) - } - - console.log( - 'Gas Benchmarking - batching (passedUpkeeps: ', - numPassingUpkeeps, - 'failedUpkeeps:', - numFailingUpkeeps, - '): ', - 'overheadsGotCapped', - overheadsGotCapped, - 'calculated overhead', - upkeepPerformedLogs[0].args.gasOverhead.toString(), - ' margin over gasUsed', - netGasUsedPlusOverhead.sub(receipt.gasUsed).toString(), - ) - - // If overheads dont get capped then total gas charged should be greater than tx gas - // We don't check whether the net is within gasMargin as the margin changes with numFailedUpkeeps - // Which is ok, as long as individual gas overhead is capped - if (!overheadsGotCapped) { - assert.isTrue( - netGasUsedPlusOverhead.gt(receipt.gasUsed), - 'Gas overhead is too low, increase ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD', - ) - } - }) - }, - ) - }) - }) - - it('has enough perform gas overhead for large batches [ @skip-coverage ]', async () => { - const numUpkeeps = 20 - const upkeepIds: string[] = [] - let totalExecuteGas = BigNumber.from('0') - for (let i = 0; i < numUpkeeps; i++) { - mock = await upkeepMockFactory.deploy() - const tx = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - randomBytes, - emptyBytes, - ) - upkeepId = await getUpkeepID(tx) - upkeepIds.push(upkeepId.toString()) - - // Add funds to passing upkeeps - await registry.connect(owner).addFunds(upkeepId, toWei('10')) - - mock.setCanPerform(true) - mock.setPerformGasToBurn(executeGas) - - totalExecuteGas = totalExecuteGas.add(executeGas) - } - - // Should revert with no overhead added - await evmRevert( - getTransmitTx(registry, keeper1, upkeepIds, f + 1, { - gasLimit: totalExecuteGas, - }), - ) - // Should not revert with overhead added - await getTransmitTx(registry, keeper1, upkeepIds, f + 1, { - gasLimit: totalExecuteGas.add(transmitGasOverhead), - }) - }) - - it('splits l2 payment among performed upkeeps', async () => { - const numUpkeeps = 7 - const upkeepIds: string[] = [] - // Same as MockArbGasInfo.sol - const l1CostWeiArb = BigNumber.from(1000000) - - // Deploy a new registry since we change payment model - const registryLogic = await keeperRegistryLogicFactory - .connect(owner) - .deploy( - Mode.ARBITRUM, - linkToken.address, - linkEthFeed.address, - gasPriceFeed.address, - ) - // Deploy a new registry since we change payment model - const registry = await keeperRegistryFactory - .connect(owner) - .deploy(registryLogic.address) - await registry - .connect(owner) - .setConfig( - signerAddresses, - keeperAddresses, - f, - encodeConfig(config), - offchainVersion, - offchainBytes, - ) - await linkToken.connect(owner).approve(registry.address, toWei('10000')) - for (let i = 0; i < numUpkeeps; i++) { - mock = await upkeepMockFactory.deploy() - const tx = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - randomBytes, - emptyBytes, - ) - upkeepId = await getUpkeepID(tx) - upkeepIds.push(upkeepId.toString()) - - // Add funds to passing upkeeps - await registry.connect(owner).addFunds(upkeepId, toWei('100')) - } - - // Do the thing - const tx = await getTransmitTx( - registry, - keeper1, - upkeepIds, - f + 1, - { gasPrice: gasWei.mul('5') }, // High gas price so that it gets capped - ) - - const receipt = await tx.wait() - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - // exactly numPassingUpkeeps Upkeep Performed should be emitted - assert.equal(upkeepPerformedLogs.length, numUpkeeps) - - // Verify the payment calculation in upkeepPerformed[0] - const upkeepPerformedLog = upkeepPerformedLogs[0] - - const gasUsed = upkeepPerformedLog.args.gasUsed - const gasOverhead = upkeepPerformedLog.args.gasOverhead - const totalPayment = upkeepPerformedLog.args.totalPayment - - assert.equal( - linkForGas( - gasUsed, - gasOverhead, - gasCeilingMultiplier, - paymentPremiumPPB, - flatFeeMicroLink, - l1CostWeiArb.div(gasCeilingMultiplier), // Dividing by gasCeilingMultiplier as it gets multiplied later - BigNumber.from(numUpkeeps), - ).total.toString(), - totalPayment.toString(), - ) - }) - }) - }) - - describe('#recoverFunds', () => { - const sent = toWei('7') - - beforeEach(async () => { - await linkToken.connect(admin).approve(registry.address, toWei('100')) - await linkToken - .connect(owner) - .transfer(await keeper1.getAddress(), toWei('1000')) - - // add funds to upkeep 1 and perform and withdraw some payment - const tx = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - emptyBytes, - ) - - const id1 = await getUpkeepID(tx) - await registry.connect(admin).addFunds(id1, toWei('5')) - - await getTransmitTx(registry, keeper1, [id1.toString()], f + 1) - await getTransmitTx(registry, keeper2, [id1.toString()], f + 1) - await getTransmitTx(registry, keeper3, [id1.toString()], f + 1) - - await registry - .connect(payee1) - .withdrawPayment( - await keeper1.getAddress(), - await nonkeeper.getAddress(), - ) - - // transfer funds directly to the registry - await linkToken.connect(keeper1).transfer(registry.address, sent) - - // add funds to upkeep 2 and perform and withdraw some payment - const tx2 = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - emptyBytes, - ) - const id2 = await getUpkeepID(tx2) - await registry.connect(admin).addFunds(id2, toWei('5')) - - await getTransmitTx(registry, keeper1, [id2.toString()], f + 1) - await getTransmitTx(registry, keeper2, [id2.toString()], f + 1) - await getTransmitTx(registry, keeper3, [id2.toString()], f + 1) - - await registry - .connect(payee2) - .withdrawPayment( - await keeper2.getAddress(), - await nonkeeper.getAddress(), - ) - - // transfer funds using onTokenTransfer - const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [id2]) - await linkToken - .connect(owner) - .transferAndCall(registry.address, toWei('1'), data) - - // withdraw some funds - await registry.connect(owner).cancelUpkeep(id1) - await registry - .connect(admin) - .withdrawFunds(id1, await nonkeeper.getAddress()) - }) - - it('reverts if not called by owner', async () => { - await evmRevert( - registry.connect(keeper1).recoverFunds(), - 'Only callable by owner', - ) - }) - - it('allows any funds that have been accidentally transfered to be moved', async () => { - const balanceBefore = await linkToken.balanceOf(registry.address) - const ownerBefore = await linkToken.balanceOf(await owner.getAddress()) - - await registry.connect(owner).recoverFunds() - - const balanceAfter = await linkToken.balanceOf(registry.address) - const ownerAfter = await linkToken.balanceOf(await owner.getAddress()) - - assert.isTrue(balanceBefore.eq(balanceAfter.add(sent))) - assert.isTrue(ownerAfter.eq(ownerBefore.add(sent))) - }) - }) - - describe('#getMinBalanceForUpkeep / #checkUpkeep / #transmit', () => { - it('calculates the minimum balance appropriately', async () => { - await mock.setCanCheck(true) - - const oneWei = BigNumber.from(1) - const minBalance = await registry.getMinBalanceForUpkeep(upkeepId) - const tooLow = minBalance.sub(oneWei) - - await registry.connect(admin).addFunds(upkeepId, tooLow) - let checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(upkeepId) - - assert.equal(checkUpkeepResult.upkeepNeeded, false) - assert.equal( - checkUpkeepResult.upkeepFailureReason, - UpkeepFailureReason.INSUFFICIENT_BALANCE, - ) - - await registry.connect(admin).addFunds(upkeepId, oneWei) - checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(upkeepId) - assert.equal(checkUpkeepResult.upkeepNeeded, true) - }) - - it('uses maxPerformData size in checkUpkeep but actual performDataSize in transmit', async () => { - const tx1 = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - randomBytes, - emptyBytes, - ) - const upkeepID1 = await getUpkeepID(tx1) - const tx2 = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - randomBytes, - emptyBytes, - ) - const upkeepID2 = await getUpkeepID(tx2) - await mock.setCanCheck(true) - await mock.setCanPerform(true) - - // upkeep 1 is underfunded, 2 is fully funded - const minBalance1 = ( - await registry.getMinBalanceForUpkeep(upkeepID1) - ).sub(1) - const minBalance2 = await registry.getMinBalanceForUpkeep(upkeepID2) - await registry.connect(owner).addFunds(upkeepID1, minBalance1) - await registry.connect(owner).addFunds(upkeepID2, minBalance2) - - // upkeep 1 check should return false, 2 should return true - let checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(upkeepID1) - assert.equal(checkUpkeepResult.upkeepNeeded, false) - assert.equal( - checkUpkeepResult.upkeepFailureReason, - UpkeepFailureReason.INSUFFICIENT_BALANCE, - ) - - checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(upkeepID2) - assert.equal(checkUpkeepResult.upkeepNeeded, true) - - // upkeep 1 perform should return with insufficient balance using max performData size - let maxPerformData = '0x' - for (let i = 0; i < maxPerformDataSize.toNumber(); i++) { - maxPerformData += '11' - } - - const tx = await getTransmitTx( - registry, - keeper1, - [upkeepID1.toString()], - f + 1, - { gasPrice: gasWei.mul(gasCeilingMultiplier) }, - maxPerformData, - ) - - const receipt = await tx.wait() - const insufficientFundsUpkeepReportLogs = - parseInsufficientFundsUpkeepReportLogs(receipt) - // exactly 1 InsufficientFundsUpkeepReportLogs log should be emitted - assert.equal(insufficientFundsUpkeepReportLogs.length, 1) - - // upkeep 1 perform should succeed with empty performData - await getTransmitTx( - registry, - keeper1, - [upkeepID1.toString()], - f + 1, - { gasPrice: gasWei.mul(gasCeilingMultiplier) }, - '0x', - ), - // upkeep 2 perform should succeed with max performData size - await getTransmitTx( - registry, - keeper1, - [upkeepID2.toString()], - f + 1, - { gasPrice: gasWei.mul(gasCeilingMultiplier) }, - maxPerformData, - ) - }) - }) - - describe('#withdrawFunds', () => { - let upkeepId2: BigNumber - - beforeEach(async () => { - const tx = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - randomBytes, - emptyBytes, - ) - upkeepId2 = await getUpkeepID(tx) - - await registry.connect(admin).addFunds(upkeepId, toWei('100')) - await registry.connect(admin).addFunds(upkeepId2, toWei('100')) - - // Do a perform so that upkeep is charged some amount - await getTransmitTx(registry, keeper1, [upkeepId.toString()], f + 1) - await getTransmitTx(registry, keeper1, [upkeepId2.toString()], f + 1) - }) - - it('reverts if called on a non existing ID', async () => { - await evmRevert( - registry - .connect(admin) - .withdrawFunds(upkeepId.add(1), await payee1.getAddress()), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if called by anyone but the admin', async () => { - await evmRevert( - registry - .connect(owner) - .withdrawFunds(upkeepId, await payee1.getAddress()), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if called on an uncanceled upkeep', async () => { - await evmRevert( - registry - .connect(admin) - .withdrawFunds(upkeepId, await payee1.getAddress()), - 'UpkeepNotCanceled()', - ) - }) - - it('reverts if called with the 0 address', async () => { - await evmRevert( - registry.connect(admin).withdrawFunds(upkeepId, zeroAddress), - 'InvalidRecipient()', - ) - }) - - describe('after the registration is cancelled', () => { - beforeEach(async () => { - await registry.connect(owner).cancelUpkeep(upkeepId) - await registry.connect(owner).cancelUpkeep(upkeepId2) - }) - - it('can be called successively on two upkeeps', async () => { - await registry - .connect(admin) - .withdrawFunds(upkeepId, await payee1.getAddress()) - await registry - .connect(admin) - .withdrawFunds(upkeepId2, await payee1.getAddress()) - }) - - it('moves the funds out and updates the balance and emits an event', async () => { - const payee1Before = await linkToken.balanceOf( - await payee1.getAddress(), - ) - const registryBefore = await linkToken.balanceOf(registry.address) - - let registration = await registry.getUpkeep(upkeepId) - const previousBalance = registration.balance - - const tx = await registry - .connect(admin) - .withdrawFunds(upkeepId, await payee1.getAddress()) - await expect(tx) - .to.emit(registry, 'FundsWithdrawn') - .withArgs(upkeepId, previousBalance, await payee1.getAddress()) - - const payee1After = await linkToken.balanceOf(await payee1.getAddress()) - const registryAfter = await linkToken.balanceOf(registry.address) - - assert.isTrue(payee1Before.add(previousBalance).eq(payee1After)) - assert.isTrue(registryBefore.sub(previousBalance).eq(registryAfter)) - - registration = await registry.getUpkeep(upkeepId) - assert.equal(0, registration.balance.toNumber()) - }) - }) - }) - - describe('#simulatePerformUpkeep', () => { - it('reverts if called by non zero address', async () => { - await evmRevert( - registry - .connect(await owner.getAddress()) - .callStatic.simulatePerformUpkeep(upkeepId, '0x'), - 'OnlySimulatedBackend()', - ) - }) - - it('reverts when registry is paused', async () => { - await registry.connect(owner).pause() - await evmRevert( - registry - .connect(zeroAddress) - .callStatic.simulatePerformUpkeep(upkeepId, '0x'), - 'RegistryPaused()', - ) - }) - - it('returns false and gasUsed when perform fails', async () => { - await mock.setCanPerform(false) - - const simulatePerformResult = await registry - .connect(zeroAddress) - .callStatic.simulatePerformUpkeep(upkeepId, '0x') - - assert.equal(simulatePerformResult.success, false) - assert.isTrue(simulatePerformResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used - }) - - it('returns true and gasUsed when perform succeeds', async () => { - await mock.setCanPerform(true) - - const simulatePerformResult = await registry - .connect(zeroAddress) - .callStatic.simulatePerformUpkeep(upkeepId, '0x') - - assert.equal(simulatePerformResult.success, true) - assert.isTrue(simulatePerformResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used - }) - - it('returns correct amount of gasUsed when perform succeeds', async () => { - await mock.setCanPerform(true) - await mock.setPerformGasToBurn(executeGas) - - const simulatePerformResult = await registry - .connect(zeroAddress) - .callStatic.simulatePerformUpkeep(upkeepId, '0x') - - assert.equal(simulatePerformResult.success, true) - // Full execute gas should be used, with some performGasBuffer(1000) - assert.isTrue( - simulatePerformResult.gasUsed.gt( - executeGas.sub(BigNumber.from('1000')), - ), - ) - }) - }) - - describe('#checkUpkeep', () => { - it('reverts if called by non zero address', async () => { - await evmRevert( - registry - .connect(await owner.getAddress()) - .callStatic.checkUpkeep(upkeepId), - 'OnlySimulatedBackend()', - ) - }) - - it('returns false and error code if the upkeep is cancelled by admin', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - - const checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(upkeepId) - - assert.equal(checkUpkeepResult.upkeepNeeded, false) - assert.equal(checkUpkeepResult.performData, '0x') - assert.equal( - checkUpkeepResult.upkeepFailureReason, - UpkeepFailureReason.UPKEEP_CANCELLED, - ) - assert.equal(checkUpkeepResult.gasUsed.toString(), '0') - }) - - it('returns false and error code if the upkeep is cancelled by owner', async () => { - await registry.connect(owner).cancelUpkeep(upkeepId) - - const checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(upkeepId) - - assert.equal(checkUpkeepResult.upkeepNeeded, false) - assert.equal(checkUpkeepResult.performData, '0x') - assert.equal( - checkUpkeepResult.upkeepFailureReason, - UpkeepFailureReason.UPKEEP_CANCELLED, - ) - assert.equal(checkUpkeepResult.gasUsed.toString(), '0') - }) - - it('returns false and error code if the upkeep is paused', async () => { - await registry.connect(admin).pauseUpkeep(upkeepId) - - const checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(upkeepId) - - assert.equal(checkUpkeepResult.upkeepNeeded, false) - assert.equal(checkUpkeepResult.performData, '0x') - assert.equal( - checkUpkeepResult.upkeepFailureReason, - UpkeepFailureReason.UPKEEP_PAUSED, - ) - assert.equal(checkUpkeepResult.gasUsed.toString(), '0') - }) - - it('returns false and error code if user is out of funds', async () => { - const checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(upkeepId) - - assert.equal(checkUpkeepResult.upkeepNeeded, false) - assert.equal(checkUpkeepResult.performData, '0x') - assert.equal( - checkUpkeepResult.upkeepFailureReason, - UpkeepFailureReason.INSUFFICIENT_BALANCE, - ) - assert.equal(checkUpkeepResult.gasUsed.toString(), '0') - }) - - context('when the registration is funded', () => { - beforeEach(async () => { - await linkToken.connect(admin).approve(registry.address, toWei('100')) - await registry.connect(admin).addFunds(upkeepId, toWei('100')) - }) - - it('returns false, error code, and revert data if the target check reverts', async () => { - await mock.setShouldRevertCheck(true) - const checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(upkeepId) - assert.equal(checkUpkeepResult.upkeepNeeded, false) - - const wrappedPerfromData = ethers.utils.defaultAbiCoder.decode( - [ - 'tuple(uint32 checkBlockNum, bytes32 checkBlockHash, bytes performData)', - ], - checkUpkeepResult.performData, - ) - const revertReasonBytes = `0x${wrappedPerfromData[0][2].slice(10)}` // remove sighash - assert.equal( - ethers.utils.defaultAbiCoder.decode(['string'], revertReasonBytes)[0], - 'shouldRevertCheck should be false', - ) - assert.equal( - checkUpkeepResult.upkeepFailureReason, - UpkeepFailureReason.TARGET_CHECK_REVERTED, - ) - assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used - }) - - it('returns false and error code if the upkeep is not needed', async () => { - await mock.setCanCheck(false) - const checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(upkeepId) - - assert.equal(checkUpkeepResult.upkeepNeeded, false) - assert.equal(checkUpkeepResult.performData, '0x') - assert.equal( - checkUpkeepResult.upkeepFailureReason, - UpkeepFailureReason.UPKEEP_NOT_NEEDED, - ) - assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used - }) - - it('returns false and error code if the performData exceeds limit', async () => { - let longBytes = '0x' - for (let i = 0; i < 5000; i++) { - longBytes += '1' - } - await mock.setCanCheck(true) - await mock.setPerformData(longBytes) - - const checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(upkeepId) - - assert.equal(checkUpkeepResult.upkeepNeeded, false) - assert.equal(checkUpkeepResult.performData, '0x') - assert.equal( - checkUpkeepResult.upkeepFailureReason, - UpkeepFailureReason.PERFORM_DATA_EXCEEDS_LIMIT, - ) - assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used - }) - - it('returns true with wrapped perform data and gas used if the target can execute', async () => { - await mock.setCanCheck(true) - await mock.setPerformData(randomBytes) - - const latestBlock = await ethers.provider.getBlock('latest') - - const checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(upkeepId, { - blockTag: latestBlock.number, - }) - - const wrappedPerfromData = ethers.utils.defaultAbiCoder.decode( - [ - 'tuple(uint32 checkBlockNum, bytes32 checkBlockHash, bytes performData)', - ], - checkUpkeepResult.performData, - ) - - assert.equal(checkUpkeepResult.upkeepNeeded, true) - assert.equal( - wrappedPerfromData[0].checkBlockNum, - latestBlock.number - 1, - ) - assert.equal( - wrappedPerfromData[0].checkBlockHash, - latestBlock.parentHash, - ) - assert.equal(wrappedPerfromData[0].performData, randomBytes) - assert.equal( - checkUpkeepResult.upkeepFailureReason, - UpkeepFailureReason.NONE, - ) - assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used - assert.isTrue(checkUpkeepResult.fastGasWei.eq(gasWei)) - assert.isTrue(checkUpkeepResult.linkNative.eq(linkEth)) - }) - - it('has a large enough gas overhead to cover upkeeps that use all their gas [ @skip-coverage ]', async () => { - await mock.setCanCheck(true) - await mock.setCheckGasToBurn(checkGasLimit) - const gas = checkGasLimit.add(checkGasOverhead) - const checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic.checkUpkeep(upkeepId, { - gasLimit: gas, - }) - - assert.equal(checkUpkeepResult.upkeepNeeded, true) - }) - }) - }) - - describe('#addFunds', () => { - const amount = toWei('1') - - it('reverts if the registration does not exist', async () => { - await evmRevert( - registry.connect(keeper1).addFunds(upkeepId.add(1), amount), - 'UpkeepCancelled()', - ) - }) - - it('adds to the balance of the registration', async () => { - await registry.connect(admin).addFunds(upkeepId, amount) - const registration = await registry.getUpkeep(upkeepId) - assert.isTrue(amount.eq(registration.balance)) - }) - - it('lets anyone add funds to an upkeep not just admin', async () => { - await linkToken.connect(owner).transfer(await payee1.getAddress(), amount) - await linkToken.connect(payee1).approve(registry.address, amount) - - await registry.connect(payee1).addFunds(upkeepId, amount) - const registration = await registry.getUpkeep(upkeepId) - assert.isTrue(amount.eq(registration.balance)) - }) - - it('emits a log', async () => { - const tx = await registry.connect(admin).addFunds(upkeepId, amount) - await expect(tx) - .to.emit(registry, 'FundsAdded') - .withArgs(upkeepId, await admin.getAddress(), amount) - }) - - it('reverts if the upkeep is canceled', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( - registry.connect(keeper1).addFunds(upkeepId, amount), - 'UpkeepCancelled()', - ) - }) - }) - - describe('#getActiveUpkeepIDs', () => { - let upkeepId2: BigNumber - - beforeEach(async () => { - // Register another upkeep so that we have 2 - const tx = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - randomBytes, - emptyBytes, - ) - upkeepId2 = await getUpkeepID(tx) - }) - - it('reverts if startIndex is out of bounds ', async () => { - await evmRevert(registry.getActiveUpkeepIDs(4, 0), 'IndexOutOfRange()') - }) - - it('reverts if startIndex + maxCount is out of bounds', async () => { - await evmRevert(registry.getActiveUpkeepIDs(0, 4)) - }) - - it('returns upkeep IDs bounded by maxCount', async () => { - let upkeepIds = await registry.getActiveUpkeepIDs(0, 1) - assert( - upkeepIds.length == 1, - 'Only maxCount number of upkeeps should be returned', - ) - assert( - upkeepIds[0].toString() == upkeepId.toString(), - 'Correct upkeep ID should be returned', - ) - - upkeepIds = await registry.getActiveUpkeepIDs(1, 1) - assert( - upkeepIds.length == 1, - 'Only maxCount number of upkeeps should be returned', - ) - assert( - upkeepIds[0].toString() == upkeepId2.toString(), - 'Correct upkeep ID should be returned', - ) - }) - - it('returns all upkeep IDs if maxCount is 0', async () => { - const upkeepIds = await registry.getActiveUpkeepIDs(0, 0) - assert(upkeepIds.length == 2, 'All upkeeps should be returned') - assert( - upkeepIds[0].toString() == upkeepId.toString(), - 'Correct upkeep ID should be returned', - ) - assert( - upkeepIds[1].toString() == upkeepId2.toString(), - 'Correct upkeep ID should be returned', - ) - }) - }) - - describe('#getMaxPaymentForGas', () => { - const multipliers = [BigNumber.from(1), BigNumber.from(3)] - const gasAmounts = [100000, 10000000] - const premiums = [0, 250000000] - const flatFees = [0, 1000000] - // Same as MockArbGasInfo.sol - const l1CostWeiArb = BigNumber.from(1000000) - // Same as MockOVMGasPriceOracle.sol - const l1CostWeiOpt = BigNumber.from(2000000) - - it('calculates the max fee appropriately', async () => { - await verifyMaxPayment( - Mode.DEFAULT, - multipliers, - gasAmounts, - premiums, - flatFees, - ) - }) - - it('calculates the max fee appropriately for Arbitrum', async () => { - await verifyMaxPayment( - Mode.ARBITRUM, - multipliers, - gasAmounts, - premiums, - flatFees, - l1CostWeiArb, - ) - }) - - it('calculates the max fee appropriately for Optimism', async () => { - await verifyMaxPayment( - Mode.OPTIMISM, - multipliers, - gasAmounts, - premiums, - flatFees, - l1CostWeiOpt, - ) - }) - - it('uses the fallback gas price if the feed has issues', async () => { - const expectedFallbackMaxPayment = linkForGas( - executeGas, - registryGasOverhead - .add(registryPerSignerGasOverhead.mul(f + 1)) - .add(maxPerformDataSize.mul(registryPerPerformByteGasOverhead)), - gasCeilingMultiplier.mul('2'), // fallbackGasPrice is 2x gas price - paymentPremiumPPB, - flatFeeMicroLink, - ).total - - // Stale feed - let roundId = 99 - const answer = 100 - let updatedAt = 946684800 // New Years 2000 🥳 - let startedAt = 946684799 - await gasPriceFeed - .connect(owner) - .updateRoundData(roundId, answer, updatedAt, startedAt) - - assert.equal( - expectedFallbackMaxPayment.toString(), - (await registry.getMaxPaymentForGas(executeGas)).toString(), - ) - - // Negative feed price - roundId = 100 - updatedAt = Math.floor(Date.now() / 1000) - startedAt = 946684799 - await gasPriceFeed - .connect(owner) - .updateRoundData(roundId, -100, updatedAt, startedAt) - - assert.equal( - expectedFallbackMaxPayment.toString(), - (await registry.getMaxPaymentForGas(executeGas)).toString(), - ) - - // Zero feed price - roundId = 101 - updatedAt = Math.floor(Date.now() / 1000) - startedAt = 946684799 - await gasPriceFeed - .connect(owner) - .updateRoundData(roundId, 0, updatedAt, startedAt) - - assert.equal( - expectedFallbackMaxPayment.toString(), - (await registry.getMaxPaymentForGas(executeGas)).toString(), - ) - }) - - it('uses the fallback link price if the feed has issues', async () => { - const expectedFallbackMaxPayment = linkForGas( - executeGas, - registryGasOverhead - .add(registryPerSignerGasOverhead.mul(f + 1)) - .add(maxPerformDataSize.mul(registryPerPerformByteGasOverhead)), - gasCeilingMultiplier.mul('2'), // fallbackLinkPrice is 1/2 link price, so multiply by 2 - paymentPremiumPPB, - flatFeeMicroLink, - ).total - - // Stale feed - let roundId = 99 - const answer = 100 - let updatedAt = 946684800 // New Years 2000 🥳 - let startedAt = 946684799 - await linkEthFeed - .connect(owner) - .updateRoundData(roundId, answer, updatedAt, startedAt) - - assert.equal( - expectedFallbackMaxPayment.toString(), - (await registry.getMaxPaymentForGas(executeGas)).toString(), - ) - - // Negative feed price - roundId = 100 - updatedAt = Math.floor(Date.now() / 1000) - startedAt = 946684799 - await linkEthFeed - .connect(owner) - .updateRoundData(roundId, -100, updatedAt, startedAt) - - assert.equal( - expectedFallbackMaxPayment.toString(), - (await registry.getMaxPaymentForGas(executeGas)).toString(), - ) - - // Zero feed price - roundId = 101 - updatedAt = Math.floor(Date.now() / 1000) - startedAt = 946684799 - await linkEthFeed - .connect(owner) - .updateRoundData(roundId, 0, updatedAt, startedAt) - - assert.equal( - expectedFallbackMaxPayment.toString(), - (await registry.getMaxPaymentForGas(executeGas)).toString(), - ) - }) - }) - - describe('#typeAndVersion', () => { - it('uses the correct type and version', async () => { - const typeAndVersion = await registry.typeAndVersion() - assert.equal(typeAndVersion, 'KeeperRegistry 2.0.2') - }) - }) - - describe('#onTokenTransfer', () => { - const amount = toWei('1') - - it('reverts if not called by the LINK token', async () => { - const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [upkeepId]) - - await evmRevert( - registry - .connect(keeper1) - .onTokenTransfer(await keeper1.getAddress(), amount, data), - 'OnlyCallableByLINKToken()', - ) - }) - - it('reverts if not called with more or less than 32 bytes', async () => { - const longData = ethers.utils.defaultAbiCoder.encode( - ['uint256', 'uint256'], - ['33', '34'], - ) - const shortData = '0x12345678' - - await evmRevert( - linkToken - .connect(owner) - .transferAndCall(registry.address, amount, longData), - ) - await evmRevert( - linkToken - .connect(owner) - .transferAndCall(registry.address, amount, shortData), - ) - }) - - it('reverts if the upkeep is canceled', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( - registry.connect(keeper1).addFunds(upkeepId, amount), - 'UpkeepCancelled()', - ) - }) - - it('updates the funds of the job id passed', async () => { - const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [upkeepId]) - - const before = (await registry.getUpkeep(upkeepId)).balance - await linkToken - .connect(owner) - .transferAndCall(registry.address, amount, data) - const after = (await registry.getUpkeep(upkeepId)).balance - - assert.isTrue(before.add(amount).eq(after)) - }) - }) - - describe('#setConfig - onchain', () => { - const payment = BigNumber.from(1) - const flatFee = BigNumber.from(2) - const staleness = BigNumber.from(4) - const ceiling = BigNumber.from(5) - const maxGas = BigNumber.from(6) - const fbGasEth = BigNumber.from(7) - const fbLinkEth = BigNumber.from(8) - const newMinUpkeepSpend = BigNumber.from(9) - const newMaxCheckDataSize = BigNumber.from(10000) - const newMaxPerformDataSize = BigNumber.from(10000) - const newMaxPerformGas = BigNumber.from(10000000) - - it('reverts when called by anyone but the proposed owner', async () => { - await evmRevert( - registry.connect(payee1).setConfig( - signerAddresses, - keeperAddresses, - f, - encodeConfig({ - paymentPremiumPPB: payment, - flatFeeMicroLink: flatFee, - checkGasLimit: maxGas, - stalenessSeconds: staleness, - gasCeilingMultiplier: ceiling, - minUpkeepSpend: newMinUpkeepSpend, - maxCheckDataSize: newMaxCheckDataSize, - maxPerformDataSize: newMaxPerformDataSize, - maxPerformGas: newMaxPerformGas, - fallbackGasPrice: fbGasEth, - fallbackLinkPrice: fbLinkEth, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }), - offchainVersion, - offchainBytes, - ), - 'Only callable by owner', - ) - }) - - it('updates the onchainConfig and configDigest', async () => { - const old = await registry.getState() - const oldConfig = old.config - const oldState = old.state - assert.isTrue(paymentPremiumPPB.eq(oldConfig.paymentPremiumPPB)) - assert.isTrue(flatFeeMicroLink.eq(oldConfig.flatFeeMicroLink)) - assert.isTrue(stalenessSeconds.eq(oldConfig.stalenessSeconds)) - assert.isTrue(gasCeilingMultiplier.eq(oldConfig.gasCeilingMultiplier)) - - await registry.connect(owner).setConfig( - signerAddresses, - keeperAddresses, - f, - encodeConfig({ - paymentPremiumPPB: payment, - flatFeeMicroLink: flatFee, - checkGasLimit: maxGas, - stalenessSeconds: staleness, - gasCeilingMultiplier: ceiling, - minUpkeepSpend: newMinUpkeepSpend, - maxCheckDataSize: newMaxCheckDataSize, - maxPerformDataSize: newMaxPerformDataSize, - maxPerformGas: newMaxPerformGas, - fallbackGasPrice: fbGasEth, - fallbackLinkPrice: fbLinkEth, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }), - offchainVersion, - offchainBytes, - ) - - const updated = await registry.getState() - const updatedConfig = updated.config - const updatedState = updated.state - assert.equal(updatedConfig.paymentPremiumPPB, payment.toNumber()) - assert.equal(updatedConfig.flatFeeMicroLink, flatFee.toNumber()) - assert.equal(updatedConfig.stalenessSeconds, staleness.toNumber()) - assert.equal(updatedConfig.gasCeilingMultiplier, ceiling.toNumber()) - assert.equal( - updatedConfig.minUpkeepSpend.toString(), - newMinUpkeepSpend.toString(), - ) - assert.equal( - updatedConfig.maxCheckDataSize, - newMaxCheckDataSize.toNumber(), - ) - assert.equal( - updatedConfig.maxPerformDataSize, - newMaxPerformDataSize.toNumber(), - ) - assert.equal(updatedConfig.maxPerformGas, newMaxPerformGas.toNumber()) - assert.equal(updatedConfig.checkGasLimit, maxGas.toNumber()) - assert.equal( - updatedConfig.fallbackGasPrice.toNumber(), - fbGasEth.toNumber(), - ) - assert.equal( - updatedConfig.fallbackLinkPrice.toNumber(), - fbLinkEth.toNumber(), - ) - assert.equal(updatedState.latestEpoch, 0) - - assert(oldState.configCount + 1 == updatedState.configCount) - assert( - oldState.latestConfigBlockNumber != - updatedState.latestConfigBlockNumber, - ) - assert(oldState.latestConfigDigest != updatedState.latestConfigDigest) - }) - - it('emits an event', async () => { - const tx = await registry.connect(owner).setConfig( - signerAddresses, - keeperAddresses, - f, - encodeConfig({ - paymentPremiumPPB: payment, - flatFeeMicroLink: flatFee, - checkGasLimit: maxGas, - stalenessSeconds: staleness, - gasCeilingMultiplier: ceiling, - minUpkeepSpend: newMinUpkeepSpend, - maxCheckDataSize: newMaxCheckDataSize, - maxPerformDataSize: newMaxPerformDataSize, - maxPerformGas: newMaxPerformGas, - fallbackGasPrice: fbGasEth, - fallbackLinkPrice: fbLinkEth, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }), - offchainVersion, - offchainBytes, - ) - await expect(tx).to.emit(registry, 'ConfigSet') - }) - - it('reverts upon decreasing max limits', async () => { - await evmRevert( - registry.connect(owner).setConfig( - signerAddresses, - keeperAddresses, - f, - encodeConfig({ - paymentPremiumPPB: payment, - flatFeeMicroLink: flatFee, - checkGasLimit: maxGas, - stalenessSeconds: staleness, - gasCeilingMultiplier: ceiling, - minUpkeepSpend: newMinUpkeepSpend, - maxCheckDataSize: BigNumber.from(1), - maxPerformDataSize: newMaxPerformDataSize, - maxPerformGas: newMaxPerformGas, - fallbackGasPrice: fbGasEth, - fallbackLinkPrice: fbLinkEth, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }), - offchainVersion, - offchainBytes, - ), - 'MaxCheckDataSizeCanOnlyIncrease()', - ) - await evmRevert( - registry.connect(owner).setConfig( - signerAddresses, - keeperAddresses, - f, - encodeConfig({ - paymentPremiumPPB: payment, - flatFeeMicroLink: flatFee, - checkGasLimit: maxGas, - stalenessSeconds: staleness, - gasCeilingMultiplier: ceiling, - minUpkeepSpend: newMinUpkeepSpend, - maxCheckDataSize: newMaxCheckDataSize, - maxPerformDataSize: BigNumber.from(1), - maxPerformGas: newMaxPerformGas, - fallbackGasPrice: fbGasEth, - fallbackLinkPrice: fbLinkEth, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }), - offchainVersion, - offchainBytes, - ), - 'MaxPerformDataSizeCanOnlyIncrease()', - ) - await evmRevert( - registry.connect(owner).setConfig( - signerAddresses, - keeperAddresses, - f, - encodeConfig({ - paymentPremiumPPB: payment, - flatFeeMicroLink: flatFee, - checkGasLimit: maxGas, - stalenessSeconds: staleness, - gasCeilingMultiplier: ceiling, - minUpkeepSpend: newMinUpkeepSpend, - maxCheckDataSize: newMaxCheckDataSize, - maxPerformDataSize: newMaxPerformDataSize, - maxPerformGas: BigNumber.from(1), - fallbackGasPrice: fbGasEth, - fallbackLinkPrice: fbLinkEth, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }), - offchainVersion, - offchainBytes, - ), - 'GasLimitCanOnlyIncrease()', - ) - }) - }) - - describe('#setConfig - offchain', () => { - let newKeepers: string[] - - beforeEach(async () => { - newKeepers = [ - await personas.Eddy.getAddress(), - await personas.Nick.getAddress(), - await personas.Neil.getAddress(), - await personas.Carol.getAddress(), - ] - }) - - it('reverts when called by anyone but the owner', async () => { - await evmRevert( - registry - .connect(payee1) - .setConfig( - newKeepers, - newKeepers, - f, - encodeConfig(config), - offchainVersion, - offchainBytes, - ), - 'Only callable by owner', - ) - }) - - it('reverts if too many keeperAddresses set', async () => { - for (let i = 0; i < 40; i++) { - newKeepers.push(randomAddress()) - } - await evmRevert( - registry - .connect(owner) - .setConfig( - newKeepers, - newKeepers, - f, - encodeConfig(config), - offchainVersion, - offchainBytes, - ), - 'TooManyOracles()', - ) - }) - - it('reverts if f=0', async () => { - await evmRevert( - registry - .connect(owner) - .setConfig( - newKeepers, - newKeepers, - 0, - encodeConfig(config), - offchainVersion, - offchainBytes, - ), - 'IncorrectNumberOfFaultyOracles()', - ) - }) - - it('reverts if signers != transmitters length', async () => { - const signers = [randomAddress()] - await evmRevert( - registry - .connect(owner) - .setConfig( - signers, - newKeepers, - f, - encodeConfig(config), - offchainVersion, - offchainBytes, - ), - 'IncorrectNumberOfSigners()', - ) - }) - - it('reverts if signers <= 3f', async () => { - newKeepers.pop() - await evmRevert( - registry - .connect(owner) - .setConfig( - newKeepers, - newKeepers, - f, - encodeConfig(config), - offchainVersion, - offchainBytes, - ), - 'IncorrectNumberOfSigners()', - ) - }) - - it('reverts on repeated signers', async () => { - const newSigners = [ - await personas.Eddy.getAddress(), - await personas.Eddy.getAddress(), - await personas.Eddy.getAddress(), - await personas.Eddy.getAddress(), - ] - await evmRevert( - registry - .connect(owner) - .setConfig( - newSigners, - newKeepers, - f, - encodeConfig(config), - offchainVersion, - offchainBytes, - ), - 'RepeatedSigner()', - ) - }) - - it('reverts on repeated transmitters', async () => { - const newTransmitters = [ - await personas.Eddy.getAddress(), - await personas.Eddy.getAddress(), - await personas.Eddy.getAddress(), - await personas.Eddy.getAddress(), - ] - await evmRevert( - registry - .connect(owner) - .setConfig( - newKeepers, - newTransmitters, - f, - encodeConfig(config), - offchainVersion, - offchainBytes, - ), - 'RepeatedTransmitter()', - ) - }) - - it('stores new config and emits event', async () => { - // Perform an upkeep so that totalPremium is updated - await registry.connect(admin).addFunds(upkeepId, toWei('100')) - let tx = await getTransmitTx( - registry, - keeper1, - [upkeepId.toString()], - f + 1, - ) - await tx.wait() - - const newOffChainVersion = BigNumber.from('2') - const newOffChainConfig = '0x1122' - - const old = await registry.getState() - const oldState = old.state - assert(oldState.totalPremium.gt(BigNumber.from('0'))) - - const newSigners = newKeepers - tx = await registry - .connect(owner) - .setConfig( - newSigners, - newKeepers, - f, - encodeConfig(config), - newOffChainVersion, - newOffChainConfig, - ) - - const updated = await registry.getState() - const updatedState = updated.state - assert(oldState.totalPremium.eq(updatedState.totalPremium)) - - // Old signer addresses which are not in new signers should be non active - for (let i = 0; i < signerAddresses.length; i++) { - const signer = signerAddresses[i] - if (!newSigners.includes(signer)) { - assert((await registry.getSignerInfo(signer)).active == false) - assert((await registry.getSignerInfo(signer)).index == 0) - } - } - // New signer addresses should be active - for (let i = 0; i < newSigners.length; i++) { - const signer = newSigners[i] - assert((await registry.getSignerInfo(signer)).active == true) - assert((await registry.getSignerInfo(signer)).index == i) - } - // Old transmitter addresses which are not in new transmitter should be non active, update lastCollected but retain other info - for (let i = 0; i < keeperAddresses.length; i++) { - const transmitter = keeperAddresses[i] - if (!newKeepers.includes(transmitter)) { - assert( - (await registry.getTransmitterInfo(transmitter)).active == false, - ) - assert((await registry.getTransmitterInfo(transmitter)).index == i) - assert( - ( - await registry.getTransmitterInfo(transmitter) - ).lastCollected.toString() == oldState.totalPremium.toString(), - ) - } - } - // New transmitter addresses should be active - for (let i = 0; i < newKeepers.length; i++) { - const transmitter = newKeepers[i] - assert((await registry.getTransmitterInfo(transmitter)).active == true) - assert((await registry.getTransmitterInfo(transmitter)).index == i) - assert( - ( - await registry.getTransmitterInfo(transmitter) - ).lastCollected.toString() == oldState.totalPremium.toString(), - ) - } - - // config digest should be updated - assert(oldState.configCount + 1 == updatedState.configCount) - assert( - oldState.latestConfigBlockNumber != - updatedState.latestConfigBlockNumber, - ) - assert(oldState.latestConfigDigest != updatedState.latestConfigDigest) - - //New config should be updated - assert.deepEqual(updated.signers, newKeepers) - assert.deepEqual(updated.transmitters, newKeepers) - - // Event should have been emitted - await expect(tx).to.emit(registry, 'ConfigSet') - }) - }) - - describe('#setPeerRegistryMigrationPermission() / #getPeerRegistryMigrationPermission()', () => { - const peer = randomAddress() - it('allows the owner to set the peer registries', async () => { - let permission = await registry.getPeerRegistryMigrationPermission(peer) - expect(permission).to.equal(0) - await registry.setPeerRegistryMigrationPermission(peer, 1) - permission = await registry.getPeerRegistryMigrationPermission(peer) - expect(permission).to.equal(1) - await registry.setPeerRegistryMigrationPermission(peer, 2) - permission = await registry.getPeerRegistryMigrationPermission(peer) - expect(permission).to.equal(2) - await registry.setPeerRegistryMigrationPermission(peer, 0) - permission = await registry.getPeerRegistryMigrationPermission(peer) - expect(permission).to.equal(0) - }) - it('reverts if passed an unsupported permission', async () => { - await expect( - registry.connect(admin).setPeerRegistryMigrationPermission(peer, 10), - ).to.be.reverted - }) - it('reverts if not called by the owner', async () => { - await expect( - registry.connect(admin).setPeerRegistryMigrationPermission(peer, 1), - ).to.be.revertedWith('Only callable by owner') - }) - }) - - describe('#registerUpkeep', () => { - it('reverts when registry is paused', async () => { - await registry.connect(owner).pause() - await evmRevert( - registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - emptyBytes, - ), - 'RegistryPaused()', - ) - }) - - it('reverts if the target is not a contract', async () => { - await evmRevert( - registry - .connect(owner) - .registerUpkeep( - zeroAddress, - executeGas, - await admin.getAddress(), - emptyBytes, - emptyBytes, - ), - 'NotAContract()', - ) - }) - - it('reverts if called by a non-owner', async () => { - await evmRevert( - registry - .connect(keeper1) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - emptyBytes, - ), - 'OnlyCallableByOwnerOrRegistrar()', - ) - }) - - it('reverts if execute gas is too low', async () => { - await evmRevert( - registry - .connect(owner) - .registerUpkeep( - mock.address, - 2299, - await admin.getAddress(), - emptyBytes, - emptyBytes, - ), - 'GasLimitOutsideRange()', - ) - }) - - it('reverts if execute gas is too high', async () => { - await evmRevert( - registry - .connect(owner) - .registerUpkeep( - mock.address, - 5000001, - await admin.getAddress(), - emptyBytes, - emptyBytes, - ), - 'GasLimitOutsideRange()', - ) - }) - - it('reverts if checkData is too long', async () => { - let longBytes = '0x' - for (let i = 0; i < 10000; i++) { - longBytes += '1' - } - await evmRevert( - registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - longBytes, - emptyBytes, - ), - 'CheckDataExceedsLimit()', - ) - }) - - it('creates a record of the registration', async () => { - const executeGases = [100000, 500000] - const checkDatas = [emptyBytes, '0x12'] - const offchainConfig = '0x1234567890' - - for (let jdx = 0; jdx < executeGases.length; jdx++) { - const executeGas = executeGases[jdx] - for (let kdx = 0; kdx < checkDatas.length; kdx++) { - const checkData = checkDatas[kdx] - const tx = await registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - checkData, - offchainConfig, - ) - - //confirm the upkeep details - upkeepId = await getUpkeepID(tx) - await expect(tx) - .to.emit(registry, 'UpkeepRegistered') - .withArgs(upkeepId, executeGas, await admin.getAddress()) - const registration = await registry.getUpkeep(upkeepId) - - assert.equal(mock.address, registration.target) - assert.equal( - executeGas.toString(), - registration.executeGas.toString(), - ) - assert.equal(await admin.getAddress(), registration.admin) - assert.equal(0, registration.balance.toNumber()) - assert.equal(0, registration.amountSpent.toNumber()) - assert.equal(0, registration.lastPerformBlockNumber) - assert.equal(checkData, registration.checkData) - assert.equal(registration.paused, false) - assert.equal(registration.offchainConfig, offchainConfig) - assert(registration.maxValidBlocknumber.eq('0xffffffff')) - } - } - }) - }) - - describe('#pauseUpkeep', () => { - it('reverts if the registration does not exist', async () => { - await evmRevert( - registry.connect(keeper1).pauseUpkeep(upkeepId.add(1)), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if the upkeep is already canceled', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - - await evmRevert( - registry.connect(admin).pauseUpkeep(upkeepId), - 'UpkeepCancelled()', - ) - }) - - it('reverts if the upkeep is already paused', async () => { - await registry.connect(admin).pauseUpkeep(upkeepId) - - await evmRevert( - registry.connect(admin).pauseUpkeep(upkeepId), - 'OnlyUnpausedUpkeep()', - ) - }) - - it('reverts if the caller is not the upkeep admin', async () => { - await evmRevert( - registry.connect(keeper1).pauseUpkeep(upkeepId), - 'OnlyCallableByAdmin()', - ) - }) - - it('pauses the upkeep and emits an event', async () => { - const tx = await registry.connect(admin).pauseUpkeep(upkeepId) - await expect(tx).to.emit(registry, 'UpkeepPaused').withArgs(upkeepId) - - const registration = await registry.getUpkeep(upkeepId) - assert.equal(registration.paused, true) - }) - }) - - describe('#unpauseUpkeep', () => { - it('reverts if the registration does not exist', async () => { - await evmRevert( - registry.connect(keeper1).unpauseUpkeep(upkeepId.add(1)), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if the upkeep is already canceled', async () => { - await registry.connect(owner).cancelUpkeep(upkeepId) - - await evmRevert( - registry.connect(admin).unpauseUpkeep(upkeepId), - 'UpkeepCancelled()', - ) - }) - - it('marks the contract as paused', async () => { - assert.isFalse((await registry.getState()).state.paused) - - await registry.connect(owner).pause() - - assert.isTrue((await registry.getState()).state.paused) - }) - - it('reverts if the upkeep is not paused', async () => { - await evmRevert( - registry.connect(admin).unpauseUpkeep(upkeepId), - 'OnlyPausedUpkeep()', - ) - }) - - it('reverts if the caller is not the upkeep admin', async () => { - await registry.connect(admin).pauseUpkeep(upkeepId) - - const registration = await registry.getUpkeep(upkeepId) - - assert.equal(registration.paused, true) - - await evmRevert( - registry.connect(keeper1).unpauseUpkeep(upkeepId), - 'OnlyCallableByAdmin()', - ) - }) - - it('unpauses the upkeep and emits an event', async () => { - await registry.connect(admin).pauseUpkeep(upkeepId) - - const tx = await registry.connect(admin).unpauseUpkeep(upkeepId) - - await expect(tx).to.emit(registry, 'UpkeepUnpaused').withArgs(upkeepId) - - const registration = await registry.getUpkeep(upkeepId) - assert.equal(registration.paused, false) - - const upkeepIds = await registry.getActiveUpkeepIDs(0, 0) - assert.equal(upkeepIds.length, 1) - }) - }) - - describe('#updateCheckData', () => { - it('reverts if the registration does not exist', async () => { - await evmRevert( - registry.connect(keeper1).updateCheckData(upkeepId.add(1), randomBytes), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if the caller is not upkeep admin', async () => { - await evmRevert( - registry.connect(keeper1).updateCheckData(upkeepId, randomBytes), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if the upkeep is cancelled', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - - await evmRevert( - registry.connect(admin).updateCheckData(upkeepId, randomBytes), - 'UpkeepCancelled()', - ) - }) - - it('is allowed to update on paused upkeep', async () => { - await registry.connect(admin).pauseUpkeep(upkeepId) - await registry.connect(admin).updateCheckData(upkeepId, randomBytes) - - const registration = await registry.getUpkeep(upkeepId) - assert.equal(randomBytes, registration.checkData) - }) - - it('reverts if newCheckData exceeds limit', async () => { - let longBytes = '0x' - for (let i = 0; i < 10000; i++) { - longBytes += '1' - } - - await evmRevert( - registry.connect(admin).updateCheckData(upkeepId, longBytes), - 'CheckDataExceedsLimit()', - ) - }) - - it('updates the upkeep check data and emits an event', async () => { - const tx = await registry - .connect(admin) - .updateCheckData(upkeepId, randomBytes) - await expect(tx) - .to.emit(registry, 'UpkeepCheckDataUpdated') - .withArgs(upkeepId, randomBytes) - - const registration = await registry.getUpkeep(upkeepId) - assert.equal(randomBytes, registration.checkData) - }) - }) - - describe('#setUpkeepGasLimit', () => { - const newGasLimit = BigNumber.from('300000') - - it('reverts if the registration does not exist', async () => { - await evmRevert( - registry.connect(admin).setUpkeepGasLimit(upkeepId.add(1), newGasLimit), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if the upkeep is canceled', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( - registry.connect(admin).setUpkeepGasLimit(upkeepId, newGasLimit), - 'UpkeepCancelled()', - ) - }) - - it('reverts if called by anyone but the admin', async () => { - await evmRevert( - registry.connect(owner).setUpkeepGasLimit(upkeepId, newGasLimit), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if new gas limit is out of bounds', async () => { - await evmRevert( - registry - .connect(admin) - .setUpkeepGasLimit(upkeepId, BigNumber.from('100')), - 'GasLimitOutsideRange()', - ) - await evmRevert( - registry - .connect(admin) - .setUpkeepGasLimit(upkeepId, BigNumber.from('6000000')), - 'GasLimitOutsideRange()', - ) - }) - - it('updates the gas limit successfully', async () => { - const initialGasLimit = (await registry.getUpkeep(upkeepId)).executeGas - assert.equal(initialGasLimit, executeGas.toNumber()) - await registry.connect(admin).setUpkeepGasLimit(upkeepId, newGasLimit) - const updatedGasLimit = (await registry.getUpkeep(upkeepId)).executeGas - assert.equal(updatedGasLimit, newGasLimit.toNumber()) - }) - - it('emits a log', async () => { - const tx = await registry - .connect(admin) - .setUpkeepGasLimit(upkeepId, newGasLimit) - await expect(tx) - .to.emit(registry, 'UpkeepGasLimitSet') - .withArgs(upkeepId, newGasLimit) - }) - }) - - describe('#setUpkeepOffchainConfig', () => { - const newConfig = '0xc0ffeec0ffee' - - it('reverts if the registration does not exist', async () => { - await evmRevert( - registry - .connect(admin) - .setUpkeepOffchainConfig(upkeepId.add(1), newConfig), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if the upkeep is canceled', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( - registry.connect(admin).setUpkeepOffchainConfig(upkeepId, newConfig), - 'UpkeepCancelled()', - ) - }) - - it('reverts if called by anyone but the admin', async () => { - await evmRevert( - registry.connect(owner).setUpkeepOffchainConfig(upkeepId, newConfig), - 'OnlyCallableByAdmin()', - ) - }) - - it('updates the config successfully', async () => { - const initialConfig = (await registry.getUpkeep(upkeepId)).offchainConfig - assert.equal(initialConfig, '0x') - await registry.connect(admin).setUpkeepOffchainConfig(upkeepId, newConfig) - const updatedConfig = (await registry.getUpkeep(upkeepId)).offchainConfig - assert.equal(newConfig, updatedConfig) - }) - - it('emits a log', async () => { - const tx = await registry - .connect(admin) - .setUpkeepOffchainConfig(upkeepId, newConfig) - await expect(tx) - .to.emit(registry, 'UpkeepOffchainConfigSet') - .withArgs(upkeepId, newConfig) - }) - }) - - describe('#transferUpkeepAdmin', () => { - it('reverts when called by anyone but the current upkeep admin', async () => { - await evmRevert( - registry - .connect(payee1) - .transferUpkeepAdmin(upkeepId, await payee2.getAddress()), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts when transferring to self', async () => { - await evmRevert( - registry - .connect(admin) - .transferUpkeepAdmin(upkeepId, await admin.getAddress()), - 'ValueNotChanged()', - ) - }) - - it('reverts when the upkeep is cancelled', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - - await evmRevert( - registry - .connect(admin) - .transferUpkeepAdmin(upkeepId, await keeper1.getAddress()), - 'UpkeepCancelled()', - ) - }) - - it('reverts when transferring to zero address', async () => { - await evmRevert( - registry - .connect(admin) - .transferUpkeepAdmin(upkeepId, ethers.constants.AddressZero), - 'InvalidRecipient()', - ) - }) - - it('does not change the upkeep admin', async () => { - await registry - .connect(admin) - .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) - - const upkeep = await registry.getUpkeep(upkeepId) - assert.equal(await admin.getAddress(), upkeep.admin) - }) - - it('emits an event announcing the new upkeep admin', async () => { - const tx = await registry - .connect(admin) - .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) - - await expect(tx) - .to.emit(registry, 'UpkeepAdminTransferRequested') - .withArgs(upkeepId, await admin.getAddress(), await payee1.getAddress()) - }) - - it('does not emit an event when called with the same proposed upkeep admin', async () => { - await registry - .connect(admin) - .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) - - const tx = await registry - .connect(admin) - .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) - const receipt = await tx.wait() - assert.equal(0, receipt.logs.length) - }) - }) - - describe('#acceptUpkeepAdmin', () => { - beforeEach(async () => { - // Start admin transfer to payee1 - await registry - .connect(admin) - .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) - }) - - it('reverts when not called by the proposed upkeep admin', async () => { - await evmRevert( - registry.connect(payee2).acceptUpkeepAdmin(upkeepId), - 'OnlyCallableByProposedAdmin()', - ) - }) - - it('reverts when the upkeep is cancelled', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - - await evmRevert( - registry.connect(payee1).acceptUpkeepAdmin(upkeepId), - 'UpkeepCancelled()', - ) - }) - - it('does change the admin', async () => { - await registry.connect(payee1).acceptUpkeepAdmin(upkeepId) - - const upkeep = await registry.getUpkeep(upkeepId) - assert.equal(await payee1.getAddress(), upkeep.admin) - }) - - it('emits an event announcing the new upkeep admin', async () => { - const tx = await registry.connect(payee1).acceptUpkeepAdmin(upkeepId) - await expect(tx) - .to.emit(registry, 'UpkeepAdminTransferred') - .withArgs(upkeepId, await admin.getAddress(), await payee1.getAddress()) - }) - }) - - describe('#withdrawOwnerFunds', () => { - it('can only be called by owner', async () => { - await evmRevert( - registry.connect(keeper1).withdrawOwnerFunds(), - 'Only callable by owner', - ) - }) - - it('withdraws the collected fees to owner', async () => { - await registry.connect(admin).addFunds(upkeepId, toWei('100')) - // Very high min spend, whole balance as cancellation fees - const minUpkeepSpend = toWei('1000') - await registry.connect(owner).setConfig( - signerAddresses, - keeperAddresses, - f, - encodeConfig({ - paymentPremiumPPB, - flatFeeMicroLink, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxCheckDataSize, - maxPerformDataSize, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }), - offchainVersion, - offchainBytes, - ) - const upkeepBalance = (await registry.getUpkeep(upkeepId)).balance - const ownerBefore = await linkToken.balanceOf(await owner.getAddress()) - - await registry.connect(owner).cancelUpkeep(upkeepId) - - // Transfered to owner balance on registry - let ownerRegistryBalance = (await registry.getState()).state - .ownerLinkBalance - assert.isTrue(ownerRegistryBalance.eq(upkeepBalance)) - - // Now withdraw - await registry.connect(owner).withdrawOwnerFunds() - - ownerRegistryBalance = (await registry.getState()).state.ownerLinkBalance - const ownerAfter = await linkToken.balanceOf(await owner.getAddress()) - - // Owner registry balance should be changed to 0 - assert.isTrue(ownerRegistryBalance.eq(BigNumber.from('0'))) - - // Owner should be credited with the balance - assert.isTrue(ownerBefore.add(upkeepBalance).eq(ownerAfter)) - }) - }) - - describe('#transferPayeeship', () => { - it('reverts when called by anyone but the current payee', async () => { - await evmRevert( - registry - .connect(payee2) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ), - 'OnlyCallableByPayee()', - ) - }) - - it('reverts when transferring to self', async () => { - await evmRevert( - registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee1.getAddress(), - ), - 'ValueNotChanged()', - ) - }) - - it('does not change the payee', async () => { - await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - - const info = await registry.getTransmitterInfo(await keeper1.getAddress()) - assert.equal(await payee1.getAddress(), info.payee) - }) - - it('emits an event announcing the new payee', async () => { - const tx = await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - await expect(tx) - .to.emit(registry, 'PayeeshipTransferRequested') - .withArgs( - await keeper1.getAddress(), - await payee1.getAddress(), - await payee2.getAddress(), - ) - }) - - it('does not emit an event when called with the same proposal', async () => { - await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - - const tx = await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - const receipt = await tx.wait() - assert.equal(0, receipt.logs.length) - }) - }) - - describe('#acceptPayeeship', () => { - beforeEach(async () => { - await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - }) - - it('reverts when called by anyone but the proposed payee', async () => { - await evmRevert( - registry.connect(payee1).acceptPayeeship(await keeper1.getAddress()), - 'OnlyCallableByProposedPayee()', - ) - }) - - it('emits an event announcing the new payee', async () => { - const tx = await registry - .connect(payee2) - .acceptPayeeship(await keeper1.getAddress()) - await expect(tx) - .to.emit(registry, 'PayeeshipTransferred') - .withArgs( - await keeper1.getAddress(), - await payee1.getAddress(), - await payee2.getAddress(), - ) - }) - - it('does change the payee', async () => { - await registry.connect(payee2).acceptPayeeship(await keeper1.getAddress()) - - const info = await registry.getTransmitterInfo(await keeper1.getAddress()) - assert.equal(await payee2.getAddress(), info.payee) - }) - }) - - describe('#pause', () => { - it('reverts if called by a non-owner', async () => { - await evmRevert( - registry.connect(keeper1).pause(), - 'Only callable by owner', - ) - }) - - it('marks the contract as paused', async () => { - assert.isFalse((await registry.getState()).state.paused) - - await registry.connect(owner).pause() - - assert.isTrue((await registry.getState()).state.paused) - }) - - it('Does not allow transmits when paused', async () => { - await registry.connect(owner).pause() - - await evmRevert( - getTransmitTx(registry, keeper1, [upkeepId.toString()], f + 1), - 'RegistryPaused()', - ) - }) - - it('Does not allow creation of new upkeeps when paused', async () => { - await registry.connect(owner).pause() - - await evmRevert( - registry - .connect(owner) - .registerUpkeep( - mock.address, - executeGas, - await admin.getAddress(), - emptyBytes, - emptyBytes, - ), - 'RegistryPaused()', - ) - }) - }) - - describe('#unpause', () => { - beforeEach(async () => { - await registry.connect(owner).pause() - }) - - it('reverts if called by a non-owner', async () => { - await evmRevert( - registry.connect(keeper1).unpause(), - 'Only callable by owner', - ) - }) - - it('marks the contract as not paused', async () => { - assert.isTrue((await registry.getState()).state.paused) - - await registry.connect(owner).unpause() - - assert.isFalse((await registry.getState()).state.paused) - }) - }) - - describe('migrateUpkeeps() / #receiveUpkeeps()', async () => { - let registry2: KeeperRegistry - let registryLogic2: KeeperRegistryLogic - - beforeEach(async () => { - registryLogic2 = await keeperRegistryLogicFactory - .connect(owner) - .deploy( - Mode.DEFAULT, - linkToken.address, - linkEthFeed.address, - gasPriceFeed.address, - ) - - const config = { - paymentPremiumPPB, - flatFeeMicroLink, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxCheckDataSize, - maxPerformDataSize, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - } - registry2 = await keeperRegistryFactory - .connect(owner) - .deploy(registryLogic2.address) - await registry2 - .connect(owner) - .setConfig( - signerAddresses, - keeperAddresses, - f, - encodeConfig(config), - 1, - '0x', - ) - }) - - context('when permissions are set', () => { - beforeEach(async () => { - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(upkeepId, toWei('100')) - await registry.setPeerRegistryMigrationPermission(registry2.address, 1) - await registry2.setPeerRegistryMigrationPermission(registry.address, 2) - }) - - it('migrates an upkeep', async () => { - expect((await registry.getUpkeep(upkeepId)).balance).to.equal( - toWei('100'), - ) - expect((await registry.getUpkeep(upkeepId)).checkData).to.equal( - randomBytes, - ) - expect((await registry.getState()).state.numUpkeeps).to.equal(1) - // Set an upkeep admin transfer in progress too - await registry - .connect(admin) - .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) - - // migrate - await registry - .connect(admin) - .migrateUpkeeps([upkeepId], registry2.address) - expect((await registry.getState()).state.numUpkeeps).to.equal(0) - expect((await registry2.getState()).state.numUpkeeps).to.equal(1) - expect((await registry.getUpkeep(upkeepId)).balance).to.equal(0) - expect((await registry.getUpkeep(upkeepId)).checkData).to.equal('0x') - expect((await registry2.getUpkeep(upkeepId)).balance).to.equal( - toWei('100'), - ) - expect((await registry2.getState()).state.expectedLinkBalance).to.equal( - toWei('100'), - ) - expect((await registry2.getUpkeep(upkeepId)).checkData).to.equal( - randomBytes, - ) - // migration will delete the upkeep and nullify admin transfer - await expect( - registry.connect(payee1).acceptUpkeepAdmin(upkeepId), - ).to.be.revertedWith('UpkeepCancelled()') - await expect( - registry2.connect(payee1).acceptUpkeepAdmin(upkeepId), - ).to.be.revertedWith('OnlyCallableByProposedAdmin()') - }) - - it('migrates a paused upkeep', async () => { - expect((await registry.getUpkeep(upkeepId)).balance).to.equal( - toWei('100'), - ) - expect((await registry.getUpkeep(upkeepId)).checkData).to.equal( - randomBytes, - ) - expect((await registry.getState()).state.numUpkeeps).to.equal(1) - await registry.connect(admin).pauseUpkeep(upkeepId) - // verify the upkeep is paused - expect((await registry.getUpkeep(upkeepId)).paused).to.equal(true) - // migrate - await registry - .connect(admin) - .migrateUpkeeps([upkeepId], registry2.address) - expect((await registry.getState()).state.numUpkeeps).to.equal(0) - expect((await registry2.getState()).state.numUpkeeps).to.equal(1) - expect((await registry.getUpkeep(upkeepId)).balance).to.equal(0) - expect((await registry2.getUpkeep(upkeepId)).balance).to.equal( - toWei('100'), - ) - expect((await registry.getUpkeep(upkeepId)).checkData).to.equal('0x') - expect((await registry2.getUpkeep(upkeepId)).checkData).to.equal( - randomBytes, - ) - expect((await registry2.getState()).state.expectedLinkBalance).to.equal( - toWei('100'), - ) - // verify the upkeep is still paused after migration - expect((await registry2.getUpkeep(upkeepId)).paused).to.equal(true) - }) - - it('emits an event on both contracts', async () => { - expect((await registry.getUpkeep(upkeepId)).balance).to.equal( - toWei('100'), - ) - expect((await registry.getUpkeep(upkeepId)).checkData).to.equal( - randomBytes, - ) - expect((await registry.getState()).state.numUpkeeps).to.equal(1) - const tx = registry - .connect(admin) - .migrateUpkeeps([upkeepId], registry2.address) - await expect(tx) - .to.emit(registry, 'UpkeepMigrated') - .withArgs(upkeepId, toWei('100'), registry2.address) - await expect(tx) - .to.emit(registry2, 'UpkeepReceived') - .withArgs(upkeepId, toWei('100'), registry.address) - }) - - it('is only migratable by the admin', async () => { - await expect( - registry.connect(owner).migrateUpkeeps([upkeepId], registry2.address), - ).to.be.revertedWith('OnlyCallableByAdmin()') - await registry - .connect(admin) - .migrateUpkeeps([upkeepId], registry2.address) - }) - }) - - context('when permissions are not set', () => { - it('reverts', async () => { - // no permissions - await registry.setPeerRegistryMigrationPermission(registry2.address, 0) - await registry2.setPeerRegistryMigrationPermission(registry.address, 0) - await expect(registry.migrateUpkeeps([upkeepId], registry2.address)).to - .be.reverted - // only outgoing permissions - await registry.setPeerRegistryMigrationPermission(registry2.address, 1) - await registry2.setPeerRegistryMigrationPermission(registry.address, 0) - await expect(registry.migrateUpkeeps([upkeepId], registry2.address)).to - .be.reverted - // only incoming permissions - await registry.setPeerRegistryMigrationPermission(registry2.address, 0) - await registry2.setPeerRegistryMigrationPermission(registry.address, 2) - await expect(registry.migrateUpkeeps([upkeepId], registry2.address)).to - .be.reverted - // permissions opposite direction - await registry.setPeerRegistryMigrationPermission(registry2.address, 2) - await registry2.setPeerRegistryMigrationPermission(registry.address, 1) - await expect(registry.migrateUpkeeps([upkeepId], registry2.address)).to - .be.reverted - }) - }) - }) - - describe('#setPayees', () => { - const IGNORE_ADDRESS = '0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF' - - beforeEach(async () => { - keeperAddresses = keeperAddresses.slice(0, 4) - signerAddresses = signerAddresses.slice(0, 4) - payees = payees.slice(0, 4) - - // Redeploy registry with zero address payees (non set) - registry = await keeperRegistryFactory - .connect(owner) - .deploy(registryLogic.address) - - await registry - .connect(owner) - .setConfig( - signerAddresses, - keeperAddresses, - f, - encodeConfig(config), - offchainVersion, - offchainBytes, - ) - }) - - it('reverts when not called by the owner', async () => { - await evmRevert( - registry.connect(keeper1).setPayees([]), - 'Only callable by owner', - ) - }) - - it('reverts with different numbers of payees than transmitters', async () => { - // 4 transmitters are set, so exactly 4 payess should be added - await evmRevert( - registry.connect(owner).setPayees([await payee1.getAddress()]), - 'ParameterLengthError()', - ) - await evmRevert( - registry - .connect(owner) - .setPayees([ - await payee1.getAddress(), - await payee1.getAddress(), - await payee1.getAddress(), - await payee1.getAddress(), - await payee1.getAddress(), - ]), - 'ParameterLengthError()', - ) - }) - - it('reverts if the payee is the zero address', async () => { - await evmRevert( - registry - .connect(owner) - .setPayees([ - await payee1.getAddress(), - '0x0000000000000000000000000000000000000000', - await payee3.getAddress(), - await payee4.getAddress(), - ]), - 'InvalidPayee()', - ) - }) - - it('sets the payees when exisitng payees are zero address', async () => { - //Initial payees should be zero address - for (let i = 0; i < keeperAddresses.length; i++) { - const payee = (await registry.getTransmitterInfo(keeperAddresses[i])) - .payee - assert.equal(payee, zeroAddress) - } - - await registry.connect(owner).setPayees(payees) - - for (let i = 0; i < keeperAddresses.length; i++) { - const payee = (await registry.getTransmitterInfo(keeperAddresses[i])) - .payee - assert.equal(payee, payees[i]) - } - }) - - it('does not change the payee if IGNORE_ADDRESS is used as payee', async () => { - // Set initial payees - await registry.connect(owner).setPayees(payees) - - const newPayees = [ - await payee1.getAddress(), - IGNORE_ADDRESS, - await payee3.getAddress(), - await payee4.getAddress(), - ] - await registry.connect(owner).setPayees(newPayees) - - const ignored = await registry.getTransmitterInfo( - await keeper2.getAddress(), - ) - assert.equal(await payee2.getAddress(), ignored.payee) - assert.equal(true, ignored.active) - }) - - it('reverts if payee is non zero and owner tries to change payee', async () => { - // Set initial payees - await registry.connect(owner).setPayees(payees) - - const newPayees = [ - await payee1.getAddress(), - await owner.getAddress(), - await payee3.getAddress(), - await payee4.getAddress(), - ] - await evmRevert( - registry.connect(owner).setPayees(newPayees), - 'InvalidPayee()', - ) - }) - - it('emits events for every payee added and removed', async () => { - const tx = await registry.connect(owner).setPayees(payees) - await expect(tx) - .to.emit(registry, 'PayeesUpdated') - .withArgs(keeperAddresses, payees) - }) - }) - - describe('#cancelUpkeep', () => { - it('reverts if the ID is not valid', async () => { - await evmRevert( - registry.connect(owner).cancelUpkeep(upkeepId.add(1)), - 'CannotCancel()', - ) - }) - - it('reverts if called by a non-owner/non-admin', async () => { - await evmRevert( - registry.connect(keeper1).cancelUpkeep(upkeepId), - 'OnlyCallableByOwnerOrAdmin()', - ) - }) - - describe('when called by the owner', async () => { - it('sets the registration to invalid immediately', async () => { - const tx = await registry.connect(owner).cancelUpkeep(upkeepId) - const receipt = await tx.wait() - const registration = await registry.getUpkeep(upkeepId) - assert.equal( - registration.maxValidBlocknumber.toNumber(), - receipt.blockNumber, - ) - }) - - it('emits an event', async () => { - const tx = await registry.connect(owner).cancelUpkeep(upkeepId) - const receipt = await tx.wait() - await expect(tx) - .to.emit(registry, 'UpkeepCanceled') - .withArgs(upkeepId, BigNumber.from(receipt.blockNumber)) - }) - - it('immediately prevents upkeep', async () => { - await registry.connect(owner).cancelUpkeep(upkeepId) - - const tx = await getTransmitTx( - registry, - keeper1, - [upkeepId.toString()], - f + 1, - ) - const receipt = await tx.wait() - const cancelledUpkeepReportLogs = - parseCancelledUpkeepReportLogs(receipt) - // exactly 1 CancelledUpkeepReport log should be emitted - assert.equal(cancelledUpkeepReportLogs.length, 1) - }) - - it('does not revert if reverts if called multiple times', async () => { - await registry.connect(owner).cancelUpkeep(upkeepId) - await evmRevert( - registry.connect(owner).cancelUpkeep(upkeepId), - 'CannotCancel()', - ) - }) - - describe('when called by the owner when the admin has just canceled', () => { - let oldExpiration: BigNumber - - beforeEach(async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - const registration = await registry.getUpkeep(upkeepId) - oldExpiration = registration.maxValidBlocknumber - }) - - it('allows the owner to cancel it more quickly', async () => { - await registry.connect(owner).cancelUpkeep(upkeepId) - - const registration = await registry.getUpkeep(upkeepId) - const newExpiration = registration.maxValidBlocknumber - assert.isTrue(newExpiration.lt(oldExpiration)) - }) - }) - }) - - describe('when called by the admin', async () => { - it('reverts if called again by the admin', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - - await evmRevert( - registry.connect(admin).cancelUpkeep(upkeepId), - 'CannotCancel()', - ) - }) - - it('reverts if called by the owner after the timeout', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - - for (let i = 0; i < cancellationDelay; i++) { - await ethers.provider.send('evm_mine', []) - } - - await evmRevert( - registry.connect(owner).cancelUpkeep(upkeepId), - 'CannotCancel()', - ) - }) - - it('sets the registration to invalid in 50 blocks', async () => { - const tx = await registry.connect(admin).cancelUpkeep(upkeepId) - const receipt = await tx.wait() - const registration = await registry.getUpkeep(upkeepId) - assert.equal( - registration.maxValidBlocknumber.toNumber(), - receipt.blockNumber + 50, - ) - }) - - it('emits an event', async () => { - const tx = await registry.connect(admin).cancelUpkeep(upkeepId) - const receipt = await tx.wait() - await expect(tx) - .to.emit(registry, 'UpkeepCanceled') - .withArgs( - upkeepId, - BigNumber.from(receipt.blockNumber + cancellationDelay), - ) - }) - - it('immediately prevents upkeep', async () => { - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(upkeepId, toWei('100')) - await registry.connect(admin).cancelUpkeep(upkeepId) - - await getTransmitTx(registry, keeper1, [upkeepId.toString()], f + 1) - - for (let i = 0; i < cancellationDelay; i++) { - await ethers.provider.send('evm_mine', []) - } - - const tx = await getTransmitTx( - registry, - keeper1, - [upkeepId.toString()], - f + 1, - ) - - const receipt = await tx.wait() - const cancelledUpkeepReportLogs = - parseCancelledUpkeepReportLogs(receipt) - // exactly 1 CancelledUpkeepReport log should be emitted - assert.equal(cancelledUpkeepReportLogs.length, 1) - }) - - describe('when an upkeep has been performed', async () => { - beforeEach(async () => { - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(upkeepId, toWei('100')) - await getTransmitTx(registry, keeper1, [upkeepId.toString()], f + 1) - }) - - it('deducts a cancellation fee from the upkeep and gives to owner', async () => { - const minUpkeepSpend = toWei('10') - - await registry.connect(owner).setConfig( - signerAddresses, - keeperAddresses, - f, - encodeConfig({ - paymentPremiumPPB, - flatFeeMicroLink, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxCheckDataSize, - maxPerformDataSize, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }), - offchainVersion, - offchainBytes, - ) - - const payee1Before = await linkToken.balanceOf( - await payee1.getAddress(), - ) - const upkeepBefore = (await registry.getUpkeep(upkeepId)).balance - const ownerBefore = (await registry.getState()).state.ownerLinkBalance - - const amountSpent = toWei('100').sub(upkeepBefore) - const cancellationFee = minUpkeepSpend.sub(amountSpent) - - await registry.connect(admin).cancelUpkeep(upkeepId) - - const payee1After = await linkToken.balanceOf( - await payee1.getAddress(), - ) - const upkeepAfter = (await registry.getUpkeep(upkeepId)).balance - const ownerAfter = (await registry.getState()).state.ownerLinkBalance - - // post upkeep balance should be previous balance minus cancellation fee - assert.isTrue(upkeepBefore.sub(cancellationFee).eq(upkeepAfter)) - // payee balance should not change - assert.isTrue(payee1Before.eq(payee1After)) - // owner should receive the cancellation fee - assert.isTrue(ownerAfter.sub(ownerBefore).eq(cancellationFee)) - }) - - it('deducts up to balance as cancellation fee', async () => { - // Very high min spend, should deduct whole balance as cancellation fees - const minUpkeepSpend = toWei('1000') - await registry.connect(owner).setConfig( - signerAddresses, - keeperAddresses, - f, - encodeConfig({ - paymentPremiumPPB, - flatFeeMicroLink, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxCheckDataSize, - maxPerformDataSize, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }), - offchainVersion, - offchainBytes, - ) - const payee1Before = await linkToken.balanceOf( - await payee1.getAddress(), - ) - const upkeepBefore = (await registry.getUpkeep(upkeepId)).balance - const ownerBefore = (await registry.getState()).state.ownerLinkBalance - - await registry.connect(admin).cancelUpkeep(upkeepId) - const payee1After = await linkToken.balanceOf( - await payee1.getAddress(), - ) - const ownerAfter = (await registry.getState()).state.ownerLinkBalance - const upkeepAfter = (await registry.getUpkeep(upkeepId)).balance - - // all upkeep balance is deducted for cancellation fee - assert.equal(0, upkeepAfter.toNumber()) - // payee balance should not change - assert.isTrue(payee1After.eq(payee1Before)) - // all upkeep balance is transferred to the owner - assert.isTrue(ownerAfter.sub(ownerBefore).eq(upkeepBefore)) - }) - - it('does not deduct cancellation fee if more than minUpkeepSpend is spent', async () => { - // Very low min spend, already spent in one perform upkeep - const minUpkeepSpend = BigNumber.from(420) - await registry.connect(owner).setConfig( - signerAddresses, - keeperAddresses, - f, - encodeConfig({ - paymentPremiumPPB, - flatFeeMicroLink, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxCheckDataSize, - maxPerformDataSize, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrar: ethers.constants.AddressZero, - }), - offchainVersion, - offchainBytes, - ) - const payee1Before = await linkToken.balanceOf( - await payee1.getAddress(), - ) - const upkeepBefore = (await registry.getUpkeep(upkeepId)).balance - const ownerBefore = (await registry.getState()).state.ownerLinkBalance - - await registry.connect(admin).cancelUpkeep(upkeepId) - const payee1After = await linkToken.balanceOf( - await payee1.getAddress(), - ) - const ownerAfter = (await registry.getState()).state.ownerLinkBalance - const upkeepAfter = (await registry.getUpkeep(upkeepId)).balance - - // upkeep does not pay cancellation fee after cancellation because minimum upkeep spent is met - assert.isTrue(upkeepBefore.eq(upkeepAfter)) - // owner balance does not change - assert.isTrue(ownerAfter.eq(ownerBefore)) - // payee balance does not change - assert.isTrue(payee1Before.eq(payee1After)) - }) - }) - }) - }) - - describe('#withdrawPayment', () => { - beforeEach(async () => { - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(upkeepId, toWei('100')) - await getTransmitTx(registry, keeper1, [upkeepId.toString()], f + 1) - }) - - it('reverts if called by anyone but the payee', async () => { - await evmRevert( - registry - .connect(payee2) - .withdrawPayment( - await keeper1.getAddress(), - await nonkeeper.getAddress(), - ), - 'OnlyCallableByPayee()', - ) - }) - - it('reverts if called with the 0 address', async () => { - await evmRevert( - registry - .connect(payee2) - .withdrawPayment(await keeper1.getAddress(), zeroAddress), - 'InvalidRecipient()', - ) - }) - - it('updates the balances', async () => { - const to = await nonkeeper.getAddress() - const keeperBefore = await registry.getTransmitterInfo( - await keeper1.getAddress(), - ) - const registrationBefore = (await registry.getUpkeep(upkeepId)).balance - const toLinkBefore = await linkToken.balanceOf(to) - const registryLinkBefore = await linkToken.balanceOf(registry.address) - const registryPremiumBefore = (await registry.getState()).state - .totalPremium - const ownerBefore = (await registry.getState()).state.ownerLinkBalance - - // Withdrawing for first time, last collected = 0 - assert.equal(keeperBefore.lastCollected.toString(), '0') - - //// Do the thing - await registry - .connect(payee1) - .withdrawPayment(await keeper1.getAddress(), to) - - const keeperAfter = await registry.getTransmitterInfo( - await keeper1.getAddress(), - ) - const registrationAfter = (await registry.getUpkeep(upkeepId)).balance - const toLinkAfter = await linkToken.balanceOf(to) - const registryLinkAfter = await linkToken.balanceOf(registry.address) - const registryPremiumAfter = (await registry.getState()).state - .totalPremium - const ownerAfter = (await registry.getState()).state.ownerLinkBalance - - // registry total premium should not change - assert.isTrue(registryPremiumBefore.eq(registryPremiumAfter)) - // Last collected should be updated - assert.equal( - keeperAfter.lastCollected.toString(), - registryPremiumBefore.toString(), - ) - - const spareChange = registryPremiumBefore.mod( - BigNumber.from(keeperAddresses.length), - ) - // spare change should go to owner - assert.isTrue(ownerAfter.sub(spareChange).eq(ownerBefore)) - - assert.isTrue(keeperAfter.balance.eq(BigNumber.from(0))) - assert.isTrue(registrationBefore.eq(registrationAfter)) - assert.isTrue(toLinkBefore.add(keeperBefore.balance).eq(toLinkAfter)) - assert.isTrue( - registryLinkBefore.sub(keeperBefore.balance).eq(registryLinkAfter), - ) - }) - - it('emits a log announcing the withdrawal', async () => { - const balance = ( - await registry.getTransmitterInfo(await keeper1.getAddress()) - ).balance - const tx = await registry - .connect(payee1) - .withdrawPayment( - await keeper1.getAddress(), - await nonkeeper.getAddress(), - ) - await expect(tx) - .to.emit(registry, 'PaymentWithdrawn') - .withArgs( - await keeper1.getAddress(), - balance, - await nonkeeper.getAddress(), - await payee1.getAddress(), - ) - }) - }) -}) diff --git a/contracts/test/v0.8/automation/KeeperRegistry2_1.test.ts b/contracts/test/v0.8/automation/KeeperRegistry2_1.test.ts index 65f6a596fca..05bdabbea54 100644 --- a/contracts/test/v0.8/automation/KeeperRegistry2_1.test.ts +++ b/contracts/test/v0.8/automation/KeeperRegistry2_1.test.ts @@ -1,57 +1,12 @@ import { ethers } from 'hardhat' -import { loadFixture } from '@nomicfoundation/hardhat-network-helpers' -import { assert, expect } from 'chai' -import { - BigNumber, - BigNumberish, - BytesLike, - ContractReceipt, - ContractTransaction, - Signer, - Wallet, -} from 'ethers' -import { evmRevert } from '../../test-helpers/matchers' -import { getUsers, Personas } from '../../test-helpers/setup' -import { randomAddress, toWei } from '../../test-helpers/helpers' -import { LinkToken__factory as LinkTokenFactory } from '../../../typechain/factories/LinkToken__factory' -import { StreamsLookupUpkeep__factory as StreamsLookupUpkeepFactory } from '../../../typechain/factories/StreamsLookupUpkeep__factory' -import { MockV3Aggregator__factory as MockV3AggregatorFactory } from '../../../typechain/factories/MockV3Aggregator__factory' -import { UpkeepMock__factory as UpkeepMockFactory } from '../../../typechain/factories/UpkeepMock__factory' -import { UpkeepAutoFunder__factory as UpkeepAutoFunderFactory } from '../../../typechain/factories/UpkeepAutoFunder__factory' -import { MockArbGasInfo__factory as MockArbGasInfoFactory } from '../../../typechain/factories/MockArbGasInfo__factory' -import { MockOVMGasPriceOracle__factory as MockOVMGasPriceOracleFactory } from '../../../typechain/factories/MockOVMGasPriceOracle__factory' -import { ILogAutomation__factory as ILogAutomationactory } from '../../../typechain/factories/ILogAutomation__factory' -import { IAutomationForwarder__factory as IAutomationForwarderFactory } from '../../../typechain/factories/IAutomationForwarder__factory' +import { assert } from 'chai' import { KeeperRegistry2_1__factory as KeeperRegistryFactory } from '../../../typechain/factories/KeeperRegistry2_1__factory' import { KeeperRegistryLogicA2_1__factory as KeeperRegistryLogicAFactory } from '../../../typechain/factories/KeeperRegistryLogicA2_1__factory' import { KeeperRegistryLogicB2_1__factory as KeeperRegistryLogicBFactory } from '../../../typechain/factories/KeeperRegistryLogicB2_1__factory' import { AutomationForwarderLogic__factory as AutomationForwarderLogicFactory } from '../../../typechain/factories/AutomationForwarderLogic__factory' -import { MockArbSys__factory as MockArbSysFactory } from '../../../typechain/factories/MockArbSys__factory' -import { AutomationUtils2_1 as AutomationUtils } from '../../../typechain/AutomationUtils2_1' -import { StreamsLookupUpkeep } from '../../../typechain/StreamsLookupUpkeep' -import { MockV3Aggregator } from '../../../typechain/MockV3Aggregator' -import { LinkToken } from '../../../typechain/LinkToken' -import { UpkeepMock } from '../../../typechain/UpkeepMock' -import { MockArbGasInfo } from '../../../typechain/MockArbGasInfo' -import { MockOVMGasPriceOracle } from '../../../typechain/MockOVMGasPriceOracle' -import { UpkeepTranscoder } from '../../../typechain/UpkeepTranscoder' -import { UpkeepAutoFunder } from '../../../typechain' -import { - CancelledUpkeepReportEvent, - IKeeperRegistryMaster as IKeeperRegistry, - InsufficientFundsUpkeepReportEvent, - ReorgedUpkeepReportEvent, - StaleUpkeepReportEvent, - UpkeepPerformedEvent, -} from '../../../typechain/IKeeperRegistryMaster' -import { - deployMockContract, - MockContract, -} from '@ethereum-waffle/mock-contract' -import { deployRegistry21 } from './helpers' -const describeMaybe = process.env.SKIP_SLOW ? describe.skip : describe -const itMaybe = process.env.SKIP_SLOW ? it.skip : it +// const describeMaybe = process.env.SKIP_SLOW ? describe.skip : describe +// const itMaybe = process.env.SKIP_SLOW ? it.skip : it ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// @@ -64,12 +19,12 @@ describe('KeeperRegistry2_1 - Frozen [ @skip-coverage ]', () => { it('has not changed', () => { assert.equal( ethers.utils.id(KeeperRegistryFactory.bytecode), - '0xd8dfe20e746039e8420349326becc0a15dcd8fa3cd6aa0924d214328a7c45206', + '0x05aaa1024d7400e9c4824dde093b96edf5888fa6e6be2c2fc4dca7ae47cc9de9', 'KeeperRegistry bytecode has changed', ) assert.equal( ethers.utils.id(KeeperRegistryLogicAFactory.bytecode), - '0xe69d334fa75af0d6d8572996d815c93b8be1c8546670510b0d20ef349e57b2df', + '0xdcc8805e88c550b2a25b972bee9f4e4c3649f01e26f8dda6b25d7a9c5da8ab2f', 'KeeperRegistryLogicA bytecode has changed', ) assert.equal( @@ -89,5612 +44,5612 @@ describe('KeeperRegistry2_1 - Frozen [ @skip-coverage ]', () => { ////////////////////////////////////////////////////////////////////////////////////////////////// // copied from AutomationRegistryInterface2_1.sol -enum UpkeepFailureReason { - NONE, - UPKEEP_CANCELLED, - UPKEEP_PAUSED, - TARGET_CHECK_REVERTED, - UPKEEP_NOT_NEEDED, - PERFORM_DATA_EXCEEDS_LIMIT, - INSUFFICIENT_BALANCE, - CHECK_CALLBACK_REVERTED, - REVERT_DATA_EXCEEDS_LIMIT, - REGISTRY_PAUSED, -} - -// copied from AutomationRegistryInterface2_1.sol -enum Mode { - DEFAULT, - ARBITRUM, - OPTIMISM, -} - -// copied from KeeperRegistryBase2_1.sol -enum Trigger { - CONDITION, - LOG, -} - -// un-exported types that must be extracted from the utils contract -type Report = Parameters[0] -type OnChainConfig = Parameters[0] -type LogTrigger = Parameters[0] -type ConditionalTrigger = Parameters[0] -type Log = Parameters[0] - -// ----------------------------------------------------------------------------------------------- - -// These values should match the constants declared in registry -let registryConditionalOverhead: BigNumber -let registryLogOverhead: BigNumber -let registryPerSignerGasOverhead: BigNumber -let registryPerPerformByteGasOverhead: BigNumber -let cancellationDelay: number - -// This is the margin for gas that we test for. Gas charged should always be greater -// than total gas used in tx but should not increase beyond this margin -const gasCalculationMargin = BigNumber.from(8000) - -const linkEth = BigNumber.from(5000000000000000) // 1 Link = 0.005 Eth -const gasWei = BigNumber.from(1000000000) // 1 gwei -// ----------------------------------------------------------------------------------------------- -// test-wide configs for upkeeps -const linkDivisibility = BigNumber.from('1000000000000000000') -const performGas = BigNumber.from('1000000') -const paymentPremiumBase = BigNumber.from('1000000000') -const paymentPremiumPPB = BigNumber.from('250000000') -const flatFeeMicroLink = BigNumber.from(0) - -const randomBytes = '0x1234abcd' -const emptyBytes = '0x' -const emptyBytes32 = - '0x0000000000000000000000000000000000000000000000000000000000000000' - -const transmitGasOverhead = 1_000_000 -const checkGasOverhead = 400_000 - -const stalenessSeconds = BigNumber.from(43820) -const gasCeilingMultiplier = BigNumber.from(2) -const checkGasLimit = BigNumber.from(10000000) -const fallbackGasPrice = gasWei.mul(BigNumber.from('2')) -const fallbackLinkPrice = linkEth.div(BigNumber.from('2')) -const maxCheckDataSize = BigNumber.from(1000) -const maxPerformDataSize = BigNumber.from(1000) -const maxRevertDataSize = BigNumber.from(1000) -const maxPerformGas = BigNumber.from(5000000) -const minUpkeepSpend = BigNumber.from(0) -const f = 1 -const offchainVersion = 1 -const offchainBytes = '0x' -const zeroAddress = ethers.constants.AddressZero -const epochAndRound5_1 = - '0x0000000000000000000000000000000000000000000000000000000000000501' - -let logTriggerConfig: string - -// ----------------------------------------------------------------------------------------------- - -// Smart contract factories -let linkTokenFactory: LinkTokenFactory -let mockV3AggregatorFactory: MockV3AggregatorFactory -let upkeepMockFactory: UpkeepMockFactory -let upkeepAutoFunderFactory: UpkeepAutoFunderFactory -let mockArbGasInfoFactory: MockArbGasInfoFactory -let mockOVMGasPriceOracleFactory: MockOVMGasPriceOracleFactory -let streamsLookupUpkeepFactory: StreamsLookupUpkeepFactory -let personas: Personas - -// contracts -let linkToken: LinkToken -let linkEthFeed: MockV3Aggregator -let gasPriceFeed: MockV3Aggregator -let registry: IKeeperRegistry // default registry, used for most tests -let arbRegistry: IKeeperRegistry // arbitrum registry -let opRegistry: IKeeperRegistry // optimism registry -let mgRegistry: IKeeperRegistry // "migrate registry" used in migration tests -let blankRegistry: IKeeperRegistry // used to test initial configurations -let mock: UpkeepMock -let autoFunderUpkeep: UpkeepAutoFunder -let ltUpkeep: MockContract -let transcoder: UpkeepTranscoder -let mockArbGasInfo: MockArbGasInfo -let mockOVMGasPriceOracle: MockOVMGasPriceOracle -let streamsLookupUpkeep: StreamsLookupUpkeep -let automationUtils: AutomationUtils - -function now() { - return Math.floor(Date.now() / 1000) -} - -async function getUpkeepID(tx: ContractTransaction): Promise { - const receipt = await tx.wait() - for (const event of receipt.events || []) { - if ( - event.args && - event.eventSignature == 'UpkeepRegistered(uint256,uint32,address)' - ) { - return event.args[0] - } - } - throw new Error('could not find upkeep ID in tx event logs') -} - -const getTriggerType = (upkeepId: BigNumber): Trigger => { - const hexBytes = ethers.utils.defaultAbiCoder.encode(['uint256'], [upkeepId]) - const bytes = ethers.utils.arrayify(hexBytes) - for (let idx = 4; idx < 15; idx++) { - if (bytes[idx] != 0) { - return Trigger.CONDITION - } - } - return bytes[15] as Trigger -} - -const encodeConfig = (onchainConfig: OnChainConfig) => { - return ( - '0x' + - automationUtils.interface - .encodeFunctionData('_onChainConfig', [onchainConfig]) - .slice(10) - ) -} - -const encodeBlockTrigger = (conditionalTrigger: ConditionalTrigger) => { - return ( - '0x' + - automationUtils.interface - .encodeFunctionData('_conditionalTrigger', [conditionalTrigger]) - .slice(10) - ) -} - -const encodeLogTrigger = (logTrigger: LogTrigger) => { - return ( - '0x' + - automationUtils.interface - .encodeFunctionData('_logTrigger', [logTrigger]) - .slice(10) - ) -} - -const encodeLog = (log: Log) => { - return ( - '0x' + automationUtils.interface.encodeFunctionData('_log', [log]).slice(10) - ) -} - -const encodeReport = (report: Report) => { - return ( - '0x' + - automationUtils.interface.encodeFunctionData('_report', [report]).slice(10) - ) -} - -type UpkeepData = { - Id: BigNumberish - performGas: BigNumberish - performData: BytesLike - trigger: BytesLike -} - -const makeReport = (upkeeps: UpkeepData[]) => { - const upkeepIds = upkeeps.map((u) => u.Id) - const performGases = upkeeps.map((u) => u.performGas) - const triggers = upkeeps.map((u) => u.trigger) - const performDatas = upkeeps.map((u) => u.performData) - return encodeReport({ - fastGasWei: gasWei, - linkNative: linkEth, - upkeepIds, - gasLimits: performGases, - triggers, - performDatas, - }) -} - -const makeLatestBlockReport = async (upkeepsIDs: BigNumberish[]) => { - const latestBlock = await ethers.provider.getBlock('latest') - const upkeeps: UpkeepData[] = [] - for (let i = 0; i < upkeepsIDs.length; i++) { - upkeeps.push({ - Id: upkeepsIDs[i], - performGas, - trigger: encodeBlockTrigger({ - blockNum: latestBlock.number, - blockHash: latestBlock.hash, - }), - performData: '0x', - }) - } - return makeReport(upkeeps) -} - -const signReport = ( - reportContext: string[], - report: any, - signers: Wallet[], -) => { - const reportDigest = ethers.utils.keccak256(report) - const packedArgs = ethers.utils.solidityPack( - ['bytes32', 'bytes32[3]'], - [reportDigest, reportContext], - ) - const packedDigest = ethers.utils.keccak256(packedArgs) - - const signatures = [] - for (const signer of signers) { - signatures.push(signer._signingKey().signDigest(packedDigest)) - } - const vs = signatures.map((i) => '0' + (i.v - 27).toString(16)).join('') - return { - vs: '0x' + vs.padEnd(64, '0'), - rs: signatures.map((i) => i.r), - ss: signatures.map((i) => i.s), - } -} - -const parseUpkeepPerformedLogs = (receipt: ContractReceipt) => { - const parsedLogs = [] - for (const rawLog of receipt.logs) { - try { - const log = registry.interface.parseLog(rawLog) - if ( - log.name == - registry.interface.events[ - 'UpkeepPerformed(uint256,bool,uint96,uint256,uint256,bytes)' - ].name - ) { - parsedLogs.push(log as unknown as UpkeepPerformedEvent) - } - } catch { - continue - } - } - return parsedLogs -} - -const parseReorgedUpkeepReportLogs = (receipt: ContractReceipt) => { - const parsedLogs = [] - for (const rawLog of receipt.logs) { - try { - const log = registry.interface.parseLog(rawLog) - if ( - log.name == - registry.interface.events['ReorgedUpkeepReport(uint256,bytes)'].name - ) { - parsedLogs.push(log as unknown as ReorgedUpkeepReportEvent) - } - } catch { - continue - } - } - return parsedLogs -} - -const parseStaleUpkeepReportLogs = (receipt: ContractReceipt) => { - const parsedLogs = [] - for (const rawLog of receipt.logs) { - try { - const log = registry.interface.parseLog(rawLog) - if ( - log.name == - registry.interface.events['StaleUpkeepReport(uint256,bytes)'].name - ) { - parsedLogs.push(log as unknown as StaleUpkeepReportEvent) - } - } catch { - continue - } - } - return parsedLogs -} - -const parseInsufficientFundsUpkeepReportLogs = (receipt: ContractReceipt) => { - const parsedLogs = [] - for (const rawLog of receipt.logs) { - try { - const log = registry.interface.parseLog(rawLog) - if ( - log.name == - registry.interface.events[ - 'InsufficientFundsUpkeepReport(uint256,bytes)' - ].name - ) { - parsedLogs.push(log as unknown as InsufficientFundsUpkeepReportEvent) - } - } catch { - continue - } - } - return parsedLogs -} - -const parseCancelledUpkeepReportLogs = (receipt: ContractReceipt) => { - const parsedLogs = [] - for (const rawLog of receipt.logs) { - try { - const log = registry.interface.parseLog(rawLog) - if ( - log.name == - registry.interface.events['CancelledUpkeepReport(uint256,bytes)'].name - ) { - parsedLogs.push(log as unknown as CancelledUpkeepReportEvent) - } - } catch { - continue - } - } - return parsedLogs -} - -describe('KeeperRegistry2_1', () => { - let owner: Signer - let keeper1: Signer - let keeper2: Signer - let keeper3: Signer - let keeper4: Signer - let keeper5: Signer - let nonkeeper: Signer - let signer1: Wallet - let signer2: Wallet - let signer3: Wallet - let signer4: Wallet - let signer5: Wallet - let admin: Signer - let payee1: Signer - let payee2: Signer - let payee3: Signer - let payee4: Signer - let payee5: Signer - - let upkeepId: BigNumber // conditional upkeep - let afUpkeepId: BigNumber // auto funding upkeep - let logUpkeepId: BigNumber // log trigger upkeepID - let streamsLookupUpkeepId: BigNumber // streams lookup upkeep - const numUpkeeps = 4 // see above - let keeperAddresses: string[] - let payees: string[] - let signers: Wallet[] - let signerAddresses: string[] - let config: any - let baseConfig: Parameters - let upkeepManager: string - - before(async () => { - personas = (await getUsers()).personas - - const utilsFactory = await ethers.getContractFactory('AutomationUtils2_1') - automationUtils = await utilsFactory.deploy() - - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', - ) - // need full path because there are two contracts with name MockV3Aggregator - mockV3AggregatorFactory = (await ethers.getContractFactory( - 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', - )) as unknown as MockV3AggregatorFactory - upkeepMockFactory = await ethers.getContractFactory('UpkeepMock') - upkeepAutoFunderFactory = - await ethers.getContractFactory('UpkeepAutoFunder') - mockArbGasInfoFactory = await ethers.getContractFactory('MockArbGasInfo') - mockOVMGasPriceOracleFactory = await ethers.getContractFactory( - 'MockOVMGasPriceOracle', - ) - streamsLookupUpkeepFactory = await ethers.getContractFactory( - 'StreamsLookupUpkeep', - ) - - owner = personas.Default - keeper1 = personas.Carol - keeper2 = personas.Eddy - keeper3 = personas.Nancy - keeper4 = personas.Norbert - keeper5 = personas.Nick - nonkeeper = personas.Ned - admin = personas.Neil - payee1 = personas.Nelly - payee2 = personas.Norbert - payee3 = personas.Nick - payee4 = personas.Eddy - payee5 = personas.Carol - upkeepManager = await personas.Norbert.getAddress() - // signers - signer1 = new ethers.Wallet( - '0x7777777000000000000000000000000000000000000000000000000000000001', - ) - signer2 = new ethers.Wallet( - '0x7777777000000000000000000000000000000000000000000000000000000002', - ) - signer3 = new ethers.Wallet( - '0x7777777000000000000000000000000000000000000000000000000000000003', - ) - signer4 = new ethers.Wallet( - '0x7777777000000000000000000000000000000000000000000000000000000004', - ) - signer5 = new ethers.Wallet( - '0x7777777000000000000000000000000000000000000000000000000000000005', - ) - - keeperAddresses = [ - await keeper1.getAddress(), - await keeper2.getAddress(), - await keeper3.getAddress(), - await keeper4.getAddress(), - await keeper5.getAddress(), - ] - payees = [ - await payee1.getAddress(), - await payee2.getAddress(), - await payee3.getAddress(), - await payee4.getAddress(), - await payee5.getAddress(), - ] - signers = [signer1, signer2, signer3, signer4, signer5] - - // We append 26 random addresses to keepers, payees and signers to get a system of 31 oracles - // This allows f value of 1 - 10 - for (let i = 0; i < 26; i++) { - keeperAddresses.push(randomAddress()) - payees.push(randomAddress()) - signers.push(ethers.Wallet.createRandom()) - } - signerAddresses = [] - for (const signer of signers) { - signerAddresses.push(await signer.getAddress()) - } - - logTriggerConfig = - '0x' + - automationUtils.interface - .encodeFunctionData('_logTriggerConfig', [ - { - contractAddress: randomAddress(), - filterSelector: 0, - topic0: ethers.utils.randomBytes(32), - topic1: ethers.utils.randomBytes(32), - topic2: ethers.utils.randomBytes(32), - topic3: ethers.utils.randomBytes(32), - }, - ]) - .slice(10) - }) - - const linkForGas = ( - upkeepGasSpent: BigNumber, - gasOverhead: BigNumber, - gasMultiplier: BigNumber, - premiumPPB: BigNumber, - flatFee: BigNumber, - l1CostWei?: BigNumber, - numUpkeepsBatch?: BigNumber, - ) => { - l1CostWei = l1CostWei === undefined ? BigNumber.from(0) : l1CostWei - numUpkeepsBatch = - numUpkeepsBatch === undefined ? BigNumber.from(1) : numUpkeepsBatch - - const gasSpent = gasOverhead.add(BigNumber.from(upkeepGasSpent)) - const base = gasWei - .mul(gasMultiplier) - .mul(gasSpent) - .mul(linkDivisibility) - .div(linkEth) - const l1Fee = l1CostWei - .mul(gasMultiplier) - .div(numUpkeepsBatch) - .mul(linkDivisibility) - .div(linkEth) - const gasPayment = base.add(l1Fee) - - const premium = gasWei - .mul(gasMultiplier) - .mul(upkeepGasSpent) - .add(l1CostWei.mul(gasMultiplier).div(numUpkeepsBatch)) - .mul(linkDivisibility) - .div(linkEth) - .mul(premiumPPB) - .div(paymentPremiumBase) - .add(BigNumber.from(flatFee).mul('1000000000000')) - - return { - total: gasPayment.add(premium), - gasPaymemnt: gasPayment, - premium, - } - } - - const verifyMaxPayment = async ( - registry: IKeeperRegistry, - l1CostWei?: BigNumber, - ) => { - type TestCase = { - name: string - multiplier: number - gas: number - premium: number - flatFee: number - } - - const tests: TestCase[] = [ - { - name: 'no fees', - multiplier: 1, - gas: 100000, - premium: 0, - flatFee: 0, - }, - { - name: 'basic fees', - multiplier: 1, - gas: 100000, - premium: 250000000, - flatFee: 1000000, - }, - { - name: 'max fees', - multiplier: 3, - gas: 10000000, - premium: 250000000, - flatFee: 1000000, - }, - ] - - const fPlusOne = BigNumber.from(f + 1) - const totalConditionalOverhead = registryConditionalOverhead - .add(registryPerSignerGasOverhead.mul(fPlusOne)) - .add(registryPerPerformByteGasOverhead.mul(maxPerformDataSize)) - const totalLogOverhead = registryLogOverhead - .add(registryPerSignerGasOverhead.mul(fPlusOne)) - .add(registryPerPerformByteGasOverhead.mul(maxPerformDataSize)) - - for (const test of tests) { - await registry.connect(owner).setConfig( - signerAddresses, - keeperAddresses, - f, - encodeConfig({ - paymentPremiumPPB: test.premium, - flatFeeMicroLink: test.flatFee, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier: test.multiplier, - minUpkeepSpend, - maxCheckDataSize, - maxPerformDataSize, - maxRevertDataSize, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrars: [], - upkeepPrivilegeManager: upkeepManager, - }), - offchainVersion, - offchainBytes, - ) - - const conditionalPrice = await registry.getMaxPaymentForGas( - Trigger.CONDITION, - test.gas, - ) - expect(conditionalPrice).to.equal( - linkForGas( - BigNumber.from(test.gas), - totalConditionalOverhead, - BigNumber.from(test.multiplier), - BigNumber.from(test.premium), - BigNumber.from(test.flatFee), - l1CostWei, - ).total, - ) - - const logPrice = await registry.getMaxPaymentForGas(Trigger.LOG, test.gas) - expect(logPrice).to.equal( - linkForGas( - BigNumber.from(test.gas), - totalLogOverhead, - BigNumber.from(test.multiplier), - BigNumber.from(test.premium), - BigNumber.from(test.flatFee), - l1CostWei, - ).total, - ) - } - } - - const verifyConsistentAccounting = async ( - maxAllowedSpareChange: BigNumber, - ) => { - const expectedLinkBalance = (await registry.getState()).state - .expectedLinkBalance - const linkTokenBalance = await linkToken.balanceOf(registry.address) - const upkeepIdBalance = (await registry.getUpkeep(upkeepId)).balance - let totalKeeperBalance = BigNumber.from(0) - for (let i = 0; i < keeperAddresses.length; i++) { - totalKeeperBalance = totalKeeperBalance.add( - (await registry.getTransmitterInfo(keeperAddresses[i])).balance, - ) - } - const ownerBalance = (await registry.getState()).state.ownerLinkBalance - assert.isTrue(expectedLinkBalance.eq(linkTokenBalance)) - assert.isTrue( - upkeepIdBalance - .add(totalKeeperBalance) - .add(ownerBalance) - .lte(expectedLinkBalance), - ) - assert.isTrue( - expectedLinkBalance - .sub(upkeepIdBalance) - .sub(totalKeeperBalance) - .sub(ownerBalance) - .lte(maxAllowedSpareChange), - ) - } - - interface GetTransmitTXOptions { - numSigners?: number - startingSignerIndex?: number - gasLimit?: BigNumberish - gasPrice?: BigNumberish - performGas?: BigNumberish - performData?: string - checkBlockNum?: number - checkBlockHash?: string - logBlockHash?: BytesLike - txHash?: BytesLike - logIndex?: number - timestamp?: number - } - - const getTransmitTx = async ( - registry: IKeeperRegistry, - transmitter: Signer, - upkeepIds: BigNumber[], - overrides: GetTransmitTXOptions = {}, - ) => { - const latestBlock = await ethers.provider.getBlock('latest') - const configDigest = (await registry.getState()).state.latestConfigDigest - const config = { - numSigners: f + 1, - startingSignerIndex: 0, - performData: '0x', - performGas, - checkBlockNum: latestBlock.number, - checkBlockHash: latestBlock.hash, - logIndex: 0, - txHash: undefined, // assigned uniquely below - logBlockHash: undefined, // assigned uniquely below - timestamp: now(), - gasLimit: undefined, - gasPrice: undefined, - } - Object.assign(config, overrides) - const upkeeps: UpkeepData[] = [] - for (let i = 0; i < upkeepIds.length; i++) { - let trigger: string - switch (getTriggerType(upkeepIds[i])) { - case Trigger.CONDITION: - trigger = encodeBlockTrigger({ - blockNum: config.checkBlockNum, - blockHash: config.checkBlockHash, - }) - break - case Trigger.LOG: - trigger = encodeLogTrigger({ - logBlockHash: config.logBlockHash || ethers.utils.randomBytes(32), - txHash: config.txHash || ethers.utils.randomBytes(32), - logIndex: config.logIndex, - blockNum: config.checkBlockNum, - blockHash: config.checkBlockHash, - }) - break - } - upkeeps.push({ - Id: upkeepIds[i], - performGas: config.performGas, - trigger, - performData: config.performData, - }) - } - - const report = makeReport(upkeeps) - const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] - const sigs = signReport( - reportContext, - report, - signers.slice( - config.startingSignerIndex, - config.startingSignerIndex + config.numSigners, - ), - ) - - type txOverride = { - gasLimit?: BigNumberish | Promise - gasPrice?: BigNumberish | Promise - } - const txOverrides: txOverride = {} - if (config.gasLimit) { - txOverrides.gasLimit = config.gasLimit - } - if (config.gasPrice) { - txOverrides.gasPrice = config.gasPrice - } - - return registry - .connect(transmitter) - .transmit( - [configDigest, epochAndRound5_1, emptyBytes32], - report, - sigs.rs, - sigs.ss, - sigs.vs, - txOverrides, - ) - } - - const getTransmitTxWithReport = async ( - registry: IKeeperRegistry, - transmitter: Signer, - report: BytesLike, - ) => { - const configDigest = (await registry.getState()).state.latestConfigDigest - const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] - const sigs = signReport(reportContext, report, signers.slice(0, f + 1)) - - return registry - .connect(transmitter) - .transmit( - [configDigest, epochAndRound5_1, emptyBytes32], - report, - sigs.rs, - sigs.ss, - sigs.vs, - ) - } - - const setup = async () => { - linkToken = await linkTokenFactory.connect(owner).deploy() - gasPriceFeed = await mockV3AggregatorFactory - .connect(owner) - .deploy(0, gasWei) - linkEthFeed = await mockV3AggregatorFactory - .connect(owner) - .deploy(9, linkEth) - const upkeepTranscoderFactory = await ethers.getContractFactory( - 'UpkeepTranscoder4_0', - ) - transcoder = await upkeepTranscoderFactory.connect(owner).deploy() - mockArbGasInfo = await mockArbGasInfoFactory.connect(owner).deploy() - mockOVMGasPriceOracle = await mockOVMGasPriceOracleFactory - .connect(owner) - .deploy() - streamsLookupUpkeep = await streamsLookupUpkeepFactory - .connect(owner) - .deploy( - BigNumber.from('10000'), - BigNumber.from('100'), - false /* useArbBlock */, - true /* staging */, - false /* verify mercury response */, - ) - - const arbOracleCode = await ethers.provider.send('eth_getCode', [ - mockArbGasInfo.address, - ]) - await ethers.provider.send('hardhat_setCode', [ - '0x000000000000000000000000000000000000006C', - arbOracleCode, - ]) - - const optOracleCode = await ethers.provider.send('eth_getCode', [ - mockOVMGasPriceOracle.address, - ]) - await ethers.provider.send('hardhat_setCode', [ - '0x420000000000000000000000000000000000000F', - optOracleCode, - ]) - - const mockArbSys = await new MockArbSysFactory(owner).deploy() - const arbSysCode = await ethers.provider.send('eth_getCode', [ - mockArbSys.address, - ]) - await ethers.provider.send('hardhat_setCode', [ - '0x0000000000000000000000000000000000000064', - arbSysCode, - ]) - - config = { - paymentPremiumPPB, - flatFeeMicroLink, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxCheckDataSize, - maxPerformDataSize, - maxRevertDataSize, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrars: [], - upkeepPrivilegeManager: upkeepManager, - } - - baseConfig = [ - signerAddresses, - keeperAddresses, - f, - encodeConfig(config), - offchainVersion, - offchainBytes, - ] - - registry = await deployRegistry21( - owner, - Mode.DEFAULT, - linkToken.address, - linkEthFeed.address, - gasPriceFeed.address, - ) - - arbRegistry = await deployRegistry21( - owner, - Mode.ARBITRUM, - linkToken.address, - linkEthFeed.address, - gasPriceFeed.address, - ) - - opRegistry = await deployRegistry21( - owner, - Mode.OPTIMISM, - linkToken.address, - linkEthFeed.address, - gasPriceFeed.address, - ) - - mgRegistry = await deployRegistry21( - owner, - Mode.DEFAULT, - linkToken.address, - linkEthFeed.address, - gasPriceFeed.address, - ) - - blankRegistry = await deployRegistry21( - owner, - Mode.DEFAULT, - linkToken.address, - linkEthFeed.address, - gasPriceFeed.address, - ) - - registryConditionalOverhead = await registry.getConditionalGasOverhead() - registryLogOverhead = await registry.getLogGasOverhead() - registryPerSignerGasOverhead = await registry.getPerSignerGasOverhead() - registryPerPerformByteGasOverhead = - await registry.getPerPerformByteGasOverhead() - cancellationDelay = (await registry.getCancellationDelay()).toNumber() - - for (const reg of [registry, arbRegistry, opRegistry, mgRegistry]) { - await reg.connect(owner).setConfig(...baseConfig) - await reg.connect(owner).setPayees(payees) - await linkToken.connect(admin).approve(reg.address, toWei('1000')) - await linkToken.connect(owner).approve(reg.address, toWei('1000')) - } - - mock = await upkeepMockFactory.deploy() - await linkToken - .connect(owner) - .transfer(await admin.getAddress(), toWei('1000')) - let tx = await registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') - upkeepId = await getUpkeepID(tx) - - autoFunderUpkeep = await upkeepAutoFunderFactory - .connect(owner) - .deploy(linkToken.address, registry.address) - tx = await registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](autoFunderUpkeep.address, performGas, autoFunderUpkeep.address, randomBytes, '0x') - afUpkeepId = await getUpkeepID(tx) - - ltUpkeep = await deployMockContract(owner, ILogAutomationactory.abi) - tx = await registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,uint8,bytes,bytes,bytes)' - ](ltUpkeep.address, performGas, await admin.getAddress(), Trigger.LOG, '0x', logTriggerConfig, emptyBytes) - logUpkeepId = await getUpkeepID(tx) - - await autoFunderUpkeep.setUpkeepId(afUpkeepId) - // Give enough funds for upkeep as well as to the upkeep contract - await linkToken - .connect(owner) - .transfer(autoFunderUpkeep.address, toWei('1000')) - - tx = await registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](streamsLookupUpkeep.address, performGas, await admin.getAddress(), randomBytes, '0x') - streamsLookupUpkeepId = await getUpkeepID(tx) - } - - const getMultipleUpkeepsDeployedAndFunded = async ( - numPassingConditionalUpkeeps: number, - numPassingLogUpkeeps: number, - numFailingUpkeeps: number, - ) => { - const passingConditionalUpkeepIds = [] - const passingLogUpkeepIds = [] - const failingUpkeepIds = [] - for (let i = 0; i < numPassingConditionalUpkeeps; i++) { - const mock = await upkeepMockFactory.deploy() - await mock.setCanPerform(true) - await mock.setPerformGasToBurn(BigNumber.from('0')) - const tx = await registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') - const condUpkeepId = await getUpkeepID(tx) - passingConditionalUpkeepIds.push(condUpkeepId) - - // Add funds to passing upkeeps - await registry.connect(admin).addFunds(condUpkeepId, toWei('100')) - } - for (let i = 0; i < numPassingLogUpkeeps; i++) { - const mock = await upkeepMockFactory.deploy() - await mock.setCanPerform(true) - await mock.setPerformGasToBurn(BigNumber.from('0')) - const tx = await registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,uint8,bytes,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), Trigger.LOG, '0x', logTriggerConfig, emptyBytes) - const logUpkeepId = await getUpkeepID(tx) - passingLogUpkeepIds.push(logUpkeepId) - - // Add funds to passing upkeeps - await registry.connect(admin).addFunds(logUpkeepId, toWei('100')) - } - for (let i = 0; i < numFailingUpkeeps; i++) { - const mock = await upkeepMockFactory.deploy() - await mock.setCanPerform(true) - await mock.setPerformGasToBurn(BigNumber.from('0')) - const tx = await registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') - const failingUpkeepId = await getUpkeepID(tx) - failingUpkeepIds.push(failingUpkeepId) - } - return { - passingConditionalUpkeepIds, - passingLogUpkeepIds, - failingUpkeepIds, - } - } - - beforeEach(async () => { - await loadFixture(setup) - }) - - describe('#transmit', () => { - const fArray = [1, 5, 10] - - it('reverts when registry is paused', async () => { - await registry.connect(owner).pause() - await evmRevert( - getTransmitTx(registry, keeper1, [upkeepId]), - 'RegistryPaused()', - ) - }) - - it('reverts when called by non active transmitter', async () => { - await evmRevert( - getTransmitTx(registry, payee1, [upkeepId]), - 'OnlyActiveTransmitters()', - ) - }) - - it('reverts when report data lengths mismatches', async () => { - const upkeepIds = [] - const gasLimits: BigNumber[] = [] - const triggers: string[] = [] - const performDatas = [] - - upkeepIds.push(upkeepId) - gasLimits.push(performGas) - triggers.push('0x') - performDatas.push('0x') - // Push an extra perform data - performDatas.push('0x') - - const report = encodeReport({ - fastGasWei: 0, - linkNative: 0, - upkeepIds, - gasLimits, - triggers, - performDatas, - }) - - await evmRevert( - getTransmitTxWithReport(registry, keeper1, report), - 'InvalidReport()', - ) - }) - - it('returns early when invalid upkeepIds are included in report', async () => { - const tx = await getTransmitTx(registry, keeper1, [ - upkeepId.add(BigNumber.from('1')), - ]) - - const receipt = await tx.wait() - const cancelledUpkeepReportLogs = parseCancelledUpkeepReportLogs(receipt) - // exactly 1 CancelledUpkeepReport log should be emitted - assert.equal(cancelledUpkeepReportLogs.length, 1) - }) - - it('returns early when upkeep has insufficient funds', async () => { - const tx = await getTransmitTx(registry, keeper1, [upkeepId]) - const receipt = await tx.wait() - const insufficientFundsUpkeepReportLogs = - parseInsufficientFundsUpkeepReportLogs(receipt) - // exactly 1 InsufficientFundsUpkeepReportLogs log should be emitted - assert.equal(insufficientFundsUpkeepReportLogs.length, 1) - }) - - it('permits retrying log triggers after funds are added', async () => { - const txHash = ethers.utils.randomBytes(32) - let tx = await getTransmitTx(registry, keeper1, [logUpkeepId], { - txHash, - logIndex: 0, - }) - let receipt = await tx.wait() - const insufficientFundsLogs = - parseInsufficientFundsUpkeepReportLogs(receipt) - assert.equal(insufficientFundsLogs.length, 1) - registry.connect(admin).addFunds(logUpkeepId, toWei('100')) - tx = await getTransmitTx(registry, keeper1, [logUpkeepId], { - txHash, - logIndex: 0, - }) - receipt = await tx.wait() - const performedLogs = parseUpkeepPerformedLogs(receipt) - assert.equal(performedLogs.length, 1) - }) - - context('When the upkeep is funded', async () => { - beforeEach(async () => { - // Fund the upkeep - await Promise.all([ - registry.connect(admin).addFunds(upkeepId, toWei('100')), - registry.connect(admin).addFunds(logUpkeepId, toWei('100')), - ]) - }) - - it('handles duplicate upkeepIDs', async () => { - const tests: [string, BigNumber, number, number][] = [ - // [name, upkeep, num stale, num performed] - ['conditional', upkeepId, 1, 1], // checkBlocks must be sequential - ['log-trigger', logUpkeepId, 0, 2], // logs are deduped based on the "trigger ID" - ] - for (const [type, id, nStale, nPerformed] of tests) { - const tx = await getTransmitTx(registry, keeper1, [id, id]) - const receipt = await tx.wait() - const staleUpkeepReport = parseStaleUpkeepReportLogs(receipt) - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - assert.equal( - staleUpkeepReport.length, - nStale, - `wrong log count for ${type} upkeep`, - ) - assert.equal( - upkeepPerformedLogs.length, - nPerformed, - `wrong log count for ${type} upkeep`, - ) - } - }) - - it('handles duplicate log triggers', async () => { - const logBlockHash = ethers.utils.randomBytes(32) - const txHash = ethers.utils.randomBytes(32) - const logIndex = 0 - const expectedDedupKey = ethers.utils.solidityKeccak256( - ['uint256', 'bytes32', 'bytes32', 'uint32'], - [logUpkeepId, logBlockHash, txHash, logIndex], - ) - assert.isFalse(await registry.hasDedupKey(expectedDedupKey)) - const tx = await getTransmitTx( - registry, - keeper1, - [logUpkeepId, logUpkeepId], - { logBlockHash, txHash, logIndex }, // will result in the same dedup key - ) - const receipt = await tx.wait() - const staleUpkeepReport = parseStaleUpkeepReportLogs(receipt) - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - assert.equal(staleUpkeepReport.length, 1) - assert.equal(upkeepPerformedLogs.length, 1) - assert.isTrue(await registry.hasDedupKey(expectedDedupKey)) - await expect(tx) - .to.emit(registry, 'DedupKeyAdded') - .withArgs(expectedDedupKey) - }) - - it('returns early when check block number is less than last perform (block)', async () => { - // First perform an upkeep to put last perform block number on upkeep state - const tx = await getTransmitTx(registry, keeper1, [upkeepId]) - await tx.wait() - const lastPerformed = (await registry.getUpkeep(upkeepId)) - .lastPerformedBlockNumber - const lastPerformBlock = await ethers.provider.getBlock(lastPerformed) - assert.equal(lastPerformed.toString(), tx.blockNumber?.toString()) - // Try to transmit a report which has checkBlockNumber = lastPerformed-1, should result in stale report - const transmitTx = await getTransmitTx(registry, keeper1, [upkeepId], { - checkBlockNum: lastPerformBlock.number - 1, - checkBlockHash: lastPerformBlock.parentHash, - }) - const receipt = await transmitTx.wait() - const staleUpkeepReportLogs = parseStaleUpkeepReportLogs(receipt) - // exactly 1 StaleUpkeepReportLogs log should be emitted - assert.equal(staleUpkeepReportLogs.length, 1) - }) - - it('handles case when check block hash does not match', async () => { - const tests: [string, BigNumber][] = [ - ['conditional', upkeepId], - ['log-trigger', logUpkeepId], - ] - for (const [type, id] of tests) { - const latestBlock = await ethers.provider.getBlock('latest') - // Try to transmit a report which has incorrect checkBlockHash - const tx = await getTransmitTx(registry, keeper1, [id], { - checkBlockNum: latestBlock.number - 1, - checkBlockHash: latestBlock.hash, // should be latestBlock.parentHash - }) - - const receipt = await tx.wait() - const reorgedUpkeepReportLogs = parseReorgedUpkeepReportLogs(receipt) - // exactly 1 ReorgedUpkeepReportLogs log should be emitted - assert.equal( - reorgedUpkeepReportLogs.length, - 1, - `wrong log count for ${type} upkeep`, - ) - } - }) - - it('handles case when check block number is older than 256 blocks', async () => { - for (let i = 0; i < 256; i++) { - await ethers.provider.send('evm_mine', []) - } - const tests: [string, BigNumber][] = [ - ['conditional', upkeepId], - ['log-trigger', logUpkeepId], - ] - for (const [type, id] of tests) { - const latestBlock = await ethers.provider.getBlock('latest') - const old = await ethers.provider.getBlock(latestBlock.number - 256) - // Try to transmit a report which has incorrect checkBlockHash - const tx = await getTransmitTx(registry, keeper1, [id], { - checkBlockNum: old.number, - checkBlockHash: old.hash, - }) - - const receipt = await tx.wait() - const reorgedUpkeepReportLogs = parseReorgedUpkeepReportLogs(receipt) - // exactly 1 ReorgedUpkeepReportLogs log should be emitted - assert.equal( - reorgedUpkeepReportLogs.length, - 1, - `wrong log count for ${type} upkeep`, - ) - } - }) - - it('allows bypassing reorg protection with empty blockhash', async () => { - const tests: [string, BigNumber][] = [ - ['conditional', upkeepId], - ['log-trigger', logUpkeepId], - ] - for (const [type, id] of tests) { - const latestBlock = await ethers.provider.getBlock('latest') - const tx = await getTransmitTx(registry, keeper1, [id], { - checkBlockNum: latestBlock.number, - checkBlockHash: emptyBytes32, - }) - const receipt = await tx.wait() - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - assert.equal( - upkeepPerformedLogs.length, - 1, - `wrong log count for ${type} upkeep`, - ) - } - }) - - it('allows very old trigger block numbers when bypassing reorg protection with empty blockhash', async () => { - // mine enough blocks so that blockhash(1) is unavailable - for (let i = 0; i <= 256; i++) { - await ethers.provider.send('evm_mine', []) - } - const tests: [string, BigNumber][] = [ - ['conditional', upkeepId], - ['log-trigger', logUpkeepId], - ] - for (const [type, id] of tests) { - const tx = await getTransmitTx(registry, keeper1, [id], { - checkBlockNum: 1, - checkBlockHash: emptyBytes32, - }) - const receipt = await tx.wait() - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - assert.equal( - upkeepPerformedLogs.length, - 1, - `wrong log count for ${type} upkeep`, - ) - } - }) - - it('returns early when future block number is provided as trigger, irrespective of blockhash being present', async () => { - const tests: [string, BigNumber][] = [ - ['conditional', upkeepId], - ['log-trigger', logUpkeepId], - ] - for (const [type, id] of tests) { - const latestBlock = await ethers.provider.getBlock('latest') - - // Should fail when blockhash is empty - let tx = await getTransmitTx(registry, keeper1, [id], { - checkBlockNum: latestBlock.number + 100, - checkBlockHash: emptyBytes32, - }) - let receipt = await tx.wait() - let reorgedUpkeepReportLogs = parseReorgedUpkeepReportLogs(receipt) - // exactly 1 ReorgedUpkeepReportLogs log should be emitted - assert.equal( - reorgedUpkeepReportLogs.length, - 1, - `wrong log count for ${type} upkeep`, - ) - - // Should also fail when blockhash is not empty - tx = await getTransmitTx(registry, keeper1, [id], { - checkBlockNum: latestBlock.number + 100, - checkBlockHash: latestBlock.hash, - }) - receipt = await tx.wait() - reorgedUpkeepReportLogs = parseReorgedUpkeepReportLogs(receipt) - // exactly 1 ReorgedUpkeepReportLogs log should be emitted - assert.equal( - reorgedUpkeepReportLogs.length, - 1, - `wrong log count for ${type} upkeep`, - ) - } - }) - - it('returns early when upkeep is cancelled and cancellation delay has gone', async () => { - const latestBlockReport = await makeLatestBlockReport([upkeepId]) - await registry.connect(admin).cancelUpkeep(upkeepId) - - for (let i = 0; i < cancellationDelay; i++) { - await ethers.provider.send('evm_mine', []) - } - - const tx = await getTransmitTxWithReport( - registry, - keeper1, - latestBlockReport, - ) - - const receipt = await tx.wait() - const cancelledUpkeepReportLogs = - parseCancelledUpkeepReportLogs(receipt) - // exactly 1 CancelledUpkeepReport log should be emitted - assert.equal(cancelledUpkeepReportLogs.length, 1) - }) - - it('does not revert if the target cannot execute', async () => { - await mock.setCanPerform(false) - const tx = await getTransmitTx(registry, keeper1, [upkeepId]) - - const receipt = await tx.wait() - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - // exactly 1 Upkeep Performed should be emitted - assert.equal(upkeepPerformedLogs.length, 1) - const upkeepPerformedLog = upkeepPerformedLogs[0] - - const success = upkeepPerformedLog.args.success - assert.equal(success, false) - }) - - it('does not revert if the target runs out of gas', async () => { - await mock.setCanPerform(false) - - const tx = await getTransmitTx(registry, keeper1, [upkeepId], { - performGas: 10, // too little gas - }) - - const receipt = await tx.wait() - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - // exactly 1 Upkeep Performed should be emitted - assert.equal(upkeepPerformedLogs.length, 1) - const upkeepPerformedLog = upkeepPerformedLogs[0] - - const success = upkeepPerformedLog.args.success - assert.equal(success, false) - }) - - it('reverts if not enough gas supplied', async () => { - await evmRevert( - getTransmitTx(registry, keeper1, [upkeepId], { - gasLimit: performGas, - }), - ) - }) - - it('executes the data passed to the registry', async () => { - await mock.setCanPerform(true) - - const tx = await getTransmitTx(registry, keeper1, [upkeepId], { - performData: randomBytes, - }) - const receipt = await tx.wait() - - const upkeepPerformedWithABI = [ - 'event UpkeepPerformedWith(bytes upkeepData)', - ] - const iface = new ethers.utils.Interface(upkeepPerformedWithABI) - const parsedLogs = [] - for (let i = 0; i < receipt.logs.length; i++) { - const log = receipt.logs[i] - try { - parsedLogs.push(iface.parseLog(log)) - } catch (e) { - // ignore log - } - } - assert.equal(parsedLogs.length, 1) - assert.equal(parsedLogs[0].args.upkeepData, randomBytes) - }) - - it('uses actual execution price for payment and premium calculation', async () => { - // Actual multiplier is 2, but we set gasPrice to be 1x gasWei - const gasPrice = gasWei.mul(BigNumber.from('1')) - await mock.setCanPerform(true) - const registryPremiumBefore = (await registry.getState()).state - .totalPremium - const tx = await getTransmitTx(registry, keeper1, [upkeepId], { - gasPrice, - }) - const receipt = await tx.wait() - const registryPremiumAfter = (await registry.getState()).state - .totalPremium - const premium = registryPremiumAfter.sub(registryPremiumBefore) - - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - // exactly 1 Upkeep Performed should be emitted - assert.equal(upkeepPerformedLogs.length, 1) - const upkeepPerformedLog = upkeepPerformedLogs[0] - - const gasUsed = upkeepPerformedLog.args.gasUsed - const gasOverhead = upkeepPerformedLog.args.gasOverhead - const totalPayment = upkeepPerformedLog.args.totalPayment - - assert.equal( - linkForGas( - gasUsed, - gasOverhead, - BigNumber.from('1'), // Not the config multiplier, but the actual gas used - paymentPremiumPPB, - flatFeeMicroLink, - ).total.toString(), - totalPayment.toString(), - ) - - assert.equal( - linkForGas( - gasUsed, - gasOverhead, - BigNumber.from('1'), // Not the config multiplier, but the actual gas used - paymentPremiumPPB, - flatFeeMicroLink, - ).premium.toString(), - premium.toString(), - ) - }) - - it('only pays at a rate up to the gas ceiling [ @skip-coverage ]', async () => { - // Actual multiplier is 2, but we set gasPrice to be 10x - const gasPrice = gasWei.mul(BigNumber.from('10')) - await mock.setCanPerform(true) - - const tx = await getTransmitTx(registry, keeper1, [upkeepId], { - gasPrice, - }) - const receipt = await tx.wait() - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - // exactly 1 Upkeep Performed should be emitted - assert.equal(upkeepPerformedLogs.length, 1) - const upkeepPerformedLog = upkeepPerformedLogs[0] - - const gasUsed = upkeepPerformedLog.args.gasUsed - const gasOverhead = upkeepPerformedLog.args.gasOverhead - const totalPayment = upkeepPerformedLog.args.totalPayment - - assert.equal( - linkForGas( - gasUsed, - gasOverhead, - gasCeilingMultiplier, // Should be same with exisitng multiplier - paymentPremiumPPB, - flatFeeMicroLink, - ).total.toString(), - totalPayment.toString(), - ) - }) - - it('correctly accounts for l payment', async () => { - await mock.setCanPerform(true) - // Same as MockArbGasInfo.sol - const l1CostWeiArb = BigNumber.from(1000000) - - let tx = await arbRegistry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') - const testUpkeepId = await getUpkeepID(tx) - await arbRegistry.connect(owner).addFunds(testUpkeepId, toWei('100')) - - // Do the thing - tx = await getTransmitTx( - arbRegistry, - keeper1, - [testUpkeepId], - - { gasPrice: gasWei.mul('5') }, // High gas price so that it gets capped - ) - const receipt = await tx.wait() - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - // exactly 1 Upkeep Performed should be emitted - assert.equal(upkeepPerformedLogs.length, 1) - const upkeepPerformedLog = upkeepPerformedLogs[0] - - const gasUsed = upkeepPerformedLog.args.gasUsed - const gasOverhead = upkeepPerformedLog.args.gasOverhead - const totalPayment = upkeepPerformedLog.args.totalPayment - - assert.equal( - linkForGas( - gasUsed, - gasOverhead, - gasCeilingMultiplier, - paymentPremiumPPB, - flatFeeMicroLink, - l1CostWeiArb.div(gasCeilingMultiplier), // Dividing by gasCeilingMultiplier as it gets multiplied later - ).total.toString(), - totalPayment.toString(), - ) - }) - - itMaybe('can self fund', async () => { - const maxPayment = await registry.getMaxPaymentForGas( - Trigger.CONDITION, - performGas, - ) - - // First set auto funding amount to 0 and verify that balance is deducted upon performUpkeep - let initialBalance = toWei('100') - await registry.connect(owner).addFunds(afUpkeepId, initialBalance) - await autoFunderUpkeep.setAutoFundLink(0) - await autoFunderUpkeep.setIsEligible(true) - await getTransmitTx(registry, keeper1, [afUpkeepId]) - - let postUpkeepBalance = (await registry.getUpkeep(afUpkeepId)).balance - assert.isTrue(postUpkeepBalance.lt(initialBalance)) // Balance should be deducted - assert.isTrue(postUpkeepBalance.gte(initialBalance.sub(maxPayment))) // Balance should not be deducted more than maxPayment - - // Now set auto funding amount to 100 wei and verify that the balance increases - initialBalance = postUpkeepBalance - const autoTopupAmount = toWei('100') - await autoFunderUpkeep.setAutoFundLink(autoTopupAmount) - await autoFunderUpkeep.setIsEligible(true) - await getTransmitTx(registry, keeper1, [afUpkeepId]) - - postUpkeepBalance = (await registry.getUpkeep(afUpkeepId)).balance - // Balance should increase by autoTopupAmount and decrease by max maxPayment - assert.isTrue( - postUpkeepBalance.gte( - initialBalance.add(autoTopupAmount).sub(maxPayment), - ), - ) - }) - - it('can self cancel', async () => { - await registry.connect(owner).addFunds(afUpkeepId, toWei('100')) - - await autoFunderUpkeep.setIsEligible(true) - await autoFunderUpkeep.setShouldCancel(true) - - let registration = await registry.getUpkeep(afUpkeepId) - const oldExpiration = registration.maxValidBlocknumber - - // Do the thing - await getTransmitTx(registry, keeper1, [afUpkeepId]) - - // Verify upkeep gets cancelled - registration = await registry.getUpkeep(afUpkeepId) - const newExpiration = registration.maxValidBlocknumber - assert.isTrue(newExpiration.lt(oldExpiration)) - }) - - it('reverts when configDigest mismatches', async () => { - const report = await makeLatestBlockReport([upkeepId]) - const reportContext = [emptyBytes32, epochAndRound5_1, emptyBytes32] // wrong config digest - const sigs = signReport(reportContext, report, signers.slice(0, f + 1)) - await evmRevert( - registry - .connect(keeper1) - .transmit( - [reportContext[0], reportContext[1], reportContext[2]], - report, - sigs.rs, - sigs.ss, - sigs.vs, - ), - 'ConfigDigestMismatch()', - ) - }) - - it('reverts with incorrect number of signatures', async () => { - const configDigest = (await registry.getState()).state - .latestConfigDigest - const report = await makeLatestBlockReport([upkeepId]) - const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] // wrong config digest - const sigs = signReport(reportContext, report, signers.slice(0, f + 2)) - await evmRevert( - registry - .connect(keeper1) - .transmit( - [reportContext[0], reportContext[1], reportContext[2]], - report, - sigs.rs, - sigs.ss, - sigs.vs, - ), - 'IncorrectNumberOfSignatures()', - ) - }) - - it('reverts with invalid signature for inactive signers', async () => { - const configDigest = (await registry.getState()).state - .latestConfigDigest - const report = await makeLatestBlockReport([upkeepId]) - const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] // wrong config digest - const sigs = signReport(reportContext, report, [ - new ethers.Wallet(ethers.Wallet.createRandom()), - new ethers.Wallet(ethers.Wallet.createRandom()), - ]) - await evmRevert( - registry - .connect(keeper1) - .transmit( - [reportContext[0], reportContext[1], reportContext[2]], - report, - sigs.rs, - sigs.ss, - sigs.vs, - ), - 'OnlyActiveSigners()', - ) - }) - - it('reverts with invalid signature for duplicated signers', async () => { - const configDigest = (await registry.getState()).state - .latestConfigDigest - const report = await makeLatestBlockReport([upkeepId]) - const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] // wrong config digest - const sigs = signReport(reportContext, report, [signer1, signer1]) - await evmRevert( - registry - .connect(keeper1) - .transmit( - [reportContext[0], reportContext[1], reportContext[2]], - report, - sigs.rs, - sigs.ss, - sigs.vs, - ), - 'DuplicateSigners()', - ) - }) - - itMaybe( - 'has a large enough gas overhead to cover upkeep that use all its gas [ @skip-coverage ]', - async () => { - await registry.connect(owner).setConfigTypeSafe( - signerAddresses, - keeperAddresses, - 10, // maximise f to maximise overhead - config, - offchainVersion, - offchainBytes, - ) - const tx = await registry - .connect(owner) - ['registerUpkeep(address,uint32,address,bytes,bytes)']( - mock.address, - maxPerformGas, // max allowed gas - await admin.getAddress(), - randomBytes, - '0x', - ) - const testUpkeepId = await getUpkeepID(tx) - await registry.connect(admin).addFunds(testUpkeepId, toWei('100')) - - let performData = '0x' - for (let i = 0; i < maxPerformDataSize.toNumber(); i++) { - performData += '11' - } // max allowed performData - - await mock.setCanPerform(true) - await mock.setPerformGasToBurn(maxPerformGas) - - await getTransmitTx(registry, keeper1, [testUpkeepId], { - gasLimit: maxPerformGas.add(transmitGasOverhead), - numSigners: 11, - performData, - }) // Should not revert - }, - ) - - itMaybe( - 'performs upkeep, deducts payment, updates lastPerformed and emits events', - async () => { - await mock.setCanPerform(true) - - for (const i in fArray) { - const newF = fArray[i] - await registry - .connect(owner) - .setConfigTypeSafe( - signerAddresses, - keeperAddresses, - newF, - config, - offchainVersion, - offchainBytes, - ) - const checkBlock = await ethers.provider.getBlock('latest') - - const keeperBefore = await registry.getTransmitterInfo( - await keeper1.getAddress(), - ) - const registrationBefore = await registry.getUpkeep(upkeepId) - const registryPremiumBefore = (await registry.getState()).state - .totalPremium - const keeperLinkBefore = await linkToken.balanceOf( - await keeper1.getAddress(), - ) - const registryLinkBefore = await linkToken.balanceOf( - registry.address, - ) - - // Do the thing - const tx = await getTransmitTx(registry, keeper1, [upkeepId], { - checkBlockNum: checkBlock.number, - checkBlockHash: checkBlock.hash, - numSigners: newF + 1, - }) - - const receipt = await tx.wait() - - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - // exactly 1 Upkeep Performed should be emitted - assert.equal(upkeepPerformedLogs.length, 1) - const upkeepPerformedLog = upkeepPerformedLogs[0] - - const id = upkeepPerformedLog.args.id - const success = upkeepPerformedLog.args.success - const trigger = upkeepPerformedLog.args.trigger - const gasUsed = upkeepPerformedLog.args.gasUsed - const gasOverhead = upkeepPerformedLog.args.gasOverhead - const totalPayment = upkeepPerformedLog.args.totalPayment - assert.equal(id.toString(), upkeepId.toString()) - assert.equal(success, true) - assert.equal( - trigger, - encodeBlockTrigger({ - blockNum: checkBlock.number, - blockHash: checkBlock.hash, - }), - ) - assert.isTrue(gasUsed.gt(BigNumber.from('0'))) - assert.isTrue(gasOverhead.gt(BigNumber.from('0'))) - assert.isTrue(totalPayment.gt(BigNumber.from('0'))) - - const keeperAfter = await registry.getTransmitterInfo( - await keeper1.getAddress(), - ) - const registrationAfter = await registry.getUpkeep(upkeepId) - const keeperLinkAfter = await linkToken.balanceOf( - await keeper1.getAddress(), - ) - const registryLinkAfter = await linkToken.balanceOf( - registry.address, - ) - const registryPremiumAfter = (await registry.getState()).state - .totalPremium - const premium = registryPremiumAfter.sub(registryPremiumBefore) - // Keeper payment is gasPayment + premium / num keepers - const keeperPayment = totalPayment - .sub(premium) - .add(premium.div(BigNumber.from(keeperAddresses.length))) - - assert.equal( - keeperAfter.balance.sub(keeperPayment).toString(), - keeperBefore.balance.toString(), - ) - assert.equal( - registrationBefore.balance.sub(totalPayment).toString(), - registrationAfter.balance.toString(), - ) - assert.isTrue(keeperLinkAfter.eq(keeperLinkBefore)) - assert.isTrue(registryLinkBefore.eq(registryLinkAfter)) - - // Amount spent should be updated correctly - assert.equal( - registrationAfter.amountSpent.sub(totalPayment).toString(), - registrationBefore.amountSpent.toString(), - ) - assert.isTrue( - registrationAfter.amountSpent - .sub(registrationBefore.amountSpent) - .eq(registrationBefore.balance.sub(registrationAfter.balance)), - ) - // Last perform block number should be updated - assert.equal( - registrationAfter.lastPerformedBlockNumber.toString(), - tx.blockNumber?.toString(), - ) - - // Latest epoch should be 5 - assert.equal((await registry.getState()).state.latestEpoch, 5) - } - }, - ) - - describeMaybe( - 'Gas benchmarking conditional upkeeps [ @skip-coverage ]', - function () { - const fs = [1, 10] - fs.forEach(function (newF) { - it( - 'When f=' + - newF + - ' calculates gas overhead appropriately within a margin for different scenarios', - async () => { - // Perform the upkeep once to remove non-zero storage slots and have predictable gas measurement - let tx = await getTransmitTx(registry, keeper1, [upkeepId]) - await tx.wait() - - // Different test scenarios - let longBytes = '0x' - for (let i = 0; i < maxPerformDataSize.toNumber(); i++) { - longBytes += '11' - } - const upkeepSuccessArray = [true, false] - const performGasArray = [5000, performGas] - const performDataArray = ['0x', longBytes] - - for (const i in upkeepSuccessArray) { - for (const j in performGasArray) { - for (const k in performDataArray) { - const upkeepSuccess = upkeepSuccessArray[i] - const performGas = performGasArray[j] - const performData = performDataArray[k] - - await mock.setCanPerform(upkeepSuccess) - await mock.setPerformGasToBurn(performGas) - await registry - .connect(owner) - .setConfigTypeSafe( - signerAddresses, - keeperAddresses, - newF, - config, - offchainVersion, - offchainBytes, - ) - tx = await getTransmitTx(registry, keeper1, [upkeepId], { - numSigners: newF + 1, - performData, - }) - const receipt = await tx.wait() - const upkeepPerformedLogs = - parseUpkeepPerformedLogs(receipt) - // exactly 1 Upkeep Performed should be emitted - assert.equal(upkeepPerformedLogs.length, 1) - const upkeepPerformedLog = upkeepPerformedLogs[0] - - const upkeepGasUsed = upkeepPerformedLog.args.gasUsed - const chargedGasOverhead = - upkeepPerformedLog.args.gasOverhead - const actualGasOverhead = - receipt.gasUsed.sub(upkeepGasUsed) - - assert.isTrue(upkeepGasUsed.gt(BigNumber.from('0'))) - assert.isTrue(chargedGasOverhead.gt(BigNumber.from('0'))) - - console.log( - 'Gas Benchmarking conditional upkeeps:', - 'upkeepSuccess=', - upkeepSuccess, - 'performGas=', - performGas.toString(), - 'performData length=', - performData.length / 2 - 1, - 'sig verification ( f =', - newF, - '): calculated overhead: ', - chargedGasOverhead.toString(), - ' actual overhead: ', - actualGasOverhead.toString(), - ' margin over gasUsed: ', - chargedGasOverhead.sub(actualGasOverhead).toString(), - ) - - // Overhead should not get capped - const gasOverheadCap = registryConditionalOverhead - .add( - registryPerSignerGasOverhead.mul( - BigNumber.from(newF + 1), - ), - ) - .add( - BigNumber.from( - registryPerPerformByteGasOverhead.toNumber() * - performData.length, - ), - ) - const gasCapMinusOverhead = - gasOverheadCap.sub(chargedGasOverhead) - assert.isTrue( - gasCapMinusOverhead.gt(BigNumber.from(0)), - 'Gas overhead got capped. Verify gas overhead variables in test match those in the registry. To not have the overheads capped increase REGISTRY_GAS_OVERHEAD by atleast ' + - gasCapMinusOverhead.toString(), - ) - // total gas charged should be greater than tx gas but within gasCalculationMargin - assert.isTrue( - chargedGasOverhead.gt(actualGasOverhead), - 'Gas overhead calculated is too low, increase account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_SIGNER_GAS_OVERHEAD) by atleast ' + - actualGasOverhead.sub(chargedGasOverhead).toString(), - ) - - assert.isTrue( - chargedGasOverhead - .sub(actualGasOverhead) - .lt(gasCalculationMargin), - ), - 'Gas overhead calculated is too high, decrease account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_SIGNER_GAS_OVERHEAD) by atleast ' + - chargedGasOverhead - .sub(chargedGasOverhead) - .sub(gasCalculationMargin) - .toString() - } - } - } - }, - ) - }) - }, - ) - - describeMaybe( - 'Gas benchmarking log upkeeps [ @skip-coverage ]', - function () { - const fs = [1, 10] - fs.forEach(function (newF) { - it( - 'When f=' + - newF + - ' calculates gas overhead appropriately within a margin', - async () => { - // Perform the upkeep once to remove non-zero storage slots and have predictable gas measurement - let tx = await getTransmitTx(registry, keeper1, [logUpkeepId]) - await tx.wait() - const performData = '0x' - await mock.setCanPerform(true) - await mock.setPerformGasToBurn(performGas) - await registry.setConfigTypeSafe( - signerAddresses, - keeperAddresses, - newF, - config, - offchainVersion, - offchainBytes, - ) - tx = await getTransmitTx(registry, keeper1, [logUpkeepId], { - numSigners: newF + 1, - performData, - }) - const receipt = await tx.wait() - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - // exactly 1 Upkeep Performed should be emitted - assert.equal(upkeepPerformedLogs.length, 1) - const upkeepPerformedLog = upkeepPerformedLogs[0] - - const upkeepGasUsed = upkeepPerformedLog.args.gasUsed - const chargedGasOverhead = upkeepPerformedLog.args.gasOverhead - const actualGasOverhead = receipt.gasUsed.sub(upkeepGasUsed) - - assert.isTrue(upkeepGasUsed.gt(BigNumber.from('0'))) - assert.isTrue(chargedGasOverhead.gt(BigNumber.from('0'))) - - console.log( - 'Gas Benchmarking log upkeeps:', - 'upkeepSuccess=', - true, - 'performGas=', - performGas.toString(), - 'performData length=', - performData.length / 2 - 1, - 'sig verification ( f =', - newF, - '): calculated overhead: ', - chargedGasOverhead.toString(), - ' actual overhead: ', - actualGasOverhead.toString(), - ' margin over gasUsed: ', - chargedGasOverhead.sub(actualGasOverhead).toString(), - ) - - // Overhead should not get capped - const gasOverheadCap = registryLogOverhead - .add( - registryPerSignerGasOverhead.mul(BigNumber.from(newF + 1)), - ) - .add( - BigNumber.from( - registryPerPerformByteGasOverhead.toNumber() * - performData.length, - ), - ) - const gasCapMinusOverhead = - gasOverheadCap.sub(chargedGasOverhead) - assert.isTrue( - gasCapMinusOverhead.gt(BigNumber.from(0)), - 'Gas overhead got capped. Verify gas overhead variables in test match those in the registry. To not have the overheads capped increase REGISTRY_GAS_OVERHEAD by atleast ' + - gasCapMinusOverhead.toString(), - ) - // total gas charged should be greater than tx gas but within gasCalculationMargin - assert.isTrue( - chargedGasOverhead.gt(actualGasOverhead), - 'Gas overhead calculated is too low, increase account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_SIGNER_GAS_OVERHEAD) by atleast ' + - actualGasOverhead.sub(chargedGasOverhead).toString(), - ) - - assert.isTrue( - chargedGasOverhead - .sub(actualGasOverhead) - .lt(gasCalculationMargin), - ), - 'Gas overhead calculated is too high, decrease account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_SIGNER_GAS_OVERHEAD) by atleast ' + - chargedGasOverhead - .sub(chargedGasOverhead) - .sub(gasCalculationMargin) - .toString() - }, - ) - }) - }, - ) - }) - }) - - describeMaybe( - '#transmit with upkeep batches [ @skip-coverage ]', - function () { - const numPassingConditionalUpkeepsArray = [0, 1, 5] - const numPassingLogUpkeepsArray = [0, 1, 5] - const numFailingUpkeepsArray = [0, 3] - - for (let idx = 0; idx < numPassingConditionalUpkeepsArray.length; idx++) { - for (let jdx = 0; jdx < numPassingLogUpkeepsArray.length; jdx++) { - for (let kdx = 0; kdx < numFailingUpkeepsArray.length; kdx++) { - const numPassingConditionalUpkeeps = - numPassingConditionalUpkeepsArray[idx] - const numPassingLogUpkeeps = numPassingLogUpkeepsArray[jdx] - const numFailingUpkeeps = numFailingUpkeepsArray[kdx] - if ( - numPassingConditionalUpkeeps == 0 && - numPassingLogUpkeeps == 0 - ) { - continue - } - it( - '[Conditional:' + - numPassingConditionalUpkeeps + - ',Log:' + - numPassingLogUpkeeps + - ',Failures:' + - numFailingUpkeeps + - '] performs successful upkeeps and does not charge failing upkeeps', - async () => { - const allUpkeeps = await getMultipleUpkeepsDeployedAndFunded( - numPassingConditionalUpkeeps, - numPassingLogUpkeeps, - numFailingUpkeeps, - ) - const passingConditionalUpkeepIds = - allUpkeeps.passingConditionalUpkeepIds - const passingLogUpkeepIds = allUpkeeps.passingLogUpkeepIds - const failingUpkeepIds = allUpkeeps.failingUpkeepIds - - const keeperBefore = await registry.getTransmitterInfo( - await keeper1.getAddress(), - ) - const keeperLinkBefore = await linkToken.balanceOf( - await keeper1.getAddress(), - ) - const registryLinkBefore = await linkToken.balanceOf( - registry.address, - ) - const registryPremiumBefore = (await registry.getState()).state - .totalPremium - const registrationConditionalPassingBefore = await Promise.all( - passingConditionalUpkeepIds.map(async (id) => { - const reg = await registry.getUpkeep(BigNumber.from(id)) - assert.equal(reg.lastPerformedBlockNumber.toString(), '0') - return reg - }), - ) - const registrationLogPassingBefore = await Promise.all( - passingLogUpkeepIds.map(async (id) => { - const reg = await registry.getUpkeep(BigNumber.from(id)) - assert.equal(reg.lastPerformedBlockNumber.toString(), '0') - return reg - }), - ) - const registrationFailingBefore = await Promise.all( - failingUpkeepIds.map(async (id) => { - const reg = await registry.getUpkeep(BigNumber.from(id)) - assert.equal(reg.lastPerformedBlockNumber.toString(), '0') - return reg - }), - ) - - const tx = await getTransmitTx( - registry, - keeper1, - passingConditionalUpkeepIds.concat( - passingLogUpkeepIds.concat(failingUpkeepIds), - ), - ) - - const receipt = await tx.wait() - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - // exactly numPassingUpkeeps Upkeep Performed should be emitted - assert.equal( - upkeepPerformedLogs.length, - numPassingConditionalUpkeeps + numPassingLogUpkeeps, - ) - const insufficientFundsLogs = - parseInsufficientFundsUpkeepReportLogs(receipt) - // exactly numFailingUpkeeps Upkeep Performed should be emitted - assert.equal(insufficientFundsLogs.length, numFailingUpkeeps) - - const keeperAfter = await registry.getTransmitterInfo( - await keeper1.getAddress(), - ) - const keeperLinkAfter = await linkToken.balanceOf( - await keeper1.getAddress(), - ) - const registryLinkAfter = await linkToken.balanceOf( - registry.address, - ) - const registrationConditionalPassingAfter = await Promise.all( - passingConditionalUpkeepIds.map(async (id) => { - return await registry.getUpkeep(BigNumber.from(id)) - }), - ) - const registrationLogPassingAfter = await Promise.all( - passingLogUpkeepIds.map(async (id) => { - return await registry.getUpkeep(BigNumber.from(id)) - }), - ) - const registrationFailingAfter = await Promise.all( - failingUpkeepIds.map(async (id) => { - return await registry.getUpkeep(BigNumber.from(id)) - }), - ) - const registryPremiumAfter = (await registry.getState()).state - .totalPremium - const premium = registryPremiumAfter.sub(registryPremiumBefore) - - let netPayment = BigNumber.from('0') - for (let i = 0; i < numPassingConditionalUpkeeps; i++) { - const id = upkeepPerformedLogs[i].args.id - const gasUsed = upkeepPerformedLogs[i].args.gasUsed - const gasOverhead = upkeepPerformedLogs[i].args.gasOverhead - const totalPayment = upkeepPerformedLogs[i].args.totalPayment - - expect(id).to.equal(passingConditionalUpkeepIds[i]) - assert.isTrue(gasUsed.gt(BigNumber.from('0'))) - assert.isTrue(gasOverhead.gt(BigNumber.from('0'))) - assert.isTrue(totalPayment.gt(BigNumber.from('0'))) - - // Balance should be deducted - assert.equal( - registrationConditionalPassingBefore[i].balance - .sub(totalPayment) - .toString(), - registrationConditionalPassingAfter[i].balance.toString(), - ) - - // Amount spent should be updated correctly - assert.equal( - registrationConditionalPassingAfter[i].amountSpent - .sub(totalPayment) - .toString(), - registrationConditionalPassingBefore[ - i - ].amountSpent.toString(), - ) - - // Last perform block number should be updated - assert.equal( - registrationConditionalPassingAfter[ - i - ].lastPerformedBlockNumber.toString(), - tx.blockNumber?.toString(), - ) - - netPayment = netPayment.add(totalPayment) - } - - for (let i = 0; i < numPassingLogUpkeeps; i++) { - const id = - upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args - .id - const gasUsed = - upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args - .gasUsed - const gasOverhead = - upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args - .gasOverhead - const totalPayment = - upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args - .totalPayment - - expect(id).to.equal(passingLogUpkeepIds[i]) - assert.isTrue(gasUsed.gt(BigNumber.from('0'))) - assert.isTrue(gasOverhead.gt(BigNumber.from('0'))) - assert.isTrue(totalPayment.gt(BigNumber.from('0'))) - - // Balance should be deducted - assert.equal( - registrationLogPassingBefore[i].balance - .sub(totalPayment) - .toString(), - registrationLogPassingAfter[i].balance.toString(), - ) - - // Amount spent should be updated correctly - assert.equal( - registrationLogPassingAfter[i].amountSpent - .sub(totalPayment) - .toString(), - registrationLogPassingBefore[i].amountSpent.toString(), - ) - - // Last perform block number should not be updated for log triggers - assert.equal( - registrationLogPassingAfter[ - i - ].lastPerformedBlockNumber.toString(), - '0', - ) - - netPayment = netPayment.add(totalPayment) - } - - for (let i = 0; i < numFailingUpkeeps; i++) { - // InsufficientFunds log should be emitted - const id = insufficientFundsLogs[i].args.id - expect(id).to.equal(failingUpkeepIds[i]) - - // Balance and amount spent should be same - assert.equal( - registrationFailingBefore[i].balance.toString(), - registrationFailingAfter[i].balance.toString(), - ) - assert.equal( - registrationFailingBefore[i].amountSpent.toString(), - registrationFailingAfter[i].amountSpent.toString(), - ) - - // Last perform block number should not be updated - assert.equal( - registrationFailingAfter[ - i - ].lastPerformedBlockNumber.toString(), - '0', - ) - } - - // Keeper payment is gasPayment + premium / num keepers - const keeperPayment = netPayment - .sub(premium) - .add(premium.div(BigNumber.from(keeperAddresses.length))) - - // Keeper should be paid net payment for all passed upkeeps - assert.equal( - keeperAfter.balance.sub(keeperPayment).toString(), - keeperBefore.balance.toString(), - ) - - assert.isTrue(keeperLinkAfter.eq(keeperLinkBefore)) - assert.isTrue(registryLinkBefore.eq(registryLinkAfter)) - }, - ) - - it( - '[Conditional:' + - numPassingConditionalUpkeeps + - ',Log' + - numPassingLogUpkeeps + - ',Failures:' + - numFailingUpkeeps + - '] splits gas overhead appropriately among performed upkeeps [ @skip-coverage ]', - async () => { - const allUpkeeps = await getMultipleUpkeepsDeployedAndFunded( - numPassingConditionalUpkeeps, - numPassingLogUpkeeps, - numFailingUpkeeps, - ) - const passingConditionalUpkeepIds = - allUpkeeps.passingConditionalUpkeepIds - const passingLogUpkeepIds = allUpkeeps.passingLogUpkeepIds - const failingUpkeepIds = allUpkeeps.failingUpkeepIds - - // Perform the upkeeps once to remove non-zero storage slots and have predictable gas measurement - let tx = await getTransmitTx( - registry, - keeper1, - passingConditionalUpkeepIds.concat( - passingLogUpkeepIds.concat(failingUpkeepIds), - ), - ) - - await tx.wait() - - // Do the actual thing - - tx = await getTransmitTx( - registry, - keeper1, - passingConditionalUpkeepIds.concat( - passingLogUpkeepIds.concat(failingUpkeepIds), - ), - ) - - const receipt = await tx.wait() - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - // exactly numPassingUpkeeps Upkeep Performed should be emitted - assert.equal( - upkeepPerformedLogs.length, - numPassingConditionalUpkeeps + numPassingLogUpkeeps, - ) - - const gasConditionalOverheadCap = - registryConditionalOverhead.add( - registryPerSignerGasOverhead.mul(BigNumber.from(f + 1)), - ) - const gasLogOverheadCap = registryLogOverhead.add( - registryPerSignerGasOverhead.mul(BigNumber.from(f + 1)), - ) - - const overheadCanGetCapped = - numFailingUpkeeps > 0 && - numPassingConditionalUpkeeps <= 1 && - numPassingLogUpkeeps <= 1 - // Can happen if there are failing upkeeps and only 1 successful upkeep of each type - let netGasUsedPlusOverhead = BigNumber.from('0') - - for (let i = 0; i < numPassingConditionalUpkeeps; i++) { - const gasUsed = upkeepPerformedLogs[i].args.gasUsed - const gasOverhead = upkeepPerformedLogs[i].args.gasOverhead - - assert.isTrue(gasUsed.gt(BigNumber.from('0'))) - assert.isTrue(gasOverhead.gt(BigNumber.from('0'))) - - // Overhead should not exceed capped - assert.isTrue(gasOverhead.lte(gasConditionalOverheadCap)) - - // Overhead should be same for every upkeep since they have equal performData, hence same caps - assert.isTrue( - gasOverhead.eq(upkeepPerformedLogs[0].args.gasOverhead), - ) - - netGasUsedPlusOverhead = netGasUsedPlusOverhead - .add(gasUsed) - .add(gasOverhead) - } - for (let i = 0; i < numPassingLogUpkeeps; i++) { - const gasUsed = - upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args - .gasUsed - const gasOverhead = - upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args - .gasOverhead - - assert.isTrue(gasUsed.gt(BigNumber.from('0'))) - assert.isTrue(gasOverhead.gt(BigNumber.from('0'))) - - // Overhead should not exceed capped - assert.isTrue(gasOverhead.lte(gasLogOverheadCap)) - - // Overhead should be same for every upkeep since they have equal performData, hence same caps - assert.isTrue( - gasOverhead.eq( - upkeepPerformedLogs[numPassingConditionalUpkeeps].args - .gasOverhead, - ), - ) - - netGasUsedPlusOverhead = netGasUsedPlusOverhead - .add(gasUsed) - .add(gasOverhead) - } - - const overheadsGotCapped = - (numPassingConditionalUpkeeps > 0 && - upkeepPerformedLogs[0].args.gasOverhead.eq( - gasConditionalOverheadCap, - )) || - (numPassingLogUpkeeps > 0 && - upkeepPerformedLogs[ - numPassingConditionalUpkeeps - ].args.gasOverhead.eq(gasLogOverheadCap)) - // Should only get capped in certain scenarios - if (overheadsGotCapped) { - assert.isTrue( - overheadCanGetCapped, - 'Gas overhead got capped. Verify gas overhead variables in test match those in the registry. To not have the overheads capped increase REGISTRY_GAS_OVERHEAD', - ) - } - - console.log( - 'Gas Benchmarking - batching (passedConditionalUpkeeps: ', - numPassingConditionalUpkeeps, - 'passedLogUpkeeps:', - numPassingLogUpkeeps, - 'failedUpkeeps:', - numFailingUpkeeps, - '): ', - 'overheadsGotCapped', - overheadsGotCapped, - numPassingConditionalUpkeeps > 0 - ? 'calculated conditional overhead' - : '', - numPassingConditionalUpkeeps > 0 - ? upkeepPerformedLogs[0].args.gasOverhead.toString() - : '', - numPassingLogUpkeeps > 0 ? 'calculated log overhead' : '', - numPassingLogUpkeeps > 0 - ? upkeepPerformedLogs[ - numPassingConditionalUpkeeps - ].args.gasOverhead.toString() - : '', - ' margin over gasUsed', - netGasUsedPlusOverhead.sub(receipt.gasUsed).toString(), - ) - - // If overheads dont get capped then total gas charged should be greater than tx gas - // We don't check whether the net is within gasMargin as the margin changes with numFailedUpkeeps - // Which is ok, as long as individual gas overhead is capped - if (!overheadsGotCapped) { - assert.isTrue( - netGasUsedPlusOverhead.gt(receipt.gasUsed), - 'Gas overhead is too low, increase ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD', - ) - } - }, - ) - } - } - } - - it('has enough perform gas overhead for large batches [ @skip-coverage ]', async () => { - const numUpkeeps = 20 - const upkeepIds: BigNumber[] = [] - let totalPerformGas = BigNumber.from('0') - for (let i = 0; i < numUpkeeps; i++) { - const mock = await upkeepMockFactory.deploy() - const tx = await registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') - const testUpkeepId = await getUpkeepID(tx) - upkeepIds.push(testUpkeepId) - - // Add funds to passing upkeeps - await registry.connect(owner).addFunds(testUpkeepId, toWei('10')) - - await mock.setCanPerform(true) - await mock.setPerformGasToBurn(performGas) - - totalPerformGas = totalPerformGas.add(performGas) - } - - // Should revert with no overhead added - await evmRevert( - getTransmitTx(registry, keeper1, upkeepIds, { - gasLimit: totalPerformGas, - }), - ) - // Should not revert with overhead added - await getTransmitTx(registry, keeper1, upkeepIds, { - gasLimit: totalPerformGas.add(transmitGasOverhead), - }) - }) - - it('splits l2 payment among performed upkeeps', async () => { - const numUpkeeps = 7 - const upkeepIds: BigNumber[] = [] - // Same as MockArbGasInfo.sol - const l1CostWeiArb = BigNumber.from(1000000) - - for (let i = 0; i < numUpkeeps; i++) { - const mock = await upkeepMockFactory.deploy() - const tx = await arbRegistry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') - const testUpkeepId = await getUpkeepID(tx) - upkeepIds.push(testUpkeepId) - - // Add funds to passing upkeeps - await arbRegistry.connect(owner).addFunds(testUpkeepId, toWei('100')) - } - - // Do the thing - const tx = await getTransmitTx( - arbRegistry, - keeper1, - upkeepIds, - - { gasPrice: gasWei.mul('5') }, // High gas price so that it gets capped - ) - - const receipt = await tx.wait() - const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) - // exactly numPassingUpkeeps Upkeep Performed should be emitted - assert.equal(upkeepPerformedLogs.length, numUpkeeps) - - // Verify the payment calculation in upkeepPerformed[0] - const upkeepPerformedLog = upkeepPerformedLogs[0] - - const gasUsed = upkeepPerformedLog.args.gasUsed - const gasOverhead = upkeepPerformedLog.args.gasOverhead - const totalPayment = upkeepPerformedLog.args.totalPayment - - assert.equal( - linkForGas( - gasUsed, - gasOverhead, - gasCeilingMultiplier, - paymentPremiumPPB, - flatFeeMicroLink, - l1CostWeiArb.div(gasCeilingMultiplier), // Dividing by gasCeilingMultiplier as it gets multiplied later - BigNumber.from(numUpkeeps), - ).total.toString(), - totalPayment.toString(), - ) - }) - }, - ) - - describe('#recoverFunds', () => { - const sent = toWei('7') - - beforeEach(async () => { - await linkToken.connect(admin).approve(registry.address, toWei('100')) - await linkToken - .connect(owner) - .transfer(await keeper1.getAddress(), toWei('1000')) - - // add funds to upkeep 1 and perform and withdraw some payment - const tx = await registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), emptyBytes, emptyBytes) - - const id1 = await getUpkeepID(tx) - await registry.connect(admin).addFunds(id1, toWei('5')) - - await getTransmitTx(registry, keeper1, [id1]) - await getTransmitTx(registry, keeper2, [id1]) - await getTransmitTx(registry, keeper3, [id1]) - - await registry - .connect(payee1) - .withdrawPayment( - await keeper1.getAddress(), - await nonkeeper.getAddress(), - ) - - // transfer funds directly to the registry - await linkToken.connect(keeper1).transfer(registry.address, sent) - - // add funds to upkeep 2 and perform and withdraw some payment - const tx2 = await registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), emptyBytes, emptyBytes) - const id2 = await getUpkeepID(tx2) - await registry.connect(admin).addFunds(id2, toWei('5')) - - await getTransmitTx(registry, keeper1, [id2]) - await getTransmitTx(registry, keeper2, [id2]) - await getTransmitTx(registry, keeper3, [id2]) - - await registry - .connect(payee2) - .withdrawPayment( - await keeper2.getAddress(), - await nonkeeper.getAddress(), - ) - - // transfer funds using onTokenTransfer - const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [id2]) - await linkToken - .connect(owner) - .transferAndCall(registry.address, toWei('1'), data) - - // withdraw some funds - await registry.connect(owner).cancelUpkeep(id1) - await registry - .connect(admin) - .withdrawFunds(id1, await nonkeeper.getAddress()) - }) - - it('reverts if not called by owner', async () => { - await evmRevert( - registry.connect(keeper1).recoverFunds(), - 'Only callable by owner', - ) - }) - - it('allows any funds that have been accidentally transfered to be moved', async () => { - const balanceBefore = await linkToken.balanceOf(registry.address) - const ownerBefore = await linkToken.balanceOf(await owner.getAddress()) - - await registry.connect(owner).recoverFunds() - - const balanceAfter = await linkToken.balanceOf(registry.address) - const ownerAfter = await linkToken.balanceOf(await owner.getAddress()) - - assert.isTrue(balanceBefore.eq(balanceAfter.add(sent))) - assert.isTrue(ownerAfter.eq(ownerBefore.add(sent))) - }) - }) - - describe('#getMinBalanceForUpkeep / #checkUpkeep / #transmit', () => { - it('calculates the minimum balance appropriately', async () => { - await mock.setCanCheck(true) - - const oneWei = BigNumber.from(1) - const minBalance = await registry.getMinBalanceForUpkeep(upkeepId) - const tooLow = minBalance.sub(oneWei) - - await registry.connect(admin).addFunds(upkeepId, tooLow) - let checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic['checkUpkeep(uint256)'](upkeepId) - - assert.equal(checkUpkeepResult.upkeepNeeded, false) - assert.equal( - checkUpkeepResult.upkeepFailureReason, - UpkeepFailureReason.INSUFFICIENT_BALANCE, - ) - - await registry.connect(admin).addFunds(upkeepId, oneWei) - checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic['checkUpkeep(uint256)'](upkeepId) - assert.equal(checkUpkeepResult.upkeepNeeded, true) - }) - - it('uses maxPerformData size in checkUpkeep but actual performDataSize in transmit', async () => { - const tx1 = await registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') - const upkeepID1 = await getUpkeepID(tx1) - const tx2 = await registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') - const upkeepID2 = await getUpkeepID(tx2) - await mock.setCanCheck(true) - await mock.setCanPerform(true) - - // upkeep 1 is underfunded, 2 is fully funded - const minBalance1 = ( - await registry.getMinBalanceForUpkeep(upkeepID1) - ).sub(1) - const minBalance2 = await registry.getMinBalanceForUpkeep(upkeepID2) - await registry.connect(owner).addFunds(upkeepID1, minBalance1) - await registry.connect(owner).addFunds(upkeepID2, minBalance2) - - // upkeep 1 check should return false, 2 should return true - let checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic['checkUpkeep(uint256)'](upkeepID1) - assert.equal(checkUpkeepResult.upkeepNeeded, false) - assert.equal( - checkUpkeepResult.upkeepFailureReason, - UpkeepFailureReason.INSUFFICIENT_BALANCE, - ) - - checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic['checkUpkeep(uint256)'](upkeepID2) - assert.equal(checkUpkeepResult.upkeepNeeded, true) - - // upkeep 1 perform should return with insufficient balance using max performData size - let maxPerformData = '0x' - for (let i = 0; i < maxPerformDataSize.toNumber(); i++) { - maxPerformData += '11' - } - - const tx = await getTransmitTx(registry, keeper1, [upkeepID1], { - gasPrice: gasWei.mul(gasCeilingMultiplier), - performData: maxPerformData, - }) - - const receipt = await tx.wait() - const insufficientFundsUpkeepReportLogs = - parseInsufficientFundsUpkeepReportLogs(receipt) - // exactly 1 InsufficientFundsUpkeepReportLogs log should be emitted - assert.equal(insufficientFundsUpkeepReportLogs.length, 1) - - // upkeep 1 perform should succeed with empty performData - await getTransmitTx(registry, keeper1, [upkeepID1], { - gasPrice: gasWei.mul(gasCeilingMultiplier), - }), - // upkeep 2 perform should succeed with max performData size - await getTransmitTx(registry, keeper1, [upkeepID2], { - gasPrice: gasWei.mul(gasCeilingMultiplier), - performData: maxPerformData, - }) - }) - }) - - describe('#withdrawFunds', () => { - let upkeepId2: BigNumber - - beforeEach(async () => { - const tx = await registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') - upkeepId2 = await getUpkeepID(tx) - - await registry.connect(admin).addFunds(upkeepId, toWei('100')) - await registry.connect(admin).addFunds(upkeepId2, toWei('100')) - - // Do a perform so that upkeep is charged some amount - await getTransmitTx(registry, keeper1, [upkeepId]) - await getTransmitTx(registry, keeper1, [upkeepId2]) - }) - - it('reverts if called on a non existing ID', async () => { - await evmRevert( - registry - .connect(admin) - .withdrawFunds(upkeepId.add(1), await payee1.getAddress()), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if called by anyone but the admin', async () => { - await evmRevert( - registry - .connect(owner) - .withdrawFunds(upkeepId, await payee1.getAddress()), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if called on an uncanceled upkeep', async () => { - await evmRevert( - registry - .connect(admin) - .withdrawFunds(upkeepId, await payee1.getAddress()), - 'UpkeepNotCanceled()', - ) - }) - - it('reverts if called with the 0 address', async () => { - await evmRevert( - registry.connect(admin).withdrawFunds(upkeepId, zeroAddress), - 'InvalidRecipient()', - ) - }) - - describe('after the registration is paused, then cancelled', () => { - it('allows the admin to withdraw', async () => { - const balance = await registry.getBalance(upkeepId) - const payee = await payee1.getAddress() - await registry.connect(admin).pauseUpkeep(upkeepId) - await registry.connect(owner).cancelUpkeep(upkeepId) - await expect(() => - registry.connect(admin).withdrawFunds(upkeepId, payee), - ).to.changeTokenBalance(linkToken, payee1, balance) - }) - }) - - describe('after the registration is cancelled', () => { - beforeEach(async () => { - await registry.connect(owner).cancelUpkeep(upkeepId) - await registry.connect(owner).cancelUpkeep(upkeepId2) - }) - - it('can be called successively on two upkeeps', async () => { - await registry - .connect(admin) - .withdrawFunds(upkeepId, await payee1.getAddress()) - await registry - .connect(admin) - .withdrawFunds(upkeepId2, await payee1.getAddress()) - }) - - it('moves the funds out and updates the balance and emits an event', async () => { - const payee1Before = await linkToken.balanceOf( - await payee1.getAddress(), - ) - const registryBefore = await linkToken.balanceOf(registry.address) - - let registration = await registry.getUpkeep(upkeepId) - const previousBalance = registration.balance - - const tx = await registry - .connect(admin) - .withdrawFunds(upkeepId, await payee1.getAddress()) - await expect(tx) - .to.emit(registry, 'FundsWithdrawn') - .withArgs(upkeepId, previousBalance, await payee1.getAddress()) - - const payee1After = await linkToken.balanceOf(await payee1.getAddress()) - const registryAfter = await linkToken.balanceOf(registry.address) - - assert.isTrue(payee1Before.add(previousBalance).eq(payee1After)) - assert.isTrue(registryBefore.sub(previousBalance).eq(registryAfter)) - - registration = await registry.getUpkeep(upkeepId) - assert.equal(0, registration.balance.toNumber()) - }) - }) - }) - - describe('#simulatePerformUpkeep', () => { - it('reverts if called by non zero address', async () => { - await evmRevert( - registry - .connect(await owner.getAddress()) - .callStatic.simulatePerformUpkeep(upkeepId, '0x'), - 'OnlySimulatedBackend()', - ) - }) - - it('reverts when registry is paused', async () => { - await registry.connect(owner).pause() - await evmRevert( - registry - .connect(zeroAddress) - .callStatic.simulatePerformUpkeep(upkeepId, '0x'), - 'RegistryPaused()', - ) - }) - - it('returns false and gasUsed when perform fails', async () => { - await mock.setCanPerform(false) - - const simulatePerformResult = await registry - .connect(zeroAddress) - .callStatic.simulatePerformUpkeep(upkeepId, '0x') - - assert.equal(simulatePerformResult.success, false) - assert.isTrue(simulatePerformResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used - }) - - it('returns true, gasUsed, and performGas when perform succeeds', async () => { - await mock.setCanPerform(true) - - const simulatePerformResult = await registry - .connect(zeroAddress) - .callStatic.simulatePerformUpkeep(upkeepId, '0x') - - assert.equal(simulatePerformResult.success, true) - assert.isTrue(simulatePerformResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used - }) - - it('returns correct amount of gasUsed when perform succeeds', async () => { - await mock.setCanPerform(true) - await mock.setPerformGasToBurn(performGas) - - const simulatePerformResult = await registry - .connect(zeroAddress) - .callStatic.simulatePerformUpkeep(upkeepId, '0x') - - assert.equal(simulatePerformResult.success, true) - // Full execute gas should be used, with some performGasBuffer(1000) - assert.isTrue( - simulatePerformResult.gasUsed.gt( - performGas.sub(BigNumber.from('1000')), - ), - ) - }) - }) - - describe('#checkUpkeep', () => { - it('reverts if called by non zero address', async () => { - await evmRevert( - registry - .connect(await owner.getAddress()) - .callStatic['checkUpkeep(uint256)'](upkeepId), - 'OnlySimulatedBackend()', - ) - }) - - it('returns false and error code if the upkeep is cancelled by admin', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - - const checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic['checkUpkeep(uint256)'](upkeepId) - - assert.equal(checkUpkeepResult.upkeepNeeded, false) - assert.equal(checkUpkeepResult.performData, '0x') - assert.equal( - checkUpkeepResult.upkeepFailureReason, - UpkeepFailureReason.UPKEEP_CANCELLED, - ) - expect(checkUpkeepResult.gasUsed).to.equal(0) - expect(checkUpkeepResult.gasLimit).to.equal(performGas) - }) - - it('returns false and error code if the upkeep is cancelled by owner', async () => { - await registry.connect(owner).cancelUpkeep(upkeepId) - - const checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic['checkUpkeep(uint256)'](upkeepId) - - assert.equal(checkUpkeepResult.upkeepNeeded, false) - assert.equal(checkUpkeepResult.performData, '0x') - assert.equal( - checkUpkeepResult.upkeepFailureReason, - UpkeepFailureReason.UPKEEP_CANCELLED, - ) - expect(checkUpkeepResult.gasUsed).to.equal(0) - expect(checkUpkeepResult.gasLimit).to.equal(performGas) - }) - - it('returns false and error code if the registry is paused', async () => { - await registry.connect(owner).pause() - - const checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic['checkUpkeep(uint256)'](upkeepId) - - assert.equal(checkUpkeepResult.upkeepNeeded, false) - assert.equal(checkUpkeepResult.performData, '0x') - assert.equal( - checkUpkeepResult.upkeepFailureReason, - UpkeepFailureReason.REGISTRY_PAUSED, - ) - expect(checkUpkeepResult.gasUsed).to.equal(0) - expect(checkUpkeepResult.gasLimit).to.equal(performGas) - }) - - it('returns false and error code if the upkeep is paused', async () => { - await registry.connect(admin).pauseUpkeep(upkeepId) - - const checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic['checkUpkeep(uint256)'](upkeepId) - - assert.equal(checkUpkeepResult.upkeepNeeded, false) - assert.equal(checkUpkeepResult.performData, '0x') - assert.equal( - checkUpkeepResult.upkeepFailureReason, - UpkeepFailureReason.UPKEEP_PAUSED, - ) - expect(checkUpkeepResult.gasUsed).to.equal(0) - expect(checkUpkeepResult.gasLimit).to.equal(performGas) - }) - - it('returns false and error code if user is out of funds', async () => { - const checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic['checkUpkeep(uint256)'](upkeepId) - - assert.equal(checkUpkeepResult.upkeepNeeded, false) - assert.equal(checkUpkeepResult.performData, '0x') - assert.equal( - checkUpkeepResult.upkeepFailureReason, - UpkeepFailureReason.INSUFFICIENT_BALANCE, - ) - expect(checkUpkeepResult.gasUsed).to.equal(0) - expect(checkUpkeepResult.gasLimit).to.equal(performGas) - }) - - context('when the registration is funded', () => { - beforeEach(async () => { - await linkToken.connect(admin).approve(registry.address, toWei('200')) - await registry.connect(admin).addFunds(upkeepId, toWei('100')) - await registry.connect(admin).addFunds(logUpkeepId, toWei('100')) - }) - - it('returns false, error code, and revert data if the target check reverts', async () => { - await mock.setShouldRevertCheck(true) - await mock.setCheckRevertReason( - 'custom revert error, clever way to insert offchain data', - ) - const checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic['checkUpkeep(uint256)'](upkeepId) - assert.equal(checkUpkeepResult.upkeepNeeded, false) - - const revertReasonBytes = `0x${checkUpkeepResult.performData.slice(10)}` // remove sighash - assert.equal( - ethers.utils.defaultAbiCoder.decode(['string'], revertReasonBytes)[0], - 'custom revert error, clever way to insert offchain data', - ) - assert.equal( - checkUpkeepResult.upkeepFailureReason, - UpkeepFailureReason.TARGET_CHECK_REVERTED, - ) - assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used - expect(checkUpkeepResult.gasLimit).to.equal(performGas) - // Feed data should be returned here - assert.isTrue(checkUpkeepResult.fastGasWei.gt(BigNumber.from('0'))) - assert.isTrue(checkUpkeepResult.linkNative.gt(BigNumber.from('0'))) - }) - - it('returns false, error code, and no revert data if the target check revert data exceeds maxRevertDataSize', async () => { - await mock.setShouldRevertCheck(true) - let longRevertReason = '' - for (let i = 0; i <= maxRevertDataSize.toNumber(); i++) { - longRevertReason += 'x' - } - await mock.setCheckRevertReason(longRevertReason) - const checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic['checkUpkeep(uint256)'](upkeepId) - assert.equal(checkUpkeepResult.upkeepNeeded, false) - - assert.equal(checkUpkeepResult.performData, '0x') - assert.equal( - checkUpkeepResult.upkeepFailureReason, - UpkeepFailureReason.REVERT_DATA_EXCEEDS_LIMIT, - ) - assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used - expect(checkUpkeepResult.gasLimit).to.equal(performGas) - }) - - it('returns false and error code if the upkeep is not needed', async () => { - await mock.setCanCheck(false) - const checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic['checkUpkeep(uint256)'](upkeepId) - - assert.equal(checkUpkeepResult.upkeepNeeded, false) - assert.equal(checkUpkeepResult.performData, '0x') - assert.equal( - checkUpkeepResult.upkeepFailureReason, - UpkeepFailureReason.UPKEEP_NOT_NEEDED, - ) - assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used - expect(checkUpkeepResult.gasLimit).to.equal(performGas) - }) - - it('returns false and error code if the performData exceeds limit', async () => { - let longBytes = '0x' - for (let i = 0; i < 5000; i++) { - longBytes += '1' - } - await mock.setCanCheck(true) - await mock.setPerformData(longBytes) - - const checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic['checkUpkeep(uint256)'](upkeepId) - - assert.equal(checkUpkeepResult.upkeepNeeded, false) - assert.equal(checkUpkeepResult.performData, '0x') - assert.equal( - checkUpkeepResult.upkeepFailureReason, - UpkeepFailureReason.PERFORM_DATA_EXCEEDS_LIMIT, - ) - assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used - expect(checkUpkeepResult.gasLimit).to.equal(performGas) - }) - - it('returns true with gas used if the target can execute', async () => { - await mock.setCanCheck(true) - await mock.setPerformData(randomBytes) - - const latestBlock = await ethers.provider.getBlock('latest') - - const checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic['checkUpkeep(uint256)'](upkeepId, { - blockTag: latestBlock.number, - }) - - assert.equal(checkUpkeepResult.upkeepNeeded, true) - assert.equal(checkUpkeepResult.performData, randomBytes) - assert.equal( - checkUpkeepResult.upkeepFailureReason, - UpkeepFailureReason.NONE, - ) - assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used - expect(checkUpkeepResult.gasLimit).to.equal(performGas) - assert.isTrue(checkUpkeepResult.fastGasWei.eq(gasWei)) - assert.isTrue(checkUpkeepResult.linkNative.eq(linkEth)) - }) - - it('calls checkLog for log-trigger upkeeps', async () => { - const log: Log = { - index: 0, - timestamp: 0, - txHash: ethers.utils.randomBytes(32), - blockNumber: 100, - blockHash: ethers.utils.randomBytes(32), - source: randomAddress(), - topics: [ethers.utils.randomBytes(32), ethers.utils.randomBytes(32)], - data: ethers.utils.randomBytes(1000), - } - - await ltUpkeep.mock.checkLog.withArgs(log, '0x').returns(true, '0x1234') - - const checkData = encodeLog(log) - - const checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic['checkUpkeep(uint256,bytes)'](logUpkeepId, checkData) - - expect(checkUpkeepResult.upkeepNeeded).to.be.true - expect(checkUpkeepResult.performData).to.equal('0x1234') - }) - - itMaybe( - 'has a large enough gas overhead to cover upkeeps that use all their gas [ @skip-coverage ]', - async () => { - await mock.setCanCheck(true) - await mock.setCheckGasToBurn(checkGasLimit) - const gas = checkGasLimit.add(checkGasOverhead) - const checkUpkeepResult = await registry - .connect(zeroAddress) - .callStatic['checkUpkeep(uint256)'](upkeepId, { - gasLimit: gas, - }) - - assert.equal(checkUpkeepResult.upkeepNeeded, true) - }, - ) - }) - }) - - describe('#addFunds', () => { - const amount = toWei('1') - - it('reverts if the registration does not exist', async () => { - await evmRevert( - registry.connect(keeper1).addFunds(upkeepId.add(1), amount), - 'UpkeepCancelled()', - ) - }) - - it('adds to the balance of the registration', async () => { - await registry.connect(admin).addFunds(upkeepId, amount) - const registration = await registry.getUpkeep(upkeepId) - assert.isTrue(amount.eq(registration.balance)) - }) - - it('lets anyone add funds to an upkeep not just admin', async () => { - await linkToken.connect(owner).transfer(await payee1.getAddress(), amount) - await linkToken.connect(payee1).approve(registry.address, amount) - - await registry.connect(payee1).addFunds(upkeepId, amount) - const registration = await registry.getUpkeep(upkeepId) - assert.isTrue(amount.eq(registration.balance)) - }) - - it('emits a log', async () => { - const tx = await registry.connect(admin).addFunds(upkeepId, amount) - await expect(tx) - .to.emit(registry, 'FundsAdded') - .withArgs(upkeepId, await admin.getAddress(), amount) - }) - - it('reverts if the upkeep is canceled', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( - registry.connect(keeper1).addFunds(upkeepId, amount), - 'UpkeepCancelled()', - ) - }) - }) - - describe('#getActiveUpkeepIDs', () => { - it('reverts if startIndex is out of bounds ', async () => { - await evmRevert( - registry.getActiveUpkeepIDs(numUpkeeps, 0), - 'IndexOutOfRange()', - ) - await evmRevert( - registry.getActiveUpkeepIDs(numUpkeeps + 1, 0), - 'IndexOutOfRange()', - ) - }) - - it('returns upkeep IDs bounded by maxCount', async () => { - let upkeepIds = await registry.getActiveUpkeepIDs(0, 1) - assert(upkeepIds.length == 1) - assert(upkeepIds[0].eq(upkeepId)) - upkeepIds = await registry.getActiveUpkeepIDs(1, 3) - assert(upkeepIds.length == 3) - expect(upkeepIds).to.deep.equal([ - afUpkeepId, - logUpkeepId, - streamsLookupUpkeepId, - ]) - }) - - it('returns as many ids as possible if maxCount > num available', async () => { - const upkeepIds = await registry.getActiveUpkeepIDs(1, numUpkeeps + 100) - assert(upkeepIds.length == numUpkeeps - 1) - }) - - it('returns all upkeep IDs if maxCount is 0', async () => { - let upkeepIds = await registry.getActiveUpkeepIDs(0, 0) - assert(upkeepIds.length == numUpkeeps) - upkeepIds = await registry.getActiveUpkeepIDs(2, 0) - assert(upkeepIds.length == numUpkeeps - 2) - }) - }) - - describe('#getMaxPaymentForGas', () => { - const arbL1PriceinWei = BigNumber.from(1000) // Same as MockArbGasInfo.sol - const l1CostWeiArb = arbL1PriceinWei.mul(16).mul(maxPerformDataSize) - const l1CostWeiOpt = BigNumber.from(2000000) // Same as MockOVMGasPriceOracle.sol - itMaybe('calculates the max fee appropriately', async () => { - await verifyMaxPayment(registry) - }) - - itMaybe('calculates the max fee appropriately for Arbitrum', async () => { - await verifyMaxPayment(arbRegistry, l1CostWeiArb) - }) - - itMaybe('calculates the max fee appropriately for Optimism', async () => { - await verifyMaxPayment(opRegistry, l1CostWeiOpt) - }) - - it('uses the fallback gas price if the feed has issues', async () => { - const expectedFallbackMaxPayment = linkForGas( - performGas, - registryConditionalOverhead - .add(registryPerSignerGasOverhead.mul(f + 1)) - .add(maxPerformDataSize.mul(registryPerPerformByteGasOverhead)), - gasCeilingMultiplier.mul('2'), // fallbackGasPrice is 2x gas price - paymentPremiumPPB, - flatFeeMicroLink, - ).total - - // Stale feed - let roundId = 99 - const answer = 100 - let updatedAt = 946684800 // New Years 2000 🥳 - let startedAt = 946684799 - await gasPriceFeed - .connect(owner) - .updateRoundData(roundId, answer, updatedAt, startedAt) - - assert.equal( - expectedFallbackMaxPayment.toString(), - ( - await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) - ).toString(), - ) - - // Negative feed price - roundId = 100 - updatedAt = now() - startedAt = 946684799 - await gasPriceFeed - .connect(owner) - .updateRoundData(roundId, -100, updatedAt, startedAt) - - assert.equal( - expectedFallbackMaxPayment.toString(), - ( - await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) - ).toString(), - ) - - // Zero feed price - roundId = 101 - updatedAt = now() - startedAt = 946684799 - await gasPriceFeed - .connect(owner) - .updateRoundData(roundId, 0, updatedAt, startedAt) - - assert.equal( - expectedFallbackMaxPayment.toString(), - ( - await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) - ).toString(), - ) - }) - - it('uses the fallback link price if the feed has issues', async () => { - const expectedFallbackMaxPayment = linkForGas( - performGas, - registryConditionalOverhead - .add(registryPerSignerGasOverhead.mul(f + 1)) - .add(maxPerformDataSize.mul(registryPerPerformByteGasOverhead)), - gasCeilingMultiplier.mul('2'), // fallbackLinkPrice is 1/2 link price, so multiply by 2 - paymentPremiumPPB, - flatFeeMicroLink, - ).total - - // Stale feed - let roundId = 99 - const answer = 100 - let updatedAt = 946684800 // New Years 2000 🥳 - let startedAt = 946684799 - await linkEthFeed - .connect(owner) - .updateRoundData(roundId, answer, updatedAt, startedAt) - - assert.equal( - expectedFallbackMaxPayment.toString(), - ( - await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) - ).toString(), - ) - - // Negative feed price - roundId = 100 - updatedAt = now() - startedAt = 946684799 - await linkEthFeed - .connect(owner) - .updateRoundData(roundId, -100, updatedAt, startedAt) - - assert.equal( - expectedFallbackMaxPayment.toString(), - ( - await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) - ).toString(), - ) - - // Zero feed price - roundId = 101 - updatedAt = now() - startedAt = 946684799 - await linkEthFeed - .connect(owner) - .updateRoundData(roundId, 0, updatedAt, startedAt) - - assert.equal( - expectedFallbackMaxPayment.toString(), - ( - await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) - ).toString(), - ) - }) - }) - - describe('#typeAndVersion', () => { - it('uses the correct type and version', async () => { - const typeAndVersion = await registry.typeAndVersion() - assert.equal(typeAndVersion, 'KeeperRegistry 2.1.0') - }) - }) - - describe('#onTokenTransfer', () => { - const amount = toWei('1') - - it('reverts if not called by the LINK token', async () => { - const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [upkeepId]) - - await evmRevert( - registry - .connect(keeper1) - .onTokenTransfer(await keeper1.getAddress(), amount, data), - 'OnlyCallableByLINKToken()', - ) - }) - - it('reverts if not called with more or less than 32 bytes', async () => { - const longData = ethers.utils.defaultAbiCoder.encode( - ['uint256', 'uint256'], - ['33', '34'], - ) - const shortData = '0x12345678' - - await evmRevert( - linkToken - .connect(owner) - .transferAndCall(registry.address, amount, longData), - ) - await evmRevert( - linkToken - .connect(owner) - .transferAndCall(registry.address, amount, shortData), - ) - }) - - it('reverts if the upkeep is canceled', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( - registry.connect(keeper1).addFunds(upkeepId, amount), - 'UpkeepCancelled()', - ) - }) - - it('updates the funds of the job id passed', async () => { - const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [upkeepId]) - - const before = (await registry.getUpkeep(upkeepId)).balance - await linkToken - .connect(owner) - .transferAndCall(registry.address, amount, data) - const after = (await registry.getUpkeep(upkeepId)).balance - - assert.isTrue(before.add(amount).eq(after)) - }) - }) - - describeMaybe('#setConfig - onchain', () => { - const payment = BigNumber.from(1) - const flatFee = BigNumber.from(2) - const maxGas = BigNumber.from(6) - const staleness = BigNumber.from(4) - const ceiling = BigNumber.from(5) - const newMinUpkeepSpend = BigNumber.from(9) - const newMaxCheckDataSize = BigNumber.from(10000) - const newMaxPerformDataSize = BigNumber.from(10000) - const newMaxRevertDataSize = BigNumber.from(10000) - const newMaxPerformGas = BigNumber.from(10000000) - const fbGasEth = BigNumber.from(7) - const fbLinkEth = BigNumber.from(8) - const newTranscoder = randomAddress() - const newRegistrars = [randomAddress(), randomAddress()] - const upkeepManager = randomAddress() - - const newConfig: OnChainConfig = { - paymentPremiumPPB: payment, - flatFeeMicroLink: flatFee, - checkGasLimit: maxGas, - stalenessSeconds: staleness, - gasCeilingMultiplier: ceiling, - minUpkeepSpend: newMinUpkeepSpend, - maxCheckDataSize: newMaxCheckDataSize, - maxPerformDataSize: newMaxPerformDataSize, - maxRevertDataSize: newMaxRevertDataSize, - maxPerformGas: newMaxPerformGas, - fallbackGasPrice: fbGasEth, - fallbackLinkPrice: fbLinkEth, - transcoder: newTranscoder, - registrars: newRegistrars, - upkeepPrivilegeManager: upkeepManager, - } - - it('reverts when called by anyone but the proposed owner', async () => { - await evmRevert( - registry - .connect(payee1) - .setConfigTypeSafe( - signerAddresses, - keeperAddresses, - f, - newConfig, - offchainVersion, - offchainBytes, - ), - 'Only callable by owner', - ) - }) - - it('reverts if signers or transmitters are the zero address', async () => { - await evmRevert( - registry - .connect(owner) - .setConfigTypeSafe( - [randomAddress(), randomAddress(), randomAddress(), zeroAddress], - [ - randomAddress(), - randomAddress(), - randomAddress(), - randomAddress(), - ], - f, - newConfig, - offchainVersion, - offchainBytes, - ), - 'InvalidSigner()', - ) - - await evmRevert( - registry - .connect(owner) - .setConfigTypeSafe( - [ - randomAddress(), - randomAddress(), - randomAddress(), - randomAddress(), - ], - [randomAddress(), randomAddress(), randomAddress(), zeroAddress], - f, - newConfig, - offchainVersion, - offchainBytes, - ), - 'InvalidTransmitter()', - ) - }) - - it('updates the onchainConfig and configDigest', async () => { - const old = await registry.getState() - const oldConfig = old.config - const oldState = old.state - assert.isTrue(paymentPremiumPPB.eq(oldConfig.paymentPremiumPPB)) - assert.isTrue(flatFeeMicroLink.eq(oldConfig.flatFeeMicroLink)) - assert.isTrue(stalenessSeconds.eq(oldConfig.stalenessSeconds)) - assert.isTrue(gasCeilingMultiplier.eq(oldConfig.gasCeilingMultiplier)) - - await registry - .connect(owner) - .setConfigTypeSafe( - signerAddresses, - keeperAddresses, - f, - newConfig, - offchainVersion, - offchainBytes, - ) - - const updated = await registry.getState() - const updatedConfig = updated.config - const updatedState = updated.state - assert.equal(updatedConfig.paymentPremiumPPB, payment.toNumber()) - assert.equal(updatedConfig.flatFeeMicroLink, flatFee.toNumber()) - assert.equal(updatedConfig.stalenessSeconds, staleness.toNumber()) - assert.equal(updatedConfig.gasCeilingMultiplier, ceiling.toNumber()) - assert.equal( - updatedConfig.minUpkeepSpend.toString(), - newMinUpkeepSpend.toString(), - ) - assert.equal( - updatedConfig.maxCheckDataSize, - newMaxCheckDataSize.toNumber(), - ) - assert.equal( - updatedConfig.maxPerformDataSize, - newMaxPerformDataSize.toNumber(), - ) - assert.equal( - updatedConfig.maxRevertDataSize, - newMaxRevertDataSize.toNumber(), - ) - assert.equal(updatedConfig.maxPerformGas, newMaxPerformGas.toNumber()) - assert.equal(updatedConfig.checkGasLimit, maxGas.toNumber()) - assert.equal( - updatedConfig.fallbackGasPrice.toNumber(), - fbGasEth.toNumber(), - ) - assert.equal( - updatedConfig.fallbackLinkPrice.toNumber(), - fbLinkEth.toNumber(), - ) - assert.equal(updatedState.latestEpoch, 0) - - assert(oldState.configCount + 1 == updatedState.configCount) - assert( - oldState.latestConfigBlockNumber != - updatedState.latestConfigBlockNumber, - ) - assert(oldState.latestConfigDigest != updatedState.latestConfigDigest) - - assert.equal(updatedConfig.transcoder, newTranscoder) - assert.deepEqual(updatedConfig.registrars, newRegistrars) - assert.equal(updatedConfig.upkeepPrivilegeManager, upkeepManager) - }) - - it('maintains paused state when config is changed', async () => { - await registry.pause() - const old = await registry.getState() - assert.isTrue(old.state.paused) - - await registry - .connect(owner) - .setConfigTypeSafe( - signerAddresses, - keeperAddresses, - f, - newConfig, - offchainVersion, - offchainBytes, - ) - - const updated = await registry.getState() - assert.isTrue(updated.state.paused) - }) - - it('emits an event', async () => { - const tx = await registry - .connect(owner) - .setConfigTypeSafe( - signerAddresses, - keeperAddresses, - f, - newConfig, - offchainVersion, - offchainBytes, - ) - await expect(tx).to.emit(registry, 'ConfigSet') - }) - }) - - describe('#setConfig - offchain', () => { - let newKeepers: string[] - - beforeEach(async () => { - newKeepers = [ - await personas.Eddy.getAddress(), - await personas.Nick.getAddress(), - await personas.Neil.getAddress(), - await personas.Carol.getAddress(), - ] - }) - - it('reverts when called by anyone but the owner', async () => { - await evmRevert( - registry - .connect(payee1) - .setConfigTypeSafe( - newKeepers, - newKeepers, - f, - config, - offchainVersion, - offchainBytes, - ), - 'Only callable by owner', - ) - }) - - it('reverts if too many keeperAddresses set', async () => { - for (let i = 0; i < 40; i++) { - newKeepers.push(randomAddress()) - } - await evmRevert( - registry - .connect(owner) - .setConfigTypeSafe( - newKeepers, - newKeepers, - f, - config, - offchainVersion, - offchainBytes, - ), - 'TooManyOracles()', - ) - }) - - it('reverts if f=0', async () => { - await evmRevert( - registry - .connect(owner) - .setConfigTypeSafe( - newKeepers, - newKeepers, - 0, - config, - offchainVersion, - offchainBytes, - ), - 'IncorrectNumberOfFaultyOracles()', - ) - }) - - it('reverts if signers != transmitters length', async () => { - const signers = [randomAddress()] - await evmRevert( - registry - .connect(owner) - .setConfigTypeSafe( - signers, - newKeepers, - f, - config, - offchainVersion, - offchainBytes, - ), - 'IncorrectNumberOfSigners()', - ) - }) - - it('reverts if signers <= 3f', async () => { - newKeepers.pop() - await evmRevert( - registry - .connect(owner) - .setConfigTypeSafe( - newKeepers, - newKeepers, - f, - config, - offchainVersion, - offchainBytes, - ), - 'IncorrectNumberOfSigners()', - ) - }) - - it('reverts on repeated signers', async () => { - const newSigners = [ - await personas.Eddy.getAddress(), - await personas.Eddy.getAddress(), - await personas.Eddy.getAddress(), - await personas.Eddy.getAddress(), - ] - await evmRevert( - registry - .connect(owner) - .setConfigTypeSafe( - newSigners, - newKeepers, - f, - config, - offchainVersion, - offchainBytes, - ), - 'RepeatedSigner()', - ) - }) - - it('reverts on repeated transmitters', async () => { - const newTransmitters = [ - await personas.Eddy.getAddress(), - await personas.Eddy.getAddress(), - await personas.Eddy.getAddress(), - await personas.Eddy.getAddress(), - ] - await evmRevert( - registry - .connect(owner) - .setConfigTypeSafe( - newKeepers, - newTransmitters, - f, - config, - offchainVersion, - offchainBytes, - ), - 'RepeatedTransmitter()', - ) - }) - - itMaybe('stores new config and emits event', async () => { - // Perform an upkeep so that totalPremium is updated - await registry.connect(admin).addFunds(upkeepId, toWei('100')) - let tx = await getTransmitTx(registry, keeper1, [upkeepId]) - await tx.wait() - - const newOffChainVersion = BigNumber.from('2') - const newOffChainConfig = '0x1122' - - const old = await registry.getState() - const oldState = old.state - assert(oldState.totalPremium.gt(BigNumber.from('0'))) - - const newSigners = newKeepers - tx = await registry - .connect(owner) - .setConfigTypeSafe( - newSigners, - newKeepers, - f, - config, - newOffChainVersion, - newOffChainConfig, - ) - - const updated = await registry.getState() - const updatedState = updated.state - assert(oldState.totalPremium.eq(updatedState.totalPremium)) - - // Old signer addresses which are not in new signers should be non active - for (let i = 0; i < signerAddresses.length; i++) { - const signer = signerAddresses[i] - if (!newSigners.includes(signer)) { - assert((await registry.getSignerInfo(signer)).active == false) - assert((await registry.getSignerInfo(signer)).index == 0) - } - } - // New signer addresses should be active - for (let i = 0; i < newSigners.length; i++) { - const signer = newSigners[i] - assert((await registry.getSignerInfo(signer)).active == true) - assert((await registry.getSignerInfo(signer)).index == i) - } - // Old transmitter addresses which are not in new transmitter should be non active, update lastCollected but retain other info - for (let i = 0; i < keeperAddresses.length; i++) { - const transmitter = keeperAddresses[i] - if (!newKeepers.includes(transmitter)) { - assert( - (await registry.getTransmitterInfo(transmitter)).active == false, - ) - assert((await registry.getTransmitterInfo(transmitter)).index == i) - assert( - (await registry.getTransmitterInfo(transmitter)).lastCollected.eq( - oldState.totalPremium.sub( - oldState.totalPremium.mod(keeperAddresses.length), - ), - ), - ) - } - } - // New transmitter addresses should be active - for (let i = 0; i < newKeepers.length; i++) { - const transmitter = newKeepers[i] - assert((await registry.getTransmitterInfo(transmitter)).active == true) - assert((await registry.getTransmitterInfo(transmitter)).index == i) - assert( - (await registry.getTransmitterInfo(transmitter)).lastCollected.eq( - oldState.totalPremium, - ), - ) - } - - // config digest should be updated - assert(oldState.configCount + 1 == updatedState.configCount) - assert( - oldState.latestConfigBlockNumber != - updatedState.latestConfigBlockNumber, - ) - assert(oldState.latestConfigDigest != updatedState.latestConfigDigest) - - //New config should be updated - assert.deepEqual(updated.signers, newKeepers) - assert.deepEqual(updated.transmitters, newKeepers) - - // Event should have been emitted - await expect(tx).to.emit(registry, 'ConfigSet') - }) - }) - - describe('#setPeerRegistryMigrationPermission() / #getPeerRegistryMigrationPermission()', () => { - const peer = randomAddress() - it('allows the owner to set the peer registries', async () => { - let permission = await registry.getPeerRegistryMigrationPermission(peer) - expect(permission).to.equal(0) - await registry.setPeerRegistryMigrationPermission(peer, 1) - permission = await registry.getPeerRegistryMigrationPermission(peer) - expect(permission).to.equal(1) - await registry.setPeerRegistryMigrationPermission(peer, 2) - permission = await registry.getPeerRegistryMigrationPermission(peer) - expect(permission).to.equal(2) - await registry.setPeerRegistryMigrationPermission(peer, 0) - permission = await registry.getPeerRegistryMigrationPermission(peer) - expect(permission).to.equal(0) - }) - it('reverts if passed an unsupported permission', async () => { - await expect( - registry.connect(admin).setPeerRegistryMigrationPermission(peer, 10), - ).to.be.reverted - }) - it('reverts if not called by the owner', async () => { - await expect( - registry.connect(admin).setPeerRegistryMigrationPermission(peer, 1), - ).to.be.revertedWith('Only callable by owner') - }) - }) - - describe('#registerUpkeep', () => { - it('reverts when registry is paused', async () => { - await registry.connect(owner).pause() - await evmRevert( - registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), emptyBytes, '0x'), - 'RegistryPaused()', - ) - }) - - it('reverts if the target is not a contract', async () => { - await evmRevert( - registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](zeroAddress, performGas, await admin.getAddress(), emptyBytes, '0x'), - 'NotAContract()', - ) - }) - - it('reverts if called by a non-owner', async () => { - await evmRevert( - registry - .connect(keeper1) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), emptyBytes, '0x'), - 'OnlyCallableByOwnerOrRegistrar()', - ) - }) - - it('reverts if execute gas is too low', async () => { - await evmRevert( - registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, 2299, await admin.getAddress(), emptyBytes, '0x'), - 'GasLimitOutsideRange()', - ) - }) - - it('reverts if execute gas is too high', async () => { - await evmRevert( - registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, 5000001, await admin.getAddress(), emptyBytes, '0x'), - 'GasLimitOutsideRange()', - ) - }) - - it('reverts if checkData is too long', async () => { - let longBytes = '0x' - for (let i = 0; i < 10000; i++) { - longBytes += '1' - } - await evmRevert( - registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), longBytes, '0x'), - 'CheckDataExceedsLimit()', - ) - }) - - it('creates a record of the registration', async () => { - const performGases = [100000, 500000] - const checkDatas = [emptyBytes, '0x12'] - - for (let jdx = 0; jdx < performGases.length; jdx++) { - const performGas = performGases[jdx] - for (let kdx = 0; kdx < checkDatas.length; kdx++) { - const checkData = checkDatas[kdx] - const tx = await registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), checkData, '0x') - - //confirm the upkeep details and verify emitted events - const testUpkeepId = await getUpkeepID(tx) - await expect(tx) - .to.emit(registry, 'UpkeepRegistered') - .withArgs(testUpkeepId, performGas, await admin.getAddress()) - - await expect(tx) - .to.emit(registry, 'UpkeepCheckDataSet') - .withArgs(testUpkeepId, checkData) - await expect(tx) - .to.emit(registry, 'UpkeepTriggerConfigSet') - .withArgs(testUpkeepId, '0x') - - const registration = await registry.getUpkeep(testUpkeepId) - - assert.equal(mock.address, registration.target) - assert.notEqual( - ethers.constants.AddressZero, - await registry.getForwarder(testUpkeepId), - ) - assert.equal( - performGas.toString(), - registration.performGas.toString(), - ) - assert.equal(await admin.getAddress(), registration.admin) - assert.equal(0, registration.balance.toNumber()) - assert.equal(0, registration.amountSpent.toNumber()) - assert.equal(0, registration.lastPerformedBlockNumber) - assert.equal(checkData, registration.checkData) - assert.equal(registration.paused, false) - assert.equal(registration.offchainConfig, '0x') - assert(registration.maxValidBlocknumber.eq('0xffffffff')) - } - } - }) - }) - - describe('#pauseUpkeep', () => { - it('reverts if the registration does not exist', async () => { - await evmRevert( - registry.connect(keeper1).pauseUpkeep(upkeepId.add(1)), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if the upkeep is already canceled', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - - await evmRevert( - registry.connect(admin).pauseUpkeep(upkeepId), - 'UpkeepCancelled()', - ) - }) - - it('reverts if the upkeep is already paused', async () => { - await registry.connect(admin).pauseUpkeep(upkeepId) - - await evmRevert( - registry.connect(admin).pauseUpkeep(upkeepId), - 'OnlyUnpausedUpkeep()', - ) - }) - - it('reverts if the caller is not the upkeep admin', async () => { - await evmRevert( - registry.connect(keeper1).pauseUpkeep(upkeepId), - 'OnlyCallableByAdmin()', - ) - }) - - it('pauses the upkeep and emits an event', async () => { - const tx = await registry.connect(admin).pauseUpkeep(upkeepId) - await expect(tx).to.emit(registry, 'UpkeepPaused').withArgs(upkeepId) - - const registration = await registry.getUpkeep(upkeepId) - assert.equal(registration.paused, true) - }) - }) - - describe('#unpauseUpkeep', () => { - it('reverts if the registration does not exist', async () => { - await evmRevert( - registry.connect(keeper1).unpauseUpkeep(upkeepId.add(1)), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if the upkeep is already canceled', async () => { - await registry.connect(owner).cancelUpkeep(upkeepId) - - await evmRevert( - registry.connect(admin).unpauseUpkeep(upkeepId), - 'UpkeepCancelled()', - ) - }) - - it('marks the contract as paused', async () => { - assert.isFalse((await registry.getState()).state.paused) - - await registry.connect(owner).pause() - - assert.isTrue((await registry.getState()).state.paused) - }) - - it('reverts if the upkeep is not paused', async () => { - await evmRevert( - registry.connect(admin).unpauseUpkeep(upkeepId), - 'OnlyPausedUpkeep()', - ) - }) - - it('reverts if the caller is not the upkeep admin', async () => { - await registry.connect(admin).pauseUpkeep(upkeepId) - - const registration = await registry.getUpkeep(upkeepId) - - assert.equal(registration.paused, true) - - await evmRevert( - registry.connect(keeper1).unpauseUpkeep(upkeepId), - 'OnlyCallableByAdmin()', - ) - }) - - it('unpauses the upkeep and emits an event', async () => { - const originalCount = (await registry.getActiveUpkeepIDs(0, 0)).length - - await registry.connect(admin).pauseUpkeep(upkeepId) - - const tx = await registry.connect(admin).unpauseUpkeep(upkeepId) - - await expect(tx).to.emit(registry, 'UpkeepUnpaused').withArgs(upkeepId) - - const registration = await registry.getUpkeep(upkeepId) - assert.equal(registration.paused, false) - - const upkeepIds = await registry.getActiveUpkeepIDs(0, 0) - assert.equal(upkeepIds.length, originalCount) - }) - }) - - describe('#setUpkeepCheckData', () => { - it('reverts if the registration does not exist', async () => { - await evmRevert( - registry - .connect(keeper1) - .setUpkeepCheckData(upkeepId.add(1), randomBytes), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if the caller is not upkeep admin', async () => { - await evmRevert( - registry.connect(keeper1).setUpkeepCheckData(upkeepId, randomBytes), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if the upkeep is cancelled', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - - await evmRevert( - registry.connect(admin).setUpkeepCheckData(upkeepId, randomBytes), - 'UpkeepCancelled()', - ) - }) - - it('is allowed to update on paused upkeep', async () => { - await registry.connect(admin).pauseUpkeep(upkeepId) - await registry.connect(admin).setUpkeepCheckData(upkeepId, randomBytes) - - const registration = await registry.getUpkeep(upkeepId) - assert.equal(randomBytes, registration.checkData) - }) - - it('reverts if new data exceeds limit', async () => { - let longBytes = '0x' - for (let i = 0; i < 10000; i++) { - longBytes += '1' - } - - await evmRevert( - registry.connect(admin).setUpkeepCheckData(upkeepId, longBytes), - 'CheckDataExceedsLimit()', - ) - }) - - it('updates the upkeep check data and emits an event', async () => { - const tx = await registry - .connect(admin) - .setUpkeepCheckData(upkeepId, randomBytes) - await expect(tx) - .to.emit(registry, 'UpkeepCheckDataSet') - .withArgs(upkeepId, randomBytes) - - const registration = await registry.getUpkeep(upkeepId) - assert.equal(randomBytes, registration.checkData) - }) - }) - - describe('#setUpkeepGasLimit', () => { - const newGasLimit = BigNumber.from('300000') - - it('reverts if the registration does not exist', async () => { - await evmRevert( - registry.connect(admin).setUpkeepGasLimit(upkeepId.add(1), newGasLimit), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if the upkeep is canceled', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( - registry.connect(admin).setUpkeepGasLimit(upkeepId, newGasLimit), - 'UpkeepCancelled()', - ) - }) - - it('reverts if called by anyone but the admin', async () => { - await evmRevert( - registry.connect(owner).setUpkeepGasLimit(upkeepId, newGasLimit), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if new gas limit is out of bounds', async () => { - await evmRevert( - registry - .connect(admin) - .setUpkeepGasLimit(upkeepId, BigNumber.from('100')), - 'GasLimitOutsideRange()', - ) - await evmRevert( - registry - .connect(admin) - .setUpkeepGasLimit(upkeepId, BigNumber.from('6000000')), - 'GasLimitOutsideRange()', - ) - }) - - it('updates the gas limit successfully', async () => { - const initialGasLimit = (await registry.getUpkeep(upkeepId)).performGas - assert.equal(initialGasLimit, performGas.toNumber()) - await registry.connect(admin).setUpkeepGasLimit(upkeepId, newGasLimit) - const updatedGasLimit = (await registry.getUpkeep(upkeepId)).performGas - assert.equal(updatedGasLimit, newGasLimit.toNumber()) - }) - - it('emits a log', async () => { - const tx = await registry - .connect(admin) - .setUpkeepGasLimit(upkeepId, newGasLimit) - await expect(tx) - .to.emit(registry, 'UpkeepGasLimitSet') - .withArgs(upkeepId, newGasLimit) - }) - }) - - describe('#setUpkeepOffchainConfig', () => { - const newConfig = '0xc0ffeec0ffee' - - it('reverts if the registration does not exist', async () => { - await evmRevert( - registry - .connect(admin) - .setUpkeepOffchainConfig(upkeepId.add(1), newConfig), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if the upkeep is canceled', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( - registry.connect(admin).setUpkeepOffchainConfig(upkeepId, newConfig), - 'UpkeepCancelled()', - ) - }) - - it('reverts if called by anyone but the admin', async () => { - await evmRevert( - registry.connect(owner).setUpkeepOffchainConfig(upkeepId, newConfig), - 'OnlyCallableByAdmin()', - ) - }) - - it('updates the config successfully', async () => { - const initialConfig = (await registry.getUpkeep(upkeepId)).offchainConfig - assert.equal(initialConfig, '0x') - await registry.connect(admin).setUpkeepOffchainConfig(upkeepId, newConfig) - const updatedConfig = (await registry.getUpkeep(upkeepId)).offchainConfig - assert.equal(newConfig, updatedConfig) - }) - - it('emits a log', async () => { - const tx = await registry - .connect(admin) - .setUpkeepOffchainConfig(upkeepId, newConfig) - await expect(tx) - .to.emit(registry, 'UpkeepOffchainConfigSet') - .withArgs(upkeepId, newConfig) - }) - }) - - describe('#setUpkeepTriggerConfig', () => { - const newConfig = '0xdeadbeef' - - it('reverts if the registration does not exist', async () => { - await evmRevert( - registry - .connect(admin) - .setUpkeepTriggerConfig(upkeepId.add(1), newConfig), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts if the upkeep is canceled', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - await evmRevert( - registry.connect(admin).setUpkeepTriggerConfig(upkeepId, newConfig), - 'UpkeepCancelled()', - ) - }) - - it('reverts if called by anyone but the admin', async () => { - await evmRevert( - registry.connect(owner).setUpkeepTriggerConfig(upkeepId, newConfig), - 'OnlyCallableByAdmin()', - ) - }) - - it('emits a log', async () => { - const tx = await registry - .connect(admin) - .setUpkeepTriggerConfig(upkeepId, newConfig) - await expect(tx) - .to.emit(registry, 'UpkeepTriggerConfigSet') - .withArgs(upkeepId, newConfig) - }) - }) - - describe('#transferUpkeepAdmin', () => { - it('reverts when called by anyone but the current upkeep admin', async () => { - await evmRevert( - registry - .connect(payee1) - .transferUpkeepAdmin(upkeepId, await payee2.getAddress()), - 'OnlyCallableByAdmin()', - ) - }) - - it('reverts when transferring to self', async () => { - await evmRevert( - registry - .connect(admin) - .transferUpkeepAdmin(upkeepId, await admin.getAddress()), - 'ValueNotChanged()', - ) - }) - - it('reverts when the upkeep is cancelled', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - - await evmRevert( - registry - .connect(admin) - .transferUpkeepAdmin(upkeepId, await keeper1.getAddress()), - 'UpkeepCancelled()', - ) - }) - - it('allows cancelling transfer by reverting to zero address', async () => { - await registry - .connect(admin) - .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) - const tx = await registry - .connect(admin) - .transferUpkeepAdmin(upkeepId, ethers.constants.AddressZero) - - await expect(tx) - .to.emit(registry, 'UpkeepAdminTransferRequested') - .withArgs( - upkeepId, - await admin.getAddress(), - ethers.constants.AddressZero, - ) - }) - - it('does not change the upkeep admin', async () => { - await registry - .connect(admin) - .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) - - const upkeep = await registry.getUpkeep(upkeepId) - assert.equal(await admin.getAddress(), upkeep.admin) - }) - - it('emits an event announcing the new upkeep admin', async () => { - const tx = await registry - .connect(admin) - .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) - - await expect(tx) - .to.emit(registry, 'UpkeepAdminTransferRequested') - .withArgs(upkeepId, await admin.getAddress(), await payee1.getAddress()) - }) - - it('does not emit an event when called with the same proposed upkeep admin', async () => { - await registry - .connect(admin) - .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) - - const tx = await registry - .connect(admin) - .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) - const receipt = await tx.wait() - assert.equal(0, receipt.logs.length) - }) - }) - - describe('#acceptUpkeepAdmin', () => { - beforeEach(async () => { - // Start admin transfer to payee1 - await registry - .connect(admin) - .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) - }) - - it('reverts when not called by the proposed upkeep admin', async () => { - await evmRevert( - registry.connect(payee2).acceptUpkeepAdmin(upkeepId), - 'OnlyCallableByProposedAdmin()', - ) - }) - - it('reverts when the upkeep is cancelled', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - - await evmRevert( - registry.connect(payee1).acceptUpkeepAdmin(upkeepId), - 'UpkeepCancelled()', - ) - }) - - it('does change the admin', async () => { - await registry.connect(payee1).acceptUpkeepAdmin(upkeepId) - - const upkeep = await registry.getUpkeep(upkeepId) - assert.equal(await payee1.getAddress(), upkeep.admin) - }) - - it('emits an event announcing the new upkeep admin', async () => { - const tx = await registry.connect(payee1).acceptUpkeepAdmin(upkeepId) - await expect(tx) - .to.emit(registry, 'UpkeepAdminTransferred') - .withArgs(upkeepId, await admin.getAddress(), await payee1.getAddress()) - }) - }) - - describe('#withdrawOwnerFunds', () => { - it('can only be called by owner', async () => { - await evmRevert( - registry.connect(keeper1).withdrawOwnerFunds(), - 'Only callable by owner', - ) - }) - - itMaybe('withdraws the collected fees to owner', async () => { - await registry.connect(admin).addFunds(upkeepId, toWei('100')) - // Very high min spend, whole balance as cancellation fees - const minUpkeepSpend = toWei('1000') - await registry.connect(owner).setConfigTypeSafe( - signerAddresses, - keeperAddresses, - f, - { - paymentPremiumPPB, - flatFeeMicroLink, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxCheckDataSize, - maxPerformDataSize, - maxRevertDataSize, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrars: [], - upkeepPrivilegeManager: upkeepManager, - }, - offchainVersion, - offchainBytes, - ) - const upkeepBalance = (await registry.getUpkeep(upkeepId)).balance - const ownerBefore = await linkToken.balanceOf(await owner.getAddress()) - - await registry.connect(owner).cancelUpkeep(upkeepId) - - // Transfered to owner balance on registry - let ownerRegistryBalance = (await registry.getState()).state - .ownerLinkBalance - assert.isTrue(ownerRegistryBalance.eq(upkeepBalance)) - - // Now withdraw - await registry.connect(owner).withdrawOwnerFunds() - - ownerRegistryBalance = (await registry.getState()).state.ownerLinkBalance - const ownerAfter = await linkToken.balanceOf(await owner.getAddress()) - - // Owner registry balance should be changed to 0 - assert.isTrue(ownerRegistryBalance.eq(BigNumber.from('0'))) - - // Owner should be credited with the balance - assert.isTrue(ownerBefore.add(upkeepBalance).eq(ownerAfter)) - }) - }) - - describe('#transferPayeeship', () => { - it('reverts when called by anyone but the current payee', async () => { - await evmRevert( - registry - .connect(payee2) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ), - 'OnlyCallableByPayee()', - ) - }) - - it('reverts when transferring to self', async () => { - await evmRevert( - registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee1.getAddress(), - ), - 'ValueNotChanged()', - ) - }) - - it('does not change the payee', async () => { - await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - - const info = await registry.getTransmitterInfo(await keeper1.getAddress()) - assert.equal(await payee1.getAddress(), info.payee) - }) - - it('emits an event announcing the new payee', async () => { - const tx = await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - await expect(tx) - .to.emit(registry, 'PayeeshipTransferRequested') - .withArgs( - await keeper1.getAddress(), - await payee1.getAddress(), - await payee2.getAddress(), - ) - }) - - it('does not emit an event when called with the same proposal', async () => { - await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - - const tx = await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - const receipt = await tx.wait() - assert.equal(0, receipt.logs.length) - }) - }) - - describe('#acceptPayeeship', () => { - beforeEach(async () => { - await registry - .connect(payee1) - .transferPayeeship( - await keeper1.getAddress(), - await payee2.getAddress(), - ) - }) - - it('reverts when called by anyone but the proposed payee', async () => { - await evmRevert( - registry.connect(payee1).acceptPayeeship(await keeper1.getAddress()), - 'OnlyCallableByProposedPayee()', - ) - }) - - it('emits an event announcing the new payee', async () => { - const tx = await registry - .connect(payee2) - .acceptPayeeship(await keeper1.getAddress()) - await expect(tx) - .to.emit(registry, 'PayeeshipTransferred') - .withArgs( - await keeper1.getAddress(), - await payee1.getAddress(), - await payee2.getAddress(), - ) - }) - - it('does change the payee', async () => { - await registry.connect(payee2).acceptPayeeship(await keeper1.getAddress()) - - const info = await registry.getTransmitterInfo(await keeper1.getAddress()) - assert.equal(await payee2.getAddress(), info.payee) - }) - }) - - describe('#pause', () => { - it('reverts if called by a non-owner', async () => { - await evmRevert( - registry.connect(keeper1).pause(), - 'Only callable by owner', - ) - }) - - it('marks the contract as paused', async () => { - assert.isFalse((await registry.getState()).state.paused) - - await registry.connect(owner).pause() - - assert.isTrue((await registry.getState()).state.paused) - }) - - it('Does not allow transmits when paused', async () => { - await registry.connect(owner).pause() - - await evmRevert( - getTransmitTx(registry, keeper1, [upkeepId]), - 'RegistryPaused()', - ) - }) - - it('Does not allow creation of new upkeeps when paused', async () => { - await registry.connect(owner).pause() - - await evmRevert( - registry - .connect(owner) - [ - 'registerUpkeep(address,uint32,address,bytes,bytes)' - ](mock.address, performGas, await admin.getAddress(), emptyBytes, '0x'), - 'RegistryPaused()', - ) - }) - }) - - describe('#unpause', () => { - beforeEach(async () => { - await registry.connect(owner).pause() - }) - - it('reverts if called by a non-owner', async () => { - await evmRevert( - registry.connect(keeper1).unpause(), - 'Only callable by owner', - ) - }) - - it('marks the contract as not paused', async () => { - assert.isTrue((await registry.getState()).state.paused) - - await registry.connect(owner).unpause() - - assert.isFalse((await registry.getState()).state.paused) - }) - }) - - describe('#migrateUpkeeps() / #receiveUpkeeps()', async () => { - context('when permissions are set', () => { - beforeEach(async () => { - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(upkeepId, toWei('100')) - await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 1) - await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 2) - }) - - it('migrates an upkeep', async () => { - const offchainBytes = '0x987654abcd' - await registry - .connect(admin) - .setUpkeepOffchainConfig(upkeepId, offchainBytes) - const reg1Upkeep = await registry.getUpkeep(upkeepId) - const forwarderAddress = await registry.getForwarder(upkeepId) - expect(reg1Upkeep.balance).to.equal(toWei('100')) - expect(reg1Upkeep.checkData).to.equal(randomBytes) - expect(forwarderAddress).to.not.equal(ethers.constants.AddressZero) - expect(reg1Upkeep.offchainConfig).to.equal(offchainBytes) - expect((await registry.getState()).state.numUpkeeps).to.equal( - numUpkeeps, - ) - const forwarder = await IAutomationForwarderFactory.connect( - forwarderAddress, - owner, - ) - expect(await forwarder.getRegistry()).to.equal(registry.address) - // Set an upkeep admin transfer in progress too - await registry - .connect(admin) - .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) - - // migrate - await registry - .connect(admin) - .migrateUpkeeps([upkeepId], mgRegistry.address) - expect((await registry.getState()).state.numUpkeeps).to.equal( - numUpkeeps - 1, - ) - expect((await mgRegistry.getState()).state.numUpkeeps).to.equal(1) - expect((await registry.getUpkeep(upkeepId)).balance).to.equal(0) - expect((await registry.getUpkeep(upkeepId)).checkData).to.equal('0x') - expect((await mgRegistry.getUpkeep(upkeepId)).balance).to.equal( - toWei('100'), - ) - expect( - (await mgRegistry.getState()).state.expectedLinkBalance, - ).to.equal(toWei('100')) - expect((await mgRegistry.getUpkeep(upkeepId)).checkData).to.equal( - randomBytes, - ) - expect((await mgRegistry.getUpkeep(upkeepId)).offchainConfig).to.equal( - offchainBytes, - ) - expect(await mgRegistry.getForwarder(upkeepId)).to.equal( - forwarderAddress, - ) - // test that registry is updated on forwarder - expect(await forwarder.getRegistry()).to.equal(mgRegistry.address) - // migration will delete the upkeep and nullify admin transfer - await expect( - registry.connect(payee1).acceptUpkeepAdmin(upkeepId), - ).to.be.revertedWith('UpkeepCancelled()') - await expect( - mgRegistry.connect(payee1).acceptUpkeepAdmin(upkeepId), - ).to.be.revertedWith('OnlyCallableByProposedAdmin()') - }) - - it('migrates a paused upkeep', async () => { - expect((await registry.getUpkeep(upkeepId)).balance).to.equal( - toWei('100'), - ) - expect((await registry.getUpkeep(upkeepId)).checkData).to.equal( - randomBytes, - ) - expect((await registry.getState()).state.numUpkeeps).to.equal( - numUpkeeps, - ) - await registry.connect(admin).pauseUpkeep(upkeepId) - // verify the upkeep is paused - expect((await registry.getUpkeep(upkeepId)).paused).to.equal(true) - // migrate - await registry - .connect(admin) - .migrateUpkeeps([upkeepId], mgRegistry.address) - expect((await registry.getState()).state.numUpkeeps).to.equal( - numUpkeeps - 1, - ) - expect((await mgRegistry.getState()).state.numUpkeeps).to.equal(1) - expect((await registry.getUpkeep(upkeepId)).balance).to.equal(0) - expect((await mgRegistry.getUpkeep(upkeepId)).balance).to.equal( - toWei('100'), - ) - expect((await registry.getUpkeep(upkeepId)).checkData).to.equal('0x') - expect((await mgRegistry.getUpkeep(upkeepId)).checkData).to.equal( - randomBytes, - ) - expect( - (await mgRegistry.getState()).state.expectedLinkBalance, - ).to.equal(toWei('100')) - // verify the upkeep is still paused after migration - expect((await mgRegistry.getUpkeep(upkeepId)).paused).to.equal(true) - }) - - it('emits an event on both contracts', async () => { - expect((await registry.getUpkeep(upkeepId)).balance).to.equal( - toWei('100'), - ) - expect((await registry.getUpkeep(upkeepId)).checkData).to.equal( - randomBytes, - ) - expect((await registry.getState()).state.numUpkeeps).to.equal( - numUpkeeps, - ) - const tx = registry - .connect(admin) - .migrateUpkeeps([upkeepId], mgRegistry.address) - await expect(tx) - .to.emit(registry, 'UpkeepMigrated') - .withArgs(upkeepId, toWei('100'), mgRegistry.address) - await expect(tx) - .to.emit(mgRegistry, 'UpkeepReceived') - .withArgs(upkeepId, toWei('100'), registry.address) - }) - - it('is only migratable by the admin', async () => { - await expect( - registry - .connect(owner) - .migrateUpkeeps([upkeepId], mgRegistry.address), - ).to.be.revertedWith('OnlyCallableByAdmin()') - await registry - .connect(admin) - .migrateUpkeeps([upkeepId], mgRegistry.address) - }) - }) - - context('when permissions are not set', () => { - it('reverts', async () => { - // no permissions - await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 0) - await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 0) - await expect(registry.migrateUpkeeps([upkeepId], mgRegistry.address)).to - .be.reverted - // only outgoing permissions - await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 1) - await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 0) - await expect(registry.migrateUpkeeps([upkeepId], mgRegistry.address)).to - .be.reverted - // only incoming permissions - await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 0) - await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 2) - await expect(registry.migrateUpkeeps([upkeepId], mgRegistry.address)).to - .be.reverted - // permissions opposite direction - await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 2) - await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 1) - await expect(registry.migrateUpkeeps([upkeepId], mgRegistry.address)).to - .be.reverted - }) - }) - }) - - describe('#setPayees', () => { - const IGNORE_ADDRESS = '0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF' - - it('reverts when not called by the owner', async () => { - await evmRevert( - registry.connect(keeper1).setPayees(payees), - 'Only callable by owner', - ) - }) - - it('reverts with different numbers of payees than transmitters', async () => { - await evmRevert( - registry.connect(owner).setPayees([...payees, randomAddress()]), - 'ParameterLengthError()', - ) - }) - - it('reverts if the payee is the zero address', async () => { - await blankRegistry.connect(owner).setConfig(...baseConfig) // used to test initial config - - await evmRevert( - blankRegistry // used to test initial config - .connect(owner) - .setPayees([ethers.constants.AddressZero, ...payees.slice(1)]), - 'InvalidPayee()', - ) - }) - - itMaybe( - 'sets the payees when exisitng payees are zero address', - async () => { - //Initial payees should be zero address - await blankRegistry.connect(owner).setConfig(...baseConfig) // used to test initial config - - for (let i = 0; i < keeperAddresses.length; i++) { - const payee = ( - await blankRegistry.getTransmitterInfo(keeperAddresses[i]) - ).payee // used to test initial config - assert.equal(payee, zeroAddress) - } - - await blankRegistry.connect(owner).setPayees(payees) // used to test initial config - - for (let i = 0; i < keeperAddresses.length; i++) { - const payee = ( - await blankRegistry.getTransmitterInfo(keeperAddresses[i]) - ).payee - assert.equal(payee, payees[i]) - } - }, - ) - - it('does not change the payee if IGNORE_ADDRESS is used as payee', async () => { - const signers = Array.from({ length: 5 }, randomAddress) - const keepers = Array.from({ length: 5 }, randomAddress) - const payees = Array.from({ length: 5 }, randomAddress) - const newTransmitter = randomAddress() - const newPayee = randomAddress() - const ignoreAddresses = new Array(payees.length).fill(IGNORE_ADDRESS) - const newPayees = [...ignoreAddresses, newPayee] - // arbitrum registry - // configure registry with 5 keepers // optimism registry - await blankRegistry // used to test initial configurations - .connect(owner) - .setConfigTypeSafe( - signers, - keepers, - f, - config, - offchainVersion, - offchainBytes, - ) - // arbitrum registry - // set initial payees // optimism registry - await blankRegistry.connect(owner).setPayees(payees) // used to test initial configurations - // arbitrum registry - // add another keeper // optimism registry - await blankRegistry // used to test initial configurations - .connect(owner) - .setConfigTypeSafe( - [...signers, randomAddress()], - [...keepers, newTransmitter], - f, - config, - offchainVersion, - offchainBytes, - ) - // arbitrum registry - // update payee list // optimism registry // arbitrum registry - await blankRegistry.connect(owner).setPayees(newPayees) // used to test initial configurations // optimism registry - const ignored = await blankRegistry.getTransmitterInfo(newTransmitter) // used to test initial configurations - assert.equal(newPayee, ignored.payee) - assert.equal(true, ignored.active) - }) - - it('reverts if payee is non zero and owner tries to change payee', async () => { - const newPayees = [randomAddress(), ...payees.slice(1)] - - await evmRevert( - registry.connect(owner).setPayees(newPayees), - 'InvalidPayee()', - ) - }) - - it('emits events for every payee added and removed', async () => { - const tx = await registry.connect(owner).setPayees(payees) - await expect(tx) - .to.emit(registry, 'PayeesUpdated') - .withArgs(keeperAddresses, payees) - }) - }) - - describe('#cancelUpkeep', () => { - it('reverts if the ID is not valid', async () => { - await evmRevert( - registry.connect(owner).cancelUpkeep(upkeepId.add(1)), - 'CannotCancel()', - ) - }) - - it('reverts if called by a non-owner/non-admin', async () => { - await evmRevert( - registry.connect(keeper1).cancelUpkeep(upkeepId), - 'OnlyCallableByOwnerOrAdmin()', - ) - }) - - describe('when called by the owner', async () => { - it('sets the registration to invalid immediately', async () => { - const tx = await registry.connect(owner).cancelUpkeep(upkeepId) - const receipt = await tx.wait() - const registration = await registry.getUpkeep(upkeepId) - assert.equal( - registration.maxValidBlocknumber.toNumber(), - receipt.blockNumber, - ) - }) - - it('emits an event', async () => { - const tx = await registry.connect(owner).cancelUpkeep(upkeepId) - const receipt = await tx.wait() - await expect(tx) - .to.emit(registry, 'UpkeepCanceled') - .withArgs(upkeepId, BigNumber.from(receipt.blockNumber)) - }) - - it('immediately prevents upkeep', async () => { - await registry.connect(owner).cancelUpkeep(upkeepId) - - const tx = await getTransmitTx(registry, keeper1, [upkeepId]) - const receipt = await tx.wait() - const cancelledUpkeepReportLogs = - parseCancelledUpkeepReportLogs(receipt) - // exactly 1 CancelledUpkeepReport log should be emitted - assert.equal(cancelledUpkeepReportLogs.length, 1) - }) - - it('does not revert if reverts if called multiple times', async () => { - await registry.connect(owner).cancelUpkeep(upkeepId) - await evmRevert( - registry.connect(owner).cancelUpkeep(upkeepId), - 'CannotCancel()', - ) - }) - - describe('when called by the owner when the admin has just canceled', () => { - let oldExpiration: BigNumber - - beforeEach(async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - const registration = await registry.getUpkeep(upkeepId) - oldExpiration = registration.maxValidBlocknumber - }) - - it('allows the owner to cancel it more quickly', async () => { - await registry.connect(owner).cancelUpkeep(upkeepId) - - const registration = await registry.getUpkeep(upkeepId) - const newExpiration = registration.maxValidBlocknumber - assert.isTrue(newExpiration.lt(oldExpiration)) - }) - }) - }) - - describe('when called by the admin', async () => { - it('reverts if called again by the admin', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - - await evmRevert( - registry.connect(admin).cancelUpkeep(upkeepId), - 'CannotCancel()', - ) - }) - - it('reverts if called by the owner after the timeout', async () => { - await registry.connect(admin).cancelUpkeep(upkeepId) - - for (let i = 0; i < cancellationDelay; i++) { - await ethers.provider.send('evm_mine', []) - } - - await evmRevert( - registry.connect(owner).cancelUpkeep(upkeepId), - 'CannotCancel()', - ) - }) - - it('sets the registration to invalid in 50 blocks', async () => { - const tx = await registry.connect(admin).cancelUpkeep(upkeepId) - const receipt = await tx.wait() - const registration = await registry.getUpkeep(upkeepId) - assert.equal( - registration.maxValidBlocknumber.toNumber(), - receipt.blockNumber + 50, - ) - }) - - it('emits an event', async () => { - const tx = await registry.connect(admin).cancelUpkeep(upkeepId) - const receipt = await tx.wait() - await expect(tx) - .to.emit(registry, 'UpkeepCanceled') - .withArgs( - upkeepId, - BigNumber.from(receipt.blockNumber + cancellationDelay), - ) - }) - - it('immediately prevents upkeep', async () => { - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(upkeepId, toWei('100')) - await registry.connect(admin).cancelUpkeep(upkeepId) - - await getTransmitTx(registry, keeper1, [upkeepId]) - - for (let i = 0; i < cancellationDelay; i++) { - await ethers.provider.send('evm_mine', []) - } - - const tx = await getTransmitTx(registry, keeper1, [upkeepId]) - - const receipt = await tx.wait() - const cancelledUpkeepReportLogs = - parseCancelledUpkeepReportLogs(receipt) - // exactly 1 CancelledUpkeepReport log should be emitted - assert.equal(cancelledUpkeepReportLogs.length, 1) - }) - - describeMaybe('when an upkeep has been performed', async () => { - beforeEach(async () => { - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(upkeepId, toWei('100')) - await getTransmitTx(registry, keeper1, [upkeepId]) - }) - - it('deducts a cancellation fee from the upkeep and gives to owner', async () => { - const minUpkeepSpend = toWei('10') - - await registry.connect(owner).setConfigTypeSafe( - signerAddresses, - keeperAddresses, - f, - { - paymentPremiumPPB, - flatFeeMicroLink, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxCheckDataSize, - maxPerformDataSize, - maxRevertDataSize, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrars: [], - upkeepPrivilegeManager: upkeepManager, - }, - offchainVersion, - offchainBytes, - ) - - const payee1Before = await linkToken.balanceOf( - await payee1.getAddress(), - ) - const upkeepBefore = (await registry.getUpkeep(upkeepId)).balance - const ownerBefore = (await registry.getState()).state.ownerLinkBalance - - const amountSpent = toWei('100').sub(upkeepBefore) - const cancellationFee = minUpkeepSpend.sub(amountSpent) - - await registry.connect(admin).cancelUpkeep(upkeepId) - - const payee1After = await linkToken.balanceOf( - await payee1.getAddress(), - ) - const upkeepAfter = (await registry.getUpkeep(upkeepId)).balance - const ownerAfter = (await registry.getState()).state.ownerLinkBalance - - // post upkeep balance should be previous balance minus cancellation fee - assert.isTrue(upkeepBefore.sub(cancellationFee).eq(upkeepAfter)) - // payee balance should not change - assert.isTrue(payee1Before.eq(payee1After)) - // owner should receive the cancellation fee - assert.isTrue(ownerAfter.sub(ownerBefore).eq(cancellationFee)) - }) - - it('deducts up to balance as cancellation fee', async () => { - // Very high min spend, should deduct whole balance as cancellation fees - const minUpkeepSpend = toWei('1000') - await registry.connect(owner).setConfigTypeSafe( - signerAddresses, - keeperAddresses, - f, - { - paymentPremiumPPB, - flatFeeMicroLink, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxCheckDataSize, - maxPerformDataSize, - maxRevertDataSize, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrars: [], - upkeepPrivilegeManager: upkeepManager, - }, - offchainVersion, - offchainBytes, - ) - const payee1Before = await linkToken.balanceOf( - await payee1.getAddress(), - ) - const upkeepBefore = (await registry.getUpkeep(upkeepId)).balance - const ownerBefore = (await registry.getState()).state.ownerLinkBalance - - await registry.connect(admin).cancelUpkeep(upkeepId) - const payee1After = await linkToken.balanceOf( - await payee1.getAddress(), - ) - const ownerAfter = (await registry.getState()).state.ownerLinkBalance - const upkeepAfter = (await registry.getUpkeep(upkeepId)).balance - - // all upkeep balance is deducted for cancellation fee - assert.equal(0, upkeepAfter.toNumber()) - // payee balance should not change - assert.isTrue(payee1After.eq(payee1Before)) - // all upkeep balance is transferred to the owner - assert.isTrue(ownerAfter.sub(ownerBefore).eq(upkeepBefore)) - }) - - it('does not deduct cancellation fee if more than minUpkeepSpend is spent', async () => { - // Very low min spend, already spent in one perform upkeep - const minUpkeepSpend = BigNumber.from(420) - await registry.connect(owner).setConfigTypeSafe( - signerAddresses, - keeperAddresses, - f, - { - paymentPremiumPPB, - flatFeeMicroLink, - checkGasLimit, - stalenessSeconds, - gasCeilingMultiplier, - minUpkeepSpend, - maxCheckDataSize, - maxPerformDataSize, - maxRevertDataSize, - maxPerformGas, - fallbackGasPrice, - fallbackLinkPrice, - transcoder: transcoder.address, - registrars: [], - upkeepPrivilegeManager: upkeepManager, - }, - offchainVersion, - offchainBytes, - ) - const payee1Before = await linkToken.balanceOf( - await payee1.getAddress(), - ) - const upkeepBefore = (await registry.getUpkeep(upkeepId)).balance - const ownerBefore = (await registry.getState()).state.ownerLinkBalance - - await registry.connect(admin).cancelUpkeep(upkeepId) - const payee1After = await linkToken.balanceOf( - await payee1.getAddress(), - ) - const ownerAfter = (await registry.getState()).state.ownerLinkBalance - const upkeepAfter = (await registry.getUpkeep(upkeepId)).balance - - // upkeep does not pay cancellation fee after cancellation because minimum upkeep spent is met - assert.isTrue(upkeepBefore.eq(upkeepAfter)) - // owner balance does not change - assert.isTrue(ownerAfter.eq(ownerBefore)) - // payee balance does not change - assert.isTrue(payee1Before.eq(payee1After)) - }) - }) - }) - }) - - describe('#withdrawPayment', () => { - beforeEach(async () => { - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(upkeepId, toWei('100')) - await getTransmitTx(registry, keeper1, [upkeepId]) - }) - - it('reverts if called by anyone but the payee', async () => { - await evmRevert( - registry - .connect(payee2) - .withdrawPayment( - await keeper1.getAddress(), - await nonkeeper.getAddress(), - ), - 'OnlyCallableByPayee()', - ) - }) - - it('reverts if called with the 0 address', async () => { - await evmRevert( - registry - .connect(payee2) - .withdrawPayment(await keeper1.getAddress(), zeroAddress), - 'InvalidRecipient()', - ) - }) - - it('updates the balances', async () => { - const to = await nonkeeper.getAddress() - const keeperBefore = await registry.getTransmitterInfo( - await keeper1.getAddress(), - ) - const registrationBefore = (await registry.getUpkeep(upkeepId)).balance - const toLinkBefore = await linkToken.balanceOf(to) - const registryLinkBefore = await linkToken.balanceOf(registry.address) - const registryPremiumBefore = (await registry.getState()).state - .totalPremium - const ownerBefore = (await registry.getState()).state.ownerLinkBalance - - // Withdrawing for first time, last collected = 0 - assert.equal(keeperBefore.lastCollected.toString(), '0') - - //// Do the thing - await registry - .connect(payee1) - .withdrawPayment(await keeper1.getAddress(), to) - - const keeperAfter = await registry.getTransmitterInfo( - await keeper1.getAddress(), - ) - const registrationAfter = (await registry.getUpkeep(upkeepId)).balance - const toLinkAfter = await linkToken.balanceOf(to) - const registryLinkAfter = await linkToken.balanceOf(registry.address) - const registryPremiumAfter = (await registry.getState()).state - .totalPremium - const ownerAfter = (await registry.getState()).state.ownerLinkBalance - - // registry total premium should not change - assert.isTrue(registryPremiumBefore.eq(registryPremiumAfter)) - - // Last collected should be updated to premium-change - assert.isTrue( - keeperAfter.lastCollected.eq( - registryPremiumBefore.sub( - registryPremiumBefore.mod(keeperAddresses.length), - ), - ), - ) - - // owner balance should remain unchanged - assert.isTrue(ownerAfter.eq(ownerBefore)) - - assert.isTrue(keeperAfter.balance.eq(BigNumber.from(0))) - assert.isTrue(registrationBefore.eq(registrationAfter)) - assert.isTrue(toLinkBefore.add(keeperBefore.balance).eq(toLinkAfter)) - assert.isTrue( - registryLinkBefore.sub(keeperBefore.balance).eq(registryLinkAfter), - ) - }) - - it('emits a log announcing the withdrawal', async () => { - const balance = ( - await registry.getTransmitterInfo(await keeper1.getAddress()) - ).balance - const tx = await registry - .connect(payee1) - .withdrawPayment( - await keeper1.getAddress(), - await nonkeeper.getAddress(), - ) - await expect(tx) - .to.emit(registry, 'PaymentWithdrawn') - .withArgs( - await keeper1.getAddress(), - balance, - await nonkeeper.getAddress(), - await payee1.getAddress(), - ) - }) - }) - - describe('#checkCallback', () => { - it('returns false with appropriate failure reason when target callback reverts', async () => { - await streamsLookupUpkeep.setShouldRevertCallback(true) - - const values: any[] = ['0x1234', '0xabcd'] - const res = await registry - .connect(zeroAddress) - .callStatic.checkCallback(streamsLookupUpkeepId, values, '0x') - - assert.isFalse(res.upkeepNeeded) - assert.equal(res.performData, '0x') - assert.equal( - res.upkeepFailureReason, - UpkeepFailureReason.CHECK_CALLBACK_REVERTED, - ) - assert.isTrue(res.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used - }) - - it('returns false with appropriate failure reason when target callback returns big performData', async () => { - let longBytes = '0x' - for (let i = 0; i <= maxPerformDataSize.toNumber(); i++) { - longBytes += '11' - } - const values: any[] = [longBytes, longBytes] - const res = await registry - .connect(zeroAddress) - .callStatic.checkCallback(streamsLookupUpkeepId, values, '0x') - - assert.isFalse(res.upkeepNeeded) - assert.equal(res.performData, '0x') - assert.equal( - res.upkeepFailureReason, - UpkeepFailureReason.PERFORM_DATA_EXCEEDS_LIMIT, - ) - assert.isTrue(res.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used - }) - - it('returns false with appropriate failure reason when target callback returns false', async () => { - await streamsLookupUpkeep.setCallbackReturnBool(false) - const values: any[] = ['0x1234', '0xabcd'] - const res = await registry - .connect(zeroAddress) - .callStatic.checkCallback(streamsLookupUpkeepId, values, '0x') - - assert.isFalse(res.upkeepNeeded) - assert.equal(res.performData, '0x') - assert.equal( - res.upkeepFailureReason, - UpkeepFailureReason.UPKEEP_NOT_NEEDED, - ) - assert.isTrue(res.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used - }) - - it('succeeds with upkeep needed', async () => { - const values: any[] = ['0x1234', '0xabcd'] - - const res = await registry - .connect(zeroAddress) - .callStatic.checkCallback(streamsLookupUpkeepId, values, '0x') - const expectedPerformData = ethers.utils.defaultAbiCoder.encode( - ['bytes[]', 'bytes'], - [values, '0x'], - ) - - assert.isTrue(res.upkeepNeeded) - assert.equal(res.performData, expectedPerformData) - assert.equal(res.upkeepFailureReason, UpkeepFailureReason.NONE) - assert.isTrue(res.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used - }) - }) - - describe('#setUpkeepPrivilegeConfig() / #getUpkeepPrivilegeConfig()', () => { - it('reverts when non manager tries to set privilege config', async () => { - await evmRevert( - registry.connect(payee3).setUpkeepPrivilegeConfig(upkeepId, '0x1234'), - 'OnlyCallableByUpkeepPrivilegeManager()', - ) - }) - - it('returns empty bytes for upkeep privilege config before setting', async () => { - const cfg = await registry.getUpkeepPrivilegeConfig(upkeepId) - assert.equal(cfg, '0x') - }) - - it('allows upkeep manager to set privilege config', async () => { - const tx = await registry - .connect(personas.Norbert) - .setUpkeepPrivilegeConfig(upkeepId, '0x1234') - await expect(tx) - .to.emit(registry, 'UpkeepPrivilegeConfigSet') - .withArgs(upkeepId, '0x1234') - - const cfg = await registry.getUpkeepPrivilegeConfig(upkeepId) - assert.equal(cfg, '0x1234') - }) - }) - - describe('#setAdminPrivilegeConfig() / #getAdminPrivilegeConfig()', () => { - const admin = randomAddress() - - it('reverts when non manager tries to set privilege config', async () => { - await evmRevert( - registry.connect(payee3).setAdminPrivilegeConfig(admin, '0x1234'), - 'OnlyCallableByUpkeepPrivilegeManager()', - ) - }) - - it('returns empty bytes for upkeep privilege config before setting', async () => { - const cfg = await registry.getAdminPrivilegeConfig(admin) - assert.equal(cfg, '0x') - }) - - it('allows upkeep manager to set privilege config', async () => { - const tx = await registry - .connect(personas.Norbert) - .setAdminPrivilegeConfig(admin, '0x1234') - await expect(tx) - .to.emit(registry, 'AdminPrivilegeConfigSet') - .withArgs(admin, '0x1234') - - const cfg = await registry.getAdminPrivilegeConfig(admin) - assert.equal(cfg, '0x1234') - }) - }) - - describe('transmitterPremiumSplit [ @skip-coverage ]', () => { - beforeEach(async () => { - await linkToken.connect(owner).approve(registry.address, toWei('100')) - await registry.connect(owner).addFunds(upkeepId, toWei('100')) - }) - - it('splits premium evenly across transmitters', async () => { - // Do a transmit from keeper1 - await getTransmitTx(registry, keeper1, [upkeepId]) - - const registryPremium = (await registry.getState()).state.totalPremium - assert.isTrue(registryPremium.gt(BigNumber.from(0))) - - const premiumPerTransmitter = registryPremium.div( - BigNumber.from(keeperAddresses.length), - ) - const k1Balance = ( - await registry.getTransmitterInfo(await keeper1.getAddress()) - ).balance - // transmitter should be reimbursed for gas and get the premium - assert.isTrue(k1Balance.gt(premiumPerTransmitter)) - const k1GasReimbursement = k1Balance.sub(premiumPerTransmitter) - - const k2Balance = ( - await registry.getTransmitterInfo(await keeper2.getAddress()) - ).balance - // non transmitter should get its share of premium - assert.isTrue(k2Balance.eq(premiumPerTransmitter)) - - // Now do a transmit from keeper 2 - await getTransmitTx(registry, keeper2, [upkeepId]) - const registryPremiumNew = (await registry.getState()).state.totalPremium - assert.isTrue(registryPremiumNew.gt(registryPremium)) - const premiumPerTransmitterNew = registryPremiumNew.div( - BigNumber.from(keeperAddresses.length), - ) - const additionalPremium = premiumPerTransmitterNew.sub( - premiumPerTransmitter, - ) - - const k1BalanceNew = ( - await registry.getTransmitterInfo(await keeper1.getAddress()) - ).balance - // k1 should get the new premium - assert.isTrue( - k1BalanceNew.eq(k1GasReimbursement.add(premiumPerTransmitterNew)), - ) - - const k2BalanceNew = ( - await registry.getTransmitterInfo(await keeper2.getAddress()) - ).balance - // k2 should get gas reimbursement in addition to new premium - assert.isTrue(k2BalanceNew.gt(k2Balance.add(additionalPremium))) - }) - - it('updates last collected upon payment withdrawn', async () => { - // Do a transmit from keeper1 - await getTransmitTx(registry, keeper1, [upkeepId]) - - const registryPremium = (await registry.getState()).state.totalPremium - const k1 = await registry.getTransmitterInfo(await keeper1.getAddress()) - const k2 = await registry.getTransmitterInfo(await keeper2.getAddress()) - - // Withdrawing for first time, last collected = 0 - assert.isTrue(k1.lastCollected.eq(BigNumber.from(0))) - assert.isTrue(k2.lastCollected.eq(BigNumber.from(0))) - - //// Do the thing - await registry - .connect(payee1) - .withdrawPayment( - await keeper1.getAddress(), - await nonkeeper.getAddress(), - ) - - const k1New = await registry.getTransmitterInfo( - await keeper1.getAddress(), - ) - const k2New = await registry.getTransmitterInfo( - await keeper2.getAddress(), - ) - - // transmitter info lastCollected should be updated for k1, not for k2 - assert.isTrue( - k1New.lastCollected.eq( - registryPremium.sub(registryPremium.mod(keeperAddresses.length)), - ), - ) - assert.isTrue(k2New.lastCollected.eq(BigNumber.from(0))) - }) - - itMaybe( - 'maintains consistent balance information across all parties', - async () => { - // throughout transmits, withdrawals, setConfigs total claim on balances should remain less than expected balance - // some spare change can get lost but it should be less than maxAllowedSpareChange - - let maxAllowedSpareChange = BigNumber.from('0') - await verifyConsistentAccounting(maxAllowedSpareChange) - - await getTransmitTx(registry, keeper1, [upkeepId]) - maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('31')) - await verifyConsistentAccounting(maxAllowedSpareChange) - - await registry - .connect(payee1) - .withdrawPayment( - await keeper1.getAddress(), - await nonkeeper.getAddress(), - ) - await verifyConsistentAccounting(maxAllowedSpareChange) - - await registry - .connect(payee2) - .withdrawPayment( - await keeper2.getAddress(), - await nonkeeper.getAddress(), - ) - await verifyConsistentAccounting(maxAllowedSpareChange) - - await getTransmitTx(registry, keeper1, [upkeepId]) - maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('31')) - await verifyConsistentAccounting(maxAllowedSpareChange) - - await registry.connect(owner).setConfigTypeSafe( - signerAddresses.slice(2, 15), // only use 2-14th index keepers - keeperAddresses.slice(2, 15), - f, - config, - offchainVersion, - offchainBytes, - ) - await verifyConsistentAccounting(maxAllowedSpareChange) - - await getTransmitTx(registry, keeper3, [upkeepId], { - startingSignerIndex: 2, - }) - maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('13')) - await verifyConsistentAccounting(maxAllowedSpareChange) - - await registry - .connect(payee1) - .withdrawPayment( - await keeper1.getAddress(), - await nonkeeper.getAddress(), - ) - await verifyConsistentAccounting(maxAllowedSpareChange) - - await registry - .connect(payee3) - .withdrawPayment( - await keeper3.getAddress(), - await nonkeeper.getAddress(), - ) - await verifyConsistentAccounting(maxAllowedSpareChange) - - await registry.connect(owner).setConfigTypeSafe( - signerAddresses.slice(0, 4), // only use 0-3rd index keepers - keeperAddresses.slice(0, 4), - f, - config, - offchainVersion, - offchainBytes, - ) - await verifyConsistentAccounting(maxAllowedSpareChange) - await getTransmitTx(registry, keeper1, [upkeepId]) - maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('4')) - await getTransmitTx(registry, keeper3, [upkeepId]) - maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('4')) - - await verifyConsistentAccounting(maxAllowedSpareChange) - await registry - .connect(payee5) - .withdrawPayment( - await keeper5.getAddress(), - await nonkeeper.getAddress(), - ) - await verifyConsistentAccounting(maxAllowedSpareChange) - - await registry - .connect(payee1) - .withdrawPayment( - await keeper1.getAddress(), - await nonkeeper.getAddress(), - ) - await verifyConsistentAccounting(maxAllowedSpareChange) - }, - ) - }) -}) +// enum UpkeepFailureReason { +// NONE, +// UPKEEP_CANCELLED, +// UPKEEP_PAUSED, +// TARGET_CHECK_REVERTED, +// UPKEEP_NOT_NEEDED, +// PERFORM_DATA_EXCEEDS_LIMIT, +// INSUFFICIENT_BALANCE, +// CHECK_CALLBACK_REVERTED, +// REVERT_DATA_EXCEEDS_LIMIT, +// REGISTRY_PAUSED, +// } +// +// // copied from AutomationRegistryInterface2_1.sol +// enum Mode { +// DEFAULT, +// ARBITRUM, +// OPTIMISM, +// } +// +// // copied from KeeperRegistryBase2_1.sol +// enum Trigger { +// CONDITION, +// LOG, +// } +// +// // un-exported types that must be extracted from the utils contract +// type Report = Parameters[0] +// type OnChainConfig = Parameters[0] +// type LogTrigger = Parameters[0] +// type ConditionalTrigger = Parameters[0] +// type Log = Parameters[0] +// +// // ----------------------------------------------------------------------------------------------- +// +// // These values should match the constants declared in registry +// let registryConditionalOverhead: BigNumber +// let registryLogOverhead: BigNumber +// let registryPerSignerGasOverhead: BigNumber +// let registryPerPerformByteGasOverhead: BigNumber +// let cancellationDelay: number +// +// // This is the margin for gas that we test for. Gas charged should always be greater +// // than total gas used in tx but should not increase beyond this margin +// const gasCalculationMargin = BigNumber.from(8000) +// +// const linkEth = BigNumber.from(5000000000000000) // 1 Link = 0.005 Eth +// const gasWei = BigNumber.from(1000000000) // 1 gwei +// // ----------------------------------------------------------------------------------------------- +// // test-wide configs for upkeeps +// const linkDivisibility = BigNumber.from('1000000000000000000') +// const performGas = BigNumber.from('1000000') +// const paymentPremiumBase = BigNumber.from('1000000000') +// const paymentPremiumPPB = BigNumber.from('250000000') +// const flatFeeMicroLink = BigNumber.from(0) +// +// const randomBytes = '0x1234abcd' +// const emptyBytes = '0x' +// const emptyBytes32 = +// '0x0000000000000000000000000000000000000000000000000000000000000000' +// +// const transmitGasOverhead = 1_000_000 +// const checkGasOverhead = 400_000 +// +// const stalenessSeconds = BigNumber.from(43820) +// const gasCeilingMultiplier = BigNumber.from(2) +// const checkGasLimit = BigNumber.from(10000000) +// const fallbackGasPrice = gasWei.mul(BigNumber.from('2')) +// const fallbackLinkPrice = linkEth.div(BigNumber.from('2')) +// const maxCheckDataSize = BigNumber.from(1000) +// const maxPerformDataSize = BigNumber.from(1000) +// const maxRevertDataSize = BigNumber.from(1000) +// const maxPerformGas = BigNumber.from(5000000) +// const minUpkeepSpend = BigNumber.from(0) +// const f = 1 +// const offchainVersion = 1 +// const offchainBytes = '0x' +// const zeroAddress = ethers.constants.AddressZero +// const epochAndRound5_1 = +// '0x0000000000000000000000000000000000000000000000000000000000000501' +// +// let logTriggerConfig: string +// +// // ----------------------------------------------------------------------------------------------- +// +// // Smart contract factories +// let linkTokenFactory: LinkTokenFactory +// let mockV3AggregatorFactory: MockV3AggregatorFactory +// let upkeepMockFactory: UpkeepMockFactory +// let upkeepAutoFunderFactory: UpkeepAutoFunderFactory +// let mockArbGasInfoFactory: MockArbGasInfoFactory +// let mockOVMGasPriceOracleFactory: MockOVMGasPriceOracleFactory +// let streamsLookupUpkeepFactory: StreamsLookupUpkeepFactory +// let personas: Personas +// +// // contracts +// let linkToken: LinkToken +// let linkEthFeed: MockV3Aggregator +// let gasPriceFeed: MockV3Aggregator +// let registry: IKeeperRegistry // default registry, used for most tests +// let arbRegistry: IKeeperRegistry // arbitrum registry +// let opRegistry: IKeeperRegistry // optimism registry +// let mgRegistry: IKeeperRegistry // "migrate registry" used in migration tests +// let blankRegistry: IKeeperRegistry // used to test initial configurations +// let mock: UpkeepMock +// let autoFunderUpkeep: UpkeepAutoFunder +// let ltUpkeep: MockContract +// let transcoder: UpkeepTranscoder +// let mockArbGasInfo: MockArbGasInfo +// let mockOVMGasPriceOracle: MockOVMGasPriceOracle +// let streamsLookupUpkeep: StreamsLookupUpkeep +// let automationUtils: AutomationUtils +// +// function now() { +// return Math.floor(Date.now() / 1000) +// } +// +// async function getUpkeepID(tx: ContractTransaction): Promise { +// const receipt = await tx.wait() +// for (const event of receipt.events || []) { +// if ( +// event.args && +// event.eventSignature == 'UpkeepRegistered(uint256,uint32,address)' +// ) { +// return event.args[0] +// } +// } +// throw new Error('could not find upkeep ID in tx event logs') +// } +// +// const getTriggerType = (upkeepId: BigNumber): Trigger => { +// const hexBytes = ethers.utils.defaultAbiCoder.encode(['uint256'], [upkeepId]) +// const bytes = ethers.utils.arrayify(hexBytes) +// for (let idx = 4; idx < 15; idx++) { +// if (bytes[idx] != 0) { +// return Trigger.CONDITION +// } +// } +// return bytes[15] as Trigger +// } +// +// const encodeConfig = (onchainConfig: OnChainConfig) => { +// return ( +// '0x' + +// automationUtils.interface +// .encodeFunctionData('_onChainConfig', [onchainConfig]) +// .slice(10) +// ) +// } +// +// const encodeBlockTrigger = (conditionalTrigger: ConditionalTrigger) => { +// return ( +// '0x' + +// automationUtils.interface +// .encodeFunctionData('_conditionalTrigger', [conditionalTrigger]) +// .slice(10) +// ) +// } +// +// const encodeLogTrigger = (logTrigger: LogTrigger) => { +// return ( +// '0x' + +// automationUtils.interface +// .encodeFunctionData('_logTrigger', [logTrigger]) +// .slice(10) +// ) +// } +// +// const encodeLog = (log: Log) => { +// return ( +// '0x' + automationUtils.interface.encodeFunctionData('_log', [log]).slice(10) +// ) +// } +// +// const encodeReport = (report: Report) => { +// return ( +// '0x' + +// automationUtils.interface.encodeFunctionData('_report', [report]).slice(10) +// ) +// } +// +// type UpkeepData = { +// Id: BigNumberish +// performGas: BigNumberish +// performData: BytesLike +// trigger: BytesLike +// } +// +// const makeReport = (upkeeps: UpkeepData[]) => { +// const upkeepIds = upkeeps.map((u) => u.Id) +// const performGases = upkeeps.map((u) => u.performGas) +// const triggers = upkeeps.map((u) => u.trigger) +// const performDatas = upkeeps.map((u) => u.performData) +// return encodeReport({ +// fastGasWei: gasWei, +// linkNative: linkEth, +// upkeepIds, +// gasLimits: performGases, +// triggers, +// performDatas, +// }) +// } +// +// const makeLatestBlockReport = async (upkeepsIDs: BigNumberish[]) => { +// const latestBlock = await ethers.provider.getBlock('latest') +// const upkeeps: UpkeepData[] = [] +// for (let i = 0; i < upkeepsIDs.length; i++) { +// upkeeps.push({ +// Id: upkeepsIDs[i], +// performGas, +// trigger: encodeBlockTrigger({ +// blockNum: latestBlock.number, +// blockHash: latestBlock.hash, +// }), +// performData: '0x', +// }) +// } +// return makeReport(upkeeps) +// } +// +// const signReport = ( +// reportContext: string[], +// report: any, +// signers: Wallet[], +// ) => { +// const reportDigest = ethers.utils.keccak256(report) +// const packedArgs = ethers.utils.solidityPack( +// ['bytes32', 'bytes32[3]'], +// [reportDigest, reportContext], +// ) +// const packedDigest = ethers.utils.keccak256(packedArgs) +// +// const signatures = [] +// for (const signer of signers) { +// signatures.push(signer._signingKey().signDigest(packedDigest)) +// } +// const vs = signatures.map((i) => '0' + (i.v - 27).toString(16)).join('') +// return { +// vs: '0x' + vs.padEnd(64, '0'), +// rs: signatures.map((i) => i.r), +// ss: signatures.map((i) => i.s), +// } +// } +// +// const parseUpkeepPerformedLogs = (receipt: ContractReceipt) => { +// const parsedLogs = [] +// for (const rawLog of receipt.logs) { +// try { +// const log = registry.interface.parseLog(rawLog) +// if ( +// log.name == +// registry.interface.events[ +// 'UpkeepPerformed(uint256,bool,uint96,uint256,uint256,bytes)' +// ].name +// ) { +// parsedLogs.push(log as unknown as UpkeepPerformedEvent) +// } +// } catch { +// continue +// } +// } +// return parsedLogs +// } +// +// const parseReorgedUpkeepReportLogs = (receipt: ContractReceipt) => { +// const parsedLogs = [] +// for (const rawLog of receipt.logs) { +// try { +// const log = registry.interface.parseLog(rawLog) +// if ( +// log.name == +// registry.interface.events['ReorgedUpkeepReport(uint256,bytes)'].name +// ) { +// parsedLogs.push(log as unknown as ReorgedUpkeepReportEvent) +// } +// } catch { +// continue +// } +// } +// return parsedLogs +// } +// +// const parseStaleUpkeepReportLogs = (receipt: ContractReceipt) => { +// const parsedLogs = [] +// for (const rawLog of receipt.logs) { +// try { +// const log = registry.interface.parseLog(rawLog) +// if ( +// log.name == +// registry.interface.events['StaleUpkeepReport(uint256,bytes)'].name +// ) { +// parsedLogs.push(log as unknown as StaleUpkeepReportEvent) +// } +// } catch { +// continue +// } +// } +// return parsedLogs +// } +// +// const parseInsufficientFundsUpkeepReportLogs = (receipt: ContractReceipt) => { +// const parsedLogs = [] +// for (const rawLog of receipt.logs) { +// try { +// const log = registry.interface.parseLog(rawLog) +// if ( +// log.name == +// registry.interface.events[ +// 'InsufficientFundsUpkeepReport(uint256,bytes)' +// ].name +// ) { +// parsedLogs.push(log as unknown as InsufficientFundsUpkeepReportEvent) +// } +// } catch { +// continue +// } +// } +// return parsedLogs +// } +// +// const parseCancelledUpkeepReportLogs = (receipt: ContractReceipt) => { +// const parsedLogs = [] +// for (const rawLog of receipt.logs) { +// try { +// const log = registry.interface.parseLog(rawLog) +// if ( +// log.name == +// registry.interface.events['CancelledUpkeepReport(uint256,bytes)'].name +// ) { +// parsedLogs.push(log as unknown as CancelledUpkeepReportEvent) +// } +// } catch { +// continue +// } +// } +// return parsedLogs +// } +// +// describe('KeeperRegistry2_1', () => { +// let owner: Signer +// let keeper1: Signer +// let keeper2: Signer +// let keeper3: Signer +// let keeper4: Signer +// let keeper5: Signer +// let nonkeeper: Signer +// let signer1: Wallet +// let signer2: Wallet +// let signer3: Wallet +// let signer4: Wallet +// let signer5: Wallet +// let admin: Signer +// let payee1: Signer +// let payee2: Signer +// let payee3: Signer +// let payee4: Signer +// let payee5: Signer +// +// let upkeepId: BigNumber // conditional upkeep +// let afUpkeepId: BigNumber // auto funding upkeep +// let logUpkeepId: BigNumber // log trigger upkeepID +// let streamsLookupUpkeepId: BigNumber // streams lookup upkeep +// const numUpkeeps = 4 // see above +// let keeperAddresses: string[] +// let payees: string[] +// let signers: Wallet[] +// let signerAddresses: string[] +// let config: any +// let baseConfig: Parameters +// let upkeepManager: string +// +// before(async () => { +// personas = (await getUsers()).personas +// +// const utilsFactory = await ethers.getContractFactory('AutomationUtils2_1') +// automationUtils = await utilsFactory.deploy() +// +// linkTokenFactory = await ethers.getContractFactory( +// 'src/v0.8/shared/test/helpers/LinkTokenTestHelper.sol:LinkTokenTestHelper', +// ) +// // need full path because there are two contracts with name MockV3Aggregator +// mockV3AggregatorFactory = (await ethers.getContractFactory( +// 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', +// )) as unknown as MockV3AggregatorFactory +// upkeepMockFactory = await ethers.getContractFactory('UpkeepMock') +// upkeepAutoFunderFactory = +// await ethers.getContractFactory('UpkeepAutoFunder') +// mockArbGasInfoFactory = await ethers.getContractFactory('MockArbGasInfo') +// mockOVMGasPriceOracleFactory = await ethers.getContractFactory( +// 'MockOVMGasPriceOracle', +// ) +// streamsLookupUpkeepFactory = await ethers.getContractFactory( +// 'StreamsLookupUpkeep', +// ) +// +// owner = personas.Default +// keeper1 = personas.Carol +// keeper2 = personas.Eddy +// keeper3 = personas.Nancy +// keeper4 = personas.Norbert +// keeper5 = personas.Nick +// nonkeeper = personas.Ned +// admin = personas.Neil +// payee1 = personas.Nelly +// payee2 = personas.Norbert +// payee3 = personas.Nick +// payee4 = personas.Eddy +// payee5 = personas.Carol +// upkeepManager = await personas.Norbert.getAddress() +// // signers +// signer1 = new ethers.Wallet( +// '0x7777777000000000000000000000000000000000000000000000000000000001', +// ) +// signer2 = new ethers.Wallet( +// '0x7777777000000000000000000000000000000000000000000000000000000002', +// ) +// signer3 = new ethers.Wallet( +// '0x7777777000000000000000000000000000000000000000000000000000000003', +// ) +// signer4 = new ethers.Wallet( +// '0x7777777000000000000000000000000000000000000000000000000000000004', +// ) +// signer5 = new ethers.Wallet( +// '0x7777777000000000000000000000000000000000000000000000000000000005', +// ) +// +// keeperAddresses = [ +// await keeper1.getAddress(), +// await keeper2.getAddress(), +// await keeper3.getAddress(), +// await keeper4.getAddress(), +// await keeper5.getAddress(), +// ] +// payees = [ +// await payee1.getAddress(), +// await payee2.getAddress(), +// await payee3.getAddress(), +// await payee4.getAddress(), +// await payee5.getAddress(), +// ] +// signers = [signer1, signer2, signer3, signer4, signer5] +// +// // We append 26 random addresses to keepers, payees and signers to get a system of 31 oracles +// // This allows f value of 1 - 10 +// for (let i = 0; i < 26; i++) { +// keeperAddresses.push(randomAddress()) +// payees.push(randomAddress()) +// signers.push(ethers.Wallet.createRandom()) +// } +// signerAddresses = [] +// for (const signer of signers) { +// signerAddresses.push(await signer.getAddress()) +// } +// +// logTriggerConfig = +// '0x' + +// automationUtils.interface +// .encodeFunctionData('_logTriggerConfig', [ +// { +// contractAddress: randomAddress(), +// filterSelector: 0, +// topic0: ethers.utils.randomBytes(32), +// topic1: ethers.utils.randomBytes(32), +// topic2: ethers.utils.randomBytes(32), +// topic3: ethers.utils.randomBytes(32), +// }, +// ]) +// .slice(10) +// }) +// +// const linkForGas = ( +// upkeepGasSpent: BigNumber, +// gasOverhead: BigNumber, +// gasMultiplier: BigNumber, +// premiumPPB: BigNumber, +// flatFee: BigNumber, +// l1CostWei?: BigNumber, +// numUpkeepsBatch?: BigNumber, +// ) => { +// l1CostWei = l1CostWei === undefined ? BigNumber.from(0) : l1CostWei +// numUpkeepsBatch = +// numUpkeepsBatch === undefined ? BigNumber.from(1) : numUpkeepsBatch +// +// const gasSpent = gasOverhead.add(BigNumber.from(upkeepGasSpent)) +// const base = gasWei +// .mul(gasMultiplier) +// .mul(gasSpent) +// .mul(linkDivisibility) +// .div(linkEth) +// const l1Fee = l1CostWei +// .mul(gasMultiplier) +// .div(numUpkeepsBatch) +// .mul(linkDivisibility) +// .div(linkEth) +// const gasPayment = base.add(l1Fee) +// +// const premium = gasWei +// .mul(gasMultiplier) +// .mul(upkeepGasSpent) +// .add(l1CostWei.mul(gasMultiplier).div(numUpkeepsBatch)) +// .mul(linkDivisibility) +// .div(linkEth) +// .mul(premiumPPB) +// .div(paymentPremiumBase) +// .add(BigNumber.from(flatFee).mul('1000000000000')) +// +// return { +// total: gasPayment.add(premium), +// gasPaymemnt: gasPayment, +// premium, +// } +// } +// +// const verifyMaxPayment = async ( +// registry: IKeeperRegistry, +// l1CostWei?: BigNumber, +// ) => { +// type TestCase = { +// name: string +// multiplier: number +// gas: number +// premium: number +// flatFee: number +// } +// +// const tests: TestCase[] = [ +// { +// name: 'no fees', +// multiplier: 1, +// gas: 100000, +// premium: 0, +// flatFee: 0, +// }, +// { +// name: 'basic fees', +// multiplier: 1, +// gas: 100000, +// premium: 250000000, +// flatFee: 1000000, +// }, +// { +// name: 'max fees', +// multiplier: 3, +// gas: 10000000, +// premium: 250000000, +// flatFee: 1000000, +// }, +// ] +// +// const fPlusOne = BigNumber.from(f + 1) +// const totalConditionalOverhead = registryConditionalOverhead +// .add(registryPerSignerGasOverhead.mul(fPlusOne)) +// .add(registryPerPerformByteGasOverhead.mul(maxPerformDataSize)) +// const totalLogOverhead = registryLogOverhead +// .add(registryPerSignerGasOverhead.mul(fPlusOne)) +// .add(registryPerPerformByteGasOverhead.mul(maxPerformDataSize)) +// +// for (const test of tests) { +// await registry.connect(owner).setConfig( +// signerAddresses, +// keeperAddresses, +// f, +// encodeConfig({ +// paymentPremiumPPB: test.premium, +// flatFeeMicroLink: test.flatFee, +// checkGasLimit, +// stalenessSeconds, +// gasCeilingMultiplier: test.multiplier, +// minUpkeepSpend, +// maxCheckDataSize, +// maxPerformDataSize, +// maxRevertDataSize, +// maxPerformGas, +// fallbackGasPrice, +// fallbackLinkPrice, +// transcoder: transcoder.address, +// registrars: [], +// upkeepPrivilegeManager: upkeepManager, +// }), +// offchainVersion, +// offchainBytes, +// ) +// +// const conditionalPrice = await registry.getMaxPaymentForGas( +// Trigger.CONDITION, +// test.gas, +// ) +// expect(conditionalPrice).to.equal( +// linkForGas( +// BigNumber.from(test.gas), +// totalConditionalOverhead, +// BigNumber.from(test.multiplier), +// BigNumber.from(test.premium), +// BigNumber.from(test.flatFee), +// l1CostWei, +// ).total, +// ) +// +// const logPrice = await registry.getMaxPaymentForGas(Trigger.LOG, test.gas) +// expect(logPrice).to.equal( +// linkForGas( +// BigNumber.from(test.gas), +// totalLogOverhead, +// BigNumber.from(test.multiplier), +// BigNumber.from(test.premium), +// BigNumber.from(test.flatFee), +// l1CostWei, +// ).total, +// ) +// } +// } +// +// const verifyConsistentAccounting = async ( +// maxAllowedSpareChange: BigNumber, +// ) => { +// const expectedLinkBalance = (await registry.getState()).state +// .expectedLinkBalance +// const linkTokenBalance = await linkToken.balanceOf(registry.address) +// const upkeepIdBalance = (await registry.getUpkeep(upkeepId)).balance +// let totalKeeperBalance = BigNumber.from(0) +// for (let i = 0; i < keeperAddresses.length; i++) { +// totalKeeperBalance = totalKeeperBalance.add( +// (await registry.getTransmitterInfo(keeperAddresses[i])).balance, +// ) +// } +// const ownerBalance = (await registry.getState()).state.ownerLinkBalance +// assert.isTrue(expectedLinkBalance.eq(linkTokenBalance)) +// assert.isTrue( +// upkeepIdBalance +// .add(totalKeeperBalance) +// .add(ownerBalance) +// .lte(expectedLinkBalance), +// ) +// assert.isTrue( +// expectedLinkBalance +// .sub(upkeepIdBalance) +// .sub(totalKeeperBalance) +// .sub(ownerBalance) +// .lte(maxAllowedSpareChange), +// ) +// } +// +// interface GetTransmitTXOptions { +// numSigners?: number +// startingSignerIndex?: number +// gasLimit?: BigNumberish +// gasPrice?: BigNumberish +// performGas?: BigNumberish +// performData?: string +// checkBlockNum?: number +// checkBlockHash?: string +// logBlockHash?: BytesLike +// txHash?: BytesLike +// logIndex?: number +// timestamp?: number +// } +// +// const getTransmitTx = async ( +// registry: IKeeperRegistry, +// transmitter: Signer, +// upkeepIds: BigNumber[], +// overrides: GetTransmitTXOptions = {}, +// ) => { +// const latestBlock = await ethers.provider.getBlock('latest') +// const configDigest = (await registry.getState()).state.latestConfigDigest +// const config = { +// numSigners: f + 1, +// startingSignerIndex: 0, +// performData: '0x', +// performGas, +// checkBlockNum: latestBlock.number, +// checkBlockHash: latestBlock.hash, +// logIndex: 0, +// txHash: undefined, // assigned uniquely below +// logBlockHash: undefined, // assigned uniquely below +// timestamp: now(), +// gasLimit: undefined, +// gasPrice: undefined, +// } +// Object.assign(config, overrides) +// const upkeeps: UpkeepData[] = [] +// for (let i = 0; i < upkeepIds.length; i++) { +// let trigger: string +// switch (getTriggerType(upkeepIds[i])) { +// case Trigger.CONDITION: +// trigger = encodeBlockTrigger({ +// blockNum: config.checkBlockNum, +// blockHash: config.checkBlockHash, +// }) +// break +// case Trigger.LOG: +// trigger = encodeLogTrigger({ +// logBlockHash: config.logBlockHash || ethers.utils.randomBytes(32), +// txHash: config.txHash || ethers.utils.randomBytes(32), +// logIndex: config.logIndex, +// blockNum: config.checkBlockNum, +// blockHash: config.checkBlockHash, +// }) +// break +// } +// upkeeps.push({ +// Id: upkeepIds[i], +// performGas: config.performGas, +// trigger, +// performData: config.performData, +// }) +// } +// +// const report = makeReport(upkeeps) +// const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] +// const sigs = signReport( +// reportContext, +// report, +// signers.slice( +// config.startingSignerIndex, +// config.startingSignerIndex + config.numSigners, +// ), +// ) +// +// type txOverride = { +// gasLimit?: BigNumberish | Promise +// gasPrice?: BigNumberish | Promise +// } +// const txOverrides: txOverride = {} +// if (config.gasLimit) { +// txOverrides.gasLimit = config.gasLimit +// } +// if (config.gasPrice) { +// txOverrides.gasPrice = config.gasPrice +// } +// +// return registry +// .connect(transmitter) +// .transmit( +// [configDigest, epochAndRound5_1, emptyBytes32], +// report, +// sigs.rs, +// sigs.ss, +// sigs.vs, +// txOverrides, +// ) +// } +// +// const getTransmitTxWithReport = async ( +// registry: IKeeperRegistry, +// transmitter: Signer, +// report: BytesLike, +// ) => { +// const configDigest = (await registry.getState()).state.latestConfigDigest +// const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] +// const sigs = signReport(reportContext, report, signers.slice(0, f + 1)) +// +// return registry +// .connect(transmitter) +// .transmit( +// [configDigest, epochAndRound5_1, emptyBytes32], +// report, +// sigs.rs, +// sigs.ss, +// sigs.vs, +// ) +// } +// +// const setup = async () => { +// linkToken = await linkTokenFactory.connect(owner).deploy() +// gasPriceFeed = await mockV3AggregatorFactory +// .connect(owner) +// .deploy(0, gasWei) +// linkEthFeed = await mockV3AggregatorFactory +// .connect(owner) +// .deploy(9, linkEth) +// const upkeepTranscoderFactory = await ethers.getContractFactory( +// 'UpkeepTranscoder4_0', +// ) +// transcoder = await upkeepTranscoderFactory.connect(owner).deploy() +// mockArbGasInfo = await mockArbGasInfoFactory.connect(owner).deploy() +// mockOVMGasPriceOracle = await mockOVMGasPriceOracleFactory +// .connect(owner) +// .deploy() +// streamsLookupUpkeep = await streamsLookupUpkeepFactory +// .connect(owner) +// .deploy( +// BigNumber.from('10000'), +// BigNumber.from('100'), +// false /* useArbBlock */, +// true /* staging */, +// false /* verify mercury response */, +// ) +// +// const arbOracleCode = await ethers.provider.send('eth_getCode', [ +// mockArbGasInfo.address, +// ]) +// await ethers.provider.send('hardhat_setCode', [ +// '0x000000000000000000000000000000000000006C', +// arbOracleCode, +// ]) +// +// const optOracleCode = await ethers.provider.send('eth_getCode', [ +// mockOVMGasPriceOracle.address, +// ]) +// await ethers.provider.send('hardhat_setCode', [ +// '0x420000000000000000000000000000000000000F', +// optOracleCode, +// ]) +// +// const mockArbSys = await new MockArbSysFactory(owner).deploy() +// const arbSysCode = await ethers.provider.send('eth_getCode', [ +// mockArbSys.address, +// ]) +// await ethers.provider.send('hardhat_setCode', [ +// '0x0000000000000000000000000000000000000064', +// arbSysCode, +// ]) +// +// config = { +// paymentPremiumPPB, +// flatFeeMicroLink, +// checkGasLimit, +// stalenessSeconds, +// gasCeilingMultiplier, +// minUpkeepSpend, +// maxCheckDataSize, +// maxPerformDataSize, +// maxRevertDataSize, +// maxPerformGas, +// fallbackGasPrice, +// fallbackLinkPrice, +// transcoder: transcoder.address, +// registrars: [], +// upkeepPrivilegeManager: upkeepManager, +// } +// +// baseConfig = [ +// signerAddresses, +// keeperAddresses, +// f, +// encodeConfig(config), +// offchainVersion, +// offchainBytes, +// ] +// +// registry = await deployRegistry21( +// owner, +// Mode.DEFAULT, +// linkToken.address, +// linkEthFeed.address, +// gasPriceFeed.address, +// ) +// +// arbRegistry = await deployRegistry21( +// owner, +// Mode.ARBITRUM, +// linkToken.address, +// linkEthFeed.address, +// gasPriceFeed.address, +// ) +// +// opRegistry = await deployRegistry21( +// owner, +// Mode.OPTIMISM, +// linkToken.address, +// linkEthFeed.address, +// gasPriceFeed.address, +// ) +// +// mgRegistry = await deployRegistry21( +// owner, +// Mode.DEFAULT, +// linkToken.address, +// linkEthFeed.address, +// gasPriceFeed.address, +// ) +// +// blankRegistry = await deployRegistry21( +// owner, +// Mode.DEFAULT, +// linkToken.address, +// linkEthFeed.address, +// gasPriceFeed.address, +// ) +// +// registryConditionalOverhead = await registry.getConditionalGasOverhead() +// registryLogOverhead = await registry.getLogGasOverhead() +// registryPerSignerGasOverhead = await registry.getPerSignerGasOverhead() +// registryPerPerformByteGasOverhead = +// await registry.getPerPerformByteGasOverhead() +// cancellationDelay = (await registry.getCancellationDelay()).toNumber() +// +// for (const reg of [registry, arbRegistry, opRegistry, mgRegistry]) { +// await reg.connect(owner).setConfig(...baseConfig) +// await reg.connect(owner).setPayees(payees) +// await linkToken.connect(admin).approve(reg.address, toWei('1000')) +// await linkToken.connect(owner).approve(reg.address, toWei('1000')) +// } +// +// mock = await upkeepMockFactory.deploy() +// await linkToken +// .connect(owner) +// .transfer(await admin.getAddress(), toWei('1000')) +// let tx = await registry +// .connect(owner) +// [ +// 'registerUpkeep(address,uint32,address,bytes,bytes)' +// ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') +// upkeepId = await getUpkeepID(tx) +// +// autoFunderUpkeep = await upkeepAutoFunderFactory +// .connect(owner) +// .deploy(linkToken.address, registry.address) +// tx = await registry +// .connect(owner) +// [ +// 'registerUpkeep(address,uint32,address,bytes,bytes)' +// ](autoFunderUpkeep.address, performGas, autoFunderUpkeep.address, randomBytes, '0x') +// afUpkeepId = await getUpkeepID(tx) +// +// ltUpkeep = await deployMockContract(owner, ILogAutomationactory.abi) +// tx = await registry +// .connect(owner) +// [ +// 'registerUpkeep(address,uint32,address,uint8,bytes,bytes,bytes)' +// ](ltUpkeep.address, performGas, await admin.getAddress(), Trigger.LOG, '0x', logTriggerConfig, emptyBytes) +// logUpkeepId = await getUpkeepID(tx) +// +// await autoFunderUpkeep.setUpkeepId(afUpkeepId) +// // Give enough funds for upkeep as well as to the upkeep contract +// await linkToken +// .connect(owner) +// .transfer(autoFunderUpkeep.address, toWei('1000')) +// +// tx = await registry +// .connect(owner) +// [ +// 'registerUpkeep(address,uint32,address,bytes,bytes)' +// ](streamsLookupUpkeep.address, performGas, await admin.getAddress(), randomBytes, '0x') +// streamsLookupUpkeepId = await getUpkeepID(tx) +// } +// +// const getMultipleUpkeepsDeployedAndFunded = async ( +// numPassingConditionalUpkeeps: number, +// numPassingLogUpkeeps: number, +// numFailingUpkeeps: number, +// ) => { +// const passingConditionalUpkeepIds = [] +// const passingLogUpkeepIds = [] +// const failingUpkeepIds = [] +// for (let i = 0; i < numPassingConditionalUpkeeps; i++) { +// const mock = await upkeepMockFactory.deploy() +// await mock.setCanPerform(true) +// await mock.setPerformGasToBurn(BigNumber.from('0')) +// const tx = await registry +// .connect(owner) +// [ +// 'registerUpkeep(address,uint32,address,bytes,bytes)' +// ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') +// const condUpkeepId = await getUpkeepID(tx) +// passingConditionalUpkeepIds.push(condUpkeepId) +// +// // Add funds to passing upkeeps +// await registry.connect(admin).addFunds(condUpkeepId, toWei('100')) +// } +// for (let i = 0; i < numPassingLogUpkeeps; i++) { +// const mock = await upkeepMockFactory.deploy() +// await mock.setCanPerform(true) +// await mock.setPerformGasToBurn(BigNumber.from('0')) +// const tx = await registry +// .connect(owner) +// [ +// 'registerUpkeep(address,uint32,address,uint8,bytes,bytes,bytes)' +// ](mock.address, performGas, await admin.getAddress(), Trigger.LOG, '0x', logTriggerConfig, emptyBytes) +// const logUpkeepId = await getUpkeepID(tx) +// passingLogUpkeepIds.push(logUpkeepId) +// +// // Add funds to passing upkeeps +// await registry.connect(admin).addFunds(logUpkeepId, toWei('100')) +// } +// for (let i = 0; i < numFailingUpkeeps; i++) { +// const mock = await upkeepMockFactory.deploy() +// await mock.setCanPerform(true) +// await mock.setPerformGasToBurn(BigNumber.from('0')) +// const tx = await registry +// .connect(owner) +// [ +// 'registerUpkeep(address,uint32,address,bytes,bytes)' +// ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') +// const failingUpkeepId = await getUpkeepID(tx) +// failingUpkeepIds.push(failingUpkeepId) +// } +// return { +// passingConditionalUpkeepIds, +// passingLogUpkeepIds, +// failingUpkeepIds, +// } +// } +// +// beforeEach(async () => { +// await loadFixture(setup) +// }) +// +// describe('#transmit', () => { +// const fArray = [1, 5, 10] +// +// it('reverts when registry is paused', async () => { +// await registry.connect(owner).pause() +// await evmRevert( +// getTransmitTx(registry, keeper1, [upkeepId]), +// 'RegistryPaused()', +// ) +// }) +// +// it('reverts when called by non active transmitter', async () => { +// await evmRevert( +// getTransmitTx(registry, payee1, [upkeepId]), +// 'OnlyActiveTransmitters()', +// ) +// }) +// +// it('reverts when report data lengths mismatches', async () => { +// const upkeepIds = [] +// const gasLimits: BigNumber[] = [] +// const triggers: string[] = [] +// const performDatas = [] +// +// upkeepIds.push(upkeepId) +// gasLimits.push(performGas) +// triggers.push('0x') +// performDatas.push('0x') +// // Push an extra perform data +// performDatas.push('0x') +// +// const report = encodeReport({ +// fastGasWei: 0, +// linkNative: 0, +// upkeepIds, +// gasLimits, +// triggers, +// performDatas, +// }) +// +// await evmRevert( +// getTransmitTxWithReport(registry, keeper1, report), +// 'InvalidReport()', +// ) +// }) +// +// it('returns early when invalid upkeepIds are included in report', async () => { +// const tx = await getTransmitTx(registry, keeper1, [ +// upkeepId.add(BigNumber.from('1')), +// ]) +// +// const receipt = await tx.wait() +// const cancelledUpkeepReportLogs = parseCancelledUpkeepReportLogs(receipt) +// // exactly 1 CancelledUpkeepReport log should be emitted +// assert.equal(cancelledUpkeepReportLogs.length, 1) +// }) +// +// it('returns early when upkeep has insufficient funds', async () => { +// const tx = await getTransmitTx(registry, keeper1, [upkeepId]) +// const receipt = await tx.wait() +// const insufficientFundsUpkeepReportLogs = +// parseInsufficientFundsUpkeepReportLogs(receipt) +// // exactly 1 InsufficientFundsUpkeepReportLogs log should be emitted +// assert.equal(insufficientFundsUpkeepReportLogs.length, 1) +// }) +// +// it('permits retrying log triggers after funds are added', async () => { +// const txHash = ethers.utils.randomBytes(32) +// let tx = await getTransmitTx(registry, keeper1, [logUpkeepId], { +// txHash, +// logIndex: 0, +// }) +// let receipt = await tx.wait() +// const insufficientFundsLogs = +// parseInsufficientFundsUpkeepReportLogs(receipt) +// assert.equal(insufficientFundsLogs.length, 1) +// registry.connect(admin).addFunds(logUpkeepId, toWei('100')) +// tx = await getTransmitTx(registry, keeper1, [logUpkeepId], { +// txHash, +// logIndex: 0, +// }) +// receipt = await tx.wait() +// const performedLogs = parseUpkeepPerformedLogs(receipt) +// assert.equal(performedLogs.length, 1) +// }) +// +// context('When the upkeep is funded', async () => { +// beforeEach(async () => { +// // Fund the upkeep +// await Promise.all([ +// registry.connect(admin).addFunds(upkeepId, toWei('100')), +// registry.connect(admin).addFunds(logUpkeepId, toWei('100')), +// ]) +// }) +// +// it('handles duplicate upkeepIDs', async () => { +// const tests: [string, BigNumber, number, number][] = [ +// // [name, upkeep, num stale, num performed] +// ['conditional', upkeepId, 1, 1], // checkBlocks must be sequential +// ['log-trigger', logUpkeepId, 0, 2], // logs are deduped based on the "trigger ID" +// ] +// for (const [type, id, nStale, nPerformed] of tests) { +// const tx = await getTransmitTx(registry, keeper1, [id, id]) +// const receipt = await tx.wait() +// const staleUpkeepReport = parseStaleUpkeepReportLogs(receipt) +// const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) +// assert.equal( +// staleUpkeepReport.length, +// nStale, +// `wrong log count for ${type} upkeep`, +// ) +// assert.equal( +// upkeepPerformedLogs.length, +// nPerformed, +// `wrong log count for ${type} upkeep`, +// ) +// } +// }) +// +// it('handles duplicate log triggers', async () => { +// const logBlockHash = ethers.utils.randomBytes(32) +// const txHash = ethers.utils.randomBytes(32) +// const logIndex = 0 +// const expectedDedupKey = ethers.utils.solidityKeccak256( +// ['uint256', 'bytes32', 'bytes32', 'uint32'], +// [logUpkeepId, logBlockHash, txHash, logIndex], +// ) +// assert.isFalse(await registry.hasDedupKey(expectedDedupKey)) +// const tx = await getTransmitTx( +// registry, +// keeper1, +// [logUpkeepId, logUpkeepId], +// { logBlockHash, txHash, logIndex }, // will result in the same dedup key +// ) +// const receipt = await tx.wait() +// const staleUpkeepReport = parseStaleUpkeepReportLogs(receipt) +// const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) +// assert.equal(staleUpkeepReport.length, 1) +// assert.equal(upkeepPerformedLogs.length, 1) +// assert.isTrue(await registry.hasDedupKey(expectedDedupKey)) +// await expect(tx) +// .to.emit(registry, 'DedupKeyAdded') +// .withArgs(expectedDedupKey) +// }) +// +// it('returns early when check block number is less than last perform (block)', async () => { +// // First perform an upkeep to put last perform block number on upkeep state +// const tx = await getTransmitTx(registry, keeper1, [upkeepId]) +// await tx.wait() +// const lastPerformed = (await registry.getUpkeep(upkeepId)) +// .lastPerformedBlockNumber +// const lastPerformBlock = await ethers.provider.getBlock(lastPerformed) +// assert.equal(lastPerformed.toString(), tx.blockNumber?.toString()) +// // Try to transmit a report which has checkBlockNumber = lastPerformed-1, should result in stale report +// const transmitTx = await getTransmitTx(registry, keeper1, [upkeepId], { +// checkBlockNum: lastPerformBlock.number - 1, +// checkBlockHash: lastPerformBlock.parentHash, +// }) +// const receipt = await transmitTx.wait() +// const staleUpkeepReportLogs = parseStaleUpkeepReportLogs(receipt) +// // exactly 1 StaleUpkeepReportLogs log should be emitted +// assert.equal(staleUpkeepReportLogs.length, 1) +// }) +// +// it('handles case when check block hash does not match', async () => { +// const tests: [string, BigNumber][] = [ +// ['conditional', upkeepId], +// ['log-trigger', logUpkeepId], +// ] +// for (const [type, id] of tests) { +// const latestBlock = await ethers.provider.getBlock('latest') +// // Try to transmit a report which has incorrect checkBlockHash +// const tx = await getTransmitTx(registry, keeper1, [id], { +// checkBlockNum: latestBlock.number - 1, +// checkBlockHash: latestBlock.hash, // should be latestBlock.parentHash +// }) +// +// const receipt = await tx.wait() +// const reorgedUpkeepReportLogs = parseReorgedUpkeepReportLogs(receipt) +// // exactly 1 ReorgedUpkeepReportLogs log should be emitted +// assert.equal( +// reorgedUpkeepReportLogs.length, +// 1, +// `wrong log count for ${type} upkeep`, +// ) +// } +// }) +// +// it('handles case when check block number is older than 256 blocks', async () => { +// for (let i = 0; i < 256; i++) { +// await ethers.provider.send('evm_mine', []) +// } +// const tests: [string, BigNumber][] = [ +// ['conditional', upkeepId], +// ['log-trigger', logUpkeepId], +// ] +// for (const [type, id] of tests) { +// const latestBlock = await ethers.provider.getBlock('latest') +// const old = await ethers.provider.getBlock(latestBlock.number - 256) +// // Try to transmit a report which has incorrect checkBlockHash +// const tx = await getTransmitTx(registry, keeper1, [id], { +// checkBlockNum: old.number, +// checkBlockHash: old.hash, +// }) +// +// const receipt = await tx.wait() +// const reorgedUpkeepReportLogs = parseReorgedUpkeepReportLogs(receipt) +// // exactly 1 ReorgedUpkeepReportLogs log should be emitted +// assert.equal( +// reorgedUpkeepReportLogs.length, +// 1, +// `wrong log count for ${type} upkeep`, +// ) +// } +// }) +// +// it('allows bypassing reorg protection with empty blockhash', async () => { +// const tests: [string, BigNumber][] = [ +// ['conditional', upkeepId], +// ['log-trigger', logUpkeepId], +// ] +// for (const [type, id] of tests) { +// const latestBlock = await ethers.provider.getBlock('latest') +// const tx = await getTransmitTx(registry, keeper1, [id], { +// checkBlockNum: latestBlock.number, +// checkBlockHash: emptyBytes32, +// }) +// const receipt = await tx.wait() +// const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) +// assert.equal( +// upkeepPerformedLogs.length, +// 1, +// `wrong log count for ${type} upkeep`, +// ) +// } +// }) +// +// it('allows very old trigger block numbers when bypassing reorg protection with empty blockhash', async () => { +// // mine enough blocks so that blockhash(1) is unavailable +// for (let i = 0; i <= 256; i++) { +// await ethers.provider.send('evm_mine', []) +// } +// const tests: [string, BigNumber][] = [ +// ['conditional', upkeepId], +// ['log-trigger', logUpkeepId], +// ] +// for (const [type, id] of tests) { +// const tx = await getTransmitTx(registry, keeper1, [id], { +// checkBlockNum: 1, +// checkBlockHash: emptyBytes32, +// }) +// const receipt = await tx.wait() +// const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) +// assert.equal( +// upkeepPerformedLogs.length, +// 1, +// `wrong log count for ${type} upkeep`, +// ) +// } +// }) +// +// it('returns early when future block number is provided as trigger, irrespective of blockhash being present', async () => { +// const tests: [string, BigNumber][] = [ +// ['conditional', upkeepId], +// ['log-trigger', logUpkeepId], +// ] +// for (const [type, id] of tests) { +// const latestBlock = await ethers.provider.getBlock('latest') +// +// // Should fail when blockhash is empty +// let tx = await getTransmitTx(registry, keeper1, [id], { +// checkBlockNum: latestBlock.number + 100, +// checkBlockHash: emptyBytes32, +// }) +// let receipt = await tx.wait() +// let reorgedUpkeepReportLogs = parseReorgedUpkeepReportLogs(receipt) +// // exactly 1 ReorgedUpkeepReportLogs log should be emitted +// assert.equal( +// reorgedUpkeepReportLogs.length, +// 1, +// `wrong log count for ${type} upkeep`, +// ) +// +// // Should also fail when blockhash is not empty +// tx = await getTransmitTx(registry, keeper1, [id], { +// checkBlockNum: latestBlock.number + 100, +// checkBlockHash: latestBlock.hash, +// }) +// receipt = await tx.wait() +// reorgedUpkeepReportLogs = parseReorgedUpkeepReportLogs(receipt) +// // exactly 1 ReorgedUpkeepReportLogs log should be emitted +// assert.equal( +// reorgedUpkeepReportLogs.length, +// 1, +// `wrong log count for ${type} upkeep`, +// ) +// } +// }) +// +// it('returns early when upkeep is cancelled and cancellation delay has gone', async () => { +// const latestBlockReport = await makeLatestBlockReport([upkeepId]) +// await registry.connect(admin).cancelUpkeep(upkeepId) +// +// for (let i = 0; i < cancellationDelay; i++) { +// await ethers.provider.send('evm_mine', []) +// } +// +// const tx = await getTransmitTxWithReport( +// registry, +// keeper1, +// latestBlockReport, +// ) +// +// const receipt = await tx.wait() +// const cancelledUpkeepReportLogs = +// parseCancelledUpkeepReportLogs(receipt) +// // exactly 1 CancelledUpkeepReport log should be emitted +// assert.equal(cancelledUpkeepReportLogs.length, 1) +// }) +// +// it('does not revert if the target cannot execute', async () => { +// await mock.setCanPerform(false) +// const tx = await getTransmitTx(registry, keeper1, [upkeepId]) +// +// const receipt = await tx.wait() +// const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) +// // exactly 1 Upkeep Performed should be emitted +// assert.equal(upkeepPerformedLogs.length, 1) +// const upkeepPerformedLog = upkeepPerformedLogs[0] +// +// const success = upkeepPerformedLog.args.success +// assert.equal(success, false) +// }) +// +// it('does not revert if the target runs out of gas', async () => { +// await mock.setCanPerform(false) +// +// const tx = await getTransmitTx(registry, keeper1, [upkeepId], { +// performGas: 10, // too little gas +// }) +// +// const receipt = await tx.wait() +// const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) +// // exactly 1 Upkeep Performed should be emitted +// assert.equal(upkeepPerformedLogs.length, 1) +// const upkeepPerformedLog = upkeepPerformedLogs[0] +// +// const success = upkeepPerformedLog.args.success +// assert.equal(success, false) +// }) +// +// it('reverts if not enough gas supplied', async () => { +// await evmRevert( +// getTransmitTx(registry, keeper1, [upkeepId], { +// gasLimit: performGas, +// }), +// ) +// }) +// +// it('executes the data passed to the registry', async () => { +// await mock.setCanPerform(true) +// +// const tx = await getTransmitTx(registry, keeper1, [upkeepId], { +// performData: randomBytes, +// }) +// const receipt = await tx.wait() +// +// const upkeepPerformedWithABI = [ +// 'event UpkeepPerformedWith(bytes upkeepData)', +// ] +// const iface = new ethers.utils.Interface(upkeepPerformedWithABI) +// const parsedLogs = [] +// for (let i = 0; i < receipt.logs.length; i++) { +// const log = receipt.logs[i] +// try { +// parsedLogs.push(iface.parseLog(log)) +// } catch (e) { +// // ignore log +// } +// } +// assert.equal(parsedLogs.length, 1) +// assert.equal(parsedLogs[0].args.upkeepData, randomBytes) +// }) +// +// it('uses actual execution price for payment and premium calculation', async () => { +// // Actual multiplier is 2, but we set gasPrice to be 1x gasWei +// const gasPrice = gasWei.mul(BigNumber.from('1')) +// await mock.setCanPerform(true) +// const registryPremiumBefore = (await registry.getState()).state +// .totalPremium +// const tx = await getTransmitTx(registry, keeper1, [upkeepId], { +// gasPrice, +// }) +// const receipt = await tx.wait() +// const registryPremiumAfter = (await registry.getState()).state +// .totalPremium +// const premium = registryPremiumAfter.sub(registryPremiumBefore) +// +// const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) +// // exactly 1 Upkeep Performed should be emitted +// assert.equal(upkeepPerformedLogs.length, 1) +// const upkeepPerformedLog = upkeepPerformedLogs[0] +// +// const gasUsed = upkeepPerformedLog.args.gasUsed +// const gasOverhead = upkeepPerformedLog.args.gasOverhead +// const totalPayment = upkeepPerformedLog.args.totalPayment +// +// assert.equal( +// linkForGas( +// gasUsed, +// gasOverhead, +// BigNumber.from('1'), // Not the config multiplier, but the actual gas used +// paymentPremiumPPB, +// flatFeeMicroLink, +// ).total.toString(), +// totalPayment.toString(), +// ) +// +// assert.equal( +// linkForGas( +// gasUsed, +// gasOverhead, +// BigNumber.from('1'), // Not the config multiplier, but the actual gas used +// paymentPremiumPPB, +// flatFeeMicroLink, +// ).premium.toString(), +// premium.toString(), +// ) +// }) +// +// it('only pays at a rate up to the gas ceiling [ @skip-coverage ]', async () => { +// // Actual multiplier is 2, but we set gasPrice to be 10x +// const gasPrice = gasWei.mul(BigNumber.from('10')) +// await mock.setCanPerform(true) +// +// const tx = await getTransmitTx(registry, keeper1, [upkeepId], { +// gasPrice, +// }) +// const receipt = await tx.wait() +// const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) +// // exactly 1 Upkeep Performed should be emitted +// assert.equal(upkeepPerformedLogs.length, 1) +// const upkeepPerformedLog = upkeepPerformedLogs[0] +// +// const gasUsed = upkeepPerformedLog.args.gasUsed +// const gasOverhead = upkeepPerformedLog.args.gasOverhead +// const totalPayment = upkeepPerformedLog.args.totalPayment +// +// assert.equal( +// linkForGas( +// gasUsed, +// gasOverhead, +// gasCeilingMultiplier, // Should be same with exisitng multiplier +// paymentPremiumPPB, +// flatFeeMicroLink, +// ).total.toString(), +// totalPayment.toString(), +// ) +// }) +// +// it('correctly accounts for l payment', async () => { +// await mock.setCanPerform(true) +// // Same as MockArbGasInfo.sol +// const l1CostWeiArb = BigNumber.from(1000000) +// +// let tx = await arbRegistry +// .connect(owner) +// [ +// 'registerUpkeep(address,uint32,address,bytes,bytes)' +// ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') +// const testUpkeepId = await getUpkeepID(tx) +// await arbRegistry.connect(owner).addFunds(testUpkeepId, toWei('100')) +// +// // Do the thing +// tx = await getTransmitTx( +// arbRegistry, +// keeper1, +// [testUpkeepId], +// +// { gasPrice: gasWei.mul('5') }, // High gas price so that it gets capped +// ) +// const receipt = await tx.wait() +// const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) +// // exactly 1 Upkeep Performed should be emitted +// assert.equal(upkeepPerformedLogs.length, 1) +// const upkeepPerformedLog = upkeepPerformedLogs[0] +// +// const gasUsed = upkeepPerformedLog.args.gasUsed +// const gasOverhead = upkeepPerformedLog.args.gasOverhead +// const totalPayment = upkeepPerformedLog.args.totalPayment +// +// assert.equal( +// linkForGas( +// gasUsed, +// gasOverhead, +// gasCeilingMultiplier, +// paymentPremiumPPB, +// flatFeeMicroLink, +// l1CostWeiArb.div(gasCeilingMultiplier), // Dividing by gasCeilingMultiplier as it gets multiplied later +// ).total.toString(), +// totalPayment.toString(), +// ) +// }) +// +// itMaybe('can self fund', async () => { +// const maxPayment = await registry.getMaxPaymentForGas( +// Trigger.CONDITION, +// performGas, +// ) +// +// // First set auto funding amount to 0 and verify that balance is deducted upon performUpkeep +// let initialBalance = toWei('100') +// await registry.connect(owner).addFunds(afUpkeepId, initialBalance) +// await autoFunderUpkeep.setAutoFundLink(0) +// await autoFunderUpkeep.setIsEligible(true) +// await getTransmitTx(registry, keeper1, [afUpkeepId]) +// +// let postUpkeepBalance = (await registry.getUpkeep(afUpkeepId)).balance +// assert.isTrue(postUpkeepBalance.lt(initialBalance)) // Balance should be deducted +// assert.isTrue(postUpkeepBalance.gte(initialBalance.sub(maxPayment))) // Balance should not be deducted more than maxPayment +// +// // Now set auto funding amount to 100 wei and verify that the balance increases +// initialBalance = postUpkeepBalance +// const autoTopupAmount = toWei('100') +// await autoFunderUpkeep.setAutoFundLink(autoTopupAmount) +// await autoFunderUpkeep.setIsEligible(true) +// await getTransmitTx(registry, keeper1, [afUpkeepId]) +// +// postUpkeepBalance = (await registry.getUpkeep(afUpkeepId)).balance +// // Balance should increase by autoTopupAmount and decrease by max maxPayment +// assert.isTrue( +// postUpkeepBalance.gte( +// initialBalance.add(autoTopupAmount).sub(maxPayment), +// ), +// ) +// }) +// +// it('can self cancel', async () => { +// await registry.connect(owner).addFunds(afUpkeepId, toWei('100')) +// +// await autoFunderUpkeep.setIsEligible(true) +// await autoFunderUpkeep.setShouldCancel(true) +// +// let registration = await registry.getUpkeep(afUpkeepId) +// const oldExpiration = registration.maxValidBlocknumber +// +// // Do the thing +// await getTransmitTx(registry, keeper1, [afUpkeepId]) +// +// // Verify upkeep gets cancelled +// registration = await registry.getUpkeep(afUpkeepId) +// const newExpiration = registration.maxValidBlocknumber +// assert.isTrue(newExpiration.lt(oldExpiration)) +// }) +// +// it('reverts when configDigest mismatches', async () => { +// const report = await makeLatestBlockReport([upkeepId]) +// const reportContext = [emptyBytes32, epochAndRound5_1, emptyBytes32] // wrong config digest +// const sigs = signReport(reportContext, report, signers.slice(0, f + 1)) +// await evmRevert( +// registry +// .connect(keeper1) +// .transmit( +// [reportContext[0], reportContext[1], reportContext[2]], +// report, +// sigs.rs, +// sigs.ss, +// sigs.vs, +// ), +// 'ConfigDigestMismatch()', +// ) +// }) +// +// it('reverts with incorrect number of signatures', async () => { +// const configDigest = (await registry.getState()).state +// .latestConfigDigest +// const report = await makeLatestBlockReport([upkeepId]) +// const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] // wrong config digest +// const sigs = signReport(reportContext, report, signers.slice(0, f + 2)) +// await evmRevert( +// registry +// .connect(keeper1) +// .transmit( +// [reportContext[0], reportContext[1], reportContext[2]], +// report, +// sigs.rs, +// sigs.ss, +// sigs.vs, +// ), +// 'IncorrectNumberOfSignatures()', +// ) +// }) +// +// it('reverts with invalid signature for inactive signers', async () => { +// const configDigest = (await registry.getState()).state +// .latestConfigDigest +// const report = await makeLatestBlockReport([upkeepId]) +// const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] // wrong config digest +// const sigs = signReport(reportContext, report, [ +// new ethers.Wallet(ethers.Wallet.createRandom()), +// new ethers.Wallet(ethers.Wallet.createRandom()), +// ]) +// await evmRevert( +// registry +// .connect(keeper1) +// .transmit( +// [reportContext[0], reportContext[1], reportContext[2]], +// report, +// sigs.rs, +// sigs.ss, +// sigs.vs, +// ), +// 'OnlyActiveSigners()', +// ) +// }) +// +// it('reverts with invalid signature for duplicated signers', async () => { +// const configDigest = (await registry.getState()).state +// .latestConfigDigest +// const report = await makeLatestBlockReport([upkeepId]) +// const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] // wrong config digest +// const sigs = signReport(reportContext, report, [signer1, signer1]) +// await evmRevert( +// registry +// .connect(keeper1) +// .transmit( +// [reportContext[0], reportContext[1], reportContext[2]], +// report, +// sigs.rs, +// sigs.ss, +// sigs.vs, +// ), +// 'DuplicateSigners()', +// ) +// }) +// +// itMaybe( +// 'has a large enough gas overhead to cover upkeep that use all its gas [ @skip-coverage ]', +// async () => { +// await registry.connect(owner).setConfigTypeSafe( +// signerAddresses, +// keeperAddresses, +// 10, // maximise f to maximise overhead +// config, +// offchainVersion, +// offchainBytes, +// ) +// const tx = await registry +// .connect(owner) +// ['registerUpkeep(address,uint32,address,bytes,bytes)']( +// mock.address, +// maxPerformGas, // max allowed gas +// await admin.getAddress(), +// randomBytes, +// '0x', +// ) +// const testUpkeepId = await getUpkeepID(tx) +// await registry.connect(admin).addFunds(testUpkeepId, toWei('100')) +// +// let performData = '0x' +// for (let i = 0; i < maxPerformDataSize.toNumber(); i++) { +// performData += '11' +// } // max allowed performData +// +// await mock.setCanPerform(true) +// await mock.setPerformGasToBurn(maxPerformGas) +// +// await getTransmitTx(registry, keeper1, [testUpkeepId], { +// gasLimit: maxPerformGas.add(transmitGasOverhead), +// numSigners: 11, +// performData, +// }) // Should not revert +// }, +// ) +// +// itMaybe( +// 'performs upkeep, deducts payment, updates lastPerformed and emits events', +// async () => { +// await mock.setCanPerform(true) +// +// for (const i in fArray) { +// const newF = fArray[i] +// await registry +// .connect(owner) +// .setConfigTypeSafe( +// signerAddresses, +// keeperAddresses, +// newF, +// config, +// offchainVersion, +// offchainBytes, +// ) +// const checkBlock = await ethers.provider.getBlock('latest') +// +// const keeperBefore = await registry.getTransmitterInfo( +// await keeper1.getAddress(), +// ) +// const registrationBefore = await registry.getUpkeep(upkeepId) +// const registryPremiumBefore = (await registry.getState()).state +// .totalPremium +// const keeperLinkBefore = await linkToken.balanceOf( +// await keeper1.getAddress(), +// ) +// const registryLinkBefore = await linkToken.balanceOf( +// registry.address, +// ) +// +// // Do the thing +// const tx = await getTransmitTx(registry, keeper1, [upkeepId], { +// checkBlockNum: checkBlock.number, +// checkBlockHash: checkBlock.hash, +// numSigners: newF + 1, +// }) +// +// const receipt = await tx.wait() +// +// const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) +// // exactly 1 Upkeep Performed should be emitted +// assert.equal(upkeepPerformedLogs.length, 1) +// const upkeepPerformedLog = upkeepPerformedLogs[0] +// +// const id = upkeepPerformedLog.args.id +// const success = upkeepPerformedLog.args.success +// const trigger = upkeepPerformedLog.args.trigger +// const gasUsed = upkeepPerformedLog.args.gasUsed +// const gasOverhead = upkeepPerformedLog.args.gasOverhead +// const totalPayment = upkeepPerformedLog.args.totalPayment +// assert.equal(id.toString(), upkeepId.toString()) +// assert.equal(success, true) +// assert.equal( +// trigger, +// encodeBlockTrigger({ +// blockNum: checkBlock.number, +// blockHash: checkBlock.hash, +// }), +// ) +// assert.isTrue(gasUsed.gt(BigNumber.from('0'))) +// assert.isTrue(gasOverhead.gt(BigNumber.from('0'))) +// assert.isTrue(totalPayment.gt(BigNumber.from('0'))) +// +// const keeperAfter = await registry.getTransmitterInfo( +// await keeper1.getAddress(), +// ) +// const registrationAfter = await registry.getUpkeep(upkeepId) +// const keeperLinkAfter = await linkToken.balanceOf( +// await keeper1.getAddress(), +// ) +// const registryLinkAfter = await linkToken.balanceOf( +// registry.address, +// ) +// const registryPremiumAfter = (await registry.getState()).state +// .totalPremium +// const premium = registryPremiumAfter.sub(registryPremiumBefore) +// // Keeper payment is gasPayment + premium / num keepers +// const keeperPayment = totalPayment +// .sub(premium) +// .add(premium.div(BigNumber.from(keeperAddresses.length))) +// +// assert.equal( +// keeperAfter.balance.sub(keeperPayment).toString(), +// keeperBefore.balance.toString(), +// ) +// assert.equal( +// registrationBefore.balance.sub(totalPayment).toString(), +// registrationAfter.balance.toString(), +// ) +// assert.isTrue(keeperLinkAfter.eq(keeperLinkBefore)) +// assert.isTrue(registryLinkBefore.eq(registryLinkAfter)) +// +// // Amount spent should be updated correctly +// assert.equal( +// registrationAfter.amountSpent.sub(totalPayment).toString(), +// registrationBefore.amountSpent.toString(), +// ) +// assert.isTrue( +// registrationAfter.amountSpent +// .sub(registrationBefore.amountSpent) +// .eq(registrationBefore.balance.sub(registrationAfter.balance)), +// ) +// // Last perform block number should be updated +// assert.equal( +// registrationAfter.lastPerformedBlockNumber.toString(), +// tx.blockNumber?.toString(), +// ) +// +// // Latest epoch should be 5 +// assert.equal((await registry.getState()).state.latestEpoch, 5) +// } +// }, +// ) +// +// describeMaybe( +// 'Gas benchmarking conditional upkeeps [ @skip-coverage ]', +// function () { +// const fs = [1, 10] +// fs.forEach(function (newF) { +// it( +// 'When f=' + +// newF + +// ' calculates gas overhead appropriately within a margin for different scenarios', +// async () => { +// // Perform the upkeep once to remove non-zero storage slots and have predictable gas measurement +// let tx = await getTransmitTx(registry, keeper1, [upkeepId]) +// await tx.wait() +// +// // Different test scenarios +// let longBytes = '0x' +// for (let i = 0; i < maxPerformDataSize.toNumber(); i++) { +// longBytes += '11' +// } +// const upkeepSuccessArray = [true, false] +// const performGasArray = [5000, performGas] +// const performDataArray = ['0x', longBytes] +// +// for (const i in upkeepSuccessArray) { +// for (const j in performGasArray) { +// for (const k in performDataArray) { +// const upkeepSuccess = upkeepSuccessArray[i] +// const performGas = performGasArray[j] +// const performData = performDataArray[k] +// +// await mock.setCanPerform(upkeepSuccess) +// await mock.setPerformGasToBurn(performGas) +// await registry +// .connect(owner) +// .setConfigTypeSafe( +// signerAddresses, +// keeperAddresses, +// newF, +// config, +// offchainVersion, +// offchainBytes, +// ) +// tx = await getTransmitTx(registry, keeper1, [upkeepId], { +// numSigners: newF + 1, +// performData, +// }) +// const receipt = await tx.wait() +// const upkeepPerformedLogs = +// parseUpkeepPerformedLogs(receipt) +// // exactly 1 Upkeep Performed should be emitted +// assert.equal(upkeepPerformedLogs.length, 1) +// const upkeepPerformedLog = upkeepPerformedLogs[0] +// +// const upkeepGasUsed = upkeepPerformedLog.args.gasUsed +// const chargedGasOverhead = +// upkeepPerformedLog.args.gasOverhead +// const actualGasOverhead = +// receipt.gasUsed.sub(upkeepGasUsed) +// +// assert.isTrue(upkeepGasUsed.gt(BigNumber.from('0'))) +// assert.isTrue(chargedGasOverhead.gt(BigNumber.from('0'))) +// +// console.log( +// 'Gas Benchmarking conditional upkeeps:', +// 'upkeepSuccess=', +// upkeepSuccess, +// 'performGas=', +// performGas.toString(), +// 'performData length=', +// performData.length / 2 - 1, +// 'sig verification ( f =', +// newF, +// '): calculated overhead: ', +// chargedGasOverhead.toString(), +// ' actual overhead: ', +// actualGasOverhead.toString(), +// ' margin over gasUsed: ', +// chargedGasOverhead.sub(actualGasOverhead).toString(), +// ) +// +// // Overhead should not get capped +// const gasOverheadCap = registryConditionalOverhead +// .add( +// registryPerSignerGasOverhead.mul( +// BigNumber.from(newF + 1), +// ), +// ) +// .add( +// BigNumber.from( +// registryPerPerformByteGasOverhead.toNumber() * +// performData.length, +// ), +// ) +// const gasCapMinusOverhead = +// gasOverheadCap.sub(chargedGasOverhead) +// assert.isTrue( +// gasCapMinusOverhead.gt(BigNumber.from(0)), +// 'Gas overhead got capped. Verify gas overhead variables in test match those in the registry. To not have the overheads capped increase REGISTRY_GAS_OVERHEAD by atleast ' + +// gasCapMinusOverhead.toString(), +// ) +// // total gas charged should be greater than tx gas but within gasCalculationMargin +// assert.isTrue( +// chargedGasOverhead.gt(actualGasOverhead), +// 'Gas overhead calculated is too low, increase account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_SIGNER_GAS_OVERHEAD) by atleast ' + +// actualGasOverhead.sub(chargedGasOverhead).toString(), +// ) +// +// assert.isTrue( +// chargedGasOverhead +// .sub(actualGasOverhead) +// .lt(gasCalculationMargin), +// ), +// 'Gas overhead calculated is too high, decrease account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_SIGNER_GAS_OVERHEAD) by atleast ' + +// chargedGasOverhead +// .sub(chargedGasOverhead) +// .sub(gasCalculationMargin) +// .toString() +// } +// } +// } +// }, +// ) +// }) +// }, +// ) +// +// describeMaybe( +// 'Gas benchmarking log upkeeps [ @skip-coverage ]', +// function () { +// const fs = [1, 10] +// fs.forEach(function (newF) { +// it( +// 'When f=' + +// newF + +// ' calculates gas overhead appropriately within a margin', +// async () => { +// // Perform the upkeep once to remove non-zero storage slots and have predictable gas measurement +// let tx = await getTransmitTx(registry, keeper1, [logUpkeepId]) +// await tx.wait() +// const performData = '0x' +// await mock.setCanPerform(true) +// await mock.setPerformGasToBurn(performGas) +// await registry.setConfigTypeSafe( +// signerAddresses, +// keeperAddresses, +// newF, +// config, +// offchainVersion, +// offchainBytes, +// ) +// tx = await getTransmitTx(registry, keeper1, [logUpkeepId], { +// numSigners: newF + 1, +// performData, +// }) +// const receipt = await tx.wait() +// const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) +// // exactly 1 Upkeep Performed should be emitted +// assert.equal(upkeepPerformedLogs.length, 1) +// const upkeepPerformedLog = upkeepPerformedLogs[0] +// +// const upkeepGasUsed = upkeepPerformedLog.args.gasUsed +// const chargedGasOverhead = upkeepPerformedLog.args.gasOverhead +// const actualGasOverhead = receipt.gasUsed.sub(upkeepGasUsed) +// +// assert.isTrue(upkeepGasUsed.gt(BigNumber.from('0'))) +// assert.isTrue(chargedGasOverhead.gt(BigNumber.from('0'))) +// +// console.log( +// 'Gas Benchmarking log upkeeps:', +// 'upkeepSuccess=', +// true, +// 'performGas=', +// performGas.toString(), +// 'performData length=', +// performData.length / 2 - 1, +// 'sig verification ( f =', +// newF, +// '): calculated overhead: ', +// chargedGasOverhead.toString(), +// ' actual overhead: ', +// actualGasOverhead.toString(), +// ' margin over gasUsed: ', +// chargedGasOverhead.sub(actualGasOverhead).toString(), +// ) +// +// // Overhead should not get capped +// const gasOverheadCap = registryLogOverhead +// .add( +// registryPerSignerGasOverhead.mul(BigNumber.from(newF + 1)), +// ) +// .add( +// BigNumber.from( +// registryPerPerformByteGasOverhead.toNumber() * +// performData.length, +// ), +// ) +// const gasCapMinusOverhead = +// gasOverheadCap.sub(chargedGasOverhead) +// assert.isTrue( +// gasCapMinusOverhead.gt(BigNumber.from(0)), +// 'Gas overhead got capped. Verify gas overhead variables in test match those in the registry. To not have the overheads capped increase REGISTRY_GAS_OVERHEAD by atleast ' + +// gasCapMinusOverhead.toString(), +// ) +// // total gas charged should be greater than tx gas but within gasCalculationMargin +// assert.isTrue( +// chargedGasOverhead.gt(actualGasOverhead), +// 'Gas overhead calculated is too low, increase account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_SIGNER_GAS_OVERHEAD) by atleast ' + +// actualGasOverhead.sub(chargedGasOverhead).toString(), +// ) +// +// assert.isTrue( +// chargedGasOverhead +// .sub(actualGasOverhead) +// .lt(gasCalculationMargin), +// ), +// 'Gas overhead calculated is too high, decrease account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_SIGNER_GAS_OVERHEAD) by atleast ' + +// chargedGasOverhead +// .sub(chargedGasOverhead) +// .sub(gasCalculationMargin) +// .toString() +// }, +// ) +// }) +// }, +// ) +// }) +// }) +// +// describeMaybe( +// '#transmit with upkeep batches [ @skip-coverage ]', +// function () { +// const numPassingConditionalUpkeepsArray = [0, 1, 5] +// const numPassingLogUpkeepsArray = [0, 1, 5] +// const numFailingUpkeepsArray = [0, 3] +// +// for (let idx = 0; idx < numPassingConditionalUpkeepsArray.length; idx++) { +// for (let jdx = 0; jdx < numPassingLogUpkeepsArray.length; jdx++) { +// for (let kdx = 0; kdx < numFailingUpkeepsArray.length; kdx++) { +// const numPassingConditionalUpkeeps = +// numPassingConditionalUpkeepsArray[idx] +// const numPassingLogUpkeeps = numPassingLogUpkeepsArray[jdx] +// const numFailingUpkeeps = numFailingUpkeepsArray[kdx] +// if ( +// numPassingConditionalUpkeeps == 0 && +// numPassingLogUpkeeps == 0 +// ) { +// continue +// } +// it( +// '[Conditional:' + +// numPassingConditionalUpkeeps + +// ',Log:' + +// numPassingLogUpkeeps + +// ',Failures:' + +// numFailingUpkeeps + +// '] performs successful upkeeps and does not charge failing upkeeps', +// async () => { +// const allUpkeeps = await getMultipleUpkeepsDeployedAndFunded( +// numPassingConditionalUpkeeps, +// numPassingLogUpkeeps, +// numFailingUpkeeps, +// ) +// const passingConditionalUpkeepIds = +// allUpkeeps.passingConditionalUpkeepIds +// const passingLogUpkeepIds = allUpkeeps.passingLogUpkeepIds +// const failingUpkeepIds = allUpkeeps.failingUpkeepIds +// +// const keeperBefore = await registry.getTransmitterInfo( +// await keeper1.getAddress(), +// ) +// const keeperLinkBefore = await linkToken.balanceOf( +// await keeper1.getAddress(), +// ) +// const registryLinkBefore = await linkToken.balanceOf( +// registry.address, +// ) +// const registryPremiumBefore = (await registry.getState()).state +// .totalPremium +// const registrationConditionalPassingBefore = await Promise.all( +// passingConditionalUpkeepIds.map(async (id) => { +// const reg = await registry.getUpkeep(BigNumber.from(id)) +// assert.equal(reg.lastPerformedBlockNumber.toString(), '0') +// return reg +// }), +// ) +// const registrationLogPassingBefore = await Promise.all( +// passingLogUpkeepIds.map(async (id) => { +// const reg = await registry.getUpkeep(BigNumber.from(id)) +// assert.equal(reg.lastPerformedBlockNumber.toString(), '0') +// return reg +// }), +// ) +// const registrationFailingBefore = await Promise.all( +// failingUpkeepIds.map(async (id) => { +// const reg = await registry.getUpkeep(BigNumber.from(id)) +// assert.equal(reg.lastPerformedBlockNumber.toString(), '0') +// return reg +// }), +// ) +// +// const tx = await getTransmitTx( +// registry, +// keeper1, +// passingConditionalUpkeepIds.concat( +// passingLogUpkeepIds.concat(failingUpkeepIds), +// ), +// ) +// +// const receipt = await tx.wait() +// const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) +// // exactly numPassingUpkeeps Upkeep Performed should be emitted +// assert.equal( +// upkeepPerformedLogs.length, +// numPassingConditionalUpkeeps + numPassingLogUpkeeps, +// ) +// const insufficientFundsLogs = +// parseInsufficientFundsUpkeepReportLogs(receipt) +// // exactly numFailingUpkeeps Upkeep Performed should be emitted +// assert.equal(insufficientFundsLogs.length, numFailingUpkeeps) +// +// const keeperAfter = await registry.getTransmitterInfo( +// await keeper1.getAddress(), +// ) +// const keeperLinkAfter = await linkToken.balanceOf( +// await keeper1.getAddress(), +// ) +// const registryLinkAfter = await linkToken.balanceOf( +// registry.address, +// ) +// const registrationConditionalPassingAfter = await Promise.all( +// passingConditionalUpkeepIds.map(async (id) => { +// return await registry.getUpkeep(BigNumber.from(id)) +// }), +// ) +// const registrationLogPassingAfter = await Promise.all( +// passingLogUpkeepIds.map(async (id) => { +// return await registry.getUpkeep(BigNumber.from(id)) +// }), +// ) +// const registrationFailingAfter = await Promise.all( +// failingUpkeepIds.map(async (id) => { +// return await registry.getUpkeep(BigNumber.from(id)) +// }), +// ) +// const registryPremiumAfter = (await registry.getState()).state +// .totalPremium +// const premium = registryPremiumAfter.sub(registryPremiumBefore) +// +// let netPayment = BigNumber.from('0') +// for (let i = 0; i < numPassingConditionalUpkeeps; i++) { +// const id = upkeepPerformedLogs[i].args.id +// const gasUsed = upkeepPerformedLogs[i].args.gasUsed +// const gasOverhead = upkeepPerformedLogs[i].args.gasOverhead +// const totalPayment = upkeepPerformedLogs[i].args.totalPayment +// +// expect(id).to.equal(passingConditionalUpkeepIds[i]) +// assert.isTrue(gasUsed.gt(BigNumber.from('0'))) +// assert.isTrue(gasOverhead.gt(BigNumber.from('0'))) +// assert.isTrue(totalPayment.gt(BigNumber.from('0'))) +// +// // Balance should be deducted +// assert.equal( +// registrationConditionalPassingBefore[i].balance +// .sub(totalPayment) +// .toString(), +// registrationConditionalPassingAfter[i].balance.toString(), +// ) +// +// // Amount spent should be updated correctly +// assert.equal( +// registrationConditionalPassingAfter[i].amountSpent +// .sub(totalPayment) +// .toString(), +// registrationConditionalPassingBefore[ +// i +// ].amountSpent.toString(), +// ) +// +// // Last perform block number should be updated +// assert.equal( +// registrationConditionalPassingAfter[ +// i +// ].lastPerformedBlockNumber.toString(), +// tx.blockNumber?.toString(), +// ) +// +// netPayment = netPayment.add(totalPayment) +// } +// +// for (let i = 0; i < numPassingLogUpkeeps; i++) { +// const id = +// upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args +// .id +// const gasUsed = +// upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args +// .gasUsed +// const gasOverhead = +// upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args +// .gasOverhead +// const totalPayment = +// upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args +// .totalPayment +// +// expect(id).to.equal(passingLogUpkeepIds[i]) +// assert.isTrue(gasUsed.gt(BigNumber.from('0'))) +// assert.isTrue(gasOverhead.gt(BigNumber.from('0'))) +// assert.isTrue(totalPayment.gt(BigNumber.from('0'))) +// +// // Balance should be deducted +// assert.equal( +// registrationLogPassingBefore[i].balance +// .sub(totalPayment) +// .toString(), +// registrationLogPassingAfter[i].balance.toString(), +// ) +// +// // Amount spent should be updated correctly +// assert.equal( +// registrationLogPassingAfter[i].amountSpent +// .sub(totalPayment) +// .toString(), +// registrationLogPassingBefore[i].amountSpent.toString(), +// ) +// +// // Last perform block number should not be updated for log triggers +// assert.equal( +// registrationLogPassingAfter[ +// i +// ].lastPerformedBlockNumber.toString(), +// '0', +// ) +// +// netPayment = netPayment.add(totalPayment) +// } +// +// for (let i = 0; i < numFailingUpkeeps; i++) { +// // InsufficientFunds log should be emitted +// const id = insufficientFundsLogs[i].args.id +// expect(id).to.equal(failingUpkeepIds[i]) +// +// // Balance and amount spent should be same +// assert.equal( +// registrationFailingBefore[i].balance.toString(), +// registrationFailingAfter[i].balance.toString(), +// ) +// assert.equal( +// registrationFailingBefore[i].amountSpent.toString(), +// registrationFailingAfter[i].amountSpent.toString(), +// ) +// +// // Last perform block number should not be updated +// assert.equal( +// registrationFailingAfter[ +// i +// ].lastPerformedBlockNumber.toString(), +// '0', +// ) +// } +// +// // Keeper payment is gasPayment + premium / num keepers +// const keeperPayment = netPayment +// .sub(premium) +// .add(premium.div(BigNumber.from(keeperAddresses.length))) +// +// // Keeper should be paid net payment for all passed upkeeps +// assert.equal( +// keeperAfter.balance.sub(keeperPayment).toString(), +// keeperBefore.balance.toString(), +// ) +// +// assert.isTrue(keeperLinkAfter.eq(keeperLinkBefore)) +// assert.isTrue(registryLinkBefore.eq(registryLinkAfter)) +// }, +// ) +// +// it( +// '[Conditional:' + +// numPassingConditionalUpkeeps + +// ',Log' + +// numPassingLogUpkeeps + +// ',Failures:' + +// numFailingUpkeeps + +// '] splits gas overhead appropriately among performed upkeeps [ @skip-coverage ]', +// async () => { +// const allUpkeeps = await getMultipleUpkeepsDeployedAndFunded( +// numPassingConditionalUpkeeps, +// numPassingLogUpkeeps, +// numFailingUpkeeps, +// ) +// const passingConditionalUpkeepIds = +// allUpkeeps.passingConditionalUpkeepIds +// const passingLogUpkeepIds = allUpkeeps.passingLogUpkeepIds +// const failingUpkeepIds = allUpkeeps.failingUpkeepIds +// +// // Perform the upkeeps once to remove non-zero storage slots and have predictable gas measurement +// let tx = await getTransmitTx( +// registry, +// keeper1, +// passingConditionalUpkeepIds.concat( +// passingLogUpkeepIds.concat(failingUpkeepIds), +// ), +// ) +// +// await tx.wait() +// +// // Do the actual thing +// +// tx = await getTransmitTx( +// registry, +// keeper1, +// passingConditionalUpkeepIds.concat( +// passingLogUpkeepIds.concat(failingUpkeepIds), +// ), +// ) +// +// const receipt = await tx.wait() +// const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) +// // exactly numPassingUpkeeps Upkeep Performed should be emitted +// assert.equal( +// upkeepPerformedLogs.length, +// numPassingConditionalUpkeeps + numPassingLogUpkeeps, +// ) +// +// const gasConditionalOverheadCap = +// registryConditionalOverhead.add( +// registryPerSignerGasOverhead.mul(BigNumber.from(f + 1)), +// ) +// const gasLogOverheadCap = registryLogOverhead.add( +// registryPerSignerGasOverhead.mul(BigNumber.from(f + 1)), +// ) +// +// const overheadCanGetCapped = +// numFailingUpkeeps > 0 && +// numPassingConditionalUpkeeps <= 1 && +// numPassingLogUpkeeps <= 1 +// // Can happen if there are failing upkeeps and only 1 successful upkeep of each type +// let netGasUsedPlusOverhead = BigNumber.from('0') +// +// for (let i = 0; i < numPassingConditionalUpkeeps; i++) { +// const gasUsed = upkeepPerformedLogs[i].args.gasUsed +// const gasOverhead = upkeepPerformedLogs[i].args.gasOverhead +// +// assert.isTrue(gasUsed.gt(BigNumber.from('0'))) +// assert.isTrue(gasOverhead.gt(BigNumber.from('0'))) +// +// // Overhead should not exceed capped +// assert.isTrue(gasOverhead.lte(gasConditionalOverheadCap)) +// +// // Overhead should be same for every upkeep since they have equal performData, hence same caps +// assert.isTrue( +// gasOverhead.eq(upkeepPerformedLogs[0].args.gasOverhead), +// ) +// +// netGasUsedPlusOverhead = netGasUsedPlusOverhead +// .add(gasUsed) +// .add(gasOverhead) +// } +// for (let i = 0; i < numPassingLogUpkeeps; i++) { +// const gasUsed = +// upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args +// .gasUsed +// const gasOverhead = +// upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args +// .gasOverhead +// +// assert.isTrue(gasUsed.gt(BigNumber.from('0'))) +// assert.isTrue(gasOverhead.gt(BigNumber.from('0'))) +// +// // Overhead should not exceed capped +// assert.isTrue(gasOverhead.lte(gasLogOverheadCap)) +// +// // Overhead should be same for every upkeep since they have equal performData, hence same caps +// assert.isTrue( +// gasOverhead.eq( +// upkeepPerformedLogs[numPassingConditionalUpkeeps].args +// .gasOverhead, +// ), +// ) +// +// netGasUsedPlusOverhead = netGasUsedPlusOverhead +// .add(gasUsed) +// .add(gasOverhead) +// } +// +// const overheadsGotCapped = +// (numPassingConditionalUpkeeps > 0 && +// upkeepPerformedLogs[0].args.gasOverhead.eq( +// gasConditionalOverheadCap, +// )) || +// (numPassingLogUpkeeps > 0 && +// upkeepPerformedLogs[ +// numPassingConditionalUpkeeps +// ].args.gasOverhead.eq(gasLogOverheadCap)) +// // Should only get capped in certain scenarios +// if (overheadsGotCapped) { +// assert.isTrue( +// overheadCanGetCapped, +// 'Gas overhead got capped. Verify gas overhead variables in test match those in the registry. To not have the overheads capped increase REGISTRY_GAS_OVERHEAD', +// ) +// } +// +// console.log( +// 'Gas Benchmarking - batching (passedConditionalUpkeeps: ', +// numPassingConditionalUpkeeps, +// 'passedLogUpkeeps:', +// numPassingLogUpkeeps, +// 'failedUpkeeps:', +// numFailingUpkeeps, +// '): ', +// 'overheadsGotCapped', +// overheadsGotCapped, +// numPassingConditionalUpkeeps > 0 +// ? 'calculated conditional overhead' +// : '', +// numPassingConditionalUpkeeps > 0 +// ? upkeepPerformedLogs[0].args.gasOverhead.toString() +// : '', +// numPassingLogUpkeeps > 0 ? 'calculated log overhead' : '', +// numPassingLogUpkeeps > 0 +// ? upkeepPerformedLogs[ +// numPassingConditionalUpkeeps +// ].args.gasOverhead.toString() +// : '', +// ' margin over gasUsed', +// netGasUsedPlusOverhead.sub(receipt.gasUsed).toString(), +// ) +// +// // If overheads dont get capped then total gas charged should be greater than tx gas +// // We don't check whether the net is within gasMargin as the margin changes with numFailedUpkeeps +// // Which is ok, as long as individual gas overhead is capped +// if (!overheadsGotCapped) { +// assert.isTrue( +// netGasUsedPlusOverhead.gt(receipt.gasUsed), +// 'Gas overhead is too low, increase ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD', +// ) +// } +// }, +// ) +// } +// } +// } +// +// it('has enough perform gas overhead for large batches [ @skip-coverage ]', async () => { +// const numUpkeeps = 20 +// const upkeepIds: BigNumber[] = [] +// let totalPerformGas = BigNumber.from('0') +// for (let i = 0; i < numUpkeeps; i++) { +// const mock = await upkeepMockFactory.deploy() +// const tx = await registry +// .connect(owner) +// [ +// 'registerUpkeep(address,uint32,address,bytes,bytes)' +// ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') +// const testUpkeepId = await getUpkeepID(tx) +// upkeepIds.push(testUpkeepId) +// +// // Add funds to passing upkeeps +// await registry.connect(owner).addFunds(testUpkeepId, toWei('10')) +// +// await mock.setCanPerform(true) +// await mock.setPerformGasToBurn(performGas) +// +// totalPerformGas = totalPerformGas.add(performGas) +// } +// +// // Should revert with no overhead added +// await evmRevert( +// getTransmitTx(registry, keeper1, upkeepIds, { +// gasLimit: totalPerformGas, +// }), +// ) +// // Should not revert with overhead added +// await getTransmitTx(registry, keeper1, upkeepIds, { +// gasLimit: totalPerformGas.add(transmitGasOverhead), +// }) +// }) +// +// it('splits l2 payment among performed upkeeps', async () => { +// const numUpkeeps = 7 +// const upkeepIds: BigNumber[] = [] +// // Same as MockArbGasInfo.sol +// const l1CostWeiArb = BigNumber.from(1000000) +// +// for (let i = 0; i < numUpkeeps; i++) { +// const mock = await upkeepMockFactory.deploy() +// const tx = await arbRegistry +// .connect(owner) +// [ +// 'registerUpkeep(address,uint32,address,bytes,bytes)' +// ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') +// const testUpkeepId = await getUpkeepID(tx) +// upkeepIds.push(testUpkeepId) +// +// // Add funds to passing upkeeps +// await arbRegistry.connect(owner).addFunds(testUpkeepId, toWei('100')) +// } +// +// // Do the thing +// const tx = await getTransmitTx( +// arbRegistry, +// keeper1, +// upkeepIds, +// +// { gasPrice: gasWei.mul('5') }, // High gas price so that it gets capped +// ) +// +// const receipt = await tx.wait() +// const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) +// // exactly numPassingUpkeeps Upkeep Performed should be emitted +// assert.equal(upkeepPerformedLogs.length, numUpkeeps) +// +// // Verify the payment calculation in upkeepPerformed[0] +// const upkeepPerformedLog = upkeepPerformedLogs[0] +// +// const gasUsed = upkeepPerformedLog.args.gasUsed +// const gasOverhead = upkeepPerformedLog.args.gasOverhead +// const totalPayment = upkeepPerformedLog.args.totalPayment +// +// assert.equal( +// linkForGas( +// gasUsed, +// gasOverhead, +// gasCeilingMultiplier, +// paymentPremiumPPB, +// flatFeeMicroLink, +// l1CostWeiArb.div(gasCeilingMultiplier), // Dividing by gasCeilingMultiplier as it gets multiplied later +// BigNumber.from(numUpkeeps), +// ).total.toString(), +// totalPayment.toString(), +// ) +// }) +// }, +// ) +// +// describe('#recoverFunds', () => { +// const sent = toWei('7') +// +// beforeEach(async () => { +// await linkToken.connect(admin).approve(registry.address, toWei('100')) +// await linkToken +// .connect(owner) +// .transfer(await keeper1.getAddress(), toWei('1000')) +// +// // add funds to upkeep 1 and perform and withdraw some payment +// const tx = await registry +// .connect(owner) +// [ +// 'registerUpkeep(address,uint32,address,bytes,bytes)' +// ](mock.address, performGas, await admin.getAddress(), emptyBytes, emptyBytes) +// +// const id1 = await getUpkeepID(tx) +// await registry.connect(admin).addFunds(id1, toWei('5')) +// +// await getTransmitTx(registry, keeper1, [id1]) +// await getTransmitTx(registry, keeper2, [id1]) +// await getTransmitTx(registry, keeper3, [id1]) +// +// await registry +// .connect(payee1) +// .withdrawPayment( +// await keeper1.getAddress(), +// await nonkeeper.getAddress(), +// ) +// +// // transfer funds directly to the registry +// await linkToken.connect(keeper1).transfer(registry.address, sent) +// +// // add funds to upkeep 2 and perform and withdraw some payment +// const tx2 = await registry +// .connect(owner) +// [ +// 'registerUpkeep(address,uint32,address,bytes,bytes)' +// ](mock.address, performGas, await admin.getAddress(), emptyBytes, emptyBytes) +// const id2 = await getUpkeepID(tx2) +// await registry.connect(admin).addFunds(id2, toWei('5')) +// +// await getTransmitTx(registry, keeper1, [id2]) +// await getTransmitTx(registry, keeper2, [id2]) +// await getTransmitTx(registry, keeper3, [id2]) +// +// await registry +// .connect(payee2) +// .withdrawPayment( +// await keeper2.getAddress(), +// await nonkeeper.getAddress(), +// ) +// +// // transfer funds using onTokenTransfer +// const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [id2]) +// await linkToken +// .connect(owner) +// .transferAndCall(registry.address, toWei('1'), data) +// +// // withdraw some funds +// await registry.connect(owner).cancelUpkeep(id1) +// await registry +// .connect(admin) +// .withdrawFunds(id1, await nonkeeper.getAddress()) +// }) +// +// it('reverts if not called by owner', async () => { +// await evmRevert( +// registry.connect(keeper1).recoverFunds(), +// 'Only callable by owner', +// ) +// }) +// +// it('allows any funds that have been accidentally transfered to be moved', async () => { +// const balanceBefore = await linkToken.balanceOf(registry.address) +// const ownerBefore = await linkToken.balanceOf(await owner.getAddress()) +// +// await registry.connect(owner).recoverFunds() +// +// const balanceAfter = await linkToken.balanceOf(registry.address) +// const ownerAfter = await linkToken.balanceOf(await owner.getAddress()) +// +// assert.isTrue(balanceBefore.eq(balanceAfter.add(sent))) +// assert.isTrue(ownerAfter.eq(ownerBefore.add(sent))) +// }) +// }) +// +// describe('#getMinBalanceForUpkeep / #checkUpkeep / #transmit', () => { +// it('calculates the minimum balance appropriately', async () => { +// await mock.setCanCheck(true) +// +// const oneWei = BigNumber.from(1) +// const minBalance = await registry.getMinBalanceForUpkeep(upkeepId) +// const tooLow = minBalance.sub(oneWei) +// +// await registry.connect(admin).addFunds(upkeepId, tooLow) +// let checkUpkeepResult = await registry +// .connect(zeroAddress) +// .callStatic['checkUpkeep(uint256)'](upkeepId) +// +// assert.equal(checkUpkeepResult.upkeepNeeded, false) +// assert.equal( +// checkUpkeepResult.upkeepFailureReason, +// UpkeepFailureReason.INSUFFICIENT_BALANCE, +// ) +// +// await registry.connect(admin).addFunds(upkeepId, oneWei) +// checkUpkeepResult = await registry +// .connect(zeroAddress) +// .callStatic['checkUpkeep(uint256)'](upkeepId) +// assert.equal(checkUpkeepResult.upkeepNeeded, true) +// }) +// +// it('uses maxPerformData size in checkUpkeep but actual performDataSize in transmit', async () => { +// const tx1 = await registry +// .connect(owner) +// [ +// 'registerUpkeep(address,uint32,address,bytes,bytes)' +// ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') +// const upkeepID1 = await getUpkeepID(tx1) +// const tx2 = await registry +// .connect(owner) +// [ +// 'registerUpkeep(address,uint32,address,bytes,bytes)' +// ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') +// const upkeepID2 = await getUpkeepID(tx2) +// await mock.setCanCheck(true) +// await mock.setCanPerform(true) +// +// // upkeep 1 is underfunded, 2 is fully funded +// const minBalance1 = ( +// await registry.getMinBalanceForUpkeep(upkeepID1) +// ).sub(1) +// const minBalance2 = await registry.getMinBalanceForUpkeep(upkeepID2) +// await registry.connect(owner).addFunds(upkeepID1, minBalance1) +// await registry.connect(owner).addFunds(upkeepID2, minBalance2) +// +// // upkeep 1 check should return false, 2 should return true +// let checkUpkeepResult = await registry +// .connect(zeroAddress) +// .callStatic['checkUpkeep(uint256)'](upkeepID1) +// assert.equal(checkUpkeepResult.upkeepNeeded, false) +// assert.equal( +// checkUpkeepResult.upkeepFailureReason, +// UpkeepFailureReason.INSUFFICIENT_BALANCE, +// ) +// +// checkUpkeepResult = await registry +// .connect(zeroAddress) +// .callStatic['checkUpkeep(uint256)'](upkeepID2) +// assert.equal(checkUpkeepResult.upkeepNeeded, true) +// +// // upkeep 1 perform should return with insufficient balance using max performData size +// let maxPerformData = '0x' +// for (let i = 0; i < maxPerformDataSize.toNumber(); i++) { +// maxPerformData += '11' +// } +// +// const tx = await getTransmitTx(registry, keeper1, [upkeepID1], { +// gasPrice: gasWei.mul(gasCeilingMultiplier), +// performData: maxPerformData, +// }) +// +// const receipt = await tx.wait() +// const insufficientFundsUpkeepReportLogs = +// parseInsufficientFundsUpkeepReportLogs(receipt) +// // exactly 1 InsufficientFundsUpkeepReportLogs log should be emitted +// assert.equal(insufficientFundsUpkeepReportLogs.length, 1) +// +// // upkeep 1 perform should succeed with empty performData +// await getTransmitTx(registry, keeper1, [upkeepID1], { +// gasPrice: gasWei.mul(gasCeilingMultiplier), +// }), +// // upkeep 2 perform should succeed with max performData size +// await getTransmitTx(registry, keeper1, [upkeepID2], { +// gasPrice: gasWei.mul(gasCeilingMultiplier), +// performData: maxPerformData, +// }) +// }) +// }) +// +// describe('#withdrawFunds', () => { +// let upkeepId2: BigNumber +// +// beforeEach(async () => { +// const tx = await registry +// .connect(owner) +// [ +// 'registerUpkeep(address,uint32,address,bytes,bytes)' +// ](mock.address, performGas, await admin.getAddress(), randomBytes, '0x') +// upkeepId2 = await getUpkeepID(tx) +// +// await registry.connect(admin).addFunds(upkeepId, toWei('100')) +// await registry.connect(admin).addFunds(upkeepId2, toWei('100')) +// +// // Do a perform so that upkeep is charged some amount +// await getTransmitTx(registry, keeper1, [upkeepId]) +// await getTransmitTx(registry, keeper1, [upkeepId2]) +// }) +// +// it('reverts if called on a non existing ID', async () => { +// await evmRevert( +// registry +// .connect(admin) +// .withdrawFunds(upkeepId.add(1), await payee1.getAddress()), +// 'OnlyCallableByAdmin()', +// ) +// }) +// +// it('reverts if called by anyone but the admin', async () => { +// await evmRevert( +// registry +// .connect(owner) +// .withdrawFunds(upkeepId, await payee1.getAddress()), +// 'OnlyCallableByAdmin()', +// ) +// }) +// +// it('reverts if called on an uncanceled upkeep', async () => { +// await evmRevert( +// registry +// .connect(admin) +// .withdrawFunds(upkeepId, await payee1.getAddress()), +// 'UpkeepNotCanceled()', +// ) +// }) +// +// it('reverts if called with the 0 address', async () => { +// await evmRevert( +// registry.connect(admin).withdrawFunds(upkeepId, zeroAddress), +// 'InvalidRecipient()', +// ) +// }) +// +// describe('after the registration is paused, then cancelled', () => { +// it('allows the admin to withdraw', async () => { +// const balance = await registry.getBalance(upkeepId) +// const payee = await payee1.getAddress() +// await registry.connect(admin).pauseUpkeep(upkeepId) +// await registry.connect(owner).cancelUpkeep(upkeepId) +// await expect(() => +// registry.connect(admin).withdrawFunds(upkeepId, payee), +// ).to.changeTokenBalance(linkToken, payee1, balance) +// }) +// }) +// +// describe('after the registration is cancelled', () => { +// beforeEach(async () => { +// await registry.connect(owner).cancelUpkeep(upkeepId) +// await registry.connect(owner).cancelUpkeep(upkeepId2) +// }) +// +// it('can be called successively on two upkeeps', async () => { +// await registry +// .connect(admin) +// .withdrawFunds(upkeepId, await payee1.getAddress()) +// await registry +// .connect(admin) +// .withdrawFunds(upkeepId2, await payee1.getAddress()) +// }) +// +// it('moves the funds out and updates the balance and emits an event', async () => { +// const payee1Before = await linkToken.balanceOf( +// await payee1.getAddress(), +// ) +// const registryBefore = await linkToken.balanceOf(registry.address) +// +// let registration = await registry.getUpkeep(upkeepId) +// const previousBalance = registration.balance +// +// const tx = await registry +// .connect(admin) +// .withdrawFunds(upkeepId, await payee1.getAddress()) +// await expect(tx) +// .to.emit(registry, 'FundsWithdrawn') +// .withArgs(upkeepId, previousBalance, await payee1.getAddress()) +// +// const payee1After = await linkToken.balanceOf(await payee1.getAddress()) +// const registryAfter = await linkToken.balanceOf(registry.address) +// +// assert.isTrue(payee1Before.add(previousBalance).eq(payee1After)) +// assert.isTrue(registryBefore.sub(previousBalance).eq(registryAfter)) +// +// registration = await registry.getUpkeep(upkeepId) +// assert.equal(0, registration.balance.toNumber()) +// }) +// }) +// }) +// +// describe('#simulatePerformUpkeep', () => { +// it('reverts if called by non zero address', async () => { +// await evmRevert( +// registry +// .connect(await owner.getAddress()) +// .callStatic.simulatePerformUpkeep(upkeepId, '0x'), +// 'OnlySimulatedBackend()', +// ) +// }) +// +// it('reverts when registry is paused', async () => { +// await registry.connect(owner).pause() +// await evmRevert( +// registry +// .connect(zeroAddress) +// .callStatic.simulatePerformUpkeep(upkeepId, '0x'), +// 'RegistryPaused()', +// ) +// }) +// +// it('returns false and gasUsed when perform fails', async () => { +// await mock.setCanPerform(false) +// +// const simulatePerformResult = await registry +// .connect(zeroAddress) +// .callStatic.simulatePerformUpkeep(upkeepId, '0x') +// +// assert.equal(simulatePerformResult.success, false) +// assert.isTrue(simulatePerformResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used +// }) +// +// it('returns true, gasUsed, and performGas when perform succeeds', async () => { +// await mock.setCanPerform(true) +// +// const simulatePerformResult = await registry +// .connect(zeroAddress) +// .callStatic.simulatePerformUpkeep(upkeepId, '0x') +// +// assert.equal(simulatePerformResult.success, true) +// assert.isTrue(simulatePerformResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used +// }) +// +// it('returns correct amount of gasUsed when perform succeeds', async () => { +// await mock.setCanPerform(true) +// await mock.setPerformGasToBurn(performGas) +// +// const simulatePerformResult = await registry +// .connect(zeroAddress) +// .callStatic.simulatePerformUpkeep(upkeepId, '0x') +// +// assert.equal(simulatePerformResult.success, true) +// // Full execute gas should be used, with some performGasBuffer(1000) +// assert.isTrue( +// simulatePerformResult.gasUsed.gt( +// performGas.sub(BigNumber.from('1000')), +// ), +// ) +// }) +// }) +// +// describe('#checkUpkeep', () => { +// it('reverts if called by non zero address', async () => { +// await evmRevert( +// registry +// .connect(await owner.getAddress()) +// .callStatic['checkUpkeep(uint256)'](upkeepId), +// 'OnlySimulatedBackend()', +// ) +// }) +// +// it('returns false and error code if the upkeep is cancelled by admin', async () => { +// await registry.connect(admin).cancelUpkeep(upkeepId) +// +// const checkUpkeepResult = await registry +// .connect(zeroAddress) +// .callStatic['checkUpkeep(uint256)'](upkeepId) +// +// assert.equal(checkUpkeepResult.upkeepNeeded, false) +// assert.equal(checkUpkeepResult.performData, '0x') +// assert.equal( +// checkUpkeepResult.upkeepFailureReason, +// UpkeepFailureReason.UPKEEP_CANCELLED, +// ) +// expect(checkUpkeepResult.gasUsed).to.equal(0) +// expect(checkUpkeepResult.gasLimit).to.equal(performGas) +// }) +// +// it('returns false and error code if the upkeep is cancelled by owner', async () => { +// await registry.connect(owner).cancelUpkeep(upkeepId) +// +// const checkUpkeepResult = await registry +// .connect(zeroAddress) +// .callStatic['checkUpkeep(uint256)'](upkeepId) +// +// assert.equal(checkUpkeepResult.upkeepNeeded, false) +// assert.equal(checkUpkeepResult.performData, '0x') +// assert.equal( +// checkUpkeepResult.upkeepFailureReason, +// UpkeepFailureReason.UPKEEP_CANCELLED, +// ) +// expect(checkUpkeepResult.gasUsed).to.equal(0) +// expect(checkUpkeepResult.gasLimit).to.equal(performGas) +// }) +// +// it('returns false and error code if the registry is paused', async () => { +// await registry.connect(owner).pause() +// +// const checkUpkeepResult = await registry +// .connect(zeroAddress) +// .callStatic['checkUpkeep(uint256)'](upkeepId) +// +// assert.equal(checkUpkeepResult.upkeepNeeded, false) +// assert.equal(checkUpkeepResult.performData, '0x') +// assert.equal( +// checkUpkeepResult.upkeepFailureReason, +// UpkeepFailureReason.REGISTRY_PAUSED, +// ) +// expect(checkUpkeepResult.gasUsed).to.equal(0) +// expect(checkUpkeepResult.gasLimit).to.equal(performGas) +// }) +// +// it('returns false and error code if the upkeep is paused', async () => { +// await registry.connect(admin).pauseUpkeep(upkeepId) +// +// const checkUpkeepResult = await registry +// .connect(zeroAddress) +// .callStatic['checkUpkeep(uint256)'](upkeepId) +// +// assert.equal(checkUpkeepResult.upkeepNeeded, false) +// assert.equal(checkUpkeepResult.performData, '0x') +// assert.equal( +// checkUpkeepResult.upkeepFailureReason, +// UpkeepFailureReason.UPKEEP_PAUSED, +// ) +// expect(checkUpkeepResult.gasUsed).to.equal(0) +// expect(checkUpkeepResult.gasLimit).to.equal(performGas) +// }) +// +// it('returns false and error code if user is out of funds', async () => { +// const checkUpkeepResult = await registry +// .connect(zeroAddress) +// .callStatic['checkUpkeep(uint256)'](upkeepId) +// +// assert.equal(checkUpkeepResult.upkeepNeeded, false) +// assert.equal(checkUpkeepResult.performData, '0x') +// assert.equal( +// checkUpkeepResult.upkeepFailureReason, +// UpkeepFailureReason.INSUFFICIENT_BALANCE, +// ) +// expect(checkUpkeepResult.gasUsed).to.equal(0) +// expect(checkUpkeepResult.gasLimit).to.equal(performGas) +// }) +// +// context('when the registration is funded', () => { +// beforeEach(async () => { +// await linkToken.connect(admin).approve(registry.address, toWei('200')) +// await registry.connect(admin).addFunds(upkeepId, toWei('100')) +// await registry.connect(admin).addFunds(logUpkeepId, toWei('100')) +// }) +// +// it('returns false, error code, and revert data if the target check reverts', async () => { +// await mock.setShouldRevertCheck(true) +// await mock.setCheckRevertReason( +// 'custom revert error, clever way to insert offchain data', +// ) +// const checkUpkeepResult = await registry +// .connect(zeroAddress) +// .callStatic['checkUpkeep(uint256)'](upkeepId) +// assert.equal(checkUpkeepResult.upkeepNeeded, false) +// +// const revertReasonBytes = `0x${checkUpkeepResult.performData.slice(10)}` // remove sighash +// assert.equal( +// ethers.utils.defaultAbiCoder.decode(['string'], revertReasonBytes)[0], +// 'custom revert error, clever way to insert offchain data', +// ) +// assert.equal( +// checkUpkeepResult.upkeepFailureReason, +// UpkeepFailureReason.TARGET_CHECK_REVERTED, +// ) +// assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used +// expect(checkUpkeepResult.gasLimit).to.equal(performGas) +// // Feed data should be returned here +// assert.isTrue(checkUpkeepResult.fastGasWei.gt(BigNumber.from('0'))) +// assert.isTrue(checkUpkeepResult.linkNative.gt(BigNumber.from('0'))) +// }) +// +// it('returns false, error code, and no revert data if the target check revert data exceeds maxRevertDataSize', async () => { +// await mock.setShouldRevertCheck(true) +// let longRevertReason = '' +// for (let i = 0; i <= maxRevertDataSize.toNumber(); i++) { +// longRevertReason += 'x' +// } +// await mock.setCheckRevertReason(longRevertReason) +// const checkUpkeepResult = await registry +// .connect(zeroAddress) +// .callStatic['checkUpkeep(uint256)'](upkeepId) +// assert.equal(checkUpkeepResult.upkeepNeeded, false) +// +// assert.equal(checkUpkeepResult.performData, '0x') +// assert.equal( +// checkUpkeepResult.upkeepFailureReason, +// UpkeepFailureReason.REVERT_DATA_EXCEEDS_LIMIT, +// ) +// assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used +// expect(checkUpkeepResult.gasLimit).to.equal(performGas) +// }) +// +// it('returns false and error code if the upkeep is not needed', async () => { +// await mock.setCanCheck(false) +// const checkUpkeepResult = await registry +// .connect(zeroAddress) +// .callStatic['checkUpkeep(uint256)'](upkeepId) +// +// assert.equal(checkUpkeepResult.upkeepNeeded, false) +// assert.equal(checkUpkeepResult.performData, '0x') +// assert.equal( +// checkUpkeepResult.upkeepFailureReason, +// UpkeepFailureReason.UPKEEP_NOT_NEEDED, +// ) +// assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used +// expect(checkUpkeepResult.gasLimit).to.equal(performGas) +// }) +// +// it('returns false and error code if the performData exceeds limit', async () => { +// let longBytes = '0x' +// for (let i = 0; i < 5000; i++) { +// longBytes += '1' +// } +// await mock.setCanCheck(true) +// await mock.setPerformData(longBytes) +// +// const checkUpkeepResult = await registry +// .connect(zeroAddress) +// .callStatic['checkUpkeep(uint256)'](upkeepId) +// +// assert.equal(checkUpkeepResult.upkeepNeeded, false) +// assert.equal(checkUpkeepResult.performData, '0x') +// assert.equal( +// checkUpkeepResult.upkeepFailureReason, +// UpkeepFailureReason.PERFORM_DATA_EXCEEDS_LIMIT, +// ) +// assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used +// expect(checkUpkeepResult.gasLimit).to.equal(performGas) +// }) +// +// it('returns true with gas used if the target can execute', async () => { +// await mock.setCanCheck(true) +// await mock.setPerformData(randomBytes) +// +// const latestBlock = await ethers.provider.getBlock('latest') +// +// const checkUpkeepResult = await registry +// .connect(zeroAddress) +// .callStatic['checkUpkeep(uint256)'](upkeepId, { +// blockTag: latestBlock.number, +// }) +// +// assert.equal(checkUpkeepResult.upkeepNeeded, true) +// assert.equal(checkUpkeepResult.performData, randomBytes) +// assert.equal( +// checkUpkeepResult.upkeepFailureReason, +// UpkeepFailureReason.NONE, +// ) +// assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used +// expect(checkUpkeepResult.gasLimit).to.equal(performGas) +// assert.isTrue(checkUpkeepResult.fastGasWei.eq(gasWei)) +// assert.isTrue(checkUpkeepResult.linkNative.eq(linkEth)) +// }) +// +// it('calls checkLog for log-trigger upkeeps', async () => { +// const log: Log = { +// index: 0, +// timestamp: 0, +// txHash: ethers.utils.randomBytes(32), +// blockNumber: 100, +// blockHash: ethers.utils.randomBytes(32), +// source: randomAddress(), +// topics: [ethers.utils.randomBytes(32), ethers.utils.randomBytes(32)], +// data: ethers.utils.randomBytes(1000), +// } +// +// await ltUpkeep.mock.checkLog.withArgs(log, '0x').returns(true, '0x1234') +// +// const checkData = encodeLog(log) +// +// const checkUpkeepResult = await registry +// .connect(zeroAddress) +// .callStatic['checkUpkeep(uint256,bytes)'](logUpkeepId, checkData) +// +// expect(checkUpkeepResult.upkeepNeeded).to.be.true +// expect(checkUpkeepResult.performData).to.equal('0x1234') +// }) +// +// itMaybe( +// 'has a large enough gas overhead to cover upkeeps that use all their gas [ @skip-coverage ]', +// async () => { +// await mock.setCanCheck(true) +// await mock.setCheckGasToBurn(checkGasLimit) +// const gas = checkGasLimit.add(checkGasOverhead) +// const checkUpkeepResult = await registry +// .connect(zeroAddress) +// .callStatic['checkUpkeep(uint256)'](upkeepId, { +// gasLimit: gas, +// }) +// +// assert.equal(checkUpkeepResult.upkeepNeeded, true) +// }, +// ) +// }) +// }) +// +// describe('#addFunds', () => { +// const amount = toWei('1') +// +// it('reverts if the registration does not exist', async () => { +// await evmRevert( +// registry.connect(keeper1).addFunds(upkeepId.add(1), amount), +// 'UpkeepCancelled()', +// ) +// }) +// +// it('adds to the balance of the registration', async () => { +// await registry.connect(admin).addFunds(upkeepId, amount) +// const registration = await registry.getUpkeep(upkeepId) +// assert.isTrue(amount.eq(registration.balance)) +// }) +// +// it('lets anyone add funds to an upkeep not just admin', async () => { +// await linkToken.connect(owner).transfer(await payee1.getAddress(), amount) +// await linkToken.connect(payee1).approve(registry.address, amount) +// +// await registry.connect(payee1).addFunds(upkeepId, amount) +// const registration = await registry.getUpkeep(upkeepId) +// assert.isTrue(amount.eq(registration.balance)) +// }) +// +// it('emits a log', async () => { +// const tx = await registry.connect(admin).addFunds(upkeepId, amount) +// await expect(tx) +// .to.emit(registry, 'FundsAdded') +// .withArgs(upkeepId, await admin.getAddress(), amount) +// }) +// +// it('reverts if the upkeep is canceled', async () => { +// await registry.connect(admin).cancelUpkeep(upkeepId) +// await evmRevert( +// registry.connect(keeper1).addFunds(upkeepId, amount), +// 'UpkeepCancelled()', +// ) +// }) +// }) +// +// describe('#getActiveUpkeepIDs', () => { +// it('reverts if startIndex is out of bounds ', async () => { +// await evmRevert( +// registry.getActiveUpkeepIDs(numUpkeeps, 0), +// 'IndexOutOfRange()', +// ) +// await evmRevert( +// registry.getActiveUpkeepIDs(numUpkeeps + 1, 0), +// 'IndexOutOfRange()', +// ) +// }) +// +// it('returns upkeep IDs bounded by maxCount', async () => { +// let upkeepIds = await registry.getActiveUpkeepIDs(0, 1) +// assert(upkeepIds.length == 1) +// assert(upkeepIds[0].eq(upkeepId)) +// upkeepIds = await registry.getActiveUpkeepIDs(1, 3) +// assert(upkeepIds.length == 3) +// expect(upkeepIds).to.deep.equal([ +// afUpkeepId, +// logUpkeepId, +// streamsLookupUpkeepId, +// ]) +// }) +// +// it('returns as many ids as possible if maxCount > num available', async () => { +// const upkeepIds = await registry.getActiveUpkeepIDs(1, numUpkeeps + 100) +// assert(upkeepIds.length == numUpkeeps - 1) +// }) +// +// it('returns all upkeep IDs if maxCount is 0', async () => { +// let upkeepIds = await registry.getActiveUpkeepIDs(0, 0) +// assert(upkeepIds.length == numUpkeeps) +// upkeepIds = await registry.getActiveUpkeepIDs(2, 0) +// assert(upkeepIds.length == numUpkeeps - 2) +// }) +// }) +// +// describe('#getMaxPaymentForGas', () => { +// const arbL1PriceinWei = BigNumber.from(1000) // Same as MockArbGasInfo.sol +// const l1CostWeiArb = arbL1PriceinWei.mul(16).mul(maxPerformDataSize) +// const l1CostWeiOpt = BigNumber.from(2000000) // Same as MockOVMGasPriceOracle.sol +// itMaybe('calculates the max fee appropriately', async () => { +// await verifyMaxPayment(registry) +// }) +// +// itMaybe('calculates the max fee appropriately for Arbitrum', async () => { +// await verifyMaxPayment(arbRegistry, l1CostWeiArb) +// }) +// +// itMaybe('calculates the max fee appropriately for Optimism', async () => { +// await verifyMaxPayment(opRegistry, l1CostWeiOpt) +// }) +// +// it('uses the fallback gas price if the feed has issues', async () => { +// const expectedFallbackMaxPayment = linkForGas( +// performGas, +// registryConditionalOverhead +// .add(registryPerSignerGasOverhead.mul(f + 1)) +// .add(maxPerformDataSize.mul(registryPerPerformByteGasOverhead)), +// gasCeilingMultiplier.mul('2'), // fallbackGasPrice is 2x gas price +// paymentPremiumPPB, +// flatFeeMicroLink, +// ).total +// +// // Stale feed +// let roundId = 99 +// const answer = 100 +// let updatedAt = 946684800 // New Years 2000 🥳 +// let startedAt = 946684799 +// await gasPriceFeed +// .connect(owner) +// .updateRoundData(roundId, answer, updatedAt, startedAt) +// +// assert.equal( +// expectedFallbackMaxPayment.toString(), +// ( +// await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) +// ).toString(), +// ) +// +// // Negative feed price +// roundId = 100 +// updatedAt = now() +// startedAt = 946684799 +// await gasPriceFeed +// .connect(owner) +// .updateRoundData(roundId, -100, updatedAt, startedAt) +// +// assert.equal( +// expectedFallbackMaxPayment.toString(), +// ( +// await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) +// ).toString(), +// ) +// +// // Zero feed price +// roundId = 101 +// updatedAt = now() +// startedAt = 946684799 +// await gasPriceFeed +// .connect(owner) +// .updateRoundData(roundId, 0, updatedAt, startedAt) +// +// assert.equal( +// expectedFallbackMaxPayment.toString(), +// ( +// await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) +// ).toString(), +// ) +// }) +// +// it('uses the fallback link price if the feed has issues', async () => { +// const expectedFallbackMaxPayment = linkForGas( +// performGas, +// registryConditionalOverhead +// .add(registryPerSignerGasOverhead.mul(f + 1)) +// .add(maxPerformDataSize.mul(registryPerPerformByteGasOverhead)), +// gasCeilingMultiplier.mul('2'), // fallbackLinkPrice is 1/2 link price, so multiply by 2 +// paymentPremiumPPB, +// flatFeeMicroLink, +// ).total +// +// // Stale feed +// let roundId = 99 +// const answer = 100 +// let updatedAt = 946684800 // New Years 2000 🥳 +// let startedAt = 946684799 +// await linkEthFeed +// .connect(owner) +// .updateRoundData(roundId, answer, updatedAt, startedAt) +// +// assert.equal( +// expectedFallbackMaxPayment.toString(), +// ( +// await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) +// ).toString(), +// ) +// +// // Negative feed price +// roundId = 100 +// updatedAt = now() +// startedAt = 946684799 +// await linkEthFeed +// .connect(owner) +// .updateRoundData(roundId, -100, updatedAt, startedAt) +// +// assert.equal( +// expectedFallbackMaxPayment.toString(), +// ( +// await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) +// ).toString(), +// ) +// +// // Zero feed price +// roundId = 101 +// updatedAt = now() +// startedAt = 946684799 +// await linkEthFeed +// .connect(owner) +// .updateRoundData(roundId, 0, updatedAt, startedAt) +// +// assert.equal( +// expectedFallbackMaxPayment.toString(), +// ( +// await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) +// ).toString(), +// ) +// }) +// }) +// +// describe('#typeAndVersion', () => { +// it('uses the correct type and version', async () => { +// const typeAndVersion = await registry.typeAndVersion() +// assert.equal(typeAndVersion, 'KeeperRegistry 2.1.0') +// }) +// }) +// +// describe('#onTokenTransfer', () => { +// const amount = toWei('1') +// +// it('reverts if not called by the LINK token', async () => { +// const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [upkeepId]) +// +// await evmRevert( +// registry +// .connect(keeper1) +// .onTokenTransfer(await keeper1.getAddress(), amount, data), +// 'OnlyCallableByLINKToken()', +// ) +// }) +// +// it('reverts if not called with more or less than 32 bytes', async () => { +// const longData = ethers.utils.defaultAbiCoder.encode( +// ['uint256', 'uint256'], +// ['33', '34'], +// ) +// const shortData = '0x12345678' +// +// await evmRevert( +// linkToken +// .connect(owner) +// .transferAndCall(registry.address, amount, longData), +// ) +// await evmRevert( +// linkToken +// .connect(owner) +// .transferAndCall(registry.address, amount, shortData), +// ) +// }) +// +// it('reverts if the upkeep is canceled', async () => { +// await registry.connect(admin).cancelUpkeep(upkeepId) +// await evmRevert( +// registry.connect(keeper1).addFunds(upkeepId, amount), +// 'UpkeepCancelled()', +// ) +// }) +// +// it('updates the funds of the job id passed', async () => { +// const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [upkeepId]) +// +// const before = (await registry.getUpkeep(upkeepId)).balance +// await linkToken +// .connect(owner) +// .transferAndCall(registry.address, amount, data) +// const after = (await registry.getUpkeep(upkeepId)).balance +// +// assert.isTrue(before.add(amount).eq(after)) +// }) +// }) +// +// describeMaybe('#setConfig - onchain', () => { +// const payment = BigNumber.from(1) +// const flatFee = BigNumber.from(2) +// const maxGas = BigNumber.from(6) +// const staleness = BigNumber.from(4) +// const ceiling = BigNumber.from(5) +// const newMinUpkeepSpend = BigNumber.from(9) +// const newMaxCheckDataSize = BigNumber.from(10000) +// const newMaxPerformDataSize = BigNumber.from(10000) +// const newMaxRevertDataSize = BigNumber.from(10000) +// const newMaxPerformGas = BigNumber.from(10000000) +// const fbGasEth = BigNumber.from(7) +// const fbLinkEth = BigNumber.from(8) +// const newTranscoder = randomAddress() +// const newRegistrars = [randomAddress(), randomAddress()] +// const upkeepManager = randomAddress() +// +// const newConfig: OnChainConfig = { +// paymentPremiumPPB: payment, +// flatFeeMicroLink: flatFee, +// checkGasLimit: maxGas, +// stalenessSeconds: staleness, +// gasCeilingMultiplier: ceiling, +// minUpkeepSpend: newMinUpkeepSpend, +// maxCheckDataSize: newMaxCheckDataSize, +// maxPerformDataSize: newMaxPerformDataSize, +// maxRevertDataSize: newMaxRevertDataSize, +// maxPerformGas: newMaxPerformGas, +// fallbackGasPrice: fbGasEth, +// fallbackLinkPrice: fbLinkEth, +// transcoder: newTranscoder, +// registrars: newRegistrars, +// upkeepPrivilegeManager: upkeepManager, +// } +// +// it('reverts when called by anyone but the proposed owner', async () => { +// await evmRevert( +// registry +// .connect(payee1) +// .setConfigTypeSafe( +// signerAddresses, +// keeperAddresses, +// f, +// newConfig, +// offchainVersion, +// offchainBytes, +// ), +// 'Only callable by owner', +// ) +// }) +// +// it('reverts if signers or transmitters are the zero address', async () => { +// await evmRevert( +// registry +// .connect(owner) +// .setConfigTypeSafe( +// [randomAddress(), randomAddress(), randomAddress(), zeroAddress], +// [ +// randomAddress(), +// randomAddress(), +// randomAddress(), +// randomAddress(), +// ], +// f, +// newConfig, +// offchainVersion, +// offchainBytes, +// ), +// 'InvalidSigner()', +// ) +// +// await evmRevert( +// registry +// .connect(owner) +// .setConfigTypeSafe( +// [ +// randomAddress(), +// randomAddress(), +// randomAddress(), +// randomAddress(), +// ], +// [randomAddress(), randomAddress(), randomAddress(), zeroAddress], +// f, +// newConfig, +// offchainVersion, +// offchainBytes, +// ), +// 'InvalidTransmitter()', +// ) +// }) +// +// it('updates the onchainConfig and configDigest', async () => { +// const old = await registry.getState() +// const oldConfig = old.config +// const oldState = old.state +// assert.isTrue(paymentPremiumPPB.eq(oldConfig.paymentPremiumPPB)) +// assert.isTrue(flatFeeMicroLink.eq(oldConfig.flatFeeMicroLink)) +// assert.isTrue(stalenessSeconds.eq(oldConfig.stalenessSeconds)) +// assert.isTrue(gasCeilingMultiplier.eq(oldConfig.gasCeilingMultiplier)) +// +// await registry +// .connect(owner) +// .setConfigTypeSafe( +// signerAddresses, +// keeperAddresses, +// f, +// newConfig, +// offchainVersion, +// offchainBytes, +// ) +// +// const updated = await registry.getState() +// const updatedConfig = updated.config +// const updatedState = updated.state +// assert.equal(updatedConfig.paymentPremiumPPB, payment.toNumber()) +// assert.equal(updatedConfig.flatFeeMicroLink, flatFee.toNumber()) +// assert.equal(updatedConfig.stalenessSeconds, staleness.toNumber()) +// assert.equal(updatedConfig.gasCeilingMultiplier, ceiling.toNumber()) +// assert.equal( +// updatedConfig.minUpkeepSpend.toString(), +// newMinUpkeepSpend.toString(), +// ) +// assert.equal( +// updatedConfig.maxCheckDataSize, +// newMaxCheckDataSize.toNumber(), +// ) +// assert.equal( +// updatedConfig.maxPerformDataSize, +// newMaxPerformDataSize.toNumber(), +// ) +// assert.equal( +// updatedConfig.maxRevertDataSize, +// newMaxRevertDataSize.toNumber(), +// ) +// assert.equal(updatedConfig.maxPerformGas, newMaxPerformGas.toNumber()) +// assert.equal(updatedConfig.checkGasLimit, maxGas.toNumber()) +// assert.equal( +// updatedConfig.fallbackGasPrice.toNumber(), +// fbGasEth.toNumber(), +// ) +// assert.equal( +// updatedConfig.fallbackLinkPrice.toNumber(), +// fbLinkEth.toNumber(), +// ) +// assert.equal(updatedState.latestEpoch, 0) +// +// assert(oldState.configCount + 1 == updatedState.configCount) +// assert( +// oldState.latestConfigBlockNumber != +// updatedState.latestConfigBlockNumber, +// ) +// assert(oldState.latestConfigDigest != updatedState.latestConfigDigest) +// +// assert.equal(updatedConfig.transcoder, newTranscoder) +// assert.deepEqual(updatedConfig.registrars, newRegistrars) +// assert.equal(updatedConfig.upkeepPrivilegeManager, upkeepManager) +// }) +// +// it('maintains paused state when config is changed', async () => { +// await registry.pause() +// const old = await registry.getState() +// assert.isTrue(old.state.paused) +// +// await registry +// .connect(owner) +// .setConfigTypeSafe( +// signerAddresses, +// keeperAddresses, +// f, +// newConfig, +// offchainVersion, +// offchainBytes, +// ) +// +// const updated = await registry.getState() +// assert.isTrue(updated.state.paused) +// }) +// +// it('emits an event', async () => { +// const tx = await registry +// .connect(owner) +// .setConfigTypeSafe( +// signerAddresses, +// keeperAddresses, +// f, +// newConfig, +// offchainVersion, +// offchainBytes, +// ) +// await expect(tx).to.emit(registry, 'ConfigSet') +// }) +// }) +// +// describe('#setConfig - offchain', () => { +// let newKeepers: string[] +// +// beforeEach(async () => { +// newKeepers = [ +// await personas.Eddy.getAddress(), +// await personas.Nick.getAddress(), +// await personas.Neil.getAddress(), +// await personas.Carol.getAddress(), +// ] +// }) +// +// it('reverts when called by anyone but the owner', async () => { +// await evmRevert( +// registry +// .connect(payee1) +// .setConfigTypeSafe( +// newKeepers, +// newKeepers, +// f, +// config, +// offchainVersion, +// offchainBytes, +// ), +// 'Only callable by owner', +// ) +// }) +// +// it('reverts if too many keeperAddresses set', async () => { +// for (let i = 0; i < 40; i++) { +// newKeepers.push(randomAddress()) +// } +// await evmRevert( +// registry +// .connect(owner) +// .setConfigTypeSafe( +// newKeepers, +// newKeepers, +// f, +// config, +// offchainVersion, +// offchainBytes, +// ), +// 'TooManyOracles()', +// ) +// }) +// +// it('reverts if f=0', async () => { +// await evmRevert( +// registry +// .connect(owner) +// .setConfigTypeSafe( +// newKeepers, +// newKeepers, +// 0, +// config, +// offchainVersion, +// offchainBytes, +// ), +// 'IncorrectNumberOfFaultyOracles()', +// ) +// }) +// +// it('reverts if signers != transmitters length', async () => { +// const signers = [randomAddress()] +// await evmRevert( +// registry +// .connect(owner) +// .setConfigTypeSafe( +// signers, +// newKeepers, +// f, +// config, +// offchainVersion, +// offchainBytes, +// ), +// 'IncorrectNumberOfSigners()', +// ) +// }) +// +// it('reverts if signers <= 3f', async () => { +// newKeepers.pop() +// await evmRevert( +// registry +// .connect(owner) +// .setConfigTypeSafe( +// newKeepers, +// newKeepers, +// f, +// config, +// offchainVersion, +// offchainBytes, +// ), +// 'IncorrectNumberOfSigners()', +// ) +// }) +// +// it('reverts on repeated signers', async () => { +// const newSigners = [ +// await personas.Eddy.getAddress(), +// await personas.Eddy.getAddress(), +// await personas.Eddy.getAddress(), +// await personas.Eddy.getAddress(), +// ] +// await evmRevert( +// registry +// .connect(owner) +// .setConfigTypeSafe( +// newSigners, +// newKeepers, +// f, +// config, +// offchainVersion, +// offchainBytes, +// ), +// 'RepeatedSigner()', +// ) +// }) +// +// it('reverts on repeated transmitters', async () => { +// const newTransmitters = [ +// await personas.Eddy.getAddress(), +// await personas.Eddy.getAddress(), +// await personas.Eddy.getAddress(), +// await personas.Eddy.getAddress(), +// ] +// await evmRevert( +// registry +// .connect(owner) +// .setConfigTypeSafe( +// newKeepers, +// newTransmitters, +// f, +// config, +// offchainVersion, +// offchainBytes, +// ), +// 'RepeatedTransmitter()', +// ) +// }) +// +// itMaybe('stores new config and emits event', async () => { +// // Perform an upkeep so that totalPremium is updated +// await registry.connect(admin).addFunds(upkeepId, toWei('100')) +// let tx = await getTransmitTx(registry, keeper1, [upkeepId]) +// await tx.wait() +// +// const newOffChainVersion = BigNumber.from('2') +// const newOffChainConfig = '0x1122' +// +// const old = await registry.getState() +// const oldState = old.state +// assert(oldState.totalPremium.gt(BigNumber.from('0'))) +// +// const newSigners = newKeepers +// tx = await registry +// .connect(owner) +// .setConfigTypeSafe( +// newSigners, +// newKeepers, +// f, +// config, +// newOffChainVersion, +// newOffChainConfig, +// ) +// +// const updated = await registry.getState() +// const updatedState = updated.state +// assert(oldState.totalPremium.eq(updatedState.totalPremium)) +// +// // Old signer addresses which are not in new signers should be non active +// for (let i = 0; i < signerAddresses.length; i++) { +// const signer = signerAddresses[i] +// if (!newSigners.includes(signer)) { +// assert((await registry.getSignerInfo(signer)).active == false) +// assert((await registry.getSignerInfo(signer)).index == 0) +// } +// } +// // New signer addresses should be active +// for (let i = 0; i < newSigners.length; i++) { +// const signer = newSigners[i] +// assert((await registry.getSignerInfo(signer)).active == true) +// assert((await registry.getSignerInfo(signer)).index == i) +// } +// // Old transmitter addresses which are not in new transmitter should be non active, update lastCollected but retain other info +// for (let i = 0; i < keeperAddresses.length; i++) { +// const transmitter = keeperAddresses[i] +// if (!newKeepers.includes(transmitter)) { +// assert( +// (await registry.getTransmitterInfo(transmitter)).active == false, +// ) +// assert((await registry.getTransmitterInfo(transmitter)).index == i) +// assert( +// (await registry.getTransmitterInfo(transmitter)).lastCollected.eq( +// oldState.totalPremium.sub( +// oldState.totalPremium.mod(keeperAddresses.length), +// ), +// ), +// ) +// } +// } +// // New transmitter addresses should be active +// for (let i = 0; i < newKeepers.length; i++) { +// const transmitter = newKeepers[i] +// assert((await registry.getTransmitterInfo(transmitter)).active == true) +// assert((await registry.getTransmitterInfo(transmitter)).index == i) +// assert( +// (await registry.getTransmitterInfo(transmitter)).lastCollected.eq( +// oldState.totalPremium, +// ), +// ) +// } +// +// // config digest should be updated +// assert(oldState.configCount + 1 == updatedState.configCount) +// assert( +// oldState.latestConfigBlockNumber != +// updatedState.latestConfigBlockNumber, +// ) +// assert(oldState.latestConfigDigest != updatedState.latestConfigDigest) +// +// //New config should be updated +// assert.deepEqual(updated.signers, newKeepers) +// assert.deepEqual(updated.transmitters, newKeepers) +// +// // Event should have been emitted +// await expect(tx).to.emit(registry, 'ConfigSet') +// }) +// }) +// +// describe('#setPeerRegistryMigrationPermission() / #getPeerRegistryMigrationPermission()', () => { +// const peer = randomAddress() +// it('allows the owner to set the peer registries', async () => { +// let permission = await registry.getPeerRegistryMigrationPermission(peer) +// expect(permission).to.equal(0) +// await registry.setPeerRegistryMigrationPermission(peer, 1) +// permission = await registry.getPeerRegistryMigrationPermission(peer) +// expect(permission).to.equal(1) +// await registry.setPeerRegistryMigrationPermission(peer, 2) +// permission = await registry.getPeerRegistryMigrationPermission(peer) +// expect(permission).to.equal(2) +// await registry.setPeerRegistryMigrationPermission(peer, 0) +// permission = await registry.getPeerRegistryMigrationPermission(peer) +// expect(permission).to.equal(0) +// }) +// it('reverts if passed an unsupported permission', async () => { +// await expect( +// registry.connect(admin).setPeerRegistryMigrationPermission(peer, 10), +// ).to.be.reverted +// }) +// it('reverts if not called by the owner', async () => { +// await expect( +// registry.connect(admin).setPeerRegistryMigrationPermission(peer, 1), +// ).to.be.revertedWith('Only callable by owner') +// }) +// }) +// +// describe('#registerUpkeep', () => { +// it('reverts when registry is paused', async () => { +// await registry.connect(owner).pause() +// await evmRevert( +// registry +// .connect(owner) +// [ +// 'registerUpkeep(address,uint32,address,bytes,bytes)' +// ](mock.address, performGas, await admin.getAddress(), emptyBytes, '0x'), +// 'RegistryPaused()', +// ) +// }) +// +// it('reverts if the target is not a contract', async () => { +// await evmRevert( +// registry +// .connect(owner) +// [ +// 'registerUpkeep(address,uint32,address,bytes,bytes)' +// ](zeroAddress, performGas, await admin.getAddress(), emptyBytes, '0x'), +// 'NotAContract()', +// ) +// }) +// +// it('reverts if called by a non-owner', async () => { +// await evmRevert( +// registry +// .connect(keeper1) +// [ +// 'registerUpkeep(address,uint32,address,bytes,bytes)' +// ](mock.address, performGas, await admin.getAddress(), emptyBytes, '0x'), +// 'OnlyCallableByOwnerOrRegistrar()', +// ) +// }) +// +// it('reverts if execute gas is too low', async () => { +// await evmRevert( +// registry +// .connect(owner) +// [ +// 'registerUpkeep(address,uint32,address,bytes,bytes)' +// ](mock.address, 2299, await admin.getAddress(), emptyBytes, '0x'), +// 'GasLimitOutsideRange()', +// ) +// }) +// +// it('reverts if execute gas is too high', async () => { +// await evmRevert( +// registry +// .connect(owner) +// [ +// 'registerUpkeep(address,uint32,address,bytes,bytes)' +// ](mock.address, 5000001, await admin.getAddress(), emptyBytes, '0x'), +// 'GasLimitOutsideRange()', +// ) +// }) +// +// it('reverts if checkData is too long', async () => { +// let longBytes = '0x' +// for (let i = 0; i < 10000; i++) { +// longBytes += '1' +// } +// await evmRevert( +// registry +// .connect(owner) +// [ +// 'registerUpkeep(address,uint32,address,bytes,bytes)' +// ](mock.address, performGas, await admin.getAddress(), longBytes, '0x'), +// 'CheckDataExceedsLimit()', +// ) +// }) +// +// it('creates a record of the registration', async () => { +// const performGases = [100000, 500000] +// const checkDatas = [emptyBytes, '0x12'] +// +// for (let jdx = 0; jdx < performGases.length; jdx++) { +// const performGas = performGases[jdx] +// for (let kdx = 0; kdx < checkDatas.length; kdx++) { +// const checkData = checkDatas[kdx] +// const tx = await registry +// .connect(owner) +// [ +// 'registerUpkeep(address,uint32,address,bytes,bytes)' +// ](mock.address, performGas, await admin.getAddress(), checkData, '0x') +// +// //confirm the upkeep details and verify emitted events +// const testUpkeepId = await getUpkeepID(tx) +// await expect(tx) +// .to.emit(registry, 'UpkeepRegistered') +// .withArgs(testUpkeepId, performGas, await admin.getAddress()) +// +// await expect(tx) +// .to.emit(registry, 'UpkeepCheckDataSet') +// .withArgs(testUpkeepId, checkData) +// await expect(tx) +// .to.emit(registry, 'UpkeepTriggerConfigSet') +// .withArgs(testUpkeepId, '0x') +// +// const registration = await registry.getUpkeep(testUpkeepId) +// +// assert.equal(mock.address, registration.target) +// assert.notEqual( +// ethers.constants.AddressZero, +// await registry.getForwarder(testUpkeepId), +// ) +// assert.equal( +// performGas.toString(), +// registration.performGas.toString(), +// ) +// assert.equal(await admin.getAddress(), registration.admin) +// assert.equal(0, registration.balance.toNumber()) +// assert.equal(0, registration.amountSpent.toNumber()) +// assert.equal(0, registration.lastPerformedBlockNumber) +// assert.equal(checkData, registration.checkData) +// assert.equal(registration.paused, false) +// assert.equal(registration.offchainConfig, '0x') +// assert(registration.maxValidBlocknumber.eq('0xffffffff')) +// } +// } +// }) +// }) +// +// describe('#pauseUpkeep', () => { +// it('reverts if the registration does not exist', async () => { +// await evmRevert( +// registry.connect(keeper1).pauseUpkeep(upkeepId.add(1)), +// 'OnlyCallableByAdmin()', +// ) +// }) +// +// it('reverts if the upkeep is already canceled', async () => { +// await registry.connect(admin).cancelUpkeep(upkeepId) +// +// await evmRevert( +// registry.connect(admin).pauseUpkeep(upkeepId), +// 'UpkeepCancelled()', +// ) +// }) +// +// it('reverts if the upkeep is already paused', async () => { +// await registry.connect(admin).pauseUpkeep(upkeepId) +// +// await evmRevert( +// registry.connect(admin).pauseUpkeep(upkeepId), +// 'OnlyUnpausedUpkeep()', +// ) +// }) +// +// it('reverts if the caller is not the upkeep admin', async () => { +// await evmRevert( +// registry.connect(keeper1).pauseUpkeep(upkeepId), +// 'OnlyCallableByAdmin()', +// ) +// }) +// +// it('pauses the upkeep and emits an event', async () => { +// const tx = await registry.connect(admin).pauseUpkeep(upkeepId) +// await expect(tx).to.emit(registry, 'UpkeepPaused').withArgs(upkeepId) +// +// const registration = await registry.getUpkeep(upkeepId) +// assert.equal(registration.paused, true) +// }) +// }) +// +// describe('#unpauseUpkeep', () => { +// it('reverts if the registration does not exist', async () => { +// await evmRevert( +// registry.connect(keeper1).unpauseUpkeep(upkeepId.add(1)), +// 'OnlyCallableByAdmin()', +// ) +// }) +// +// it('reverts if the upkeep is already canceled', async () => { +// await registry.connect(owner).cancelUpkeep(upkeepId) +// +// await evmRevert( +// registry.connect(admin).unpauseUpkeep(upkeepId), +// 'UpkeepCancelled()', +// ) +// }) +// +// it('marks the contract as paused', async () => { +// assert.isFalse((await registry.getState()).state.paused) +// +// await registry.connect(owner).pause() +// +// assert.isTrue((await registry.getState()).state.paused) +// }) +// +// it('reverts if the upkeep is not paused', async () => { +// await evmRevert( +// registry.connect(admin).unpauseUpkeep(upkeepId), +// 'OnlyPausedUpkeep()', +// ) +// }) +// +// it('reverts if the caller is not the upkeep admin', async () => { +// await registry.connect(admin).pauseUpkeep(upkeepId) +// +// const registration = await registry.getUpkeep(upkeepId) +// +// assert.equal(registration.paused, true) +// +// await evmRevert( +// registry.connect(keeper1).unpauseUpkeep(upkeepId), +// 'OnlyCallableByAdmin()', +// ) +// }) +// +// it('unpauses the upkeep and emits an event', async () => { +// const originalCount = (await registry.getActiveUpkeepIDs(0, 0)).length +// +// await registry.connect(admin).pauseUpkeep(upkeepId) +// +// const tx = await registry.connect(admin).unpauseUpkeep(upkeepId) +// +// await expect(tx).to.emit(registry, 'UpkeepUnpaused').withArgs(upkeepId) +// +// const registration = await registry.getUpkeep(upkeepId) +// assert.equal(registration.paused, false) +// +// const upkeepIds = await registry.getActiveUpkeepIDs(0, 0) +// assert.equal(upkeepIds.length, originalCount) +// }) +// }) +// +// describe('#setUpkeepCheckData', () => { +// it('reverts if the registration does not exist', async () => { +// await evmRevert( +// registry +// .connect(keeper1) +// .setUpkeepCheckData(upkeepId.add(1), randomBytes), +// 'OnlyCallableByAdmin()', +// ) +// }) +// +// it('reverts if the caller is not upkeep admin', async () => { +// await evmRevert( +// registry.connect(keeper1).setUpkeepCheckData(upkeepId, randomBytes), +// 'OnlyCallableByAdmin()', +// ) +// }) +// +// it('reverts if the upkeep is cancelled', async () => { +// await registry.connect(admin).cancelUpkeep(upkeepId) +// +// await evmRevert( +// registry.connect(admin).setUpkeepCheckData(upkeepId, randomBytes), +// 'UpkeepCancelled()', +// ) +// }) +// +// it('is allowed to update on paused upkeep', async () => { +// await registry.connect(admin).pauseUpkeep(upkeepId) +// await registry.connect(admin).setUpkeepCheckData(upkeepId, randomBytes) +// +// const registration = await registry.getUpkeep(upkeepId) +// assert.equal(randomBytes, registration.checkData) +// }) +// +// it('reverts if new data exceeds limit', async () => { +// let longBytes = '0x' +// for (let i = 0; i < 10000; i++) { +// longBytes += '1' +// } +// +// await evmRevert( +// registry.connect(admin).setUpkeepCheckData(upkeepId, longBytes), +// 'CheckDataExceedsLimit()', +// ) +// }) +// +// it('updates the upkeep check data and emits an event', async () => { +// const tx = await registry +// .connect(admin) +// .setUpkeepCheckData(upkeepId, randomBytes) +// await expect(tx) +// .to.emit(registry, 'UpkeepCheckDataSet') +// .withArgs(upkeepId, randomBytes) +// +// const registration = await registry.getUpkeep(upkeepId) +// assert.equal(randomBytes, registration.checkData) +// }) +// }) +// +// describe('#setUpkeepGasLimit', () => { +// const newGasLimit = BigNumber.from('300000') +// +// it('reverts if the registration does not exist', async () => { +// await evmRevert( +// registry.connect(admin).setUpkeepGasLimit(upkeepId.add(1), newGasLimit), +// 'OnlyCallableByAdmin()', +// ) +// }) +// +// it('reverts if the upkeep is canceled', async () => { +// await registry.connect(admin).cancelUpkeep(upkeepId) +// await evmRevert( +// registry.connect(admin).setUpkeepGasLimit(upkeepId, newGasLimit), +// 'UpkeepCancelled()', +// ) +// }) +// +// it('reverts if called by anyone but the admin', async () => { +// await evmRevert( +// registry.connect(owner).setUpkeepGasLimit(upkeepId, newGasLimit), +// 'OnlyCallableByAdmin()', +// ) +// }) +// +// it('reverts if new gas limit is out of bounds', async () => { +// await evmRevert( +// registry +// .connect(admin) +// .setUpkeepGasLimit(upkeepId, BigNumber.from('100')), +// 'GasLimitOutsideRange()', +// ) +// await evmRevert( +// registry +// .connect(admin) +// .setUpkeepGasLimit(upkeepId, BigNumber.from('6000000')), +// 'GasLimitOutsideRange()', +// ) +// }) +// +// it('updates the gas limit successfully', async () => { +// const initialGasLimit = (await registry.getUpkeep(upkeepId)).performGas +// assert.equal(initialGasLimit, performGas.toNumber()) +// await registry.connect(admin).setUpkeepGasLimit(upkeepId, newGasLimit) +// const updatedGasLimit = (await registry.getUpkeep(upkeepId)).performGas +// assert.equal(updatedGasLimit, newGasLimit.toNumber()) +// }) +// +// it('emits a log', async () => { +// const tx = await registry +// .connect(admin) +// .setUpkeepGasLimit(upkeepId, newGasLimit) +// await expect(tx) +// .to.emit(registry, 'UpkeepGasLimitSet') +// .withArgs(upkeepId, newGasLimit) +// }) +// }) +// +// describe('#setUpkeepOffchainConfig', () => { +// const newConfig = '0xc0ffeec0ffee' +// +// it('reverts if the registration does not exist', async () => { +// await evmRevert( +// registry +// .connect(admin) +// .setUpkeepOffchainConfig(upkeepId.add(1), newConfig), +// 'OnlyCallableByAdmin()', +// ) +// }) +// +// it('reverts if the upkeep is canceled', async () => { +// await registry.connect(admin).cancelUpkeep(upkeepId) +// await evmRevert( +// registry.connect(admin).setUpkeepOffchainConfig(upkeepId, newConfig), +// 'UpkeepCancelled()', +// ) +// }) +// +// it('reverts if called by anyone but the admin', async () => { +// await evmRevert( +// registry.connect(owner).setUpkeepOffchainConfig(upkeepId, newConfig), +// 'OnlyCallableByAdmin()', +// ) +// }) +// +// it('updates the config successfully', async () => { +// const initialConfig = (await registry.getUpkeep(upkeepId)).offchainConfig +// assert.equal(initialConfig, '0x') +// await registry.connect(admin).setUpkeepOffchainConfig(upkeepId, newConfig) +// const updatedConfig = (await registry.getUpkeep(upkeepId)).offchainConfig +// assert.equal(newConfig, updatedConfig) +// }) +// +// it('emits a log', async () => { +// const tx = await registry +// .connect(admin) +// .setUpkeepOffchainConfig(upkeepId, newConfig) +// await expect(tx) +// .to.emit(registry, 'UpkeepOffchainConfigSet') +// .withArgs(upkeepId, newConfig) +// }) +// }) +// +// describe('#setUpkeepTriggerConfig', () => { +// const newConfig = '0xdeadbeef' +// +// it('reverts if the registration does not exist', async () => { +// await evmRevert( +// registry +// .connect(admin) +// .setUpkeepTriggerConfig(upkeepId.add(1), newConfig), +// 'OnlyCallableByAdmin()', +// ) +// }) +// +// it('reverts if the upkeep is canceled', async () => { +// await registry.connect(admin).cancelUpkeep(upkeepId) +// await evmRevert( +// registry.connect(admin).setUpkeepTriggerConfig(upkeepId, newConfig), +// 'UpkeepCancelled()', +// ) +// }) +// +// it('reverts if called by anyone but the admin', async () => { +// await evmRevert( +// registry.connect(owner).setUpkeepTriggerConfig(upkeepId, newConfig), +// 'OnlyCallableByAdmin()', +// ) +// }) +// +// it('emits a log', async () => { +// const tx = await registry +// .connect(admin) +// .setUpkeepTriggerConfig(upkeepId, newConfig) +// await expect(tx) +// .to.emit(registry, 'UpkeepTriggerConfigSet') +// .withArgs(upkeepId, newConfig) +// }) +// }) +// +// describe('#transferUpkeepAdmin', () => { +// it('reverts when called by anyone but the current upkeep admin', async () => { +// await evmRevert( +// registry +// .connect(payee1) +// .transferUpkeepAdmin(upkeepId, await payee2.getAddress()), +// 'OnlyCallableByAdmin()', +// ) +// }) +// +// it('reverts when transferring to self', async () => { +// await evmRevert( +// registry +// .connect(admin) +// .transferUpkeepAdmin(upkeepId, await admin.getAddress()), +// 'ValueNotChanged()', +// ) +// }) +// +// it('reverts when the upkeep is cancelled', async () => { +// await registry.connect(admin).cancelUpkeep(upkeepId) +// +// await evmRevert( +// registry +// .connect(admin) +// .transferUpkeepAdmin(upkeepId, await keeper1.getAddress()), +// 'UpkeepCancelled()', +// ) +// }) +// +// it('allows cancelling transfer by reverting to zero address', async () => { +// await registry +// .connect(admin) +// .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) +// const tx = await registry +// .connect(admin) +// .transferUpkeepAdmin(upkeepId, ethers.constants.AddressZero) +// +// await expect(tx) +// .to.emit(registry, 'UpkeepAdminTransferRequested') +// .withArgs( +// upkeepId, +// await admin.getAddress(), +// ethers.constants.AddressZero, +// ) +// }) +// +// it('does not change the upkeep admin', async () => { +// await registry +// .connect(admin) +// .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) +// +// const upkeep = await registry.getUpkeep(upkeepId) +// assert.equal(await admin.getAddress(), upkeep.admin) +// }) +// +// it('emits an event announcing the new upkeep admin', async () => { +// const tx = await registry +// .connect(admin) +// .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) +// +// await expect(tx) +// .to.emit(registry, 'UpkeepAdminTransferRequested') +// .withArgs(upkeepId, await admin.getAddress(), await payee1.getAddress()) +// }) +// +// it('does not emit an event when called with the same proposed upkeep admin', async () => { +// await registry +// .connect(admin) +// .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) +// +// const tx = await registry +// .connect(admin) +// .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) +// const receipt = await tx.wait() +// assert.equal(0, receipt.logs.length) +// }) +// }) +// +// describe('#acceptUpkeepAdmin', () => { +// beforeEach(async () => { +// // Start admin transfer to payee1 +// await registry +// .connect(admin) +// .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) +// }) +// +// it('reverts when not called by the proposed upkeep admin', async () => { +// await evmRevert( +// registry.connect(payee2).acceptUpkeepAdmin(upkeepId), +// 'OnlyCallableByProposedAdmin()', +// ) +// }) +// +// it('reverts when the upkeep is cancelled', async () => { +// await registry.connect(admin).cancelUpkeep(upkeepId) +// +// await evmRevert( +// registry.connect(payee1).acceptUpkeepAdmin(upkeepId), +// 'UpkeepCancelled()', +// ) +// }) +// +// it('does change the admin', async () => { +// await registry.connect(payee1).acceptUpkeepAdmin(upkeepId) +// +// const upkeep = await registry.getUpkeep(upkeepId) +// assert.equal(await payee1.getAddress(), upkeep.admin) +// }) +// +// it('emits an event announcing the new upkeep admin', async () => { +// const tx = await registry.connect(payee1).acceptUpkeepAdmin(upkeepId) +// await expect(tx) +// .to.emit(registry, 'UpkeepAdminTransferred') +// .withArgs(upkeepId, await admin.getAddress(), await payee1.getAddress()) +// }) +// }) +// +// describe('#withdrawOwnerFunds', () => { +// it('can only be called by owner', async () => { +// await evmRevert( +// registry.connect(keeper1).withdrawOwnerFunds(), +// 'Only callable by owner', +// ) +// }) +// +// itMaybe('withdraws the collected fees to owner', async () => { +// await registry.connect(admin).addFunds(upkeepId, toWei('100')) +// // Very high min spend, whole balance as cancellation fees +// const minUpkeepSpend = toWei('1000') +// await registry.connect(owner).setConfigTypeSafe( +// signerAddresses, +// keeperAddresses, +// f, +// { +// paymentPremiumPPB, +// flatFeeMicroLink, +// checkGasLimit, +// stalenessSeconds, +// gasCeilingMultiplier, +// minUpkeepSpend, +// maxCheckDataSize, +// maxPerformDataSize, +// maxRevertDataSize, +// maxPerformGas, +// fallbackGasPrice, +// fallbackLinkPrice, +// transcoder: transcoder.address, +// registrars: [], +// upkeepPrivilegeManager: upkeepManager, +// }, +// offchainVersion, +// offchainBytes, +// ) +// const upkeepBalance = (await registry.getUpkeep(upkeepId)).balance +// const ownerBefore = await linkToken.balanceOf(await owner.getAddress()) +// +// await registry.connect(owner).cancelUpkeep(upkeepId) +// +// // Transfered to owner balance on registry +// let ownerRegistryBalance = (await registry.getState()).state +// .ownerLinkBalance +// assert.isTrue(ownerRegistryBalance.eq(upkeepBalance)) +// +// // Now withdraw +// await registry.connect(owner).withdrawOwnerFunds() +// +// ownerRegistryBalance = (await registry.getState()).state.ownerLinkBalance +// const ownerAfter = await linkToken.balanceOf(await owner.getAddress()) +// +// // Owner registry balance should be changed to 0 +// assert.isTrue(ownerRegistryBalance.eq(BigNumber.from('0'))) +// +// // Owner should be credited with the balance +// assert.isTrue(ownerBefore.add(upkeepBalance).eq(ownerAfter)) +// }) +// }) +// +// describe('#transferPayeeship', () => { +// it('reverts when called by anyone but the current payee', async () => { +// await evmRevert( +// registry +// .connect(payee2) +// .transferPayeeship( +// await keeper1.getAddress(), +// await payee2.getAddress(), +// ), +// 'OnlyCallableByPayee()', +// ) +// }) +// +// it('reverts when transferring to self', async () => { +// await evmRevert( +// registry +// .connect(payee1) +// .transferPayeeship( +// await keeper1.getAddress(), +// await payee1.getAddress(), +// ), +// 'ValueNotChanged()', +// ) +// }) +// +// it('does not change the payee', async () => { +// await registry +// .connect(payee1) +// .transferPayeeship( +// await keeper1.getAddress(), +// await payee2.getAddress(), +// ) +// +// const info = await registry.getTransmitterInfo(await keeper1.getAddress()) +// assert.equal(await payee1.getAddress(), info.payee) +// }) +// +// it('emits an event announcing the new payee', async () => { +// const tx = await registry +// .connect(payee1) +// .transferPayeeship( +// await keeper1.getAddress(), +// await payee2.getAddress(), +// ) +// await expect(tx) +// .to.emit(registry, 'PayeeshipTransferRequested') +// .withArgs( +// await keeper1.getAddress(), +// await payee1.getAddress(), +// await payee2.getAddress(), +// ) +// }) +// +// it('does not emit an event when called with the same proposal', async () => { +// await registry +// .connect(payee1) +// .transferPayeeship( +// await keeper1.getAddress(), +// await payee2.getAddress(), +// ) +// +// const tx = await registry +// .connect(payee1) +// .transferPayeeship( +// await keeper1.getAddress(), +// await payee2.getAddress(), +// ) +// const receipt = await tx.wait() +// assert.equal(0, receipt.logs.length) +// }) +// }) +// +// describe('#acceptPayeeship', () => { +// beforeEach(async () => { +// await registry +// .connect(payee1) +// .transferPayeeship( +// await keeper1.getAddress(), +// await payee2.getAddress(), +// ) +// }) +// +// it('reverts when called by anyone but the proposed payee', async () => { +// await evmRevert( +// registry.connect(payee1).acceptPayeeship(await keeper1.getAddress()), +// 'OnlyCallableByProposedPayee()', +// ) +// }) +// +// it('emits an event announcing the new payee', async () => { +// const tx = await registry +// .connect(payee2) +// .acceptPayeeship(await keeper1.getAddress()) +// await expect(tx) +// .to.emit(registry, 'PayeeshipTransferred') +// .withArgs( +// await keeper1.getAddress(), +// await payee1.getAddress(), +// await payee2.getAddress(), +// ) +// }) +// +// it('does change the payee', async () => { +// await registry.connect(payee2).acceptPayeeship(await keeper1.getAddress()) +// +// const info = await registry.getTransmitterInfo(await keeper1.getAddress()) +// assert.equal(await payee2.getAddress(), info.payee) +// }) +// }) +// +// describe('#pause', () => { +// it('reverts if called by a non-owner', async () => { +// await evmRevert( +// registry.connect(keeper1).pause(), +// 'Only callable by owner', +// ) +// }) +// +// it('marks the contract as paused', async () => { +// assert.isFalse((await registry.getState()).state.paused) +// +// await registry.connect(owner).pause() +// +// assert.isTrue((await registry.getState()).state.paused) +// }) +// +// it('Does not allow transmits when paused', async () => { +// await registry.connect(owner).pause() +// +// await evmRevert( +// getTransmitTx(registry, keeper1, [upkeepId]), +// 'RegistryPaused()', +// ) +// }) +// +// it('Does not allow creation of new upkeeps when paused', async () => { +// await registry.connect(owner).pause() +// +// await evmRevert( +// registry +// .connect(owner) +// [ +// 'registerUpkeep(address,uint32,address,bytes,bytes)' +// ](mock.address, performGas, await admin.getAddress(), emptyBytes, '0x'), +// 'RegistryPaused()', +// ) +// }) +// }) +// +// describe('#unpause', () => { +// beforeEach(async () => { +// await registry.connect(owner).pause() +// }) +// +// it('reverts if called by a non-owner', async () => { +// await evmRevert( +// registry.connect(keeper1).unpause(), +// 'Only callable by owner', +// ) +// }) +// +// it('marks the contract as not paused', async () => { +// assert.isTrue((await registry.getState()).state.paused) +// +// await registry.connect(owner).unpause() +// +// assert.isFalse((await registry.getState()).state.paused) +// }) +// }) +// +// describe('#migrateUpkeeps() / #receiveUpkeeps()', async () => { +// context('when permissions are set', () => { +// beforeEach(async () => { +// await linkToken.connect(owner).approve(registry.address, toWei('100')) +// await registry.connect(owner).addFunds(upkeepId, toWei('100')) +// await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 1) +// await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 2) +// }) +// +// it('migrates an upkeep', async () => { +// const offchainBytes = '0x987654abcd' +// await registry +// .connect(admin) +// .setUpkeepOffchainConfig(upkeepId, offchainBytes) +// const reg1Upkeep = await registry.getUpkeep(upkeepId) +// const forwarderAddress = await registry.getForwarder(upkeepId) +// expect(reg1Upkeep.balance).to.equal(toWei('100')) +// expect(reg1Upkeep.checkData).to.equal(randomBytes) +// expect(forwarderAddress).to.not.equal(ethers.constants.AddressZero) +// expect(reg1Upkeep.offchainConfig).to.equal(offchainBytes) +// expect((await registry.getState()).state.numUpkeeps).to.equal( +// numUpkeeps, +// ) +// const forwarder = await IAutomationForwarderFactory.connect( +// forwarderAddress, +// owner, +// ) +// expect(await forwarder.getRegistry()).to.equal(registry.address) +// // Set an upkeep admin transfer in progress too +// await registry +// .connect(admin) +// .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) +// +// // migrate +// await registry +// .connect(admin) +// .migrateUpkeeps([upkeepId], mgRegistry.address) +// expect((await registry.getState()).state.numUpkeeps).to.equal( +// numUpkeeps - 1, +// ) +// expect((await mgRegistry.getState()).state.numUpkeeps).to.equal(1) +// expect((await registry.getUpkeep(upkeepId)).balance).to.equal(0) +// expect((await registry.getUpkeep(upkeepId)).checkData).to.equal('0x') +// expect((await mgRegistry.getUpkeep(upkeepId)).balance).to.equal( +// toWei('100'), +// ) +// expect( +// (await mgRegistry.getState()).state.expectedLinkBalance, +// ).to.equal(toWei('100')) +// expect((await mgRegistry.getUpkeep(upkeepId)).checkData).to.equal( +// randomBytes, +// ) +// expect((await mgRegistry.getUpkeep(upkeepId)).offchainConfig).to.equal( +// offchainBytes, +// ) +// expect(await mgRegistry.getForwarder(upkeepId)).to.equal( +// forwarderAddress, +// ) +// // test that registry is updated on forwarder +// expect(await forwarder.getRegistry()).to.equal(mgRegistry.address) +// // migration will delete the upkeep and nullify admin transfer +// await expect( +// registry.connect(payee1).acceptUpkeepAdmin(upkeepId), +// ).to.be.revertedWith('UpkeepCancelled()') +// await expect( +// mgRegistry.connect(payee1).acceptUpkeepAdmin(upkeepId), +// ).to.be.revertedWith('OnlyCallableByProposedAdmin()') +// }) +// +// it('migrates a paused upkeep', async () => { +// expect((await registry.getUpkeep(upkeepId)).balance).to.equal( +// toWei('100'), +// ) +// expect((await registry.getUpkeep(upkeepId)).checkData).to.equal( +// randomBytes, +// ) +// expect((await registry.getState()).state.numUpkeeps).to.equal( +// numUpkeeps, +// ) +// await registry.connect(admin).pauseUpkeep(upkeepId) +// // verify the upkeep is paused +// expect((await registry.getUpkeep(upkeepId)).paused).to.equal(true) +// // migrate +// await registry +// .connect(admin) +// .migrateUpkeeps([upkeepId], mgRegistry.address) +// expect((await registry.getState()).state.numUpkeeps).to.equal( +// numUpkeeps - 1, +// ) +// expect((await mgRegistry.getState()).state.numUpkeeps).to.equal(1) +// expect((await registry.getUpkeep(upkeepId)).balance).to.equal(0) +// expect((await mgRegistry.getUpkeep(upkeepId)).balance).to.equal( +// toWei('100'), +// ) +// expect((await registry.getUpkeep(upkeepId)).checkData).to.equal('0x') +// expect((await mgRegistry.getUpkeep(upkeepId)).checkData).to.equal( +// randomBytes, +// ) +// expect( +// (await mgRegistry.getState()).state.expectedLinkBalance, +// ).to.equal(toWei('100')) +// // verify the upkeep is still paused after migration +// expect((await mgRegistry.getUpkeep(upkeepId)).paused).to.equal(true) +// }) +// +// it('emits an event on both contracts', async () => { +// expect((await registry.getUpkeep(upkeepId)).balance).to.equal( +// toWei('100'), +// ) +// expect((await registry.getUpkeep(upkeepId)).checkData).to.equal( +// randomBytes, +// ) +// expect((await registry.getState()).state.numUpkeeps).to.equal( +// numUpkeeps, +// ) +// const tx = registry +// .connect(admin) +// .migrateUpkeeps([upkeepId], mgRegistry.address) +// await expect(tx) +// .to.emit(registry, 'UpkeepMigrated') +// .withArgs(upkeepId, toWei('100'), mgRegistry.address) +// await expect(tx) +// .to.emit(mgRegistry, 'UpkeepReceived') +// .withArgs(upkeepId, toWei('100'), registry.address) +// }) +// +// it('is only migratable by the admin', async () => { +// await expect( +// registry +// .connect(owner) +// .migrateUpkeeps([upkeepId], mgRegistry.address), +// ).to.be.revertedWith('OnlyCallableByAdmin()') +// await registry +// .connect(admin) +// .migrateUpkeeps([upkeepId], mgRegistry.address) +// }) +// }) +// +// context('when permissions are not set', () => { +// it('reverts', async () => { +// // no permissions +// await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 0) +// await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 0) +// await expect(registry.migrateUpkeeps([upkeepId], mgRegistry.address)).to +// .be.reverted +// // only outgoing permissions +// await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 1) +// await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 0) +// await expect(registry.migrateUpkeeps([upkeepId], mgRegistry.address)).to +// .be.reverted +// // only incoming permissions +// await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 0) +// await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 2) +// await expect(registry.migrateUpkeeps([upkeepId], mgRegistry.address)).to +// .be.reverted +// // permissions opposite direction +// await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 2) +// await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 1) +// await expect(registry.migrateUpkeeps([upkeepId], mgRegistry.address)).to +// .be.reverted +// }) +// }) +// }) +// +// describe('#setPayees', () => { +// const IGNORE_ADDRESS = '0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF' +// +// it('reverts when not called by the owner', async () => { +// await evmRevert( +// registry.connect(keeper1).setPayees(payees), +// 'Only callable by owner', +// ) +// }) +// +// it('reverts with different numbers of payees than transmitters', async () => { +// await evmRevert( +// registry.connect(owner).setPayees([...payees, randomAddress()]), +// 'ParameterLengthError()', +// ) +// }) +// +// it('reverts if the payee is the zero address', async () => { +// await blankRegistry.connect(owner).setConfig(...baseConfig) // used to test initial config +// +// await evmRevert( +// blankRegistry // used to test initial config +// .connect(owner) +// .setPayees([ethers.constants.AddressZero, ...payees.slice(1)]), +// 'InvalidPayee()', +// ) +// }) +// +// itMaybe( +// 'sets the payees when exisitng payees are zero address', +// async () => { +// //Initial payees should be zero address +// await blankRegistry.connect(owner).setConfig(...baseConfig) // used to test initial config +// +// for (let i = 0; i < keeperAddresses.length; i++) { +// const payee = ( +// await blankRegistry.getTransmitterInfo(keeperAddresses[i]) +// ).payee // used to test initial config +// assert.equal(payee, zeroAddress) +// } +// +// await blankRegistry.connect(owner).setPayees(payees) // used to test initial config +// +// for (let i = 0; i < keeperAddresses.length; i++) { +// const payee = ( +// await blankRegistry.getTransmitterInfo(keeperAddresses[i]) +// ).payee +// assert.equal(payee, payees[i]) +// } +// }, +// ) +// +// it('does not change the payee if IGNORE_ADDRESS is used as payee', async () => { +// const signers = Array.from({ length: 5 }, randomAddress) +// const keepers = Array.from({ length: 5 }, randomAddress) +// const payees = Array.from({ length: 5 }, randomAddress) +// const newTransmitter = randomAddress() +// const newPayee = randomAddress() +// const ignoreAddresses = new Array(payees.length).fill(IGNORE_ADDRESS) +// const newPayees = [...ignoreAddresses, newPayee] +// // arbitrum registry +// // configure registry with 5 keepers // optimism registry +// await blankRegistry // used to test initial configurations +// .connect(owner) +// .setConfigTypeSafe( +// signers, +// keepers, +// f, +// config, +// offchainVersion, +// offchainBytes, +// ) +// // arbitrum registry +// // set initial payees // optimism registry +// await blankRegistry.connect(owner).setPayees(payees) // used to test initial configurations +// // arbitrum registry +// // add another keeper // optimism registry +// await blankRegistry // used to test initial configurations +// .connect(owner) +// .setConfigTypeSafe( +// [...signers, randomAddress()], +// [...keepers, newTransmitter], +// f, +// config, +// offchainVersion, +// offchainBytes, +// ) +// // arbitrum registry +// // update payee list // optimism registry // arbitrum registry +// await blankRegistry.connect(owner).setPayees(newPayees) // used to test initial configurations // optimism registry +// const ignored = await blankRegistry.getTransmitterInfo(newTransmitter) // used to test initial configurations +// assert.equal(newPayee, ignored.payee) +// assert.equal(true, ignored.active) +// }) +// +// it('reverts if payee is non zero and owner tries to change payee', async () => { +// const newPayees = [randomAddress(), ...payees.slice(1)] +// +// await evmRevert( +// registry.connect(owner).setPayees(newPayees), +// 'InvalidPayee()', +// ) +// }) +// +// it('emits events for every payee added and removed', async () => { +// const tx = await registry.connect(owner).setPayees(payees) +// await expect(tx) +// .to.emit(registry, 'PayeesUpdated') +// .withArgs(keeperAddresses, payees) +// }) +// }) +// +// describe('#cancelUpkeep', () => { +// it('reverts if the ID is not valid', async () => { +// await evmRevert( +// registry.connect(owner).cancelUpkeep(upkeepId.add(1)), +// 'CannotCancel()', +// ) +// }) +// +// it('reverts if called by a non-owner/non-admin', async () => { +// await evmRevert( +// registry.connect(keeper1).cancelUpkeep(upkeepId), +// 'OnlyCallableByOwnerOrAdmin()', +// ) +// }) +// +// describe('when called by the owner', async () => { +// it('sets the registration to invalid immediately', async () => { +// const tx = await registry.connect(owner).cancelUpkeep(upkeepId) +// const receipt = await tx.wait() +// const registration = await registry.getUpkeep(upkeepId) +// assert.equal( +// registration.maxValidBlocknumber.toNumber(), +// receipt.blockNumber, +// ) +// }) +// +// it('emits an event', async () => { +// const tx = await registry.connect(owner).cancelUpkeep(upkeepId) +// const receipt = await tx.wait() +// await expect(tx) +// .to.emit(registry, 'UpkeepCanceled') +// .withArgs(upkeepId, BigNumber.from(receipt.blockNumber)) +// }) +// +// it('immediately prevents upkeep', async () => { +// await registry.connect(owner).cancelUpkeep(upkeepId) +// +// const tx = await getTransmitTx(registry, keeper1, [upkeepId]) +// const receipt = await tx.wait() +// const cancelledUpkeepReportLogs = +// parseCancelledUpkeepReportLogs(receipt) +// // exactly 1 CancelledUpkeepReport log should be emitted +// assert.equal(cancelledUpkeepReportLogs.length, 1) +// }) +// +// it('does not revert if reverts if called multiple times', async () => { +// await registry.connect(owner).cancelUpkeep(upkeepId) +// await evmRevert( +// registry.connect(owner).cancelUpkeep(upkeepId), +// 'CannotCancel()', +// ) +// }) +// +// describe('when called by the owner when the admin has just canceled', () => { +// let oldExpiration: BigNumber +// +// beforeEach(async () => { +// await registry.connect(admin).cancelUpkeep(upkeepId) +// const registration = await registry.getUpkeep(upkeepId) +// oldExpiration = registration.maxValidBlocknumber +// }) +// +// it('allows the owner to cancel it more quickly', async () => { +// await registry.connect(owner).cancelUpkeep(upkeepId) +// +// const registration = await registry.getUpkeep(upkeepId) +// const newExpiration = registration.maxValidBlocknumber +// assert.isTrue(newExpiration.lt(oldExpiration)) +// }) +// }) +// }) +// +// describe('when called by the admin', async () => { +// it('reverts if called again by the admin', async () => { +// await registry.connect(admin).cancelUpkeep(upkeepId) +// +// await evmRevert( +// registry.connect(admin).cancelUpkeep(upkeepId), +// 'CannotCancel()', +// ) +// }) +// +// it('reverts if called by the owner after the timeout', async () => { +// await registry.connect(admin).cancelUpkeep(upkeepId) +// +// for (let i = 0; i < cancellationDelay; i++) { +// await ethers.provider.send('evm_mine', []) +// } +// +// await evmRevert( +// registry.connect(owner).cancelUpkeep(upkeepId), +// 'CannotCancel()', +// ) +// }) +// +// it('sets the registration to invalid in 50 blocks', async () => { +// const tx = await registry.connect(admin).cancelUpkeep(upkeepId) +// const receipt = await tx.wait() +// const registration = await registry.getUpkeep(upkeepId) +// assert.equal( +// registration.maxValidBlocknumber.toNumber(), +// receipt.blockNumber + 50, +// ) +// }) +// +// it('emits an event', async () => { +// const tx = await registry.connect(admin).cancelUpkeep(upkeepId) +// const receipt = await tx.wait() +// await expect(tx) +// .to.emit(registry, 'UpkeepCanceled') +// .withArgs( +// upkeepId, +// BigNumber.from(receipt.blockNumber + cancellationDelay), +// ) +// }) +// +// it('immediately prevents upkeep', async () => { +// await linkToken.connect(owner).approve(registry.address, toWei('100')) +// await registry.connect(owner).addFunds(upkeepId, toWei('100')) +// await registry.connect(admin).cancelUpkeep(upkeepId) +// +// await getTransmitTx(registry, keeper1, [upkeepId]) +// +// for (let i = 0; i < cancellationDelay; i++) { +// await ethers.provider.send('evm_mine', []) +// } +// +// const tx = await getTransmitTx(registry, keeper1, [upkeepId]) +// +// const receipt = await tx.wait() +// const cancelledUpkeepReportLogs = +// parseCancelledUpkeepReportLogs(receipt) +// // exactly 1 CancelledUpkeepReport log should be emitted +// assert.equal(cancelledUpkeepReportLogs.length, 1) +// }) +// +// describeMaybe('when an upkeep has been performed', async () => { +// beforeEach(async () => { +// await linkToken.connect(owner).approve(registry.address, toWei('100')) +// await registry.connect(owner).addFunds(upkeepId, toWei('100')) +// await getTransmitTx(registry, keeper1, [upkeepId]) +// }) +// +// it('deducts a cancellation fee from the upkeep and gives to owner', async () => { +// const minUpkeepSpend = toWei('10') +// +// await registry.connect(owner).setConfigTypeSafe( +// signerAddresses, +// keeperAddresses, +// f, +// { +// paymentPremiumPPB, +// flatFeeMicroLink, +// checkGasLimit, +// stalenessSeconds, +// gasCeilingMultiplier, +// minUpkeepSpend, +// maxCheckDataSize, +// maxPerformDataSize, +// maxRevertDataSize, +// maxPerformGas, +// fallbackGasPrice, +// fallbackLinkPrice, +// transcoder: transcoder.address, +// registrars: [], +// upkeepPrivilegeManager: upkeepManager, +// }, +// offchainVersion, +// offchainBytes, +// ) +// +// const payee1Before = await linkToken.balanceOf( +// await payee1.getAddress(), +// ) +// const upkeepBefore = (await registry.getUpkeep(upkeepId)).balance +// const ownerBefore = (await registry.getState()).state.ownerLinkBalance +// +// const amountSpent = toWei('100').sub(upkeepBefore) +// const cancellationFee = minUpkeepSpend.sub(amountSpent) +// +// await registry.connect(admin).cancelUpkeep(upkeepId) +// +// const payee1After = await linkToken.balanceOf( +// await payee1.getAddress(), +// ) +// const upkeepAfter = (await registry.getUpkeep(upkeepId)).balance +// const ownerAfter = (await registry.getState()).state.ownerLinkBalance +// +// // post upkeep balance should be previous balance minus cancellation fee +// assert.isTrue(upkeepBefore.sub(cancellationFee).eq(upkeepAfter)) +// // payee balance should not change +// assert.isTrue(payee1Before.eq(payee1After)) +// // owner should receive the cancellation fee +// assert.isTrue(ownerAfter.sub(ownerBefore).eq(cancellationFee)) +// }) +// +// it('deducts up to balance as cancellation fee', async () => { +// // Very high min spend, should deduct whole balance as cancellation fees +// const minUpkeepSpend = toWei('1000') +// await registry.connect(owner).setConfigTypeSafe( +// signerAddresses, +// keeperAddresses, +// f, +// { +// paymentPremiumPPB, +// flatFeeMicroLink, +// checkGasLimit, +// stalenessSeconds, +// gasCeilingMultiplier, +// minUpkeepSpend, +// maxCheckDataSize, +// maxPerformDataSize, +// maxRevertDataSize, +// maxPerformGas, +// fallbackGasPrice, +// fallbackLinkPrice, +// transcoder: transcoder.address, +// registrars: [], +// upkeepPrivilegeManager: upkeepManager, +// }, +// offchainVersion, +// offchainBytes, +// ) +// const payee1Before = await linkToken.balanceOf( +// await payee1.getAddress(), +// ) +// const upkeepBefore = (await registry.getUpkeep(upkeepId)).balance +// const ownerBefore = (await registry.getState()).state.ownerLinkBalance +// +// await registry.connect(admin).cancelUpkeep(upkeepId) +// const payee1After = await linkToken.balanceOf( +// await payee1.getAddress(), +// ) +// const ownerAfter = (await registry.getState()).state.ownerLinkBalance +// const upkeepAfter = (await registry.getUpkeep(upkeepId)).balance +// +// // all upkeep balance is deducted for cancellation fee +// assert.equal(0, upkeepAfter.toNumber()) +// // payee balance should not change +// assert.isTrue(payee1After.eq(payee1Before)) +// // all upkeep balance is transferred to the owner +// assert.isTrue(ownerAfter.sub(ownerBefore).eq(upkeepBefore)) +// }) +// +// it('does not deduct cancellation fee if more than minUpkeepSpend is spent', async () => { +// // Very low min spend, already spent in one perform upkeep +// const minUpkeepSpend = BigNumber.from(420) +// await registry.connect(owner).setConfigTypeSafe( +// signerAddresses, +// keeperAddresses, +// f, +// { +// paymentPremiumPPB, +// flatFeeMicroLink, +// checkGasLimit, +// stalenessSeconds, +// gasCeilingMultiplier, +// minUpkeepSpend, +// maxCheckDataSize, +// maxPerformDataSize, +// maxRevertDataSize, +// maxPerformGas, +// fallbackGasPrice, +// fallbackLinkPrice, +// transcoder: transcoder.address, +// registrars: [], +// upkeepPrivilegeManager: upkeepManager, +// }, +// offchainVersion, +// offchainBytes, +// ) +// const payee1Before = await linkToken.balanceOf( +// await payee1.getAddress(), +// ) +// const upkeepBefore = (await registry.getUpkeep(upkeepId)).balance +// const ownerBefore = (await registry.getState()).state.ownerLinkBalance +// +// await registry.connect(admin).cancelUpkeep(upkeepId) +// const payee1After = await linkToken.balanceOf( +// await payee1.getAddress(), +// ) +// const ownerAfter = (await registry.getState()).state.ownerLinkBalance +// const upkeepAfter = (await registry.getUpkeep(upkeepId)).balance +// +// // upkeep does not pay cancellation fee after cancellation because minimum upkeep spent is met +// assert.isTrue(upkeepBefore.eq(upkeepAfter)) +// // owner balance does not change +// assert.isTrue(ownerAfter.eq(ownerBefore)) +// // payee balance does not change +// assert.isTrue(payee1Before.eq(payee1After)) +// }) +// }) +// }) +// }) +// +// describe('#withdrawPayment', () => { +// beforeEach(async () => { +// await linkToken.connect(owner).approve(registry.address, toWei('100')) +// await registry.connect(owner).addFunds(upkeepId, toWei('100')) +// await getTransmitTx(registry, keeper1, [upkeepId]) +// }) +// +// it('reverts if called by anyone but the payee', async () => { +// await evmRevert( +// registry +// .connect(payee2) +// .withdrawPayment( +// await keeper1.getAddress(), +// await nonkeeper.getAddress(), +// ), +// 'OnlyCallableByPayee()', +// ) +// }) +// +// it('reverts if called with the 0 address', async () => { +// await evmRevert( +// registry +// .connect(payee2) +// .withdrawPayment(await keeper1.getAddress(), zeroAddress), +// 'InvalidRecipient()', +// ) +// }) +// +// it('updates the balances', async () => { +// const to = await nonkeeper.getAddress() +// const keeperBefore = await registry.getTransmitterInfo( +// await keeper1.getAddress(), +// ) +// const registrationBefore = (await registry.getUpkeep(upkeepId)).balance +// const toLinkBefore = await linkToken.balanceOf(to) +// const registryLinkBefore = await linkToken.balanceOf(registry.address) +// const registryPremiumBefore = (await registry.getState()).state +// .totalPremium +// const ownerBefore = (await registry.getState()).state.ownerLinkBalance +// +// // Withdrawing for first time, last collected = 0 +// assert.equal(keeperBefore.lastCollected.toString(), '0') +// +// //// Do the thing +// await registry +// .connect(payee1) +// .withdrawPayment(await keeper1.getAddress(), to) +// +// const keeperAfter = await registry.getTransmitterInfo( +// await keeper1.getAddress(), +// ) +// const registrationAfter = (await registry.getUpkeep(upkeepId)).balance +// const toLinkAfter = await linkToken.balanceOf(to) +// const registryLinkAfter = await linkToken.balanceOf(registry.address) +// const registryPremiumAfter = (await registry.getState()).state +// .totalPremium +// const ownerAfter = (await registry.getState()).state.ownerLinkBalance +// +// // registry total premium should not change +// assert.isTrue(registryPremiumBefore.eq(registryPremiumAfter)) +// +// // Last collected should be updated to premium-change +// assert.isTrue( +// keeperAfter.lastCollected.eq( +// registryPremiumBefore.sub( +// registryPremiumBefore.mod(keeperAddresses.length), +// ), +// ), +// ) +// +// // owner balance should remain unchanged +// assert.isTrue(ownerAfter.eq(ownerBefore)) +// +// assert.isTrue(keeperAfter.balance.eq(BigNumber.from(0))) +// assert.isTrue(registrationBefore.eq(registrationAfter)) +// assert.isTrue(toLinkBefore.add(keeperBefore.balance).eq(toLinkAfter)) +// assert.isTrue( +// registryLinkBefore.sub(keeperBefore.balance).eq(registryLinkAfter), +// ) +// }) +// +// it('emits a log announcing the withdrawal', async () => { +// const balance = ( +// await registry.getTransmitterInfo(await keeper1.getAddress()) +// ).balance +// const tx = await registry +// .connect(payee1) +// .withdrawPayment( +// await keeper1.getAddress(), +// await nonkeeper.getAddress(), +// ) +// await expect(tx) +// .to.emit(registry, 'PaymentWithdrawn') +// .withArgs( +// await keeper1.getAddress(), +// balance, +// await nonkeeper.getAddress(), +// await payee1.getAddress(), +// ) +// }) +// }) +// +// describe('#checkCallback', () => { +// it('returns false with appropriate failure reason when target callback reverts', async () => { +// await streamsLookupUpkeep.setShouldRevertCallback(true) +// +// const values: any[] = ['0x1234', '0xabcd'] +// const res = await registry +// .connect(zeroAddress) +// .callStatic.checkCallback(streamsLookupUpkeepId, values, '0x') +// +// assert.isFalse(res.upkeepNeeded) +// assert.equal(res.performData, '0x') +// assert.equal( +// res.upkeepFailureReason, +// UpkeepFailureReason.CHECK_CALLBACK_REVERTED, +// ) +// assert.isTrue(res.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used +// }) +// +// it('returns false with appropriate failure reason when target callback returns big performData', async () => { +// let longBytes = '0x' +// for (let i = 0; i <= maxPerformDataSize.toNumber(); i++) { +// longBytes += '11' +// } +// const values: any[] = [longBytes, longBytes] +// const res = await registry +// .connect(zeroAddress) +// .callStatic.checkCallback(streamsLookupUpkeepId, values, '0x') +// +// assert.isFalse(res.upkeepNeeded) +// assert.equal(res.performData, '0x') +// assert.equal( +// res.upkeepFailureReason, +// UpkeepFailureReason.PERFORM_DATA_EXCEEDS_LIMIT, +// ) +// assert.isTrue(res.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used +// }) +// +// it('returns false with appropriate failure reason when target callback returns false', async () => { +// await streamsLookupUpkeep.setCallbackReturnBool(false) +// const values: any[] = ['0x1234', '0xabcd'] +// const res = await registry +// .connect(zeroAddress) +// .callStatic.checkCallback(streamsLookupUpkeepId, values, '0x') +// +// assert.isFalse(res.upkeepNeeded) +// assert.equal(res.performData, '0x') +// assert.equal( +// res.upkeepFailureReason, +// UpkeepFailureReason.UPKEEP_NOT_NEEDED, +// ) +// assert.isTrue(res.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used +// }) +// +// it('succeeds with upkeep needed', async () => { +// const values: any[] = ['0x1234', '0xabcd'] +// +// const res = await registry +// .connect(zeroAddress) +// .callStatic.checkCallback(streamsLookupUpkeepId, values, '0x') +// const expectedPerformData = ethers.utils.defaultAbiCoder.encode( +// ['bytes[]', 'bytes'], +// [values, '0x'], +// ) +// +// assert.isTrue(res.upkeepNeeded) +// assert.equal(res.performData, expectedPerformData) +// assert.equal(res.upkeepFailureReason, UpkeepFailureReason.NONE) +// assert.isTrue(res.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used +// }) +// }) +// +// describe('#setUpkeepPrivilegeConfig() / #getUpkeepPrivilegeConfig()', () => { +// it('reverts when non manager tries to set privilege config', async () => { +// await evmRevert( +// registry.connect(payee3).setUpkeepPrivilegeConfig(upkeepId, '0x1234'), +// 'OnlyCallableByUpkeepPrivilegeManager()', +// ) +// }) +// +// it('returns empty bytes for upkeep privilege config before setting', async () => { +// const cfg = await registry.getUpkeepPrivilegeConfig(upkeepId) +// assert.equal(cfg, '0x') +// }) +// +// it('allows upkeep manager to set privilege config', async () => { +// const tx = await registry +// .connect(personas.Norbert) +// .setUpkeepPrivilegeConfig(upkeepId, '0x1234') +// await expect(tx) +// .to.emit(registry, 'UpkeepPrivilegeConfigSet') +// .withArgs(upkeepId, '0x1234') +// +// const cfg = await registry.getUpkeepPrivilegeConfig(upkeepId) +// assert.equal(cfg, '0x1234') +// }) +// }) +// +// describe('#setAdminPrivilegeConfig() / #getAdminPrivilegeConfig()', () => { +// const admin = randomAddress() +// +// it('reverts when non manager tries to set privilege config', async () => { +// await evmRevert( +// registry.connect(payee3).setAdminPrivilegeConfig(admin, '0x1234'), +// 'OnlyCallableByUpkeepPrivilegeManager()', +// ) +// }) +// +// it('returns empty bytes for upkeep privilege config before setting', async () => { +// const cfg = await registry.getAdminPrivilegeConfig(admin) +// assert.equal(cfg, '0x') +// }) +// +// it('allows upkeep manager to set privilege config', async () => { +// const tx = await registry +// .connect(personas.Norbert) +// .setAdminPrivilegeConfig(admin, '0x1234') +// await expect(tx) +// .to.emit(registry, 'AdminPrivilegeConfigSet') +// .withArgs(admin, '0x1234') +// +// const cfg = await registry.getAdminPrivilegeConfig(admin) +// assert.equal(cfg, '0x1234') +// }) +// }) +// +// describe('transmitterPremiumSplit [ @skip-coverage ]', () => { +// beforeEach(async () => { +// await linkToken.connect(owner).approve(registry.address, toWei('100')) +// await registry.connect(owner).addFunds(upkeepId, toWei('100')) +// }) +// +// it('splits premium evenly across transmitters', async () => { +// // Do a transmit from keeper1 +// await getTransmitTx(registry, keeper1, [upkeepId]) +// +// const registryPremium = (await registry.getState()).state.totalPremium +// assert.isTrue(registryPremium.gt(BigNumber.from(0))) +// +// const premiumPerTransmitter = registryPremium.div( +// BigNumber.from(keeperAddresses.length), +// ) +// const k1Balance = ( +// await registry.getTransmitterInfo(await keeper1.getAddress()) +// ).balance +// // transmitter should be reimbursed for gas and get the premium +// assert.isTrue(k1Balance.gt(premiumPerTransmitter)) +// const k1GasReimbursement = k1Balance.sub(premiumPerTransmitter) +// +// const k2Balance = ( +// await registry.getTransmitterInfo(await keeper2.getAddress()) +// ).balance +// // non transmitter should get its share of premium +// assert.isTrue(k2Balance.eq(premiumPerTransmitter)) +// +// // Now do a transmit from keeper 2 +// await getTransmitTx(registry, keeper2, [upkeepId]) +// const registryPremiumNew = (await registry.getState()).state.totalPremium +// assert.isTrue(registryPremiumNew.gt(registryPremium)) +// const premiumPerTransmitterNew = registryPremiumNew.div( +// BigNumber.from(keeperAddresses.length), +// ) +// const additionalPremium = premiumPerTransmitterNew.sub( +// premiumPerTransmitter, +// ) +// +// const k1BalanceNew = ( +// await registry.getTransmitterInfo(await keeper1.getAddress()) +// ).balance +// // k1 should get the new premium +// assert.isTrue( +// k1BalanceNew.eq(k1GasReimbursement.add(premiumPerTransmitterNew)), +// ) +// +// const k2BalanceNew = ( +// await registry.getTransmitterInfo(await keeper2.getAddress()) +// ).balance +// // k2 should get gas reimbursement in addition to new premium +// assert.isTrue(k2BalanceNew.gt(k2Balance.add(additionalPremium))) +// }) +// +// it('updates last collected upon payment withdrawn', async () => { +// // Do a transmit from keeper1 +// await getTransmitTx(registry, keeper1, [upkeepId]) +// +// const registryPremium = (await registry.getState()).state.totalPremium +// const k1 = await registry.getTransmitterInfo(await keeper1.getAddress()) +// const k2 = await registry.getTransmitterInfo(await keeper2.getAddress()) +// +// // Withdrawing for first time, last collected = 0 +// assert.isTrue(k1.lastCollected.eq(BigNumber.from(0))) +// assert.isTrue(k2.lastCollected.eq(BigNumber.from(0))) +// +// //// Do the thing +// await registry +// .connect(payee1) +// .withdrawPayment( +// await keeper1.getAddress(), +// await nonkeeper.getAddress(), +// ) +// +// const k1New = await registry.getTransmitterInfo( +// await keeper1.getAddress(), +// ) +// const k2New = await registry.getTransmitterInfo( +// await keeper2.getAddress(), +// ) +// +// // transmitter info lastCollected should be updated for k1, not for k2 +// assert.isTrue( +// k1New.lastCollected.eq( +// registryPremium.sub(registryPremium.mod(keeperAddresses.length)), +// ), +// ) +// assert.isTrue(k2New.lastCollected.eq(BigNumber.from(0))) +// }) +// +// itMaybe( +// 'maintains consistent balance information across all parties', +// async () => { +// // throughout transmits, withdrawals, setConfigs total claim on balances should remain less than expected balance +// // some spare change can get lost but it should be less than maxAllowedSpareChange +// +// let maxAllowedSpareChange = BigNumber.from('0') +// await verifyConsistentAccounting(maxAllowedSpareChange) +// +// await getTransmitTx(registry, keeper1, [upkeepId]) +// maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('31')) +// await verifyConsistentAccounting(maxAllowedSpareChange) +// +// await registry +// .connect(payee1) +// .withdrawPayment( +// await keeper1.getAddress(), +// await nonkeeper.getAddress(), +// ) +// await verifyConsistentAccounting(maxAllowedSpareChange) +// +// await registry +// .connect(payee2) +// .withdrawPayment( +// await keeper2.getAddress(), +// await nonkeeper.getAddress(), +// ) +// await verifyConsistentAccounting(maxAllowedSpareChange) +// +// await getTransmitTx(registry, keeper1, [upkeepId]) +// maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('31')) +// await verifyConsistentAccounting(maxAllowedSpareChange) +// +// await registry.connect(owner).setConfigTypeSafe( +// signerAddresses.slice(2, 15), // only use 2-14th index keepers +// keeperAddresses.slice(2, 15), +// f, +// config, +// offchainVersion, +// offchainBytes, +// ) +// await verifyConsistentAccounting(maxAllowedSpareChange) +// +// await getTransmitTx(registry, keeper3, [upkeepId], { +// startingSignerIndex: 2, +// }) +// maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('13')) +// await verifyConsistentAccounting(maxAllowedSpareChange) +// +// await registry +// .connect(payee1) +// .withdrawPayment( +// await keeper1.getAddress(), +// await nonkeeper.getAddress(), +// ) +// await verifyConsistentAccounting(maxAllowedSpareChange) +// +// await registry +// .connect(payee3) +// .withdrawPayment( +// await keeper3.getAddress(), +// await nonkeeper.getAddress(), +// ) +// await verifyConsistentAccounting(maxAllowedSpareChange) +// +// await registry.connect(owner).setConfigTypeSafe( +// signerAddresses.slice(0, 4), // only use 0-3rd index keepers +// keeperAddresses.slice(0, 4), +// f, +// config, +// offchainVersion, +// offchainBytes, +// ) +// await verifyConsistentAccounting(maxAllowedSpareChange) +// await getTransmitTx(registry, keeper1, [upkeepId]) +// maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('4')) +// await getTransmitTx(registry, keeper3, [upkeepId]) +// maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('4')) +// +// await verifyConsistentAccounting(maxAllowedSpareChange) +// await registry +// .connect(payee5) +// .withdrawPayment( +// await keeper5.getAddress(), +// await nonkeeper.getAddress(), +// ) +// await verifyConsistentAccounting(maxAllowedSpareChange) +// +// await registry +// .connect(payee1) +// .withdrawPayment( +// await keeper1.getAddress(), +// await nonkeeper.getAddress(), +// ) +// await verifyConsistentAccounting(maxAllowedSpareChange) +// }, +// ) +// }) +// }) diff --git a/contracts/test/v0.8/dev/KeeperRegistryCheckUpkeepGasUsageWrapper.test.ts b/contracts/test/v0.8/automation/KeeperRegistryCheckUpkeepGasUsageWrapper.test.ts similarity index 100% rename from contracts/test/v0.8/dev/KeeperRegistryCheckUpkeepGasUsageWrapper.test.ts rename to contracts/test/v0.8/automation/KeeperRegistryCheckUpkeepGasUsageWrapper.test.ts diff --git a/contracts/test/v0.8/automation/LinkAvailableBalanceMonitor.test.ts b/contracts/test/v0.8/automation/LinkAvailableBalanceMonitor.test.ts index 2627bee34a3..816cd03d4d8 100644 --- a/contracts/test/v0.8/automation/LinkAvailableBalanceMonitor.test.ts +++ b/contracts/test/v0.8/automation/LinkAvailableBalanceMonitor.test.ts @@ -26,7 +26,7 @@ const TARGET_PERFORM_GAS_LIMIT = 2_000_000 const TARGET_CHECK_GAS_LIMIT = 3_500_000 // // ////////////////////////////////////////////////////////////////////////////////////////////////// -const INVALID_WATCHLIST_ERR = `InvalidWatchList()` +const INVALID_WATCHLIST_ERR = `InvalidWatchList` const PAUSED_ERR = 'Pausable: paused' const zeroLINK = ethers.utils.parseEther('0') @@ -139,7 +139,7 @@ const setup = async () => { owner, ) const ltFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', + 'src/v0.8/shared/test/helpers/LinkTokenTestHelper.sol:LinkTokenTestHelper', owner, ) @@ -353,7 +353,6 @@ describe('LinkAvailableBalanceMonitor', () => { }) it('Should not allow different length arrays in the watchlist', async () => { - const errMsg = `InvalidWatchList()` let tx = labm .connect(owner) .setWatchList( @@ -362,11 +361,13 @@ describe('LinkAvailableBalanceMonitor', () => { [oneLINK, oneLINK], [1, 2], ) - await expect(tx).to.be.revertedWith(errMsg) + await expect(tx).to.be.revertedWithCustomError( + labm, + INVALID_WATCHLIST_ERR, + ) }) it('Should not allow duplicates in the watchlist', async () => { - const errMsg = `DuplicateAddress("${watchAddress1}")` let tx = labm .connect(owner) .setWatchList( @@ -375,7 +376,9 @@ describe('LinkAvailableBalanceMonitor', () => { [oneLINK, oneLINK, oneLINK], [1, 2, 3], ) - await expect(tx).to.be.revertedWith(errMsg) + await expect(tx) + .to.be.revertedWithCustomError(labm, 'DuplicateAddress') + .withArgs(watchAddress1) }) it('Should not allow strangers to set the watchlist', async () => { @@ -394,7 +397,10 @@ describe('LinkAvailableBalanceMonitor', () => { [oneLINK, oneLINK], [1, 2], ) - await expect(tx).to.be.revertedWith(INVALID_WATCHLIST_ERR) + await expect(tx).to.be.revertedWithCustomError( + labm, + INVALID_WATCHLIST_ERR, + ) }) it('Should allow owner to add multiple addresses with dstChainSelector 0 to the watchlist', async () => { diff --git a/contracts/test/v0.8/automation/UpkeepBalanceMonitor.test.ts b/contracts/test/v0.8/automation/UpkeepBalanceMonitor.test.ts index 259a9c3b9f8..0ee244130ab 100644 --- a/contracts/test/v0.8/automation/UpkeepBalanceMonitor.test.ts +++ b/contracts/test/v0.8/automation/UpkeepBalanceMonitor.test.ts @@ -27,7 +27,7 @@ const setup = async () => { stranger = accounts[1] const ltFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', + 'src/v0.8/shared/test/helpers/LinkTokenTestHelper.sol:LinkTokenTestHelper', owner, ) linkToken = (await ltFactory.deploy()) as LinkToken @@ -321,7 +321,10 @@ describe('UpkeepBalanceMonitor', () => { it('cannot be called by a non-owner', async () => { await expect( upkeepBalanceMonitor.connect(stranger).topUp([], [], []), - ).to.be.revertedWith('OnlyForwarderOrOwner()') + ).to.be.revertedWithCustomError( + upkeepBalanceMonitor, + 'OnlyForwarderOrOwner', + ) }) it('should revert if the contract is paused', async () => { diff --git a/contracts/test/v0.8/automation/UpkeepTranscoder.test.ts b/contracts/test/v0.8/automation/UpkeepTranscoder.test.ts index 6ce7673a228..fc3a2009567 100644 --- a/contracts/test/v0.8/automation/UpkeepTranscoder.test.ts +++ b/contracts/test/v0.8/automation/UpkeepTranscoder.test.ts @@ -1,6 +1,6 @@ import { ethers } from 'hardhat' import { assert } from 'chai' -import { evmRevert } from '../../test-helpers/matchers' +import { evmRevert, evmRevertCustomError } from '../../test-helpers/matchers' import { UpkeepTranscoder__factory as UpkeepTranscoderFactory } from '../../../typechain/factories/UpkeepTranscoder__factory' import { UpkeepTranscoder } from '../../../typechain' @@ -35,9 +35,10 @@ describe('UpkeepTranscoder', () => { }) it('reverts if the from type != to type', async () => { - await evmRevert( + await evmRevertCustomError( transcoder.transcodeUpkeeps(1, 2, encodedData), - 'InvalidTranscoding()', + transcoder, + 'InvalidTranscoding', ) }) diff --git a/contracts/test/v0.8/automation/UpkeepTranscoder3_0.test.ts b/contracts/test/v0.8/automation/UpkeepTranscoder3_0.test.ts index 2f0f169ab1f..d58cfd377f7 100644 --- a/contracts/test/v0.8/automation/UpkeepTranscoder3_0.test.ts +++ b/contracts/test/v0.8/automation/UpkeepTranscoder3_0.test.ts @@ -128,7 +128,7 @@ before(async () => { personas = (await getUsers()).personas linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', + 'src/v0.8/shared/test/helpers/LinkTokenTestHelper.sol:LinkTokenTestHelper', ) // need full path because there are two contracts with name MockV3Aggregator mockV3AggregatorFactory = (await ethers.getContractFactory( diff --git a/contracts/test/v0.8/automation/UpkeepTranscoder4_0.test.ts b/contracts/test/v0.8/automation/UpkeepTranscoder4_0.test.ts index 970054893d2..392a1cb5966 100644 --- a/contracts/test/v0.8/automation/UpkeepTranscoder4_0.test.ts +++ b/contracts/test/v0.8/automation/UpkeepTranscoder4_0.test.ts @@ -330,7 +330,7 @@ const setup = async () => { transcoder = await upkeepTranscoderFactory.connect(owner).deploy() linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', + 'src/v0.8/shared/test/helpers/LinkTokenTestHelper.sol:LinkTokenTestHelper', ) linkToken = await linkTokenFactory.connect(owner).deploy() // need full path because there are two contracts with name MockV3Aggregator diff --git a/contracts/test/v0.8/automation/helpers.ts b/contracts/test/v0.8/automation/helpers.ts index ea88f9d3e50..5a95fb482cd 100644 --- a/contracts/test/v0.8/automation/helpers.ts +++ b/contracts/test/v0.8/automation/helpers.ts @@ -8,7 +8,7 @@ import { IAutomationRegistryMaster as IAutomationRegistry } from '../../../typec import { IAutomationRegistryMaster__factory as IAutomationRegistryMasterFactory } from '../../../typechain/factories/IAutomationRegistryMaster__factory' import { assert } from 'chai' import { FunctionFragment } from '@ethersproject/abi' -import { AutomationRegistryLogicB2_3__factory as AutomationRegistryLogicB2_3Factory } from '../../../typechain/factories/AutomationRegistryLogicB2_3__factory' +import { AutomationRegistryLogicC2_3__factory as AutomationRegistryLogicC2_3Factory } from '../../../typechain/factories/AutomationRegistryLogicC2_3__factory' import { IAutomationRegistryMaster2_3 as IAutomationRegistry2_3 } from '../../../typechain/IAutomationRegistryMaster2_3' import { IAutomationRegistryMaster2_3__factory as IAutomationRegistryMaster2_3Factory } from '../../../typechain/factories/IAutomationRegistryMaster2_3__factory' @@ -109,6 +109,11 @@ export const assertSatisfiesInterface = ( continue } + // addFunds is a payable function starting from v2.3, skipping the stateMutability check + if (functionName === 'addFunds(uint256,uint96)') { + continue + } + const propertiesToMatch: (keyof FunctionFragment)[] = [ 'constant', 'stateMutability', @@ -162,14 +167,21 @@ export const deployRegistry22 = async ( export const deployRegistry23 = async ( from: Signer, - link: Parameters[0], - linkUSD: Parameters[1], - nativeUSD: Parameters[2], - fastgas: Parameters[2], + link: Parameters[0], + linkUSD: Parameters[1], + nativeUSD: Parameters[2], + fastgas: Parameters[2], allowedReadOnlyAddress: Parameters< - AutomationRegistryLogicB2_3Factory['deploy'] + AutomationRegistryLogicC2_3Factory['deploy'] >[3], + payoutMode: Parameters[6], + wrappedNativeTokenAddress: Parameters< + AutomationRegistryLogicC2_3Factory['deploy'] + >[7], ): Promise => { + const logicCFactory = await ethers.getContractFactory( + 'AutomationRegistryLogicC2_3', + ) const logicBFactory = await ethers.getContractFactory( 'AutomationRegistryLogicB2_3', ) @@ -183,7 +195,7 @@ export const deployRegistry23 = async ( 'AutomationForwarderLogic', ) const forwarderLogic = await forwarderLogicFactory.connect(from).deploy() - const logicB = await logicBFactory + const logicC = await logicCFactory .connect(from) .deploy( link, @@ -192,7 +204,10 @@ export const deployRegistry23 = async ( fastgas, forwarderLogic.address, allowedReadOnlyAddress, + payoutMode, + wrappedNativeTokenAddress, ) + const logicB = await logicBFactory.connect(from).deploy(logicC.address) const logicA = await logicAFactory.connect(from).deploy(logicB.address) const master = await registryFactory.connect(from).deploy(logicA.address) return IAutomationRegistryMaster2_3Factory.connect(master.address, from) diff --git a/contracts/test/cross-version/directory.test.ts b/contracts/test/v0.8/directory.test.ts similarity index 100% rename from contracts/test/cross-version/directory.test.ts rename to contracts/test/v0.8/directory.test.ts diff --git a/contracts/test/v0.8/functions/v1/Functions.test.ts b/contracts/test/v0.8/functions/v1/Functions.test.ts deleted file mode 100644 index 14a68c211b9..00000000000 --- a/contracts/test/v0.8/functions/v1/Functions.test.ts +++ /dev/null @@ -1,172 +0,0 @@ -import { ethers } from 'hardhat' -import { - publicAbi, - decodeDietCBOR, - hexToBuf, -} from '../../../test-helpers/helpers' -import { assert, expect } from 'chai' -import { Contract, ContractFactory, providers, Signer } from 'ethers' -import { Roles, getUsers } from '../../../test-helpers/setup' -import { makeDebug } from '../../../test-helpers/debug' - -const debug = makeDebug('FunctionsTestHelper') -let concreteFunctionsTestHelperFactory: ContractFactory - -let roles: Roles - -before(async () => { - roles = (await getUsers()).roles - concreteFunctionsTestHelperFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v1_X/testhelpers/FunctionsTestHelper.sol:FunctionsTestHelper', - roles.defaultAccount, - ) -}) - -describe('FunctionsTestHelper', () => { - let ctr: Contract - let defaultAccount: Signer - - beforeEach(async () => { - defaultAccount = roles.defaultAccount - ctr = await concreteFunctionsTestHelperFactory - .connect(defaultAccount) - .deploy() - }) - - it('has a limited public interface [ @skip-coverage ]', () => { - expect( - publicAbi(ctr, [ - 'closeEvent', - 'initializeRequestForInlineJavaScript', - 'addSecretsReference', - 'addTwoArgs', - 'addEmptyArgs', - ]), - ).to.equal(true) - }) - - async function parseRequestDataEvent(tx: providers.TransactionResponse) { - const receipt = await tx.wait() - const data = receipt.logs?.[0].data - const d = debug.extend('parseRequestDataEvent') - d('data %s', data) - return ethers.utils.defaultAbiCoder.decode(['bytes'], data ?? '') - } - - describe('#closeEvent', () => { - it('handles empty request', async () => { - const tx = await ctr.closeEvent() - const [payload] = await parseRequestDataEvent(tx) - const decoded = await decodeDietCBOR(payload) - assert.deepEqual( - { - ...decoded, - language: decoded.language.toNumber(), - codeLocation: decoded.codeLocation.toNumber(), - }, - { - language: 0, - codeLocation: 0, - source: '', - }, - ) - }) - }) - - describe('#initializeRequestForInlineJavaScript', () => { - it('emits simple CBOR encoded request for js', async () => { - const js = 'function run(args, responses) {}' - await ctr.initializeRequestForInlineJavaScript(js) - const tx = await ctr.closeEvent() - const [payload] = await parseRequestDataEvent(tx) - const decoded = await decodeDietCBOR(payload) - assert.deepEqual( - { - ...decoded, - language: decoded.language.toNumber(), - codeLocation: decoded.codeLocation.toNumber(), - }, - { - language: 0, - codeLocation: 0, - source: js, - }, - ) - }) - }) - - describe('#initializeRequestForInlineJavaScript to revert', () => { - it('reverts with EmptySource() if source param is empty', async () => { - await expect( - ctr.initializeRequestForInlineJavaScript(''), - ).to.be.revertedWith('EmptySource()') - }) - }) - - describe('#addSecrets', () => { - it('emits CBOR encoded request with js and secrets', async () => { - const js = 'function run(args, responses) {}' - const secrets = '0xA161616162' - await ctr.initializeRequestForInlineJavaScript(js) - await ctr.addSecretsReference(secrets) - const tx = await ctr.closeEvent() - const [payload] = await parseRequestDataEvent(tx) - const decoded = await decodeDietCBOR(payload) - assert.deepEqual( - { - ...decoded, - language: decoded.language.toNumber(), - codeLocation: decoded.codeLocation.toNumber(), - secretsLocation: decoded.secretsLocation.toNumber(), - }, - { - language: 0, - codeLocation: 0, - source: js, - secretsLocation: 1, - secrets: hexToBuf(secrets), - }, - ) - }) - }) - - describe('#addSecrets to revert', () => { - it('reverts with EmptySecrets() if secrets param is empty', async () => { - const js = 'function run(args, responses) {}' - await ctr.initializeRequestForInlineJavaScript(js) - await expect(ctr.addSecretsReference('0x')).to.be.revertedWith( - 'EmptySecrets()', - ) - }) - }) - - describe('#addArgs', () => { - it('emits CBOR encoded request with js and args', async () => { - const js = 'function run(args, responses) {}' - await ctr.initializeRequestForInlineJavaScript(js) - await ctr.addTwoArgs('arg1', 'arg2') - const tx = await ctr.closeEvent() - const [payload] = await parseRequestDataEvent(tx) - const decoded = await decodeDietCBOR(payload) - assert.deepEqual( - { - ...decoded, - language: decoded.language.toNumber(), - codeLocation: decoded.codeLocation.toNumber(), - }, - { - language: 0, - codeLocation: 0, - source: js, - args: ['arg1', 'arg2'], - }, - ) - }) - }) - - describe('#addEmptyArgs to revert', () => { - it('reverts with EmptyArgs() if args param is empty', async () => { - await expect(ctr.addEmptyArgs()).to.be.revertedWith('EmptyArgs()') - }) - }) -}) diff --git a/contracts/test/v0.8/functions/v1/FunctionsClient.test.ts b/contracts/test/v0.8/functions/v1/FunctionsClient.test.ts deleted file mode 100644 index 826953fb2c4..00000000000 --- a/contracts/test/v0.8/functions/v1/FunctionsClient.test.ts +++ /dev/null @@ -1,227 +0,0 @@ -import { ethers } from 'hardhat' -import { assert, expect } from 'chai' -import { decodeDietCBOR, stringToBytes } from '../../../test-helpers/helpers' -import { - getSetupFactory, - FunctionsContracts, - FunctionsRoles, - anyValue, - ids, - createSubscription, - getEventArg, - parseOracleRequestEventArgs, - encodeReport, -} from './utils' - -const setup = getSetupFactory() -let contracts: FunctionsContracts -let roles: FunctionsRoles - -beforeEach(async () => { - ;({ contracts, roles } = setup()) -}) - -describe('Functions Client', () => { - describe('#sendSimpleRequestWithJavaScript', () => { - it('emits events from the client and the oracle contracts', async () => { - const subscriptionId = await createSubscription( - roles.subOwner, - [contracts.client.address], - contracts.router, - contracts.accessControl, - contracts.linkToken, - ) - const flags = - '0x0101010101010101010101010101010101010101010101010101010101010101' - const callbackGas = 100_000 - await contracts.router.setFlags(subscriptionId, flags) - const defaultAccountAddress = await roles.defaultAccount.getAddress() - await expect( - contracts.client - .connect(roles.defaultAccount) - .sendSimpleRequestWithJavaScript( - 'return `hello world`', - subscriptionId, - ids.donId, - callbackGas, - ), - ) - .to.emit(contracts.client, 'RequestSent') - .withArgs(anyValue) - .to.emit(contracts.coordinator, 'OracleRequest') - .withArgs( - anyValue, - contracts.client.address, - defaultAccountAddress, - subscriptionId, - roles.subOwnerAddress, - anyValue, - anyValue, - flags, - callbackGas, - anyValue, - ) - }) - - it('respects gas flag setting', async () => { - const subscriptionId = await createSubscription( - roles.subOwner, - [contracts.client.address], - contracts.router, - contracts.accessControl, - contracts.linkToken, - ) - const flags = - '0x0101010101010101010101010101010101010101010101010101010101010101' - await contracts.router.setFlags(subscriptionId, flags) - await expect( - contracts.client - .connect(roles.defaultAccount) - .sendSimpleRequestWithJavaScript( - 'return `hello world`', - subscriptionId, - ids.donId, - 400_000, - ), - ) - .to.emit(contracts.client, 'RequestSent') - .to.emit(contracts.coordinator, 'OracleRequest') - await expect( - contracts.client - .connect(roles.defaultAccount) - .sendSimpleRequestWithJavaScript( - 'return `hello world`', - subscriptionId, - ids.donId, - 600_000, // limit set by gas flag == 1 is 500_000 - ), - ).to.be.revertedWith('GasLimitTooBig(500000)') - }) - - it('encodes user request to CBOR', async () => { - const subscriptionId = await createSubscription( - roles.subOwner, - [contracts.client.address], - contracts.router, - contracts.accessControl, - contracts.linkToken, - ) - const js = 'function run(){return response}' - const tx = await contracts.client.sendSimpleRequestWithJavaScript( - js, - subscriptionId, - ids.donId, - 20_000, - ) - const args = await parseOracleRequestEventArgs(tx) - assert.equal(args.length, 5) - const decoded = await decodeDietCBOR(args[3]) - assert.deepEqual( - { - ...decoded, - language: decoded.language.toNumber(), - codeLocation: decoded.codeLocation.toNumber(), - }, - { - language: 0, - codeLocation: 0, - source: js, - }, - ) - }) - }) - - describe('#fulfillRequest', () => { - it('emits fulfillment events', async () => { - const subscriptionId = await createSubscription( - roles.subOwner, - [contracts.client.address], - contracts.router, - contracts.accessControl, - contracts.linkToken, - ) - const tx = await contracts.client.sendSimpleRequestWithJavaScript( - 'function run(){return response}', - subscriptionId, - ids.donId, - 20_000, - ) - const { events } = await tx.wait() - const requestId = getEventArg(events, 'RequestSent', 0) - await expect(tx) - .to.emit(contracts.client, 'RequestSent') - .withArgs(requestId) - - const response = stringToBytes('response') - const error = stringToBytes('') - const oracleRequestEvent = await contracts.coordinator.queryFilter( - contracts.coordinator.filters.OracleRequest(), - ) - const onchainMetadata = oracleRequestEvent[0].args?.['commitment'] - const report = await encodeReport( - ethers.utils.hexZeroPad(requestId, 32), - response, - error, - onchainMetadata, - stringToBytes(''), - ) - await expect(contracts.coordinator.callReport(report)) - .to.emit(contracts.coordinator, 'OracleResponse') - .withArgs(requestId, await roles.defaultAccount.getAddress()) - .to.emit(contracts.client, 'FulfillRequestInvoked') - .withArgs(requestId, response, error) - }) - }) -}) - -describe('Faulty Functions Client', () => { - it('can complete requests with an empty callback', async () => { - const clientWithEmptyCallbackTestHelperFactory = - await ethers.getContractFactory( - 'src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientWithEmptyCallback.sol:FunctionsClientWithEmptyCallback', - roles.consumer, - ) - - const clientWithEmptyCallback = - await clientWithEmptyCallbackTestHelperFactory - .connect(roles.consumer) - .deploy(contracts.router.address) - - const subscriptionId = await createSubscription( - roles.subOwner, - [clientWithEmptyCallback.address], - contracts.router, - contracts.accessControl, - contracts.linkToken, - ) - const tx = await clientWithEmptyCallback.sendSimpleRequestWithJavaScript( - 'function run(){return response}', - subscriptionId, - ids.donId, - 20_000, - ) - const { events } = await tx.wait() - const requestId = getEventArg(events, 'RequestSent', 0) - await expect(tx) - .to.emit(clientWithEmptyCallback, 'RequestSent') - .withArgs(requestId) - - const response = stringToBytes('response') - const error = stringToBytes('') - const oracleRequestEvent = await contracts.coordinator.queryFilter( - contracts.coordinator.filters.OracleRequest(), - ) - const onchainMetadata = oracleRequestEvent[0].args?.['commitment'] - const report = await encodeReport( - ethers.utils.hexZeroPad(requestId, 32), - response, - error, - onchainMetadata, - stringToBytes(''), - ) - await expect(contracts.coordinator.callReport(report)) - .to.emit(contracts.coordinator, 'OracleResponse') - .withArgs(requestId, await roles.defaultAccount.getAddress()) - .to.emit(contracts.router, 'RequestProcessed') - }) -}) diff --git a/contracts/test/v0.8/functions/v1/FunctionsCoordinator.test.ts b/contracts/test/v0.8/functions/v1/FunctionsCoordinator.test.ts deleted file mode 100644 index 89444ca8661..00000000000 --- a/contracts/test/v0.8/functions/v1/FunctionsCoordinator.test.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { expect } from 'chai' -import { - getSetupFactory, - FunctionsContracts, - coordinatorConfig, - FunctionsRoles, -} from './utils' - -const setup = getSetupFactory() -let contracts: FunctionsContracts -let roles: FunctionsRoles - -beforeEach(async () => { - ;({ contracts, roles } = setup()) -}) - -describe('Functions Coordinator', () => { - describe('Config', () => { - it('non-owner is unable to update config', async () => { - await expect( - contracts.coordinator - .connect(roles.stranger) - .updateConfig(coordinatorConfig), - ).to.be.revertedWith('Only callable by owner') - }) - - it('Owner can update config', async () => { - const beforeConfig = await contracts.coordinator.getConfig() - await expect( - contracts.coordinator.updateConfig({ - ...coordinatorConfig, - donFee: 10, - }), - ).to.emit(contracts.coordinator, 'ConfigUpdated') - const afterConfig = await contracts.coordinator.getConfig() - expect(beforeConfig).to.not.equal(afterConfig) - }) - - it('returns the config set', async () => { - const config = await contracts.coordinator - .connect(roles.stranger) - .getConfig() - await Promise.all( - Object.keys(coordinatorConfig).map((key) => - expect(config[key]).to.equal( - coordinatorConfig[key as keyof typeof coordinatorConfig], - ), - ), - ) - }) - - it('#fulfillmentGasPriceOverEstimationBP overestimates gas cost', async () => { - const estimateWithNoOverestimaton = - await contracts.coordinator.estimateCost(1, 0x0, 100_000, 2000000000) - - await contracts.coordinator.updateConfig({ - ...coordinatorConfig, - fulfillmentGasPriceOverEstimationBP: 10_000, - }) - - // Halve the gas price, which should be the same estimate because of fulfillmentGasPriceOverEstimationBP doubling the gas price - const estimateWithOverestimaton = - await contracts.coordinator.estimateCost(1, 0x0, 100_000, 1000000000) - - expect(estimateWithNoOverestimaton).to.equal(estimateWithOverestimaton) - }) - }) -}) diff --git a/contracts/test/v0.8/functions/v1/FunctionsRouter.test.ts b/contracts/test/v0.8/functions/v1/FunctionsRouter.test.ts deleted file mode 100644 index e484283e80b..00000000000 --- a/contracts/test/v0.8/functions/v1/FunctionsRouter.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { expect } from 'chai' -import { ethers } from 'hardhat' -import { stringToBytes } from '../../../test-helpers/helpers' -import { - getSetupFactory, - FunctionsContracts, - functionsRouterConfig, - FunctionsRoles, -} from './utils' - -const setup = getSetupFactory() -let contracts: FunctionsContracts -let roles: FunctionsRoles - -beforeEach(async () => { - ;({ contracts, roles } = setup()) -}) - -describe('Functions Router - Request lifecycle', () => { - describe('Config', () => { - it('#typeAndVersion', async () => { - expect(await contracts.router.typeAndVersion()).to.be.equal( - 'Functions Router v2.0.0', - ) - }) - it('non-owner is unable to update config', async () => { - await expect( - contracts.router - .connect(roles.stranger) - .updateConfig(functionsRouterConfig), - ).to.be.revertedWith('Only callable by owner') - }) - - it('owner can update config', async () => { - const beforeConfig = await contracts.router.getConfig() - await expect( - contracts.router.updateConfig({ - ...functionsRouterConfig, - adminFee: 10, - }), - ).to.emit(contracts.router, 'ConfigUpdated') - const afterConfig = await contracts.router.getConfig() - expect(beforeConfig).to.not.equal(afterConfig) - }) - - it('returns the config set', async () => { - const config = await contracts.router.connect(roles.stranger).getConfig() - await Promise.all( - Object.keys(functionsRouterConfig).map((key) => - expect(config[key]).to.deep.equal( - functionsRouterConfig[key as keyof typeof functionsRouterConfig], - ), - ), - ) - }) - }) - describe('Allow List path', () => { - it('non-owner is unable to set Allow List ID', async () => { - await expect( - contracts.router - .connect(roles.stranger) - .setAllowListId(ethers.utils.hexZeroPad(stringToBytes(''), 32)), - ).to.be.revertedWith('Only callable by owner') - }) - }) -}) diff --git a/contracts/test/v0.8/functions/v1/FunctionsSubscriptions.test.ts b/contracts/test/v0.8/functions/v1/FunctionsSubscriptions.test.ts deleted file mode 100644 index 86cfb9dd5fc..00000000000 --- a/contracts/test/v0.8/functions/v1/FunctionsSubscriptions.test.ts +++ /dev/null @@ -1,862 +0,0 @@ -import { ethers } from 'hardhat' -import { expect } from 'chai' -import { BigNumber } from 'ethers' -import { randomAddressString } from 'hardhat/internal/hardhat-network/provider/utils/random' -import { - getSetupFactory, - FunctionsContracts, - FunctionsRoles, - createSubscription, - acceptTermsOfService, - ids, - getEventArg, - accessControlMockPrivateKey, - encodeReport, -} from './utils' -import { stringToBytes } from '../../../test-helpers/helpers' - -const setup = getSetupFactory() -let contracts: FunctionsContracts -let roles: FunctionsRoles - -const donLabel = ethers.utils.formatBytes32String('1') - -beforeEach(async () => { - ;({ contracts, roles } = setup()) -}) - -describe('Functions Router - Subscriptions', () => { - describe('Subscription management', () => { - describe('#createSubscription', async function () { - it('can create a subscription', async function () { - await acceptTermsOfService( - contracts.accessControl, - roles.subOwner, - roles.subOwnerAddress, - ) - await expect( - contracts.router.connect(roles.subOwner).createSubscription(), - ) - .to.emit(contracts.router, 'SubscriptionCreated') - .withArgs(1, roles.subOwnerAddress) - const s = await contracts.router.getSubscription(1) - expect(s.balance.toString()).to.equal('0') - expect(s.owner).to.equal(roles.subOwnerAddress) - }) - it('subscription id increments', async function () { - await acceptTermsOfService( - contracts.accessControl, - roles.subOwner, - roles.subOwnerAddress, - ) - await expect( - contracts.router.connect(roles.subOwner).createSubscription(), - ) - .to.emit(contracts.router, 'SubscriptionCreated') - .withArgs(1, roles.subOwnerAddress) - await expect( - contracts.router.connect(roles.subOwner).createSubscription(), - ) - .to.emit(contracts.router, 'SubscriptionCreated') - .withArgs(2, roles.subOwnerAddress) - }) - it('cannot create more than the max', async function () { - const subId = createSubscription( - roles.subOwner, - [], - contracts.router, - contracts.accessControl, - ) - for (let i = 0; i < 100; i++) { - await contracts.router - .connect(roles.subOwner) - .addConsumer(subId, randomAddressString()) - } - await expect( - contracts.router - .connect(roles.subOwner) - .addConsumer(subId, randomAddressString()), - ).to.be.revertedWith(`TooManyConsumers`) - }) - }) - - describe('#proposeSubscriptionOwnerTransfer', async function () { - let subId: number - beforeEach(async () => { - subId = await createSubscription( - roles.subOwner, - [roles.consumerAddress], - contracts.router, - contracts.accessControl, - ) - }) - it('rejects non-owner', async function () { - await expect( - contracts.router - .connect(roles.stranger) - .proposeSubscriptionOwnerTransfer(subId, roles.strangerAddress), - ).to.be.revertedWith(`MustBeSubscriptionOwner()`) - }) - it('owner can request transfer', async function () { - await expect( - contracts.router - .connect(roles.subOwner) - .proposeSubscriptionOwnerTransfer(subId, roles.strangerAddress), - ) - .to.emit(contracts.router, 'SubscriptionOwnerTransferRequested') - .withArgs(subId, roles.subOwnerAddress, roles.strangerAddress) - // Same request reverts - await expect( - contracts.router - .connect(roles.subOwner) - .proposeSubscriptionOwnerTransfer(subId, roles.strangerAddress), - ).to.be.revertedWith('InvalidCalldata') - }) - }) - - describe('#acceptSubscriptionOwnerTransfer', async function () { - let subId: number - beforeEach(async () => { - subId = await createSubscription( - roles.subOwner, - [roles.consumerAddress], - contracts.router, - contracts.accessControl, - ) - }) - it('subscription must exist', async function () { - // 0x0 is requested owner - await expect( - contracts.router - .connect(roles.subOwner) - .acceptSubscriptionOwnerTransfer(1203123123), - ).to.be.revertedWith(`MustBeProposedOwner`) - }) - it('must be requested owner to accept', async function () { - await expect( - contracts.router - .connect(roles.subOwner) - .proposeSubscriptionOwnerTransfer(subId, roles.strangerAddress), - ) - await expect( - contracts.router - .connect(roles.subOwner) - .acceptSubscriptionOwnerTransfer(subId), - ).to.be.revertedWith(`MustBeProposedOwner`) - }) - it('requested owner can accept', async function () { - await acceptTermsOfService( - contracts.accessControl, - roles.stranger, - roles.strangerAddress, - ) - await expect( - contracts.router - .connect(roles.subOwner) - .proposeSubscriptionOwnerTransfer(subId, roles.strangerAddress), - ) - .to.emit(contracts.router, 'SubscriptionOwnerTransferRequested') - .withArgs(subId, roles.subOwnerAddress, roles.strangerAddress) - await expect( - contracts.router - .connect(roles.stranger) - .acceptSubscriptionOwnerTransfer(subId), - ) - .to.emit(contracts.router, 'SubscriptionOwnerTransferred') - .withArgs(subId, roles.subOwnerAddress, roles.strangerAddress) - }) - }) - - describe('#addConsumer', async function () { - let subId: number - beforeEach(async () => { - subId = await createSubscription( - roles.subOwner, - [roles.consumerAddress], - contracts.router, - contracts.accessControl, - ) - }) - it('subscription must exist', async function () { - await expect( - contracts.router - .connect(roles.subOwner) - .addConsumer(1203123123, roles.strangerAddress), - ).to.be.revertedWith(`InvalidSubscription`) - }) - it('must be owner', async function () { - await expect( - contracts.router - .connect(roles.stranger) - .addConsumer(subId, roles.strangerAddress), - ).to.be.revertedWith(`MustBeSubscriptionOwner()`) - }) - it('add is idempotent', async function () { - await contracts.router - .connect(roles.subOwner) - .addConsumer(subId, roles.strangerAddress) - await expect( - contracts.router - .connect(roles.subOwner) - .addConsumer(subId, roles.strangerAddress), - ).to.not.be.reverted - }) - it('cannot add more than maximum', async function () { - // There is one consumer, add another 99 to hit the max - for (let i = 0; i < 99; i++) { - await contracts.router - .connect(roles.subOwner) - .addConsumer(subId, randomAddressString()) - } - // Adding one more should fail - // await contracts.router.connect(roles.subOwner).addConsumer(subId, roles.strangerAddress); - await expect( - contracts.router - .connect(roles.subOwner) - .addConsumer(subId, roles.strangerAddress), - ).to.be.revertedWith(`TooManyConsumers`) - // Same is true if we first create with the maximum - const consumers: string[] = [] - for (let i = 0; i < 100; i++) { - consumers.push(randomAddressString()) - } - subId = await createSubscription( - roles.subOwner, - consumers, - contracts.router, - contracts.accessControl, - ) - await expect( - contracts.router - .connect(roles.subOwner) - .addConsumer(subId, roles.strangerAddress), - ).to.be.revertedWith(`TooManyConsumers`) - }) - it('owner can update', async function () { - await expect( - contracts.router - .connect(roles.subOwner) - .addConsumer(subId, roles.strangerAddress), - ) - .to.emit(contracts.router, 'SubscriptionConsumerAdded') - .withArgs(subId, roles.strangerAddress) - }) - }) - - describe('#removeConsumer', async function () { - let subId: number - beforeEach(async () => { - subId = await createSubscription( - roles.subOwner, - [roles.consumerAddress], - contracts.router, - contracts.accessControl, - ) - }) - it('subscription must exist', async function () { - await expect( - contracts.router - .connect(roles.subOwner) - .removeConsumer(1203123123, roles.strangerAddress), - ).to.be.revertedWith(`InvalidSubscription`) - }) - it('must be owner', async function () { - await expect( - contracts.router - .connect(roles.stranger) - .removeConsumer(subId, roles.strangerAddress), - ).to.be.revertedWith(`MustBeSubscriptionOwner()`) - }) - it('owner can update', async function () { - const subBefore = await contracts.router.getSubscription(subId) - await contracts.router - .connect(roles.subOwner) - .addConsumer(subId, roles.strangerAddress) - await expect( - contracts.router - .connect(roles.subOwner) - .removeConsumer(subId, roles.strangerAddress), - ) - .to.emit(contracts.router, 'SubscriptionConsumerRemoved') - .withArgs(subId, roles.strangerAddress) - const subAfter = await contracts.router.getSubscription(subId) - // Subscription should NOT contain the removed consumer - expect(subBefore.consumers).to.deep.equal(subAfter.consumers) - }) - it('can remove all consumers', async function () { - // Testing the handling of zero. - await contracts.router - .connect(roles.subOwner) - .addConsumer(subId, roles.strangerAddress) - await contracts.router - .connect(roles.subOwner) - .removeConsumer(subId, roles.strangerAddress) - await contracts.router - .connect(roles.subOwner) - .removeConsumer(subId, roles.consumerAddress) - // Should be empty - const subAfter = await contracts.router.getSubscription(subId) - expect(subAfter.consumers).to.deep.equal([]) - }) - }) - - describe('#pendingRequestExists', async function () { - let subId: number - beforeEach(async () => { - subId = await createSubscription( - roles.subOwner, - [roles.consumerAddress], - contracts.router, - contracts.accessControl, - ) - - await contracts.linkToken - .connect(roles.subOwner) - .transferAndCall( - contracts.router.address, - BigNumber.from('130790416713017745'), - ethers.utils.defaultAbiCoder.encode(['uint64'], [subId]), - ) - await contracts.router - .connect(roles.subOwner) - .addConsumer(subId, contracts.client.address) - }) - it('returns false when there is no latest pending request', async function () { - expect( - await contracts.router - .connect(roles.subOwner) - .pendingRequestExists(subId), - ).to.be.false - }) - it('returns true when the latest request is pending', async function () { - await contracts.client - .connect(roles.consumer) - .sendSimpleRequestWithJavaScript( - `return 'hello world'`, - subId, - donLabel, - 20_000, - ) - expect( - await contracts.router - .connect(roles.subOwner) - .pendingRequestExists(subId), - ).to.be.true - }) - }) - - describe('#cancelSubscription', async function () { - let subId: number - beforeEach(async () => { - subId = await createSubscription( - roles.subOwner, - [roles.consumerAddress], - contracts.router, - contracts.accessControl, - ) - }) - it('subscription must exist', async function () { - await expect( - contracts.router - .connect(roles.subOwner) - .cancelSubscription(1203123123, roles.subOwnerAddress), - ).to.be.revertedWith(`InvalidSubscription`) - }) - it('must be owner', async function () { - await expect( - contracts.router - .connect(roles.stranger) - .cancelSubscription(subId, roles.subOwnerAddress), - ).to.be.revertedWith(`MustBeSubscriptionOwner()`) - }) - it('can cancel', async function () { - const strangerBalanceBefore = await contracts.linkToken.balanceOf( - roles.strangerAddress, - ) - await contracts.linkToken - .connect(roles.subOwner) - .transferAndCall( - contracts.router.address, - BigNumber.from('1000'), - ethers.utils.defaultAbiCoder.encode(['uint64'], [subId]), - ) - await expect( - contracts.router - .connect(roles.subOwner) - .cancelSubscription(subId, roles.strangerAddress), - ) - .to.emit(contracts.router, 'SubscriptionCanceled') - .withArgs(subId, roles.strangerAddress, BigNumber.from('0')) - const strangerBalance = await contracts.linkToken.balanceOf( - roles.strangerAddress, - ) - expect(strangerBalance.toString()).to.equal( - strangerBalanceBefore.toString(), - ) - await expect( - contracts.router.connect(roles.subOwner).getSubscription(subId), - ).to.be.revertedWith('InvalidSubscription') - }) - it('can add same consumer after canceling', async function () { - await contracts.linkToken - .connect(roles.subOwner) - .transferAndCall( - contracts.router.address, - BigNumber.from('1000'), - ethers.utils.defaultAbiCoder.encode(['uint64'], [subId]), - ) - await contracts.router - .connect(roles.subOwner) - .addConsumer(subId, roles.strangerAddress) - await contracts.router - .connect(roles.subOwner) - .cancelSubscription(subId, roles.strangerAddress) - subId = await createSubscription( - roles.subOwner, - [roles.consumerAddress], - contracts.router, - contracts.accessControl, - ) - // The cancel should have removed this consumer, so we can add it again. - await expect( - contracts.router - .connect(roles.subOwner) - .addConsumer(subId, roles.strangerAddress), - ).to.not.be.reverted - }) - it('cannot cancel with pending request', async function () { - await contracts.linkToken - .connect(roles.subOwner) - .transferAndCall( - contracts.router.address, - BigNumber.from('130790416713017745'), - ethers.utils.defaultAbiCoder.encode(['uint64'], [subId]), - ) - await contracts.router - .connect(roles.subOwner) - .addConsumer(subId, contracts.client.address) - await contracts.client - .connect(roles.consumer) - .sendSimpleRequestWithJavaScript( - `return 'hello world'`, - subId, - donLabel, - 20_000, - ) - // Should revert with outstanding requests - await expect( - contracts.router - .connect(roles.subOwner) - .cancelSubscription(subId, roles.strangerAddress), - ).to.be.revertedWith('CannotRemoveWithPendingRequests()') - // However the owner is able to cancel - // funds go to the sub owner. - await expect( - contracts.router - .connect(roles.defaultAccount) - .ownerCancelSubscription(subId), - ) - .to.emit(contracts.router, 'SubscriptionCanceled') - .withArgs( - subId, - roles.subOwnerAddress, - BigNumber.from('130790416713017745'), - ) - }) - }) - - describe('#recoverFunds', async function () { - let subId: number - beforeEach(async () => { - subId = await createSubscription( - roles.subOwner, - [roles.consumerAddress], - contracts.router, - contracts.accessControl, - ) - }) - - it('function that should change internal balance do', async function () { - type bf = [() => Promise, BigNumber] - const balanceChangingFns: Array = [ - [ - async function () { - const s = ethers.utils.defaultAbiCoder.encode(['uint64'], [subId]) - await contracts.linkToken - .connect(roles.subOwner) - .transferAndCall( - contracts.router.address, - BigNumber.from('1000'), - s, - ) - }, - BigNumber.from('1000'), - ], - [ - async function () { - await contracts.router - .connect(roles.subOwner) - .cancelSubscription(subId, roles.strangerAddress) - }, - BigNumber.from('0'), - ], - ] - for (const [fn, expectedBalanceChange] of balanceChangingFns) { - const startingBalance = await contracts.router.getTotalBalance() - await fn() - const endingBalance = await contracts.router.getTotalBalance() - expect(endingBalance.sub(startingBalance.toString())).to.equal( - expectedBalanceChange.toString(), - ) - } - }) - it('only owner can recover', async function () { - await expect( - contracts.router - .connect(roles.subOwner) - .recoverFunds(roles.strangerAddress), - ).to.be.revertedWith('Only callable by owner') - }) - - it('owner can recover link transferred', async function () { - // Set the internal balance - expect( - await contracts.linkToken.balanceOf(roles.strangerAddress), - ).to.equal(BigNumber.from('1000000000000000000')) - const subscription = ethers.utils.defaultAbiCoder.encode( - ['uint64'], - [subId], - ) - await contracts.linkToken - .connect(roles.subOwner) - .transferAndCall( - contracts.router.address, - BigNumber.from('1000'), - subscription, - ) - // Circumvent internal balance - await contracts.linkToken - .connect(roles.subOwner) - .transfer(contracts.router.address, BigNumber.from('1000')) - // Should recover this 1000 - await expect( - contracts.router - .connect(roles.defaultAccount) - .recoverFunds(roles.strangerAddress), - ) - .to.emit(contracts.router, 'FundsRecovered') - .withArgs(roles.strangerAddress, BigNumber.from('1000')) - expect( - await contracts.linkToken.balanceOf(roles.strangerAddress), - ).to.equal(BigNumber.from('1000000000000001000')) - }) - }) - }) - - describe('#oracleWithdraw', async function () { - it('cannot withdraw with no balance', async function () { - await expect( - contracts.router - .connect(roles.oracleNode) - .oracleWithdraw(randomAddressString(), BigNumber.from('100')), - ).to.be.revertedWith(`InsufficientBalance`) - }) - }) - - describe('#ownerWithdraw', async function () { - it('cannot withdraw more than balance', async function () { - await expect( - contracts.router.oracleWithdraw( - randomAddressString(), - BigNumber.from('100'), - ), - ).to.be.revertedWith(`InsufficientBalance`) - }) - }) - - describe('#flagsSet', async function () { - it('get flags that were previously set', async function () { - const flags = ethers.utils.formatBytes32String('arbitrary_byte_values') - await acceptTermsOfService( - contracts.accessControl, - roles.subOwner, - roles.subOwnerAddress, - ) - await expect( - contracts.router.connect(roles.subOwner).createSubscription(), - ) - .to.emit(contracts.router, 'SubscriptionCreated') - .withArgs(1, roles.subOwnerAddress) - await contracts.router.setFlags(1, flags) - expect(await contracts.router.getFlags(1)).to.equal(flags) - }) - }) - - describe('#reentrancy', async function () { - // Use a fixed gas price for these tests - const gasPrice = 3000000000 // 3 gwei - - it('allows callbacks to start another request if they have sufficient funds', async function () { - const subscriptionId = await createSubscription( - roles.subOwner, - [contracts.client.address], - contracts.router, - contracts.accessControl, - contracts.linkToken, - ) - - // Set test helper flag - await contracts.client.setDoValidReentrantOperation( - true, - subscriptionId, - ids.donId, - ) - - // Set flag so they have enough callback gas - const flags = new Uint8Array(32) - flags[0] = 1 - await contracts.router - .connect(roles.defaultAccount) - .setFlags(subscriptionId, flags) - - // Send request - const tx = await contracts.client.sendSimpleRequestWithJavaScript( - 'function run(){return response}', - subscriptionId, - ids.donId, - 400_000, - { gasPrice }, - ) - const { events } = await tx.wait() - const requestId = getEventArg(events, 'RequestSent', 0) - await expect(tx) - .to.emit(contracts.client, 'RequestSent') - .withArgs(requestId) - - const response = stringToBytes('response') - const error = stringToBytes('') - const oracleRequestEvent = await contracts.coordinator.queryFilter( - contracts.coordinator.filters.OracleRequest(), - ) - const onchainMetadata = oracleRequestEvent[0].args?.['commitment'] - const offchainMetadata = stringToBytes('') - const report = await encodeReport( - ethers.utils.hexZeroPad(requestId, 32), - response, - error, - onchainMetadata, - offchainMetadata, - ) - - await expect(contracts.coordinator.callReport(report, { gasPrice })) - .to.emit(contracts.coordinator, 'OracleResponse') - .withArgs(requestId, await roles.defaultAccount.getAddress()) - .to.emit(contracts.router, 'RequestProcessed') - .withArgs( - requestId, - subscriptionId, - () => true, - () => true, - 0, // Result code for callback failing - () => true, - () => true, - () => true, - ) - .to.emit(contracts.client, 'FulfillRequestInvoked') - .withArgs(requestId, response, error) - .to.emit(contracts.client, 'SendRequestInvoked') - }) - - it('prevents callbacks from starting another request if have insufficient funds', async function () { - await acceptTermsOfService( - contracts.accessControl, - roles.subOwner, - roles.subOwnerAddress, - ) - const createSubTx = await contracts.router - .connect(roles.subOwner) - .createSubscription() - const createSubReceipt = await createSubTx.wait() - const subscriptionId = - createSubReceipt.events[0].args['subscriptionId'].toNumber() - await contracts.router - .connect(roles.subOwner) - .addConsumer(subscriptionId, contracts.client.address) - await contracts.linkToken - .connect(roles.subOwner) - .transferAndCall( - contracts.router.address, - BigNumber.from('300000000000000000'), - ethers.utils.defaultAbiCoder.encode(['uint64'], [subscriptionId]), - ) - - // Set test helper flag - await contracts.client.setDoValidReentrantOperation( - true, - subscriptionId, - ids.donId, - ) - - // Set flag so they have enough callback gas - const flags = new Uint8Array(32) - flags[0] = 1 - await contracts.router - .connect(roles.defaultAccount) - .setFlags(subscriptionId, flags) - - // Send request - const tx = await contracts.client.sendSimpleRequestWithJavaScript( - 'function run(){return response}', - subscriptionId, - ids.donId, - 400_000, - { gasPrice }, - ) - const { events } = await tx.wait() - const requestId = getEventArg(events, 'RequestSent', 0) - await expect(tx) - .to.emit(contracts.client, 'RequestSent') - .withArgs(requestId) - - const response = stringToBytes('response') - const error = stringToBytes('') - const oracleRequestEvent = await contracts.coordinator.queryFilter( - contracts.coordinator.filters.OracleRequest(), - ) - const onchainMetadata = oracleRequestEvent[0].args?.['commitment'] - const offchainMetadata = stringToBytes('') - const report = await encodeReport( - ethers.utils.hexZeroPad(requestId, 32), - response, - error, - onchainMetadata, - offchainMetadata, - ) - - await expect(contracts.coordinator.callReport(report, { gasPrice })) - .to.emit(contracts.coordinator, 'OracleResponse') - .withArgs(requestId, await roles.defaultAccount.getAddress()) - .to.emit(contracts.client, 'FulfillRequestInvoked') - .withArgs(requestId, response, error) - .to.emit(contracts.router, 'RequestProcessed') - .withArgs( - requestId, - subscriptionId, - () => true, - () => true, - 1, // Result code for callback failing - () => true, - () => true, - () => true, - ) - }) - - it('callbacks are unable to improperly use subscription methods', async function () { - await acceptTermsOfService( - contracts.accessControl, - roles.subOwner, - roles.subOwnerAddress, - ) - const createSubTx = await contracts.router - .connect(roles.subOwner) - .createSubscription() - const createSubReceipt = await createSubTx.wait() - const subscriptionId = - createSubReceipt.events[0].args['subscriptionId'].toNumber() - await contracts.router - .connect(roles.subOwner) - .addConsumer(subscriptionId, contracts.client.address) - await contracts.linkToken - .connect(roles.subOwner) - .transferAndCall( - contracts.router.address, - BigNumber.from('1000000000000000000'), - ethers.utils.defaultAbiCoder.encode(['uint64'], [subscriptionId]), - ) - - // Set flag so they have enough callback gas - const flags = new Uint8Array(32) - flags[0] = 1 - await contracts.router - .connect(roles.defaultAccount) - .setFlags(subscriptionId, flags) - - // Accept ToS for client contract - const acceptorAddress = roles.subOwnerAddress - const recipientAddress = contracts.client.address - const message = await contracts.accessControl.getMessage( - acceptorAddress, - recipientAddress, - ) - const wallet = new ethers.Wallet(accessControlMockPrivateKey) - const flatSignature = await wallet.signMessage( - ethers.utils.arrayify(message), - ) - const { r, s, v } = ethers.utils.splitSignature(flatSignature) - await contracts.client - .connect(roles.subOwner) - .acceptTermsOfService(acceptorAddress, recipientAddress, r, s, v) - - // Transfer Subscription ownership to client contract so that it can call subscription methods - await contracts.router - .connect(roles.subOwner) - .proposeSubscriptionOwnerTransfer( - subscriptionId, - contracts.client.address, - ) - await contracts.client.acceptSubscriptionOwnerTransfer(subscriptionId) - - // Set test helper flag - await contracts.client.setDoInvalidReentrantOperation( - true, - subscriptionId, - ) - - // Send request - const tx = await contracts.client.sendSimpleRequestWithJavaScript( - 'function run(){return response}', - subscriptionId, - ids.donId, - 400_000, - { gasPrice }, - ) - const { events } = await tx.wait() - const requestId = getEventArg(events, 'RequestSent', 0) - await expect(tx) - .to.emit(contracts.client, 'RequestSent') - .withArgs(requestId) - - const response = stringToBytes('response') - const error = stringToBytes('') - const oracleRequestEvent = await contracts.coordinator.queryFilter( - contracts.coordinator.filters.OracleRequest(), - ) - const onchainMetadata = oracleRequestEvent[0].args?.['commitment'] - const offchainMetadata = stringToBytes('') - const report = await encodeReport( - ethers.utils.hexZeroPad(requestId, 32), - response, - error, - onchainMetadata, - offchainMetadata, - ) - - await expect(contracts.coordinator.callReport(report, { gasPrice })) - .to.emit(contracts.coordinator, 'OracleResponse') - .withArgs(requestId, await roles.defaultAccount.getAddress()) - .to.emit(contracts.client, 'FulfillRequestInvoked') - .withArgs(requestId, response, error) - .to.emit(contracts.router, 'RequestProcessed') - .withArgs( - requestId, - subscriptionId, - () => true, - () => true, - 1, // Result code for callback failing - () => true, - () => true, - () => true, - ) - }) - }) -}) diff --git a/contracts/test/v0.8/functions/v1/GasGolf.test.ts b/contracts/test/v0.8/functions/v1/GasGolf.test.ts deleted file mode 100644 index 32cc660beda..00000000000 --- a/contracts/test/v0.8/functions/v1/GasGolf.test.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { ethers } from 'hardhat' -import { BigNumber } from 'ethers' -import { - accessControlMockPrivateKey, - encodeReport, - FunctionsContracts, - FunctionsRoles, - getEventArg, - getSetupFactory, - ids, -} from './utils' -import { stringToBytes } from '../../../test-helpers/helpers' - -const setup = getSetupFactory() -let contracts: FunctionsContracts -let roles: FunctionsRoles - -const baselineGasUsed = 721271 -let currentGasUsed = 0 - -beforeEach(async () => { - ;({ contracts, roles } = setup()) -}) - -after(() => { - const score = currentGasUsed - baselineGasUsed - console.log(`\n ⛳ Par : ${baselineGasUsed} gas`) - console.log(`\n 🏌️ You : ${currentGasUsed} gas`) - console.log(`\n 🚩 Score : ${score} gas`) -}) - -describe('Gas Golf', () => { - it('taking a swing', async () => { - // User signs Terms of Service - const message = await contracts.accessControl.getMessage( - roles.consumerAddress, - roles.consumerAddress, - ) - const wallet = new ethers.Wallet(accessControlMockPrivateKey) - const flatSignature = await wallet.signMessage( - ethers.utils.arrayify(message), - ) - const { r, s, v } = ethers.utils.splitSignature(flatSignature) - const acceptTermsOfServiceTx = await contracts.accessControl - .connect(roles.consumer) - .acceptTermsOfService( - roles.consumerAddress, - roles.consumerAddress, - r, - s, - v, - ) - const { gasUsed: acceptTermsOfServiceGasUsed } = - await acceptTermsOfServiceTx.wait() - - // User creates a new Subscription - const createSubscriptionTx = await contracts.router - .connect(roles.consumer) - .createSubscription() - const createSubscriptionTxReceipt = await createSubscriptionTx.wait() - const createSubscriptionTxGasUsed = createSubscriptionTxReceipt.gasUsed - const subscriptionId = - createSubscriptionTxReceipt.events[0].args['subscriptionId'].toNumber() - - // User adds a consuming contract to their Subscription - const addConsumerTx = await contracts.router - .connect(roles.consumer) - .addConsumer(subscriptionId, contracts.client.address) - const { gasUsed: addConsumerTxGasUsed } = await addConsumerTx.wait() - - // User funds their subscription - const transferAndCallTx = await contracts.linkToken - .connect(roles.subOwner) - .transferAndCall( - contracts.router.address, - BigNumber.from('54666805176129187'), - ethers.utils.defaultAbiCoder.encode(['uint64'], [subscriptionId]), - ) - const { gasUsed: transferAndCallTxGasUsed } = await transferAndCallTx.wait() - - // User sends request - const requestTx = await contracts.client.sendSimpleRequestWithJavaScript( - 'function myFancyFunction(){return "woah, thats fancy"}', - subscriptionId, - ids.donId, - 20_000, - ) - const { gasUsed: requestTxGasUsed, events } = await requestTx.wait() - const requestId = getEventArg(events, 'RequestSent', 0) - const oracleRequestEvent = await contracts.coordinator.queryFilter( - contracts.coordinator.filters.OracleRequest(), - ) - // DON's transmitter submits a response - const response = stringToBytes('woah, thats fancy') - const error = stringToBytes('') - const onchainMetadata = oracleRequestEvent[0].args?.['commitment'] - const offchainMetadata = stringToBytes('') - const report = await encodeReport( - ethers.utils.hexZeroPad(requestId, 32), - response, - error, - onchainMetadata, - offchainMetadata, - ) - const fulfillmentTx = await contracts.coordinator.callReport(report) - const { gasUsed: fulfillmentTxGasUsed } = await fulfillmentTx.wait() - - currentGasUsed = acceptTermsOfServiceGasUsed - .add(createSubscriptionTxGasUsed) - .add(addConsumerTxGasUsed) - .add(transferAndCallTxGasUsed) - .add(requestTxGasUsed) - .add(fulfillmentTxGasUsed) - .toNumber() - }) -}) diff --git a/contracts/test/v0.8/functions/v1/RouterBase.test.ts b/contracts/test/v0.8/functions/v1/RouterBase.test.ts deleted file mode 100644 index 92f9c7d320b..00000000000 --- a/contracts/test/v0.8/functions/v1/RouterBase.test.ts +++ /dev/null @@ -1,160 +0,0 @@ -import { ethers } from 'hardhat' -import { expect } from 'chai' -import { - getSetupFactory, - coordinatorConfig, - FunctionsContracts, - FunctionsFactories, - FunctionsRoles, - ids, - createSubscription, - encodeReport, - stringToHex, - getEventArg, -} from './utils' - -const setup = getSetupFactory() -let contracts: FunctionsContracts -let factories: FunctionsFactories -let roles: FunctionsRoles - -beforeEach(async () => { - ;({ contracts, factories, roles } = setup()) -}) - -describe('FunctionsRouter - Base', () => { - describe('Updates', () => { - it('One or more contracts on a route can be updated by the owner', async () => { - const coordinator2 = await factories.functionsCoordinatorFactory - .connect(roles.defaultAccount) - .deploy( - contracts.router.address, - coordinatorConfig, - contracts.mockLinkEth.address, - contracts.mockLinkUsd.address, - ) - const coordinator3 = await factories.functionsCoordinatorFactory - .connect(roles.defaultAccount) - .deploy( - contracts.router.address, - coordinatorConfig, - contracts.mockLinkEth.address, - contracts.mockLinkUsd.address, - ) - const coordinator4 = await factories.functionsCoordinatorFactory - .connect(roles.defaultAccount) - .deploy( - contracts.router.address, - coordinatorConfig, - contracts.mockLinkEth.address, - contracts.mockLinkUsd.address, - ) - - await expect( - contracts.router['getContractById(bytes32)'](ids.donId2), - ).to.be.revertedWith('RouteNotFound') - await expect( - contracts.router['getContractById(bytes32)'](ids.donId3), - ).to.be.revertedWith('RouteNotFound') - await expect( - contracts.router['getContractById(bytes32)'](ids.donId4), - ).to.be.revertedWith('RouteNotFound') - await expect( - contracts.router.proposeContractsUpdate( - [ids.donId2, ids.donId3, ids.donId4], - [coordinator2.address, coordinator3.address, coordinator4.address], - ), - ).to.emit(contracts.router, `ContractProposed`) - - const subscriptionId = await createSubscription( - roles.subOwner, - [contracts.client.address], - contracts.router, - contracts.accessControl, - contracts.linkToken, - ) - - const requestProposedTx = await contracts.client.sendRequestProposed( - `return 'hello world'`, - subscriptionId, - ids.donId2, - ) - - const { events } = await requestProposedTx.wait() - const requestId = getEventArg(events, 'RequestSent', 0) - - const oracleRequestEvent = await coordinator2.queryFilter( - contracts.coordinator.filters.OracleRequest(), - ) - const onchainMetadata = oracleRequestEvent[0].args?.['commitment'] - const report = await encodeReport( - ethers.utils.hexZeroPad(requestId, 32), - stringToHex('hello world'), - stringToHex(''), - onchainMetadata, - stringToHex(''), - ) - - await expect( - coordinator2 - .connect(roles.oracleNode) - .callReport(report, { gasLimit: 500_000 }), - ).to.emit(contracts.client, 'FulfillRequestInvoked') - - await expect(contracts.router.updateContracts()).to.emit( - contracts.router, - 'ContractUpdated', - ) - expect( - await contracts.router['getContractById(bytes32)'](ids.donId2), - ).to.equal(coordinator2.address) - expect( - await contracts.router['getContractById(bytes32)'](ids.donId3), - ).to.equal(coordinator3.address) - expect( - await contracts.router['getContractById(bytes32)'](ids.donId4), - ).to.equal(coordinator4.address) - }) - - it('non-owner is unable to propose contract updates', async () => { - await expect( - contracts.router - .connect(roles.stranger) - .proposeContractsUpdate([ids.donId], [contracts.coordinator.address]), - ).to.be.revertedWith('Only callable by owner') - }) - - it('non-owner is unable to apply contract updates', async () => { - await expect( - contracts.router.connect(roles.stranger).updateContracts(), - ).to.be.revertedWith('Only callable by owner') - }) - }) - - describe('Emergency Pause', () => { - it('has paused state visible', async () => { - const paused = await contracts.router.paused() - expect(paused).to.equal(false) - }) - it('can pause the system', async () => { - const subscriptionId = await createSubscription( - roles.subOwner, - [contracts.client.address], - contracts.router, - contracts.accessControl, - contracts.linkToken, - ) - - await contracts.router.pause() - - await expect( - contracts.client.sendSimpleRequestWithJavaScript( - `return 'hello world'`, - subscriptionId, - ids.donId, - 20_000, - ), - ).to.be.revertedWith('Pausable: paused') - }) - }) -}) diff --git a/contracts/test/v0.8/functions/v1/TermsOfServiceAllowList.test.ts b/contracts/test/v0.8/functions/v1/TermsOfServiceAllowList.test.ts deleted file mode 100644 index 1e1ad18a7d6..00000000000 --- a/contracts/test/v0.8/functions/v1/TermsOfServiceAllowList.test.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { ethers } from 'hardhat' -import { expect } from 'chai' -import { - getSetupFactory, - FunctionsContracts, - FunctionsRoles, - acceptTermsOfService, - accessControlMockPrivateKey, - accessControlConfig, -} from './utils' - -const setup = getSetupFactory() -let contracts: FunctionsContracts -let roles: FunctionsRoles - -beforeEach(async () => { - ;({ contracts, roles } = setup()) -}) - -describe('ToS Access Control', () => { - describe('Config', () => { - it('non-owner is unable to update config', async () => { - await expect( - contracts.accessControl - .connect(roles.stranger) - .updateConfig(accessControlConfig), - ).to.be.revertedWith('Only callable by owner') - }) - - it('Owner can update config', async () => { - const beforeConfig = await contracts.accessControl.getConfig() - await expect( - contracts.accessControl.updateConfig({ - ...accessControlConfig, - enabled: false, - }), - ).to.emit(contracts.accessControl, 'ConfigUpdated') - const afterConfig = await contracts.accessControl.getConfig() - expect(beforeConfig).to.not.equal(afterConfig) - }) - it('returns the config set', async () => { - const config = await contracts.accessControl - .connect(roles.stranger) - .getConfig() - await Promise.all( - Object.keys(accessControlConfig).map((key) => { - expect(config[key]).to.equal( - accessControlConfig[key as keyof typeof accessControlConfig], - ) - }), - ) - }) - }) - - describe('Accepting', () => { - it('can only be done with a valid signature', async () => { - const message = await contracts.accessControl.getMessage( - roles.strangerAddress, - roles.strangerAddress, - ) - const flatSignature = await roles.stranger.signMessage( - ethers.utils.arrayify(message), - ) - const { r, s, v } = ethers.utils.splitSignature(flatSignature) - await expect( - contracts.accessControl - .connect(roles.stranger) - .acceptTermsOfService( - roles.strangerAddress, - roles.strangerAddress, - r, - s, - v, - ), - ).to.be.revertedWith('InvalidSignature') - }) - it('can be done by Externally Owned Accounts if recipient themself', async () => { - await acceptTermsOfService( - contracts.accessControl, - roles.subOwner, - roles.subOwnerAddress, - ) - expect( - await contracts.accessControl.hasAccess(roles.subOwnerAddress, '0x'), - ).to.equal(true) - }) - it('cannot be done by Externally Owned Accounts if recipient another EoA', async () => { - await expect( - acceptTermsOfService( - contracts.accessControl, - roles.subOwner, - roles.strangerAddress, - ), - ).to.be.revertedWith('InvalidUsage') - }) - it('can be done by Contract Accounts if recipient themself', async () => { - const acceptorAddress = roles.consumerAddress - const recipientAddress = contracts.client.address - const message = await contracts.accessControl.getMessage( - acceptorAddress, - recipientAddress, - ) - const wallet = new ethers.Wallet(accessControlMockPrivateKey) - const flatSignature = await wallet.signMessage( - ethers.utils.arrayify(message), - ) - const { r, s, v } = ethers.utils.splitSignature(flatSignature) - await contracts.client - .connect(roles.consumer) - .acceptTermsOfService(acceptorAddress, recipientAddress, r, s, v) - - expect( - await contracts.accessControl.hasAccess(recipientAddress, '0x'), - ).to.equal(true) - }) - it('cannot be done by Contract Accounts that if they are not the recipient', async () => { - const acceptorAddress = roles.consumerAddress - const recipientAddress = contracts.coordinator.address - const message = await contracts.accessControl.getMessage( - acceptorAddress, - recipientAddress, - ) - const wallet = new ethers.Wallet(accessControlMockPrivateKey) - const flatSignature = await wallet.signMessage( - ethers.utils.arrayify(message), - ) - const { r, s, v } = ethers.utils.splitSignature(flatSignature) - await expect( - contracts.client - .connect(roles.consumer) - .acceptTermsOfService(acceptorAddress, recipientAddress, r, s, v), - ).to.be.revertedWith('InvalidUsage') - }) - }) - - describe('Blocking', () => { - it('can only be done by the Router Owner', async () => { - await expect( - contracts.accessControl - .connect(roles.stranger) - .blockSender(roles.subOwnerAddress), - ).to.be.revertedWith('Only callable by owner') - }) - it('removes the ability to re-accept the terms of service', async () => { - await contracts.accessControl.blockSender(roles.subOwnerAddress) - await expect( - acceptTermsOfService( - contracts.accessControl, - roles.subOwner, - roles.subOwnerAddress, - ), - ).to.be.revertedWith('RecipientIsBlocked') - }) - it('removes the ability to manage subscriptions', async () => { - await acceptTermsOfService( - contracts.accessControl, - roles.subOwner, - roles.subOwnerAddress, - ) - await contracts.accessControl.blockSender(roles.subOwnerAddress) - await expect( - contracts.router.connect(roles.subOwner).createSubscription(), - ).to.be.revertedWith('SenderMustAcceptTermsOfService') - }) - }) -}) diff --git a/contracts/test/v0.8/functions/v1/utils.ts b/contracts/test/v0.8/functions/v1/utils.ts deleted file mode 100644 index dd3853c2d9d..00000000000 --- a/contracts/test/v0.8/functions/v1/utils.ts +++ /dev/null @@ -1,355 +0,0 @@ -import { ethers } from 'hardhat' -import { BigNumber, ContractFactory, Signer, Contract, providers } from 'ethers' -import { Roles, getUsers } from '../../../test-helpers/setup' -import { EventFragment } from 'ethers/lib/utils' - -export type FunctionsRoles = Roles & { - subOwner: Signer - subOwnerAddress: string - consumer: Signer - consumerAddress: string - stranger: Signer - strangerAddress: string -} - -export type FunctionsFactories = { - functionsRouterFactory: ContractFactory - functionsCoordinatorFactory: ContractFactory - clientTestHelperFactory: ContractFactory - linkTokenFactory: ContractFactory - mockAggregatorV3Factory: ContractFactory - accessControlFactory: ContractFactory -} -export type FunctionsContracts = { - router: Contract - coordinator: Contract - client: Contract - linkToken: Contract - mockLinkEth: Contract - mockLinkUsd: Contract - accessControl: Contract -} - -export const ids = { - routerId: ethers.utils.formatBytes32String(''), - donId: ethers.utils.formatBytes32String('1'), - donId2: ethers.utils.formatBytes32String('2'), - donId3: ethers.utils.formatBytes32String('3'), - donId4: ethers.utils.formatBytes32String('4'), - donId5: ethers.utils.formatBytes32String('5'), -} - -export const anyValue = () => true - -export const stringToHex = (s: string) => { - return ethers.utils.hexlify(ethers.utils.toUtf8Bytes(s)) -} - -export const encodeReport = async ( - requestId: string, - result: string, - err: string, - onchainMetadata: any, - offchainMetadata: string, -) => { - const functionsResponse = await ethers.getContractFactory( - 'src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol:FunctionsCoordinator', - ) - const onchainMetadataBytes = functionsResponse.interface._abiCoder.encode( - [ - getEventInputs( - Object.values(functionsResponse.interface.events), - 'OracleRequest', - 9, - ), - ], - [[...onchainMetadata]], - ) - const abi = ethers.utils.defaultAbiCoder - return abi.encode( - ['bytes32[]', 'bytes[]', 'bytes[]', 'bytes[]', 'bytes[]'], - [[requestId], [result], [err], [onchainMetadataBytes], [offchainMetadata]], - ) -} - -export type FunctionsRouterConfig = { - maxConsumersPerSubscription: number - adminFee: number - handleOracleFulfillmentSelector: string - maxCallbackGasLimits: number[] - gasForCallExactCheck: number - subscriptionDepositMinimumRequests: number - subscriptionDepositJuels: BigNumber -} -export const functionsRouterConfig: FunctionsRouterConfig = { - maxConsumersPerSubscription: 100, - adminFee: 0, - handleOracleFulfillmentSelector: '0x0ca76175', - maxCallbackGasLimits: [300_000, 500_000, 1_000_000], - gasForCallExactCheck: 5000, - subscriptionDepositMinimumRequests: 10, - subscriptionDepositJuels: BigNumber.from('1000000000000000000'), -} -export type CoordinatorConfig = { - feedStalenessSeconds: number - gasOverheadBeforeCallback: number - gasOverheadAfterCallback: number - requestTimeoutSeconds: number - donFeeCentsUsd: number - maxSupportedRequestDataVersion: number - fulfillmentGasPriceOverEstimationBP: number - fallbackNativePerUnitLink: BigNumber - minimumEstimateGasPriceWei: number - operationFeeCentsUsd: number - fallbackUsdPerUnitLink: number - fallbackUsdPerUnitLinkDecimals: number -} -const fallbackNativePerUnitLink = 5000000000000000 -export const coordinatorConfig: CoordinatorConfig = { - feedStalenessSeconds: 86_400, - gasOverheadBeforeCallback: 44_615, - gasOverheadAfterCallback: 44_615, - requestTimeoutSeconds: 300, - donFeeCentsUsd: 0, - maxSupportedRequestDataVersion: 1, - fulfillmentGasPriceOverEstimationBP: 0, - fallbackNativePerUnitLink: BigNumber.from(fallbackNativePerUnitLink), - minimumEstimateGasPriceWei: 1000000000, - operationFeeCentsUsd: 0, - fallbackUsdPerUnitLink: 1500000000, - fallbackUsdPerUnitLinkDecimals: 8, -} -const linkEthRate = '5021530000000000' -const linkUsdRate = '1500000000' - -export const accessControlMockPublicKey = ethers.utils.getAddress( - '0x32237412cC0321f56422d206e505dB4B3871AF5c', -) -export const accessControlMockPrivateKey = - '2e8c8eaff4159e59711b42424c1555af1b78409e12c6f9c69a6a986d75442b20' -export type AccessControlConfig = { - enabled: boolean - signerPublicKey: string // address -} -export const accessControlConfig: AccessControlConfig = { - enabled: true, - signerPublicKey: accessControlMockPublicKey, -} - -export async function setupRolesAndFactories(): Promise<{ - roles: FunctionsRoles - factories: FunctionsFactories -}> { - const roles = (await getUsers()).roles - const functionsRouterFactory = await ethers.getContractFactory( - 'src/v0.8/functions/dev/v1_X/FunctionsRouter.sol:FunctionsRouter', - roles.defaultAccount, - ) - const functionsCoordinatorFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorTestHelper.sol:FunctionsCoordinatorTestHelper', - roles.defaultAccount, - ) - const accessControlFactory = await ethers.getContractFactory( - 'src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol:TermsOfServiceAllowList', - roles.defaultAccount, - ) - const clientTestHelperFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientTestHelper.sol:FunctionsClientTestHelper', - roles.consumer, - ) - const linkTokenFactory = await ethers.getContractFactory( - 'src/v0.8/mocks/MockLinkToken.sol:MockLinkToken', - roles.defaultAccount, - ) - const mockAggregatorV3Factory = await ethers.getContractFactory( - 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', - roles.defaultAccount, - ) - return { - roles: { - ...roles, - subOwner: roles.consumer, - subOwnerAddress: await roles.consumer.getAddress(), - consumer: roles.consumer2, - consumerAddress: await roles.consumer2.getAddress(), - stranger: roles.stranger, - strangerAddress: await roles.stranger.getAddress(), - }, - factories: { - functionsRouterFactory, - functionsCoordinatorFactory, - clientTestHelperFactory, - linkTokenFactory, - mockAggregatorV3Factory, - accessControlFactory, - }, - } -} - -export async function acceptTermsOfService( - accessControl: Contract, - acceptor: Signer, - recipientAddress: string, -) { - const acceptorAddress = await acceptor.getAddress() - const message = await accessControl.getMessage( - acceptorAddress, - recipientAddress, - ) - const wallet = new ethers.Wallet(accessControlMockPrivateKey) - const flatSignature = await wallet.signMessage(ethers.utils.arrayify(message)) - const { r, s, v } = ethers.utils.splitSignature(flatSignature) - return accessControl - .connect(acceptor) - .acceptTermsOfService(acceptorAddress, recipientAddress, r, s, v) -} - -export async function createSubscription( - owner: Signer, - consumers: string[], - router: Contract, - accessControl: Contract, - linkToken?: Contract, -): Promise { - const ownerAddress = await owner.getAddress() - await acceptTermsOfService(accessControl, owner, ownerAddress) - const tx = await router.connect(owner).createSubscription() - const receipt = await tx.wait() - const subId = receipt.events[0].args['subscriptionId'].toNumber() - for (let i = 0; i < consumers.length; i++) { - await router.connect(owner).addConsumer(subId, consumers[i]) - } - if (linkToken) { - await linkToken - .connect(owner) - .transferAndCall( - router.address, - BigNumber.from('1000000000000000000'), - ethers.utils.defaultAbiCoder.encode(['uint64'], [subId]), - ) - } - return subId -} - -export function getSetupFactory(): () => { - contracts: FunctionsContracts - factories: FunctionsFactories - roles: FunctionsRoles -} { - let contracts: FunctionsContracts - let factories: FunctionsFactories - let roles: FunctionsRoles - - before(async () => { - const { roles: r, factories: f } = await setupRolesAndFactories() - factories = f - roles = r - }) - - beforeEach(async () => { - // Deploy - const linkToken = await factories.linkTokenFactory - .connect(roles.defaultAccount) - .deploy() - - const mockLinkEth = await factories.mockAggregatorV3Factory.deploy( - 0, - BigNumber.from(linkEthRate), - ) - - const mockLinkUsd = await factories.mockAggregatorV3Factory.deploy( - 0, - BigNumber.from(linkUsdRate), - ) - - const router = await factories.functionsRouterFactory - .connect(roles.defaultAccount) - .deploy(linkToken.address, functionsRouterConfig) - - const coordinator = await factories.functionsCoordinatorFactory - .connect(roles.defaultAccount) - .deploy( - router.address, - coordinatorConfig, - mockLinkEth.address, - mockLinkUsd.address, - ) - - const initialAllowedSenders: string[] = [] - const initialBlockedSenders: string[] = [] - const accessControl = await factories.accessControlFactory - .connect(roles.defaultAccount) - .deploy(accessControlConfig, initialAllowedSenders, initialBlockedSenders) - - const client = await factories.clientTestHelperFactory - .connect(roles.consumer) - .deploy(router.address) - - // Setup accounts - await linkToken.transfer( - roles.subOwnerAddress, - BigNumber.from('1000000000000000000'), // 1 LINK - ) - await linkToken.transfer( - roles.strangerAddress, - BigNumber.from('1000000000000000000'), // 1 LINK - ) - - const allowListId = await router.getAllowListId() - await router.proposeContractsUpdate( - [ids.donId, allowListId], - [coordinator.address, accessControl.address], - ) - await router.updateContracts() - - contracts = { - client, - coordinator, - router, - linkToken, - mockLinkEth, - mockLinkUsd, - accessControl, - } - }) - - return () => { - return { contracts, factories, roles } - } -} - -export function getEventArg(events: any, eventName: string, argIndex: number) { - if (Array.isArray(events)) { - const event = events.find((e: any) => e.event === eventName) - if (event && Array.isArray(event.args) && event.args.length > 0) { - return event.args[argIndex] - } - } - return undefined -} - -export function getEventInputs( - events: EventFragment[], - eventName: string, - argIndex: number, -) { - if (Array.isArray(events)) { - const event = events.find((e) => e.name.includes(eventName)) - if (event && Array.isArray(event.inputs) && event.inputs.length > 0) { - return event.inputs[argIndex] - } - } - throw 'Not found' -} - -export async function parseOracleRequestEventArgs( - tx: providers.TransactionResponse, -) { - const receipt = await tx.wait() - const data = receipt.logs?.[1].data - // NOTE: indexed args are on topics, not data - return ethers.utils.defaultAbiCoder.decode( - ['address', 'uint64', 'address', 'bytes', 'uint16'], - data ?? '', - ) -} diff --git a/contracts/test/v0.8/operatorforwarder/AuthorizedForwarder.test.ts b/contracts/test/v0.8/operatorforwarder/AuthorizedForwarder.test.ts index 368d60a46f0..2d6329e221d 100644 --- a/contracts/test/v0.8/operatorforwarder/AuthorizedForwarder.test.ts +++ b/contracts/test/v0.8/operatorforwarder/AuthorizedForwarder.test.ts @@ -18,7 +18,7 @@ before(async () => { roles = users.roles getterSetterFactory = await ethers.getContractFactory( - 'src/v0.4/tests/GetterSetter.sol:GetterSetter', + 'src/v0.8/operatorforwarder/dev/test/testhelpers/GetterSetter.sol:GetterSetter', roles.defaultAccount, ) brokenFactory = await ethers.getContractFactory( @@ -30,7 +30,7 @@ before(async () => { roles.defaultAccount, ) linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', + 'src/v0.8/shared/test/helpers/LinkTokenTestHelper.sol:LinkTokenTestHelper', roles.defaultAccount, ) }) @@ -254,7 +254,7 @@ describe('AuthorizedForwarder', () => { forwarder .connect(roles.defaultAccount) .forward(brokenMock.address, brokenMsgPayload), - "reverted with reason string 'Failure message'", + 'Failure message', ) }) }) @@ -371,7 +371,7 @@ describe('AuthorizedForwarder', () => { forwarder .connect(roles.defaultAccount) .multiForward([brokenMock.address], [brokenMsgPayload]), - "reverted with reason string 'Failure message'", + 'Failure message', ) }) }) @@ -463,7 +463,7 @@ describe('AuthorizedForwarder', () => { forwarder .connect(roles.defaultAccount) .multiForward([brokenMock.address], [brokenMsgPayload]), - "reverted with reason string 'Failure message'", + 'Failure message', ) }) }) @@ -509,7 +509,7 @@ describe('AuthorizedForwarder', () => { [brokenMock.address, mock.address], [brokenMsgPayload, payload], ), - "reverted with reason string 'Failure message'", + 'Failure message', ) await evmRevert( @@ -519,7 +519,7 @@ describe('AuthorizedForwarder', () => { [mock.address, brokenMock.address], [payload, brokenMsgPayload], ), - "reverted with reason string 'Failure message'", + 'Failure message', ) }) }) diff --git a/contracts/test/v0.8/operatorforwarder/ConfirmedOwner.test.ts b/contracts/test/v0.8/operatorforwarder/ConfirmedOwner.test.ts index 3bd347320c5..67caa28bc38 100644 --- a/contracts/test/v0.8/operatorforwarder/ConfirmedOwner.test.ts +++ b/contracts/test/v0.8/operatorforwarder/ConfirmedOwner.test.ts @@ -2,7 +2,7 @@ import { ethers } from 'hardhat' import { publicAbi } from '../../test-helpers/helpers' import { assert, expect } from 'chai' import { Contract, ContractFactory, Signer } from 'ethers' -import { Personas, getUsers } from '../../test-helpers/setup' +import { getUsers, Personas } from '../../test-helpers/setup' import { evmRevert } from '../../test-helpers/matchers' let confirmedOwnerTestHelperFactory: ContractFactory @@ -13,6 +13,7 @@ let owner: Signer let nonOwner: Signer let newOwner: Signer +// TODO rewrite in Foundry before(async () => { const users = await getUsers() personas = users.personas @@ -21,7 +22,7 @@ before(async () => { newOwner = personas.Ned confirmedOwnerTestHelperFactory = await ethers.getContractFactory( - 'src/v0.7/tests/ConfirmedOwnerTestHelper.sol:ConfirmedOwnerTestHelper', + 'src/v0.8/shared/test/testhelpers/ConfirmedOwnerTestHelper.sol:ConfirmedOwnerTestHelper', owner, ) confirmedOwnerFactory = await ethers.getContractFactory( diff --git a/contracts/test/v0.8/operatorforwarder/Operator.test.ts b/contracts/test/v0.8/operatorforwarder/Operator.test.ts index 2c64c2dc93b..0d75d8530a4 100644 --- a/contracts/test/v0.8/operatorforwarder/Operator.test.ts +++ b/contracts/test/v0.8/operatorforwarder/Operator.test.ts @@ -1,13 +1,14 @@ import { ethers } from 'hardhat' import { + getLog, + increaseTime5Minutes, publicAbi, + stringToBytes, toBytes32String, toWei, - stringToBytes, - increaseTime5Minutes, - getLog, } from '../../test-helpers/helpers' import { assert, expect } from 'chai' +import type { providers } from 'ethers' import { BigNumber, constants, @@ -19,10 +20,9 @@ import { } from 'ethers' import { getUsers, Roles } from '../../test-helpers/setup' import { bigNumEquals, evmRevert } from '../../test-helpers/matchers' -import type { providers } from 'ethers' import { - convertCancelParams, convertCancelByRequesterParams, + convertCancelParams, convertFufillParams, convertFulfill2Params, decodeRunRequest, @@ -31,7 +31,6 @@ import { RunRequest, } from '../../test-helpers/oracle' -let v7ConsumerFactory: ContractFactory let basicConsumerFactory: ContractFactory let multiWordConsumerFactory: ContractFactory let gasGuzzlingConsumerFactory: ContractFactory @@ -50,29 +49,26 @@ before(async () => { const users = await getUsers() roles = users.roles - v7ConsumerFactory = await ethers.getContractFactory( - 'src/v0.7/tests/Consumer.sol:Consumer', - ) basicConsumerFactory = await ethers.getContractFactory( - 'src/v0.6/tests/BasicConsumer.sol:BasicConsumer', + 'src/v0.8/operatorforwarder/dev/test/testhelpers/BasicConsumer.sol:BasicConsumer', ) multiWordConsumerFactory = await ethers.getContractFactory( - 'src/v0.7/tests/MultiWordConsumer.sol:MultiWordConsumer', + 'src/v0.8/operatorforwarder/dev/test/testhelpers/MultiWordConsumer.sol:MultiWordConsumer', ) gasGuzzlingConsumerFactory = await ethers.getContractFactory( - 'src/v0.6/tests/GasGuzzlingConsumer.sol:GasGuzzlingConsumer', + 'src/v0.8/operatorforwarder/dev/test/testhelpers/GasGuzzlingConsumer.sol:GasGuzzlingConsumer', ) getterSetterFactory = await ethers.getContractFactory( - 'src/v0.4/tests/GetterSetter.sol:GetterSetter', + 'src/v0.8/operatorforwarder/dev/test/testhelpers/GetterSetter.sol:GetterSetter', ) maliciousRequesterFactory = await ethers.getContractFactory( - 'src/v0.4/tests/MaliciousRequester.sol:MaliciousRequester', + 'src/v0.8/operatorforwarder/dev/test/testhelpers/MaliciousRequester.sol:MaliciousRequester', ) maliciousConsumerFactory = await ethers.getContractFactory( - 'src/v0.4/tests/MaliciousConsumer.sol:MaliciousConsumer', + 'src/v0.8/operatorforwarder/dev/test/testhelpers/MaliciousConsumer.sol:MaliciousConsumer', ) maliciousMultiWordConsumerFactory = await ethers.getContractFactory( - 'src/v0.6/tests/MaliciousMultiWordConsumer.sol:MaliciousMultiWordConsumer', + 'src/v0.8/operatorforwarder/dev/test/testhelpers/MaliciousMultiWordConsumer.sol:MaliciousMultiWordConsumer', ) operatorFactory = await ethers.getContractFactory( 'src/v0.8/operatorforwarder/dev/Operator.sol:Operator', @@ -81,7 +77,7 @@ before(async () => { 'src/v0.8/operatorforwarder/dev/AuthorizedForwarder.sol:AuthorizedForwarder', ) linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', + 'src/v0.8/shared/test/helpers/LinkTokenTestHelper.sol:LinkTokenTestHelper', ) }) @@ -303,10 +299,11 @@ describe('Operator', () => { }) describe('when called with not enough ETH', () => { - it('reverts with subtraction overflow message', async () => { + // Test fails with "Uncaught TypeError: Do not know how to serialize a BigInt" for no clear reason + it.skip('reverts with subtraction overflow message', async () => { const amountToSend = toWei('2') const ethSent = toWei('1') - await evmRevert( + await expect( operator .connect(roles.defaultAccount) .distributeFunds( @@ -316,8 +313,7 @@ describe('Operator', () => { value: ethSent, }, ), - 'Arithmetic operation underflowed or overflowed outside of an unchecked block', - ) + ).to.be.revertedWithPanic(0x11) }) }) @@ -839,19 +835,6 @@ describe('Operator', () => { await evmRevert(link.transferAndCall(operator.address, paid, args2)) }) - describe('when called with a payload less than 2 EVM words + function selector', () => { - it('throws an error', async () => { - const funcSelector = - operatorFactory.interface.getSighash('oracleRequest') - const maliciousData = - funcSelector + - '0000000000000000000000000000000000000000000000000000000000000000000' - await evmRevert( - link.transferAndCall(operator.address, paid, maliciousData), - ) - }) - }) - describe('when called with a payload between 3 and 9 EVM words', () => { it('throws an error', async () => { const funcSelector = @@ -947,32 +930,6 @@ describe('Operator', () => { ) await evmRevert(link.transferAndCall(operator.address, paid, args2)) }) - - describe('when called with a payload less than 2 EVM words + function selector', () => { - it('throws an error', async () => { - const funcSelector = - operatorFactory.interface.getSighash('oracleRequest') - const maliciousData = - funcSelector + - '0000000000000000000000000000000000000000000000000000000000000000000' - await evmRevert( - link.transferAndCall(operator.address, paid, maliciousData), - ) - }) - }) - - describe('when called with a payload between 3 and 9 EVM words', () => { - it('throws an error', async () => { - const funcSelector = - operatorFactory.interface.getSighash('oracleRequest') - const maliciousData = - funcSelector + - '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001' - await evmRevert( - link.transferAndCall(operator.address, paid, maliciousData), - ) - }) - }) }) describe('when dataVersion is higher than 255', () => { @@ -1079,15 +1036,15 @@ describe('Operator', () => { }) describe('when fulfilled with the wrong function', () => { - let v7Consumer + let basicConsumer beforeEach(async () => { - v7Consumer = await v7ConsumerFactory + basicConsumer = await basicConsumerFactory .connect(roles.defaultAccount) .deploy(link.address, operator.address, specId) const paymentAmount = toWei('1') - await link.transfer(v7Consumer.address, paymentAmount) + await link.transfer(basicConsumer.address, paymentAmount) const currency = 'USD' - const tx = await v7Consumer.requestEthereumPrice( + const tx = await basicConsumer.requestEthereumPrice( currency, paymentAmount, ) @@ -1204,15 +1161,16 @@ describe('Operator', () => { ) }) - it('cannot call functions on the LINK token through callbacks', async () => { - await evmRevert( - maliciousRequester.request( - specId, - link.address, - ethers.utils.toUtf8Bytes('transfer(address,uint256)'), - ), - ) - }) + // TODO BCF-3117 + // it('cannot call functions on the LINK token through callbacks', async () => { + // await evmRevert( + // maliciousRequester.request( + // specId, + // link.address, + // ethers.utils.toUtf8Bytes('transfer(address,uint256)'), + // ), + // ) + // }) describe('requester lies about amount of LINK sent', () => { it('the oracle uses the amount of LINK actually paid', async () => { @@ -1746,15 +1704,16 @@ describe('Operator', () => { ) }) - it('cannot call functions on the LINK token through callbacks', async () => { - await evmRevert( - maliciousRequester.request( - specId, - link.address, - ethers.utils.toUtf8Bytes('transfer(address,uint256)'), - ), - ) - }) + // TODO BCF-3117 + // it('cannot call functions on the LINK token through callbacks', async () => { + // await evmRevert( + // maliciousRequester.request( + // specId, + // link.address, + // ethers.utils.toUtf8Bytes('transfer(address,uint256)'), + // ), + // ) + // }) describe('requester lies about amount of LINK sent', () => { it('the oracle uses the amount of LINK actually paid', async () => { @@ -2302,15 +2261,16 @@ describe('Operator', () => { ) }) - it('cannot call functions on the LINK token through callbacks', async () => { - await evmRevert( - maliciousRequester.request( - specId, - link.address, - ethers.utils.toUtf8Bytes('transfer(address,uint256)'), - ), - ) - }) + // TODO BCF-3117 + // it('cannot call functions on the LINK token through callbacks', async () => { + // await evmRevert( + // maliciousRequester.request( + // specId, + // link.address, + // ethers.utils.toUtf8Bytes('transfer(address,uint256)'), + // ), + // ) + // }) describe('requester lies about amount of LINK sent', () => { it('the oracle uses the amount of LINK actually paid', async () => { @@ -2835,15 +2795,16 @@ describe('Operator', () => { ) }) - it('cannot call functions on the LINK token through callbacks', async () => { - await evmRevert( - maliciousRequester.request( - specId, - link.address, - ethers.utils.toUtf8Bytes('transfer(address,uint256)'), - ), - ) - }) + // TODO BCF-3117 + // it('cannot call functions on the LINK token through callbacks', async () => { + // await evmRevert( + // maliciousRequester.request( + // specId, + // link.address, + // ethers.utils.toUtf8Bytes('transfer(address,uint256)'), + // ), + // ) + // }) describe('requester lies about amount of LINK sent', () => { it('the oracle uses the amount of LINK actually paid', async () => { diff --git a/contracts/test/v0.8/operatorforwarder/OperatorFactory.test.ts b/contracts/test/v0.8/operatorforwarder/OperatorFactory.test.ts index 89b6d70b0a0..b9a0fe508b0 100644 --- a/contracts/test/v0.8/operatorforwarder/OperatorFactory.test.ts +++ b/contracts/test/v0.8/operatorforwarder/OperatorFactory.test.ts @@ -16,7 +16,7 @@ before(async () => { roles = users.roles linkTokenFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', + 'src/v0.8/shared/test/helpers/LinkTokenTestHelper.sol:LinkTokenTestHelper', roles.defaultAccount, ) operatorGeneratorFactory = await ethers.getContractFactory( diff --git a/contracts/test/v0.8/dev/BatchBlockhashStore.test.ts b/contracts/test/v0.8/vrf/BatchBlockhashStore.test.ts similarity index 99% rename from contracts/test/v0.8/dev/BatchBlockhashStore.test.ts rename to contracts/test/v0.8/vrf/BatchBlockhashStore.test.ts index 6821184fde1..ebdc17037ce 100644 --- a/contracts/test/v0.8/dev/BatchBlockhashStore.test.ts +++ b/contracts/test/v0.8/vrf/BatchBlockhashStore.test.ts @@ -17,7 +17,7 @@ describe('BatchBlockhashStore', () => { owner = accounts[0] const bhFactory = await ethers.getContractFactory( - 'src/v0.6/BlockhashStore.sol:BlockhashStore', + 'src/v0.8/vrf/dev/BlockhashStore.sol:BlockhashStore', accounts[0], ) diff --git a/contracts/test/v0.8/dev/VRFCoordinatorV2.test.ts b/contracts/test/v0.8/vrf/VRFCoordinatorV2.test.ts similarity index 89% rename from contracts/test/v0.8/dev/VRFCoordinatorV2.test.ts rename to contracts/test/v0.8/vrf/VRFCoordinatorV2.test.ts index 670267471ac..59f3811eedb 100644 --- a/contracts/test/v0.8/dev/VRFCoordinatorV2.test.ts +++ b/contracts/test/v0.8/vrf/VRFCoordinatorV2.test.ts @@ -1,5 +1,5 @@ import { ethers } from 'hardhat' -import { Signer, Contract, BigNumber } from 'ethers' +import { BigNumber, Contract, Signer } from 'ethers' import { assert, expect } from 'chai' import { publicAbi } from '../../test-helpers/helpers' import { randomAddressString } from 'hardhat/internal/hardhat-network/provider/utils/random' @@ -37,17 +37,17 @@ describe('VRFCoordinatorV2', () => { randomAddress = await random.getAddress() oracle = accounts[4] const ltFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', + 'src/v0.8/shared/test/helpers/LinkTokenTestHelper.sol:LinkTokenTestHelper', accounts[0], ) linkToken = await ltFactory.deploy() const bhFactory = await ethers.getContractFactory( - 'src/v0.6/BlockhashStore.sol:BlockhashStore', + 'src/v0.8/vrf/dev/BlockhashStore.sol:BlockhashStore', accounts[0], ) blockHashStore = await bhFactory.deploy() const mockAggregatorV3Factory = await ethers.getContractFactory( - 'src/v0.7/tests/MockV3Aggregator.sol:MockV3Aggregator', + 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', accounts[0], ) mockLinkEth = await mockAggregatorV3Factory.deploy(0, linkEth) @@ -179,7 +179,12 @@ describe('VRFCoordinatorV2', () => { c.weiPerUnitLink, [0, 0, 0, 0, 0, 0, 0, 0, 0], ), - ).to.be.revertedWith('InvalidRequestConfirmations(201, 201, 200)') + ) + .to.be.revertedWithCustomError( + vrfCoordinatorV2, + 'InvalidRequestConfirmations', + ) + .withArgs(201, 201, 200) }) it('positive fallback price', async function () { @@ -194,7 +199,9 @@ describe('VRFCoordinatorV2', () => { 0, [0, 0, 0, 0, 0, 0, 0, 0, 0], ), - ).to.be.revertedWith('InvalidLinkWeiPrice(0)') + ) + .to.be.revertedWithCustomError(vrfCoordinatorV2, 'InvalidLinkWeiPrice') + .withArgs(0) await expect( vrfCoordinatorV2 .connect(owner) @@ -206,7 +213,9 @@ describe('VRFCoordinatorV2', () => { -1, [0, 0, 0, 0, 0, 0, 0, 0, 0], ), - ).to.be.revertedWith('InvalidLinkWeiPrice(-1)') + ) + .to.be.revertedWithCustomError(vrfCoordinatorV2, 'InvalidLinkWeiPrice') + .withArgs(-1) }) }) @@ -261,7 +270,7 @@ describe('VRFCoordinatorV2', () => { vrfCoordinatorV2 .connect(subOwner) .addConsumer(subId, randomAddressString()), - ).to.be.revertedWith(`TooManyConsumers()`) + ).to.be.revertedWithCustomError(vrfCoordinatorV2, `TooManyConsumers`) }) }) @@ -275,7 +284,9 @@ describe('VRFCoordinatorV2', () => { vrfCoordinatorV2 .connect(random) .requestSubscriptionOwnerTransfer(subId, randomAddress), - ).to.be.revertedWith(`MustBeSubOwner("${subOwnerAddress}")`) + ) + .to.be.revertedWithCustomError(vrfCoordinatorV2, `MustBeSubOwner`) + .withArgs(subOwnerAddress) }) it('owner can request transfer', async function () { await expect( @@ -304,7 +315,7 @@ describe('VRFCoordinatorV2', () => { vrfCoordinatorV2 .connect(subOwner) .acceptSubscriptionOwnerTransfer(1203123123), - ).to.be.revertedWith(`InvalidSubscription`) + ).to.be.revertedWithCustomError(vrfCoordinatorV2, `InvalidSubscription`) }) it('must be requested owner to accept', async function () { await expect( @@ -316,7 +327,9 @@ describe('VRFCoordinatorV2', () => { vrfCoordinatorV2 .connect(subOwner) .acceptSubscriptionOwnerTransfer(subId), - ).to.be.revertedWith(`MustBeRequestedOwner("${randomAddress}")`) + ) + .to.be.revertedWithCustomError(vrfCoordinatorV2, `MustBeRequestedOwner`) + .withArgs(randomAddress) }) it('requested owner can accept', async function () { await expect( @@ -344,12 +357,14 @@ describe('VRFCoordinatorV2', () => { vrfCoordinatorV2 .connect(subOwner) .addConsumer(1203123123, randomAddress), - ).to.be.revertedWith(`InvalidSubscription`) + ).to.be.revertedWithCustomError(vrfCoordinatorV2, `InvalidSubscription`) }) it('must be owner', async function () { await expect( vrfCoordinatorV2.connect(random).addConsumer(subId, randomAddress), - ).to.be.revertedWith(`MustBeSubOwner("${subOwnerAddress}")`) + ) + .to.be.revertedWithCustomError(vrfCoordinatorV2, `MustBeSubOwner`) + .withArgs(subOwnerAddress) }) it('add is idempotent', async function () { await vrfCoordinatorV2.connect(subOwner).addConsumer(subId, randomAddress) @@ -366,7 +381,7 @@ describe('VRFCoordinatorV2', () => { // await vrfCoordinatorV2.connect(subOwner).addConsumer(subId, randomAddress); await expect( vrfCoordinatorV2.connect(subOwner).addConsumer(subId, randomAddress), - ).to.be.revertedWith(`TooManyConsumers()`) + ).to.be.revertedWithCustomError(vrfCoordinatorV2, `TooManyConsumers`) // Same is true if we first create with the maximum const consumers: string[] = [] for (let i = 0; i < 100; i++) { @@ -375,7 +390,7 @@ describe('VRFCoordinatorV2', () => { subId = await createSubscriptionWithConsumers(consumers) await expect( vrfCoordinatorV2.connect(subOwner).addConsumer(subId, randomAddress), - ).to.be.revertedWith(`TooManyConsumers()`) + ).to.be.revertedWithCustomError(vrfCoordinatorV2, `TooManyConsumers`) }) it('owner can update', async function () { await expect( @@ -396,12 +411,14 @@ describe('VRFCoordinatorV2', () => { vrfCoordinatorV2 .connect(subOwner) .removeConsumer(1203123123, randomAddress), - ).to.be.revertedWith(`InvalidSubscription`) + ).to.be.revertedWithCustomError(vrfCoordinatorV2, `InvalidSubscription`) }) it('must be owner', async function () { await expect( vrfCoordinatorV2.connect(random).removeConsumer(subId, randomAddress), - ).to.be.revertedWith(`MustBeSubOwner("${subOwnerAddress}")`) + ) + .to.be.revertedWithCustomError(vrfCoordinatorV2, `MustBeSubOwner`) + .withArgs(subOwnerAddress) }) it('owner can update', async function () { const subBefore = await vrfCoordinatorV2.getSubscription(subId) @@ -440,14 +457,16 @@ describe('VRFCoordinatorV2', () => { vrfCoordinatorV2 .connect(subOwner) .cancelSubscription(1203123123, subOwnerAddress), - ).to.be.revertedWith(`InvalidSubscription`) + ).to.be.revertedWithCustomError(vrfCoordinatorV2, `InvalidSubscription`) }) it('must be owner', async function () { await expect( vrfCoordinatorV2 .connect(random) .cancelSubscription(subId, subOwnerAddress), - ).to.be.revertedWith(`MustBeSubOwner("${subOwnerAddress}")`) + ) + .to.be.revertedWithCustomError(vrfCoordinatorV2, `MustBeSubOwner`) + .withArgs(subOwnerAddress) }) it('can cancel', async function () { await linkToken @@ -468,7 +487,7 @@ describe('VRFCoordinatorV2', () => { assert.equal(randomBalance.toString(), '1000000000000001000') await expect( vrfCoordinatorV2.connect(subOwner).getSubscription(subId), - ).to.be.revertedWith('InvalidSubscription') + ).to.be.revertedWithCustomError(vrfCoordinatorV2, 'InvalidSubscription') }) it('can add same consumer after canceling', async function () { await linkToken @@ -511,7 +530,7 @@ describe('VRFCoordinatorV2', () => { vrfCoordinatorV2 .connect(subOwner) .cancelSubscription(subId, randomAddress), - ).to.be.revertedWith('PendingRequestExists()') + ).to.be.revertedWithCustomError(vrfCoordinatorV2, 'PendingRequestExists') // However the owner is able to cancel // funds go to the sub owner. await expect( @@ -617,17 +636,23 @@ describe('VRFCoordinatorV2', () => { // Non-owners cannot change the consumers await expect( vrfCoordinatorV2.connect(random).addConsumer(subId, randomAddress), - ).to.be.revertedWith(`MustBeSubOwner("${subOwnerAddress}")`) + ) + .to.be.revertedWithCustomError(vrfCoordinatorV2, `MustBeSubOwner`) + .withArgs(subOwnerAddress) await expect( vrfCoordinatorV2.connect(random).removeConsumer(subId, randomAddress), - ).to.be.revertedWith(`MustBeSubOwner("${subOwnerAddress}")`) + ) + .to.be.revertedWithCustomError(vrfCoordinatorV2, `MustBeSubOwner`) + .withArgs(subOwnerAddress) // Non-owners cannot ask to transfer ownership await expect( vrfCoordinatorV2 .connect(random) .requestSubscriptionOwnerTransfer(subId, randomAddress), - ).to.be.revertedWith(`MustBeSubOwner("${subOwnerAddress}")`) + ) + .to.be.revertedWithCustomError(vrfCoordinatorV2, `MustBeSubOwner`) + .withArgs(subOwnerAddress) // Owners can request ownership transfership await expect( @@ -641,7 +666,9 @@ describe('VRFCoordinatorV2', () => { // Non-requested owners cannot accept await expect( vrfCoordinatorV2.connect(subOwner).acceptSubscriptionOwnerTransfer(subId), - ).to.be.revertedWith(`MustBeRequestedOwner("${randomAddress}")`) + ) + .to.be.revertedWithCustomError(vrfCoordinatorV2, `MustBeRequestedOwner`) + .withArgs(randomAddress) // Requested owners can accept await expect( @@ -659,7 +686,9 @@ describe('VRFCoordinatorV2', () => { // Non-owners cannot cancel await expect( vrfCoordinatorV2.connect(random).cancelSubscription(subId, randomAddress), - ).to.be.revertedWith(`MustBeSubOwner("${subOwnerAddress}")`) + ) + .to.be.revertedWithCustomError(vrfCoordinatorV2, `MustBeSubOwner`) + .withArgs(subOwnerAddress) await expect( vrfCoordinatorV2 @@ -689,7 +718,7 @@ describe('VRFCoordinatorV2', () => { 1000, // callbackGasLimit 1, // numWords ), - ).to.be.revertedWith(`InvalidSubscription()`) + ).to.be.revertedWithCustomError(vrfCoordinatorV2, `InvalidSubscription`) }) it('invalid consumer', async function () { await expect( @@ -700,9 +729,9 @@ describe('VRFCoordinatorV2', () => { 1000, // callbackGasLimit 1, // numWords ), - ).to.be.revertedWith( - `InvalidConsumer(${subId}, "${randomAddress.toString()}")`, ) + .to.be.revertedWithCustomError(vrfCoordinatorV2, `InvalidConsumer`) + .withArgs(subId, randomAddress) }) it('invalid req confs', async function () { await expect( @@ -713,7 +742,12 @@ describe('VRFCoordinatorV2', () => { 1000, // callbackGasLimit 1, // numWords ), - ).to.be.revertedWith(`InvalidRequestConfirmations(0, 1, 200)`) + ) + .to.be.revertedWithCustomError( + vrfCoordinatorV2, + `InvalidRequestConfirmations`, + ) + .withArgs(0, 1, 200) }) it('gas limit too high', async function () { await linkToken.connect(subOwner).transferAndCall( @@ -729,7 +763,9 @@ describe('VRFCoordinatorV2', () => { 1000001, // callbackGasLimit 1, // numWords ), - ).to.be.revertedWith(`GasLimitTooBig(1000001, 1000000)`) + ) + .to.be.revertedWithCustomError(vrfCoordinatorV2, `GasLimitTooBig`) + .withArgs(1000001, 1000000) }) it('nonce increments', async function () { @@ -817,9 +853,9 @@ describe('VRFCoordinatorV2', () => { 1000, // callbackGasLimit 1, // numWords ), - ).to.be.revertedWith( - `InvalidConsumer(${subId}, "${randomAddress.toString()}")`, ) + .to.be.revertedWithCustomError(vrfCoordinatorV2, `InvalidConsumer`) + .withArgs(subId, randomAddress) }) it('cancel/add subscription invariant', async function () { await linkToken.connect(subOwner).transferAndCall( @@ -841,9 +877,9 @@ describe('VRFCoordinatorV2', () => { 1000, // callbackGasLimit 1, // numWords ), - ).to.be.revertedWith( - `InvalidConsumer(${subId}, "${randomAddress.toString()}")`, ) + .to.be.revertedWithCustomError(vrfCoordinatorV2, `InvalidConsumer`) + .withArgs(subId, randomAddress) }) }) @@ -853,7 +889,7 @@ describe('VRFCoordinatorV2', () => { vrfCoordinatorV2 .connect(oracle) .oracleWithdraw(randomAddressString(), BigNumber.from('100')), - ).to.be.revertedWith(`InsufficientBalance`) + ).to.be.revertedWithCustomError(vrfCoordinatorV2, `InsufficientBalance`) }) }) @@ -894,12 +930,12 @@ describe('VRFCoordinatorV2', () => { 0, // Fee PPM BigNumber.from('1000000000000000000'), ), - ).to.be.revertedWith(`PaymentTooLarge()`) + ).to.be.revertedWithCustomError(vrfCoordinatorV2, `PaymentTooLarge`) }) it('non-positive link wei price should revert', async function () { const mockAggregatorV3Factory = await ethers.getContractFactory( - 'src/v0.7/tests/MockV3Aggregator.sol:MockV3Aggregator', + 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', owner, ) const vrfCoordinatorV2TestHelperFactory = await ethers.getContractFactory( @@ -917,7 +953,9 @@ describe('VRFCoordinatorV2', () => { 0, // Fee PPM BigNumber.from('1000000000000000000'), ), - ).to.be.revertedWith(`InvalidLinkWeiPrice(0)`) + ) + .to.be.revertedWithCustomError(vrfCoordinatorV2, `InvalidLinkWeiPrice`) + .withArgs(0) const mockLinkEthNegative = await mockAggregatorV3Factory.deploy(0, -1) const vrfCoordinatorV2TestHelperNegative = await vrfCoordinatorV2TestHelperFactory.deploy( @@ -931,7 +969,9 @@ describe('VRFCoordinatorV2', () => { 0, // Fee PPM BigNumber.from('1000000000000000000'), ), - ).to.be.revertedWith(`InvalidLinkWeiPrice(-1)`) + ) + .to.be.revertedWithCustomError(vrfCoordinatorV2, `InvalidLinkWeiPrice`) + .withArgs(-1) }) }) @@ -953,7 +993,12 @@ describe('VRFCoordinatorV2', () => { await vrfCoordinatorV2.registerProvingKey(subOwnerAddress, testKey) await expect( vrfCoordinatorV2.registerProvingKey(subOwnerAddress, testKey), - ).to.be.revertedWith(`ProvingKeyAlreadyRegistered("${kh}")`) + ) + .to.be.revertedWithCustomError( + vrfCoordinatorV2, + `ProvingKeyAlreadyRegistered`, + ) + .withArgs(kh) }) it('deregister key emits log', async function () { const testKey = [BigNumber.from('1'), BigNumber.from('2')] @@ -968,9 +1013,9 @@ describe('VRFCoordinatorV2', () => { it('cannot deregister unregistered key', async function () { const testKey = [BigNumber.from('1'), BigNumber.from('2')] const kh = await vrfCoordinatorV2.hashOfKey(testKey) - await expect( - vrfCoordinatorV2.deregisterProvingKey(testKey), - ).to.be.revertedWith(`NoSuchProvingKey("${kh}")`) + await expect(vrfCoordinatorV2.deregisterProvingKey(testKey)) + .to.be.revertedWithCustomError(vrfCoordinatorV2, `NoSuchProvingKey`) + .withArgs(kh) }) it('can register after deregister', async function () { const testKey = [BigNumber.from('1'), BigNumber.from('2')] @@ -1006,9 +1051,11 @@ describe('VRFCoordinatorV2', () => { ] await expect( vrfCoordinatorV2.connect(oracle).fulfillRandomWords(proof, rc), - ).to.be.revertedWith( - `NoSuchProvingKey("0xa15bc60c955c405d20d9149c709e2460f1c2d9a497496a7f46004d1772c3054c")`, ) + .to.be.revertedWithCustomError(vrfCoordinatorV2, `NoSuchProvingKey`) + .withArgs( + '0xa15bc60c955c405d20d9149c709e2460f1c2d9a497496a7f46004d1772c3054c', + ) }) it('no corresponding request', async function () { const proof = [ @@ -1031,7 +1078,10 @@ describe('VRFCoordinatorV2', () => { ] await expect( vrfCoordinatorV2.connect(oracle).fulfillRandomWords(proof, rc), - ).to.be.revertedWith(`NoCorrespondingRequest()`) + ).to.be.revertedWithCustomError( + vrfCoordinatorV2, + `NoCorrespondingRequest`, + ) }) it('incorrect commitment wrong blocknum', async function () { const subId = await createSubscription() @@ -1073,7 +1123,7 @@ describe('VRFCoordinatorV2', () => { ] await expect( vrfCoordinatorV2.connect(oracle).fulfillRandomWords(proof, rc), - ).to.be.revertedWith(`IncorrectCommitment()`) + ).to.be.revertedWithCustomError(vrfCoordinatorV2, `IncorrectCommitment`) }) }) diff --git a/contracts/test/v0.8/dev/VRFCoordinatorV2Mock.test.ts b/contracts/test/v0.8/vrf/VRFCoordinatorV2Mock.test.ts similarity index 92% rename from contracts/test/v0.8/dev/VRFCoordinatorV2Mock.test.ts rename to contracts/test/v0.8/vrf/VRFCoordinatorV2Mock.test.ts index 04771e4ef7f..5bcb2cd5fa0 100644 --- a/contracts/test/v0.8/dev/VRFCoordinatorV2Mock.test.ts +++ b/contracts/test/v0.8/vrf/VRFCoordinatorV2Mock.test.ts @@ -32,7 +32,7 @@ describe('VRFCoordinatorV2Mock', () => { ) const ltFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', + 'src/v0.8/shared/test/helpers/LinkTokenTestHelper.sol:LinkTokenTestHelper', accounts[0], ) linkToken = await ltFactory.deploy() @@ -91,7 +91,10 @@ describe('VRFCoordinatorV2Mock', () => { vrfCoordinatorV2Mock .connect(subOwner) .addConsumer(4, testConsumerAddress), - ).to.be.revertedWith('InvalidSubscription') + ).to.be.revertedWithCustomError( + vrfCoordinatorV2Mock, + 'InvalidSubscription', + ) }) it('cannot add more than the consumer maximum', async function () { let subId = await createSubscription() @@ -109,7 +112,7 @@ describe('VRFCoordinatorV2Mock', () => { vrfCoordinatorV2Mock .connect(subOwner) .addConsumer(subId, testConsumerAddress), - ).to.be.revertedWith('TooManyConsumers') + ).to.be.revertedWithCustomError(vrfCoordinatorV2Mock, 'TooManyConsumers') }) }) describe('#removeConsumer', async function () { @@ -142,7 +145,10 @@ describe('VRFCoordinatorV2Mock', () => { vrfCoordinatorV2Mock .connect(subOwner) .removeConsumer(4, testConsumerAddress), - ).to.be.revertedWith('InvalidSubscription') + ).to.be.revertedWithCustomError( + vrfCoordinatorV2Mock, + 'InvalidSubscription', + ) }) it('cannot remove a consumer after it is already removed', async function () { let subId = await createSubscription() @@ -163,7 +169,7 @@ describe('VRFCoordinatorV2Mock', () => { vrfCoordinatorV2Mock .connect(subOwner) .removeConsumer(subId, testConsumerAddress), - ).to.be.revertedWith('InvalidConsumer') + ).to.be.revertedWithCustomError(vrfCoordinatorV2Mock, 'InvalidConsumer') }) }) describe('#fundSubscription', async function () { @@ -182,7 +188,10 @@ describe('VRFCoordinatorV2Mock', () => { it('cannot fund a nonexistent subscription', async function () { await expect( vrfCoordinatorV2Mock.connect(subOwner).fundSubscription(4, oneLink), - ).to.be.revertedWith('InvalidSubscription') + ).to.be.revertedWithCustomError( + vrfCoordinatorV2Mock, + 'InvalidSubscription', + ) }) }) describe('#cancelSubscription', async function () { @@ -200,7 +209,10 @@ describe('VRFCoordinatorV2Mock', () => { await expect( vrfCoordinatorV2Mock.connect(subOwner).getSubscription(subId), - ).to.be.revertedWith('InvalidSubscription') + ).to.be.revertedWithCustomError( + vrfCoordinatorV2Mock, + 'InvalidSubscription', + ) }) }) describe('#fulfillRandomWords', async function () { @@ -211,7 +223,7 @@ describe('VRFCoordinatorV2Mock', () => { vrfCoordinatorV2Mock .connect(subOwner) .requestRandomWords(keyhash, subId, 3, 500_000, 2), - ).to.be.revertedWith('InvalidConsumer') + ).to.be.revertedWithCustomError(vrfCoordinatorV2Mock, 'InvalidConsumer') }) it('fails to fulfill with insufficient funds', async function () { let subId = await createSubscription() @@ -231,7 +243,10 @@ describe('VRFCoordinatorV2Mock', () => { vrfCoordinatorV2Mock .connect(random) .fulfillRandomWords(1, vrfConsumerV2.address), - ).to.be.revertedWith('InsufficientBalance') + ).to.be.revertedWithCustomError( + vrfCoordinatorV2Mock, + 'InsufficientBalance', + ) }) it('can request and fulfill [ @skip-coverage ]', async function () { let subId = await createSubscription() @@ -302,7 +317,10 @@ describe('VRFCoordinatorV2Mock', () => { vrfConsumerV2.address, [1, 2, 3, 4, 5], ), - ).to.be.revertedWith('InvalidRandomWords') + ).to.be.revertedWithCustomError( + vrfCoordinatorV2Mock, + 'InvalidRandomWords', + ) // Call override correctly. let tx = await vrfCoordinatorV2Mock diff --git a/contracts/test/v0.8/VRFSubscriptionBalanceMonitor.test.ts b/contracts/test/v0.8/vrf/VRFSubscriptionBalanceMonitor.test.ts similarity index 94% rename from contracts/test/v0.8/VRFSubscriptionBalanceMonitor.test.ts rename to contracts/test/v0.8/vrf/VRFSubscriptionBalanceMonitor.test.ts index c13d144776c..ea5cdb5f395 100644 --- a/contracts/test/v0.8/VRFSubscriptionBalanceMonitor.test.ts +++ b/contracts/test/v0.8/vrf/VRFSubscriptionBalanceMonitor.test.ts @@ -4,14 +4,14 @@ import type { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' import { LinkToken, VRFSubscriptionBalanceMonitorExposed, -} from '../../typechain' -import * as h from '../test-helpers/helpers' +} from '../../../typechain' +import * as h from '../../test-helpers/helpers' import { BigNumber, Contract } from 'ethers' const OWNABLE_ERR = 'Only callable by owner' -const INVALID_WATCHLIST_ERR = `InvalidWatchList()` +const INVALID_WATCHLIST_ERR = `InvalidWatchList` const PAUSED_ERR = 'Pausable: paused' -const ONLY_KEEPER_ERR = `OnlyKeeperRegistry()` +const ONLY_KEEPER_ERR = `OnlyKeeperRegistry` const zeroLINK = ethers.utils.parseEther('0') const oneLINK = ethers.utils.parseEther('1') @@ -66,7 +66,7 @@ describe('VRFSubscriptionBalanceMonitor', () => { owner, ) const ltFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', + 'src/v0.8/shared/test/helpers/LinkTokenTestHelper.sol:LinkTokenTestHelper', owner, ) @@ -240,7 +240,7 @@ describe('VRFSubscriptionBalanceMonitor', () => { }) it('Should not allow duplicates in the watchlist', async () => { - const errMsg = `DuplicateSubcriptionId(${sub1})` + const errMsg = `DuplicateSubcriptionId` const setTx = bm .connect(owner) .setWatchList( @@ -248,7 +248,9 @@ describe('VRFSubscriptionBalanceMonitor', () => { [oneLINK, twoLINK, threeLINK], [twoLINK, threeLINK, fiveLINK], ) - await expect(setTx).to.be.revertedWith(errMsg) + await expect(setTx) + .to.be.revertedWithCustomError(bm, errMsg) + .withArgs(sub1) }) it('Should not allow a topUpAmountJuels les than or equal to minBalance in the watchlist', async () => { @@ -259,7 +261,10 @@ describe('VRFSubscriptionBalanceMonitor', () => { [oneLINK, twoLINK, threeLINK], [zeroLINK, twoLINK, threeLINK], ) - await expect(setTx).to.be.revertedWith(INVALID_WATCHLIST_ERR) + await expect(setTx).to.be.revertedWithCustomError( + bm, + INVALID_WATCHLIST_ERR, + ) }) it('Should not allow strangers to set the watchlist', async () => { @@ -271,25 +276,25 @@ describe('VRFSubscriptionBalanceMonitor', () => { it('Should revert if the list lengths differ', async () => { let tx = bm.connect(owner).setWatchList([sub1], [], [twoLINK]) - await expect(tx).to.be.revertedWith(INVALID_WATCHLIST_ERR) + await expect(tx).to.be.revertedWithCustomError(bm, INVALID_WATCHLIST_ERR) tx = bm.connect(owner).setWatchList([sub1], [oneLINK], []) - await expect(tx).to.be.revertedWith(INVALID_WATCHLIST_ERR) + await expect(tx).to.be.revertedWithCustomError(bm, INVALID_WATCHLIST_ERR) tx = bm.connect(owner).setWatchList([], [oneLINK], [twoLINK]) - await expect(tx).to.be.revertedWith(INVALID_WATCHLIST_ERR) + await expect(tx).to.be.revertedWithCustomError(bm, INVALID_WATCHLIST_ERR) }) it('Should revert if any of the subIDs are zero', async () => { let tx = bm .connect(owner) .setWatchList([sub1, 0], [oneLINK, oneLINK], [twoLINK, twoLINK]) - await expect(tx).to.be.revertedWith(INVALID_WATCHLIST_ERR) + await expect(tx).to.be.revertedWithCustomError(bm, INVALID_WATCHLIST_ERR) }) it('Should revert if any of the top up amounts are 0', async () => { const tx = bm .connect(owner) .setWatchList([sub1, sub2], [oneLINK, oneLINK], [twoLINK, zeroLINK]) - await expect(tx).to.be.revertedWith(INVALID_WATCHLIST_ERR) + await expect(tx).to.be.revertedWithCustomError(bm, INVALID_WATCHLIST_ERR) }) }) @@ -573,9 +578,15 @@ describe('VRFSubscriptionBalanceMonitor', () => { it('Should only be callable by the keeper registry contract', async () => { let performTx = bm.connect(owner).performUpkeep(validPayload) - await expect(performTx).to.be.revertedWith(ONLY_KEEPER_ERR) + await expect(performTx).to.be.revertedWithCustomError( + bm, + ONLY_KEEPER_ERR, + ) performTx = bm.connect(stranger).performUpkeep(validPayload) - await expect(performTx).to.be.revertedWith(ONLY_KEEPER_ERR) + await expect(performTx).to.be.revertedWithCustomError( + bm, + ONLY_KEEPER_ERR, + ) }) it('Should protect against running out of gas', async () => { diff --git a/contracts/test/v0.8/dev/VRFV2Wrapper.test.ts b/contracts/test/v0.8/vrf/VRFV2Wrapper.test.ts similarity index 99% rename from contracts/test/v0.8/dev/VRFV2Wrapper.test.ts rename to contracts/test/v0.8/vrf/VRFV2Wrapper.test.ts index fc888fc9738..54c3b5f99b5 100644 --- a/contracts/test/v0.8/dev/VRFV2Wrapper.test.ts +++ b/contracts/test/v0.8/vrf/VRFV2Wrapper.test.ts @@ -101,7 +101,7 @@ describe('VRFV2Wrapper', () => { linkEthFeed = await linkEthFeedFactory.deploy(18, weiPerUnitLink) // 1 LINK = 0.003 ETH const linkFactory = await ethers.getContractFactory( - 'src/v0.4/LinkToken.sol:LinkToken', + 'src/v0.8/shared/test/helpers/LinkTokenTestHelper.sol:LinkTokenTestHelper', owner, ) link = await linkFactory.deploy() diff --git a/core/capabilities/remote/dispatcher.go b/core/capabilities/remote/dispatcher.go new file mode 100644 index 00000000000..f25d8cb784a --- /dev/null +++ b/core/capabilities/remote/dispatcher.go @@ -0,0 +1,168 @@ +package remote + +import ( + "context" + "fmt" + sync "sync" + "time" + + "google.golang.org/protobuf/proto" + + "github.com/smartcontractkit/chainlink-common/pkg/services" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + + "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" + remotetypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" + "github.com/smartcontractkit/chainlink/v2/core/logger" + p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" +) + +// dispatcher en/decodes messages and routes traffic between peers and capabilities +type dispatcher struct { + peerWrapper p2ptypes.PeerWrapper + peer p2ptypes.Peer + peerID p2ptypes.PeerID + signer p2ptypes.Signer + registry commontypes.CapabilitiesRegistry + receivers map[key]remotetypes.Receiver + mu sync.RWMutex + stopCh services.StopChan + wg sync.WaitGroup + lggr logger.Logger +} + +type key struct { + capId string + donId string +} + +var _ services.Service = &dispatcher{} + +const supportedVersion = 1 + +func NewDispatcher(peerWrapper p2ptypes.PeerWrapper, signer p2ptypes.Signer, registry commontypes.CapabilitiesRegistry, lggr logger.Logger) *dispatcher { + return &dispatcher{ + peerWrapper: peerWrapper, + signer: signer, + registry: registry, + receivers: make(map[key]remotetypes.Receiver), + stopCh: make(services.StopChan), + lggr: lggr.Named("Dispatcher"), + } +} + +func (d *dispatcher) Start(ctx context.Context) error { + d.peer = d.peerWrapper.GetPeer() + d.peerID = d.peer.ID() + if d.peer == nil { + return fmt.Errorf("peer is not initialized") + } + d.wg.Add(1) + go d.receive() + d.lggr.Info("dispatcher started") + return nil +} + +func (d *dispatcher) SetReceiver(capabilityId string, donId string, receiver remotetypes.Receiver) error { + d.mu.Lock() + defer d.mu.Unlock() + k := key{capabilityId, donId} + _, ok := d.receivers[k] + if ok { + return fmt.Errorf("receiver already exists for capability %s and don %s", capabilityId, donId) + } + d.receivers[k] = receiver + return nil +} + +func (d *dispatcher) RemoveReceiver(capabilityId string, donId string) { + d.mu.Lock() + defer d.mu.Unlock() + delete(d.receivers, key{capabilityId, donId}) +} + +func (d *dispatcher) Send(peerID p2ptypes.PeerID, msgBody *remotetypes.MessageBody) error { + msgBody.Version = supportedVersion + msgBody.Sender = d.peerID[:] + msgBody.Receiver = peerID[:] + msgBody.Timestamp = time.Now().UnixMilli() + rawBody, err := proto.Marshal(msgBody) + if err != nil { + return err + } + signature, err := d.signer.Sign(rawBody) + if err != nil { + return err + } + msg := &remotetypes.Message{Signature: signature, Body: rawBody} + rawMsg, err := proto.Marshal(msg) + if err != nil { + return err + } + return d.peer.Send(peerID, rawMsg) +} + +func (d *dispatcher) receive() { + defer d.wg.Done() + recvCh := d.peer.Receive() + for { + select { + case <-d.stopCh: + d.lggr.Info("stopped - exiting receive") + return + case msg := <-recvCh: + body, err := ValidateMessage(msg, d.peerID) + if err != nil { + d.lggr.Debugw("received invalid message", "error", err) + d.tryRespondWithError(msg.Sender, body, types.Error_VALIDATION_FAILED) + continue + } + k := key{body.CapabilityId, body.CapabilityDonId} + d.mu.RLock() + receiver, ok := d.receivers[k] + d.mu.RUnlock() + if !ok { + d.lggr.Debugw("received message for unregistered capability", "capabilityId", k.capId, "donId", k.donId) + d.tryRespondWithError(msg.Sender, body, types.Error_CAPABILITY_NOT_FOUND) + continue + } + receiver.Receive(body) + } + } +} + +func (d *dispatcher) tryRespondWithError(peerID p2ptypes.PeerID, body *remotetypes.MessageBody, errType types.Error) { + if body == nil { + return + } + if body.Error != types.Error_OK { + d.lggr.Debug("received an invalid message with error field set - not responding to avoid an infinite loop") + return + } + body.Error = errType + // clear payload to reduce message size + body.Payload = nil + err := d.Send(peerID, body) + if err != nil { + d.lggr.Debugw("failed to send error response", "error", err) + } +} + +func (d *dispatcher) Close() error { + close(d.stopCh) + d.wg.Wait() + d.lggr.Info("dispatcher closed") + return nil +} + +func (d *dispatcher) Ready() error { + return nil +} + +func (d *dispatcher) HealthReport() map[string]error { + return nil +} + +func (d *dispatcher) Name() string { + return "Dispatcher" +} diff --git a/core/capabilities/remote/dispatcher_test.go b/core/capabilities/remote/dispatcher_test.go new file mode 100644 index 00000000000..b6ba31aa8f2 --- /dev/null +++ b/core/capabilities/remote/dispatcher_test.go @@ -0,0 +1,123 @@ +package remote_test + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + commonMocks "github.com/smartcontractkit/chainlink-common/pkg/types/mocks" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote" + remotetypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/logger" + p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" + "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types/mocks" +) + +type testReceiver struct { + ch chan *remotetypes.MessageBody +} + +func newReceiver() *testReceiver { + return &testReceiver{ + ch: make(chan *remotetypes.MessageBody, 100), + } +} + +func (r *testReceiver) Receive(msg *remotetypes.MessageBody) { + r.ch <- msg +} + +func TestDispatcher_CleanStartClose(t *testing.T) { + lggr := logger.TestLogger(t) + ctx := testutils.Context(t) + peer := mocks.NewPeer(t) + recvCh := make(<-chan p2ptypes.Message) + peer.On("Receive", mock.Anything).Return(recvCh) + peer.On("ID", mock.Anything).Return(p2ptypes.PeerID{}) + wrapper := mocks.NewPeerWrapper(t) + wrapper.On("GetPeer").Return(peer) + signer := mocks.NewSigner(t) + registry := commonMocks.NewCapabilitiesRegistry(t) + + dispatcher := remote.NewDispatcher(wrapper, signer, registry, lggr) + require.NoError(t, dispatcher.Start(ctx)) + require.NoError(t, dispatcher.Close()) +} + +func TestDispatcher_Receive(t *testing.T) { + lggr := logger.TestLogger(t) + ctx := testutils.Context(t) + privKey1, peerId1 := newKeyPair(t) + _, peerId2 := newKeyPair(t) + + peer := mocks.NewPeer(t) + recvCh := make(chan p2ptypes.Message) + peer.On("Receive", mock.Anything).Return((<-chan p2ptypes.Message)(recvCh)) + peer.On("ID", mock.Anything).Return(peerId2) + wrapper := mocks.NewPeerWrapper(t) + wrapper.On("GetPeer").Return(peer) + signer := mocks.NewSigner(t) + signer.On("Sign", mock.Anything).Return(nil, errors.New("not implemented")) + registry := commonMocks.NewCapabilitiesRegistry(t) + + dispatcher := remote.NewDispatcher(wrapper, signer, registry, lggr) + require.NoError(t, dispatcher.Start(ctx)) + + rcv := newReceiver() + err := dispatcher.SetReceiver(capId1, donId1, rcv) + require.NoError(t, err) + + // supported capability + recvCh <- encodeAndSign(t, privKey1, peerId1, peerId2, capId1, donId1, []byte(payload1)) + // unknown capability + recvCh <- encodeAndSign(t, privKey1, peerId1, peerId2, capId2, donId1, []byte(payload1)) + // sender doesn't match + invalid := encodeAndSign(t, privKey1, peerId1, peerId2, capId2, donId1, []byte(payload1)) + invalid.Sender = peerId2 + recvCh <- invalid + // supported capability again + recvCh <- encodeAndSign(t, privKey1, peerId1, peerId2, capId1, donId1, []byte(payload2)) + + m := <-rcv.ch + require.Equal(t, payload1, string(m.Payload)) + m = <-rcv.ch + require.Equal(t, payload2, string(m.Payload)) + + dispatcher.RemoveReceiver(capId1, donId1) + require.NoError(t, dispatcher.Close()) +} + +func TestDispatcher_RespondWithError(t *testing.T) { + lggr := logger.TestLogger(t) + ctx := testutils.Context(t) + privKey1, peerId1 := newKeyPair(t) + _, peerId2 := newKeyPair(t) + + peer := mocks.NewPeer(t) + recvCh := make(chan p2ptypes.Message) + peer.On("Receive", mock.Anything).Return((<-chan p2ptypes.Message)(recvCh)) + peer.On("ID", mock.Anything).Return(peerId2) + sendCh := make(chan p2ptypes.PeerID) + peer.On("Send", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + peerID := args.Get(0).(p2ptypes.PeerID) + sendCh <- peerID + }).Return(nil) + wrapper := mocks.NewPeerWrapper(t) + wrapper.On("GetPeer").Return(peer) + signer := mocks.NewSigner(t) + signer.On("Sign", mock.Anything).Return([]byte{}, nil) + registry := commonMocks.NewCapabilitiesRegistry(t) + + dispatcher := remote.NewDispatcher(wrapper, signer, registry, lggr) + require.NoError(t, dispatcher.Start(ctx)) + + // unknown capability + recvCh <- encodeAndSign(t, privKey1, peerId1, peerId2, capId1, donId1, []byte(payload1)) + responseDestPeerID := <-sendCh + require.Equal(t, peerId1, responseDestPeerID) + + require.NoError(t, dispatcher.Close()) +} diff --git a/core/capabilities/remote/message_cache.go b/core/capabilities/remote/message_cache.go new file mode 100644 index 00000000000..27f909c5165 --- /dev/null +++ b/core/capabilities/remote/message_cache.go @@ -0,0 +1,87 @@ +package remote + +// MessageCache is a simple store for messages, grouped by event ID and peer ID. +// It is used to collect messages from multiple peers until they are ready for aggregation +// based on quantity and freshness. +type messageCache[EventID comparable, PeerID comparable] struct { + events map[EventID]*eventState[PeerID] +} + +type eventState[PeerID comparable] struct { + peerMsgs map[PeerID]*msgState + creationTimestamp int64 + wasReady bool +} + +type msgState struct { + timestamp int64 + payload []byte +} + +func NewMessageCache[EventID comparable, PeerID comparable]() *messageCache[EventID, PeerID] { + return &messageCache[EventID, PeerID]{ + events: make(map[EventID]*eventState[PeerID]), + } +} + +// Insert or overwrite a message for . Return creation timestamp of the event. +func (c *messageCache[EventID, PeerID]) Insert(eventID EventID, peerID PeerID, timestamp int64, payload []byte) int64 { + if _, ok := c.events[eventID]; !ok { + c.events[eventID] = &eventState[PeerID]{ + peerMsgs: make(map[PeerID]*msgState), + creationTimestamp: timestamp, + } + } + c.events[eventID].peerMsgs[peerID] = &msgState{ + timestamp: timestamp, + payload: payload, + } + return c.events[eventID].creationTimestamp +} + +// Return true if there are messages from at least peers, +// received more recently than . +// Return all messages that satisfy the above condition. +// Ready() will return true at most once per event if is true. +func (c *messageCache[EventID, PeerID]) Ready(eventID EventID, minCount uint32, minTimestamp int64, once bool) (bool, [][]byte) { + ev, ok := c.events[eventID] + if !ok { + return false, nil + } + if ev.wasReady && once { + return false, nil + } + if uint32(len(ev.peerMsgs)) < minCount { + return false, nil + } + countAboveMinTimestamp := uint32(0) + accPayloads := [][]byte{} + for _, msg := range ev.peerMsgs { + if msg.timestamp >= minTimestamp { + countAboveMinTimestamp++ + accPayloads = append(accPayloads, msg.payload) + if countAboveMinTimestamp >= minCount { + ev.wasReady = true + return true, accPayloads + } + } + } + return false, nil +} + +func (c *messageCache[EventID, PeerID]) Delete(eventID EventID) { + delete(c.events, eventID) +} + +// Return the number of events deleted. +// Scans all keys, which might be slow for large caches. +func (c *messageCache[EventID, PeerID]) DeleteOlderThan(cutoffTimestamp int64) int { + nDeleted := 0 + for id, event := range c.events { + if event.creationTimestamp < cutoffTimestamp { + c.Delete(id) + nDeleted++ + } + } + return nDeleted +} diff --git a/core/capabilities/remote/message_cache_test.go b/core/capabilities/remote/message_cache_test.go new file mode 100644 index 00000000000..5ca909ca4ec --- /dev/null +++ b/core/capabilities/remote/message_cache_test.go @@ -0,0 +1,61 @@ +package remote_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote" +) + +const ( + eventId1 = "event1" + eventId2 = "event2" + peerId1 = "peer1" + peerId2 = "peer2" + payloadA = "payloadA" +) + +func TestMessageCache_InsertReady(t *testing.T) { + cache := remote.NewMessageCache[string, string]() + + // not ready with one message + ts := cache.Insert(eventId1, peerId1, 100, []byte(payloadA)) + require.Equal(t, int64(100), ts) + ready, _ := cache.Ready(eventId1, 2, 100, true) + require.False(t, ready) + + // not ready with two messages but only one fresh enough + ts = cache.Insert(eventId1, peerId2, 200, []byte(payloadA)) + require.Equal(t, int64(100), ts) + ready, _ = cache.Ready(eventId1, 2, 150, true) + require.False(t, ready) + + // ready with two messages (once only) + ready, messages := cache.Ready(eventId1, 2, 100, true) + require.True(t, ready) + require.Equal(t, []byte(payloadA), messages[0]) + require.Equal(t, []byte(payloadA), messages[1]) + + // not ready again for the same event ID + ready, _ = cache.Ready(eventId1, 2, 100, true) + require.False(t, ready) +} + +func TestMessageCache_DeleteOlderThan(t *testing.T) { + cache := remote.NewMessageCache[string, string]() + + ts := cache.Insert(eventId1, peerId1, 100, []byte(payloadA)) + require.Equal(t, int64(100), ts) + ts = cache.Insert(eventId2, peerId2, 200, []byte(payloadA)) + require.Equal(t, int64(200), ts) + + deleted := cache.DeleteOlderThan(150) + require.Equal(t, 1, deleted) + + deleted = cache.DeleteOlderThan(150) + require.Equal(t, 0, deleted) + + deleted = cache.DeleteOlderThan(201) + require.Equal(t, 1, deleted) +} diff --git a/core/capabilities/remote/target.go b/core/capabilities/remote/target.go new file mode 100644 index 00000000000..bacc06c0310 --- /dev/null +++ b/core/capabilities/remote/target.go @@ -0,0 +1,84 @@ +package remote + +import ( + "context" + "errors" + + commoncap "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" + "github.com/smartcontractkit/chainlink/v2/core/logger" +) + +// remoteTargetCaller/Receiver are shims translating between capability API calls and network messages +type remoteTargetCaller struct { + capInfo commoncap.CapabilityInfo + donInfo *types.DON + dispatcher types.Dispatcher + lggr logger.Logger +} + +var _ commoncap.TargetCapability = &remoteTargetCaller{} +var _ types.Receiver = &remoteTargetCaller{} + +type remoteTargetReceiver struct { + capInfo commoncap.CapabilityInfo + donInfo *types.DON + dispatcher types.Dispatcher + lggr logger.Logger +} + +var _ types.Receiver = &remoteTargetReceiver{} + +func NewRemoteTargetCaller(capInfo commoncap.CapabilityInfo, donInfo *types.DON, dispatcher types.Dispatcher, lggr logger.Logger) *remoteTargetCaller { + return &remoteTargetCaller{ + capInfo: capInfo, + donInfo: donInfo, + dispatcher: dispatcher, + lggr: lggr, + } +} + +func (c *remoteTargetCaller) Info(ctx context.Context) (commoncap.CapabilityInfo, error) { + return c.capInfo, nil +} + +func (c *remoteTargetCaller) RegisterToWorkflow(ctx context.Context, request commoncap.RegisterToWorkflowRequest) error { + return errors.New("not implemented") +} + +func (c *remoteTargetCaller) UnregisterFromWorkflow(ctx context.Context, request commoncap.UnregisterFromWorkflowRequest) error { + return errors.New("not implemented") +} + +func (c *remoteTargetCaller) Execute(ctx context.Context, callback chan<- commoncap.CapabilityResponse, request commoncap.CapabilityRequest) error { + c.lggr.Debugw("not implemented - executing fake remote target capability", "capabilityId", c.capInfo.ID, "nMembers", len(c.donInfo.Members)) + for _, peerID := range c.donInfo.Members { + m := &types.MessageBody{ + CapabilityId: c.capInfo.ID, + CapabilityDonId: c.donInfo.ID, + Payload: []byte{0x01, 0x02, 0x03}, + } + err := c.dispatcher.Send(peerID, m) + if err != nil { + return err + } + } + return nil +} + +func (c *remoteTargetCaller) Receive(msg *types.MessageBody) { + c.lggr.Debugw("not implemented - received message", "capabilityId", c.capInfo.ID, "payload", msg.Payload) +} + +func NewRemoteTargetReceiver(capInfo commoncap.CapabilityInfo, donInfo *types.DON, dispatcher types.Dispatcher, lggr logger.Logger) *remoteTargetReceiver { + return &remoteTargetReceiver{ + capInfo: capInfo, + donInfo: donInfo, + dispatcher: dispatcher, + lggr: lggr, + } +} + +func (c *remoteTargetReceiver) Receive(msg *types.MessageBody) { + c.lggr.Debugw("not implemented - received message", "capabilityId", c.capInfo.ID, "payload", msg.Payload) +} diff --git a/core/capabilities/remote/target_test.go b/core/capabilities/remote/target_test.go new file mode 100644 index 00000000000..904cd5b9c71 --- /dev/null +++ b/core/capabilities/remote/target_test.go @@ -0,0 +1,28 @@ +package remote_test + +import ( + "testing" + + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + commoncap "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" + remoteMocks "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types/mocks" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/logger" + p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" +) + +func TestTarget_Placeholder(t *testing.T) { + lggr := logger.TestLogger(t) + ctx := testutils.Context(t) + donInfo := &types.DON{ + Members: []p2ptypes.PeerID{{}}, + } + dispatcher := remoteMocks.NewDispatcher(t) + dispatcher.On("Send", mock.Anything, mock.Anything).Return(nil) + target := remote.NewRemoteTargetCaller(commoncap.CapabilityInfo{}, donInfo, dispatcher, lggr) + require.NoError(t, target.Execute(ctx, nil, commoncap.CapabilityRequest{})) +} diff --git a/core/capabilities/remote/trigger_publisher.go b/core/capabilities/remote/trigger_publisher.go new file mode 100644 index 00000000000..94ca58e6156 --- /dev/null +++ b/core/capabilities/remote/trigger_publisher.go @@ -0,0 +1,221 @@ +package remote + +import ( + "context" + sync "sync" + "time" + + commoncap "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" + "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" + "github.com/smartcontractkit/chainlink/v2/core/logger" + p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" +) + +// TriggerPublisher manages all external users of a local trigger capability. +// Its responsibilities are: +// 1. Manage trigger registrations from external nodes (receive, store, aggregate, expire). +// 2. Send out events produced by an underlying, concrete trigger implementation. +// +// TriggerPublisher communicates with corresponding TriggerSubscribers on remote nodes. +type triggerPublisher struct { + config types.RemoteTriggerConfig + underlying commoncap.TriggerCapability + capInfo commoncap.CapabilityInfo + capDonInfo types.DON + workflowDONs map[string]types.DON + dispatcher types.Dispatcher + messageCache *messageCache[registrationKey, p2ptypes.PeerID] + registrations map[registrationKey]*pubRegState + mu sync.RWMutex // protects messageCache and registrations + stopCh services.StopChan + wg sync.WaitGroup + lggr logger.Logger +} + +type registrationKey struct { + callerDonId string + workflowId string +} + +type pubRegState struct { + callback chan<- commoncap.CapabilityResponse + request commoncap.CapabilityRequest +} + +var _ types.Receiver = &triggerPublisher{} +var _ services.Service = &triggerPublisher{} + +func NewTriggerPublisher(config types.RemoteTriggerConfig, underlying commoncap.TriggerCapability, capInfo commoncap.CapabilityInfo, capDonInfo types.DON, workflowDONs map[string]types.DON, dispatcher types.Dispatcher, lggr logger.Logger) *triggerPublisher { + config.ApplyDefaults() + return &triggerPublisher{ + config: config, + underlying: underlying, + capInfo: capInfo, + capDonInfo: capDonInfo, + workflowDONs: workflowDONs, + dispatcher: dispatcher, + messageCache: NewMessageCache[registrationKey, p2ptypes.PeerID](), + registrations: make(map[registrationKey]*pubRegState), + stopCh: make(services.StopChan), + lggr: lggr, + } +} + +func (p *triggerPublisher) Start(ctx context.Context) error { + p.wg.Add(1) + go p.registrationCleanupLoop() + p.lggr.Info("TriggerPublisher started") + return nil +} + +func (p *triggerPublisher) Receive(msg *types.MessageBody) { + sender := ToPeerID(msg.Sender) + if msg.Method == types.MethodRegisterTrigger { + req, err := pb.UnmarshalCapabilityRequest(msg.Payload) + if err != nil { + p.lggr.Errorw("failed to unmarshal capability request", "capabilityId", p.capInfo.ID, "err", err) + return + } + callerDon, ok := p.workflowDONs[msg.CallerDonId] + if !ok { + p.lggr.Errorw("received a message from unsupported workflow DON", "capabilityId", p.capInfo.ID, "callerDonId", msg.CallerDonId) + return + } + p.lggr.Debugw("received trigger registration", "capabilityId", p.capInfo.ID, "workflowId", req.Metadata.WorkflowID, "sender", sender) + key := registrationKey{msg.CallerDonId, req.Metadata.WorkflowID} + nowMs := time.Now().UnixMilli() + p.mu.Lock() + p.messageCache.Insert(key, sender, nowMs, msg.Payload) + // NOTE: require 2F+1 by default, introduce different strategies later (KS-76) + minRequired := uint32(2*callerDon.F + 1) + ready, payloads := p.messageCache.Ready(key, minRequired, nowMs-int64(p.config.RegistrationExpiryMs), false) + p.mu.Unlock() + if !ready { + p.lggr.Debugw("not ready to aggregate yet", "capabilityId", p.capInfo.ID, "workflowId", req.Metadata.WorkflowID, "minRequired", minRequired) + return + } + agg := NewDefaultModeAggregator(uint32(callerDon.F + 1)) + aggregated, err := agg.Aggregate("", payloads) + if err != nil { + p.lggr.Errorw("failed to aggregate trigger registrations", "capabilityId", p.capInfo.ID, "workflowId", req.Metadata.WorkflowID, "err", err) + return + } + unmarshaled, err := pb.UnmarshalCapabilityRequest(aggregated) + if err != nil { + p.lggr.Errorw("failed to unmarshal request", "capabilityId", p.capInfo.ID, "err", err) + return + } + p.mu.Lock() + callbackCh := make(chan commoncap.CapabilityResponse) + ctx, cancel := p.stopCh.NewCtx() + err = p.underlying.RegisterTrigger(ctx, callbackCh, unmarshaled) + cancel() + if err == nil { + p.registrations[key] = &pubRegState{ + callback: callbackCh, + request: unmarshaled, + } + p.wg.Add(1) + go p.triggerEventLoop(callbackCh, key) + p.lggr.Debugw("updated trigger registration", "capabilityId", p.capInfo.ID, "workflowId", req.Metadata.WorkflowID) + } else { + p.lggr.Errorw("failed to register trigger", "capabilityId", p.capInfo.ID, "workflowId", req.Metadata.WorkflowID, "err", err) + } + p.mu.Unlock() + } else { + p.lggr.Errorw("received trigger request with unknown method", "method", msg.Method, "sender", sender) + } +} + +func (p *triggerPublisher) registrationCleanupLoop() { + defer p.wg.Done() + ticker := time.NewTicker(time.Duration(p.config.RegistrationExpiryMs) * time.Millisecond) + defer ticker.Stop() + for { + select { + case <-p.stopCh: + return + case <-ticker.C: + now := time.Now().UnixMilli() + p.mu.RLock() + for key, req := range p.registrations { + callerDon := p.workflowDONs[key.callerDonId] + ready, _ := p.messageCache.Ready(key, uint32(2*callerDon.F+1), now-int64(p.config.RegistrationExpiryMs), false) + if !ready { + p.lggr.Infow("trigger registration expired", "capabilityId", p.capInfo.ID, "callerDonID", key.callerDonId, "workflowId", key.workflowId) + ctx, cancel := p.stopCh.NewCtx() + err := p.underlying.UnregisterTrigger(ctx, req.request) + cancel() + p.lggr.Infow("unregistered trigger", "capabilityId", p.capInfo.ID, "callerDonID", key.callerDonId, "workflowId", key.workflowId, "err", err) + // after calling UnregisterTrigger, the underlying trigger will not send any more events to the channel + close(req.callback) + delete(p.registrations, key) + p.messageCache.Delete(key) + } + } + p.mu.RUnlock() + } + } +} + +func (p *triggerPublisher) triggerEventLoop(callbackCh chan commoncap.CapabilityResponse, key registrationKey) { + defer p.wg.Done() + for { + select { + case <-p.stopCh: + return + case response, ok := <-callbackCh: + if !ok { + p.lggr.Infow("triggerEventLoop channel closed", "capabilityId", p.capInfo.ID, "workflowId", key.workflowId) + return + } + p.lggr.Debugw("received trigger event", "capabilityId", p.capInfo.ID, "workflowId", key.workflowId) + marshaled, err := pb.MarshalCapabilityResponse(response) + if err != nil { + p.lggr.Debugw("can't marshal trigger event", "err", err) + break + } + msg := &types.MessageBody{ + CapabilityId: p.capInfo.ID, + CapabilityDonId: p.capDonInfo.ID, + CallerDonId: key.callerDonId, + Method: types.MethodTriggerEvent, + Payload: marshaled, + Metadata: &types.MessageBody_TriggerEventMetadata{ + TriggerEventMetadata: &types.TriggerEventMetadata{ + // NOTE: optionally introduce batching across workflows as an optimization + WorkflowIds: []string{key.workflowId}, + }, + }, + } + // NOTE: send to all nodes by default, introduce different strategies later (KS-76) + for _, peerID := range p.workflowDONs[key.callerDonId].Members { + err = p.dispatcher.Send(peerID, msg) + if err != nil { + p.lggr.Errorw("failed to send trigger event", "capabilityId", p.capInfo.ID, "peerID", peerID, "err", err) + } + } + } + } +} + +func (p *triggerPublisher) Close() error { + close(p.stopCh) + p.wg.Wait() + p.lggr.Info("TriggerPublisher closed") + return nil +} + +func (p *triggerPublisher) Ready() error { + return nil +} + +func (p *triggerPublisher) HealthReport() map[string]error { + return nil +} + +func (p *triggerPublisher) Name() string { + return "TriggerPublisher" +} diff --git a/core/capabilities/remote/trigger_publisher_test.go b/core/capabilities/remote/trigger_publisher_test.go new file mode 100644 index 00000000000..2a31646de5b --- /dev/null +++ b/core/capabilities/remote/trigger_publisher_test.go @@ -0,0 +1,97 @@ +package remote_test + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + + commoncap "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote" + remotetypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" + remoteMocks "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types/mocks" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/logger" + p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" +) + +func TestTriggerPublisher_Register(t *testing.T) { + lggr := logger.TestLogger(t) + ctx := testutils.Context(t) + capInfo := commoncap.CapabilityInfo{ + ID: "cap_id", + CapabilityType: commoncap.CapabilityTypeTrigger, + Description: "Remote Trigger", + Version: "0.0.1", + } + p1 := p2ptypes.PeerID{} + require.NoError(t, p1.UnmarshalText([]byte(peerID1))) + p2 := p2ptypes.PeerID{} + require.NoError(t, p2.UnmarshalText([]byte(peerID2))) + capDonInfo := remotetypes.DON{ + ID: "capability-don", + Members: []p2ptypes.PeerID{p1}, + F: 0, + } + workflowDonInfo := remotetypes.DON{ + ID: "workflow-don", + Members: []p2ptypes.PeerID{p2}, + F: 0, + } + + dispatcher := remoteMocks.NewDispatcher(t) + config := remotetypes.RemoteTriggerConfig{ + RegistrationRefreshMs: 100, + RegistrationExpiryMs: 100_000, + MinResponsesToAggregate: 1, + MessageExpiryMs: 100_000, + } + workflowDONs := map[string]remotetypes.DON{ + workflowDonInfo.ID: workflowDonInfo, + } + underlying := &testTrigger{ + info: capInfo, + registrationsCh: make(chan commoncap.CapabilityRequest, 2), + } + publisher := remote.NewTriggerPublisher(config, underlying, capInfo, capDonInfo, workflowDONs, dispatcher, lggr) + require.NoError(t, publisher.Start(ctx)) + + // trigger registration event + capRequest := commoncap.CapabilityRequest{ + Metadata: commoncap.RequestMetadata{ + WorkflowID: workflowID1, + }, + } + marshaled, err := pb.MarshalCapabilityRequest(capRequest) + require.NoError(t, err) + regEvent := &remotetypes.MessageBody{ + Sender: p1[:], + Method: remotetypes.MethodRegisterTrigger, + CallerDonId: workflowDonInfo.ID, + Payload: marshaled, + } + publisher.Receive(regEvent) + forwarded := <-underlying.registrationsCh + require.Equal(t, capRequest.Metadata.WorkflowID, forwarded.Metadata.WorkflowID) + + require.NoError(t, publisher.Close()) +} + +type testTrigger struct { + info commoncap.CapabilityInfo + registrationsCh chan commoncap.CapabilityRequest +} + +func (t *testTrigger) Info(_ context.Context) (commoncap.CapabilityInfo, error) { + return t.info, nil +} + +func (t *testTrigger) RegisterTrigger(_ context.Context, _ chan<- commoncap.CapabilityResponse, request commoncap.CapabilityRequest) error { + t.registrationsCh <- request + return nil +} + +func (t *testTrigger) UnregisterTrigger(_ context.Context, request commoncap.CapabilityRequest) error { + return nil +} diff --git a/core/capabilities/remote/trigger_subscriber.go b/core/capabilities/remote/trigger_subscriber.go new file mode 100644 index 00000000000..2c893d2b86e --- /dev/null +++ b/core/capabilities/remote/trigger_subscriber.go @@ -0,0 +1,235 @@ +package remote + +import ( + "context" + "errors" + sync "sync" + "time" + + commoncap "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" + "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" + "github.com/smartcontractkit/chainlink/v2/core/logger" + p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" +) + +// TriggerSubscriber is a shim for remote trigger capabilities. +// It translatesd between capability API calls and network messages. +// Its responsibilities are: +// 1. Periodically refresh all registrations for remote triggers. +// 2. Collect trigger events from remote nodes and aggregate responses via a customizable aggregator. +// +// TriggerSubscriber communicates with corresponding TriggerReceivers on remote nodes. +type triggerSubscriber struct { + config types.RemoteTriggerConfig + capInfo commoncap.CapabilityInfo + capDonInfo types.DON + capDonMembers map[p2ptypes.PeerID]struct{} + localDonInfo types.DON + dispatcher types.Dispatcher + aggregator types.Aggregator + messageCache *messageCache[triggerEventKey, p2ptypes.PeerID] + registeredWorkflows map[string]*subRegState + mu sync.RWMutex // protects registeredWorkflows and messageCache + stopCh services.StopChan + wg sync.WaitGroup + lggr logger.Logger +} + +type triggerEventKey struct { + triggerEventId string + workflowId string +} + +type subRegState struct { + callback chan<- commoncap.CapabilityResponse + rawRequest []byte +} + +var _ commoncap.TriggerCapability = &triggerSubscriber{} +var _ types.Receiver = &triggerSubscriber{} +var _ services.Service = &triggerSubscriber{} + +func NewTriggerSubscriber(config types.RemoteTriggerConfig, capInfo commoncap.CapabilityInfo, capDonInfo types.DON, localDonInfo types.DON, dispatcher types.Dispatcher, aggregator types.Aggregator, lggr logger.Logger) *triggerSubscriber { + if aggregator == nil { + lggr.Warnw("no aggregator provided, using default MODE aggregator", "capabilityId", capInfo.ID) + aggregator = NewDefaultModeAggregator(uint32(capDonInfo.F + 1)) + } + config.ApplyDefaults() + capDonMembers := make(map[p2ptypes.PeerID]struct{}) + for _, member := range capDonInfo.Members { + capDonMembers[member] = struct{}{} + } + return &triggerSubscriber{ + config: config, + capInfo: capInfo, + capDonInfo: capDonInfo, + capDonMembers: capDonMembers, + localDonInfo: localDonInfo, + dispatcher: dispatcher, + aggregator: aggregator, + messageCache: NewMessageCache[triggerEventKey, p2ptypes.PeerID](), + registeredWorkflows: make(map[string]*subRegState), + stopCh: make(services.StopChan), + lggr: lggr, + } +} + +func (s *triggerSubscriber) Start(ctx context.Context) error { + s.wg.Add(2) + go s.registrationLoop() + go s.eventCleanupLoop() + s.lggr.Info("TriggerSubscriber started") + return nil +} + +func (s *triggerSubscriber) Info(ctx context.Context) (commoncap.CapabilityInfo, error) { + return s.capInfo, nil +} + +func (s *triggerSubscriber) RegisterTrigger(ctx context.Context, callback chan<- commoncap.CapabilityResponse, request commoncap.CapabilityRequest) error { + rawRequest, err := pb.MarshalCapabilityRequest(request) + if err != nil { + return err + } + if request.Metadata.WorkflowID == "" { + return errors.New("empty workflowID") + } + s.mu.Lock() + defer s.mu.Unlock() + s.registeredWorkflows[request.Metadata.WorkflowID] = &subRegState{ + callback: callback, + rawRequest: rawRequest, + } + return nil +} + +func (s *triggerSubscriber) registrationLoop() { + defer s.wg.Done() + ticker := time.NewTicker(time.Duration(s.config.RegistrationRefreshMs) * time.Millisecond) + defer ticker.Stop() + for { + select { + case <-s.stopCh: + return + case <-ticker.C: + s.lggr.Infow("register trigger for remote capability", "capabilityId", s.capInfo.ID, "donId", s.capDonInfo.ID, "nMembers", len(s.capDonInfo.Members)) + s.mu.RLock() + for _, registration := range s.registeredWorkflows { + // NOTE: send to all by default, introduce different strategies later (KS-76) + for _, peerID := range s.capDonInfo.Members { + m := &types.MessageBody{ + CapabilityId: s.capInfo.ID, + CapabilityDonId: s.capDonInfo.ID, + CallerDonId: s.localDonInfo.ID, + Method: types.MethodRegisterTrigger, + Payload: registration.rawRequest, + } + err := s.dispatcher.Send(peerID, m) + if err != nil { + s.lggr.Errorw("failed to send message", "capabilityId", s.capInfo.ID, "donId", s.capDonInfo.ID, "peerId", peerID, "err", err) + } + } + } + s.mu.RUnlock() + } + } +} + +func (s *triggerSubscriber) UnregisterTrigger(ctx context.Context, request commoncap.CapabilityRequest) error { + s.mu.Lock() + defer s.mu.Unlock() + delete(s.registeredWorkflows, request.Metadata.WorkflowID) + // Registrations will quickly expire on all remote nodes. + // Alternatively, we could send UnregisterTrigger messages right away. + return nil +} + +func (s *triggerSubscriber) Receive(msg *types.MessageBody) { + sender := ToPeerID(msg.Sender) + if _, found := s.capDonMembers[sender]; !found { + s.lggr.Errorw("received message from unexpected node", "capabilityId", s.capInfo.ID, "sender", sender) + return + } + if msg.Method == types.MethodTriggerEvent { + meta := msg.GetTriggerEventMetadata() + if meta == nil { + s.lggr.Errorw("received message with invalid trigger metadata", "capabilityId", s.capInfo.ID, "sender", sender) + return + } + for _, workflowId := range meta.WorkflowIds { + s.mu.RLock() + registration, found := s.registeredWorkflows[workflowId] + s.mu.RUnlock() + if !found { + s.lggr.Errorw("received message for unregistered workflow", "capabilityId", s.capInfo.ID, "workflowID", workflowId, "sender", sender) + continue + } + key := triggerEventKey{ + triggerEventId: meta.TriggerEventId, + workflowId: workflowId, + } + nowMs := time.Now().UnixMilli() + s.mu.RLock() + creationTs := s.messageCache.Insert(key, sender, nowMs, msg.Payload) + ready, payloads := s.messageCache.Ready(key, s.config.MinResponsesToAggregate, nowMs-int64(s.config.MessageExpiryMs), true) + s.mu.RUnlock() + if nowMs-creationTs > int64(s.config.RegistrationExpiryMs) { + s.lggr.Warnw("received trigger event for an expired ID", "triggerEventID", meta.TriggerEventId, "capabilityId", s.capInfo.ID, "workflowId", workflowId, "sender", sender) + continue + } + if ready { + aggregatedResponse, err := s.aggregator.Aggregate(meta.TriggerEventId, payloads) + if err != nil { + s.lggr.Errorw("failed to aggregate responses", "capabilityId", s.capInfo.ID, "workflowId", workflowId, "err", err) + continue + } + unmarshaled, err := pb.UnmarshalCapabilityResponse(aggregatedResponse) + if err != nil { + s.lggr.Errorw("failed to unmarshal responses", "capabilityId", s.capInfo.ID, "workflowId", workflowId, "err", err) + continue + } + s.lggr.Info("remote trigger event aggregated", "triggerEventID", meta.TriggerEventId, "capabilityId", s.capInfo.ID, "workflowId", workflowId) + registration.callback <- unmarshaled + } + } + } else { + s.lggr.Errorw("received trigger event with unknown method", "method", msg.Method, "sender", sender) + } +} + +func (s *triggerSubscriber) eventCleanupLoop() { + defer s.wg.Done() + ticker := time.NewTicker(time.Duration(s.config.MessageExpiryMs) * time.Millisecond) + defer ticker.Stop() + for { + select { + case <-s.stopCh: + return + case <-ticker.C: + s.mu.Lock() + s.messageCache.DeleteOlderThan(time.Now().UnixMilli() - int64(s.config.MessageExpiryMs)) + s.mu.Unlock() + } + } +} + +func (s *triggerSubscriber) Close() error { + close(s.stopCh) + s.wg.Wait() + s.lggr.Info("TriggerSubscriber closed") + return nil +} + +func (s *triggerSubscriber) Ready() error { + return nil +} + +func (s *triggerSubscriber) HealthReport() map[string]error { + return nil +} + +func (s *triggerSubscriber) Name() string { + return "TriggerSubscriber" +} diff --git a/core/capabilities/remote/trigger_subscriber_test.go b/core/capabilities/remote/trigger_subscriber_test.go new file mode 100644 index 00000000000..ce901169f10 --- /dev/null +++ b/core/capabilities/remote/trigger_subscriber_test.go @@ -0,0 +1,102 @@ +package remote_test + +import ( + "testing" + + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + commoncap "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" + "github.com/smartcontractkit/chainlink-common/pkg/values" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote" + remotetypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" + remoteMocks "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types/mocks" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/logger" + p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" +) + +const ( + peerID1 = "12D3KooWF3dVeJ6YoT5HFnYhmwQWWMoEwVFzJQ5kKCMX3ZityxMC" + peerID2 = "12D3KooWQsmok6aD8PZqt3RnJhQRrNzKHLficq7zYFRp7kZ1hHP8" + workflowID1 = "workflowID1" + triggerEvent1 = "triggerEvent1" + triggerEvent2 = "triggerEvent2" +) + +func TestTriggerSubscriber_RegisterAndReceive(t *testing.T) { + lggr := logger.TestLogger(t) + ctx := testutils.Context(t) + capInfo := commoncap.CapabilityInfo{ + ID: "cap_id", + CapabilityType: commoncap.CapabilityTypeTrigger, + Description: "Remote Trigger", + Version: "0.0.1", + } + p1 := p2ptypes.PeerID{} + require.NoError(t, p1.UnmarshalText([]byte(peerID1))) + p2 := p2ptypes.PeerID{} + require.NoError(t, p2.UnmarshalText([]byte(peerID2))) + capDonInfo := remotetypes.DON{ + ID: "capability-don", + Members: []p2ptypes.PeerID{p1}, + F: 0, + } + workflowDonInfo := remotetypes.DON{ + ID: "workflow-don", + Members: []p2ptypes.PeerID{p2}, + F: 0, + } + dispatcher := remoteMocks.NewDispatcher(t) + + awaitRegistrationMessageCh := make(chan struct{}) + dispatcher.On("Send", mock.Anything, mock.Anything).Return(nil).Run(func(args mock.Arguments) { + select { + case awaitRegistrationMessageCh <- struct{}{}: + default: + } + }) + + // register trigger + config := remotetypes.RemoteTriggerConfig{ + RegistrationRefreshMs: 100, + RegistrationExpiryMs: 100, + MinResponsesToAggregate: 1, + MessageExpiryMs: 100_000, + } + subscriber := remote.NewTriggerSubscriber(config, capInfo, capDonInfo, workflowDonInfo, dispatcher, nil, lggr) + require.NoError(t, subscriber.Start(ctx)) + triggerEventCallbackCh := make(chan commoncap.CapabilityResponse, 2) + require.NoError(t, subscriber.RegisterTrigger(ctx, triggerEventCallbackCh, commoncap.CapabilityRequest{ + Metadata: commoncap.RequestMetadata{ + WorkflowID: workflowID1, + }, + })) + <-awaitRegistrationMessageCh + + // receive trigger event + triggerEventValue, err := values.Wrap(triggerEvent1) + require.NoError(t, err) + capResponse := commoncap.CapabilityResponse{ + Value: triggerEventValue, + Err: nil, + } + marshaled, err := pb.MarshalCapabilityResponse(capResponse) + require.NoError(t, err) + triggerEvent := &remotetypes.MessageBody{ + Sender: p1[:], + Method: remotetypes.MethodTriggerEvent, + Metadata: &remotetypes.MessageBody_TriggerEventMetadata{ + TriggerEventMetadata: &remotetypes.TriggerEventMetadata{ + WorkflowIds: []string{workflowID1}, + }, + }, + Payload: marshaled, + } + subscriber.Receive(triggerEvent) + response := <-triggerEventCallbackCh + require.Equal(t, response.Value, triggerEventValue) + + require.NoError(t, subscriber.Close()) +} diff --git a/core/capabilities/remote/types/config.go b/core/capabilities/remote/types/config.go new file mode 100644 index 00000000000..588ae98095c --- /dev/null +++ b/core/capabilities/remote/types/config.go @@ -0,0 +1,28 @@ +package types + +const ( + DefaultRegistrationRefreshMs = 30_000 + DefaultRegistrationExpiryMs = 120_000 + DefaultMessageExpiryMs = 120_000 +) + +// NOTE: consider splitting this config into values stored in Registry (KS-118) +// and values defined locally by Capability owners. +type RemoteTriggerConfig struct { + RegistrationRefreshMs uint32 + RegistrationExpiryMs uint32 + MinResponsesToAggregate uint32 + MessageExpiryMs uint32 +} + +func (c *RemoteTriggerConfig) ApplyDefaults() { + if c.RegistrationRefreshMs == 0 { + c.RegistrationRefreshMs = DefaultRegistrationRefreshMs + } + if c.RegistrationExpiryMs == 0 { + c.RegistrationExpiryMs = DefaultRegistrationExpiryMs + } + if c.MessageExpiryMs == 0 { + c.MessageExpiryMs = DefaultMessageExpiryMs + } +} diff --git a/core/capabilities/remote/types/message.pb.go b/core/capabilities/remote/types/message.pb.go new file mode 100644 index 00000000000..d8e9579e96c --- /dev/null +++ b/core/capabilities/remote/types/message.pb.go @@ -0,0 +1,575 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc v3.21.8 +// source: core/capabilities/remote/types/message.proto + +package types + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Error int32 + +const ( + Error_OK Error = 0 + Error_VALIDATION_FAILED Error = 1 + Error_CAPABILITY_NOT_FOUND Error = 2 +) + +// Enum value maps for Error. +var ( + Error_name = map[int32]string{ + 0: "OK", + 1: "VALIDATION_FAILED", + 2: "CAPABILITY_NOT_FOUND", + } + Error_value = map[string]int32{ + "OK": 0, + "VALIDATION_FAILED": 1, + "CAPABILITY_NOT_FOUND": 2, + } +) + +func (x Error) Enum() *Error { + p := new(Error) + *p = x + return p +} + +func (x Error) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Error) Descriptor() protoreflect.EnumDescriptor { + return file_core_capabilities_remote_types_message_proto_enumTypes[0].Descriptor() +} + +func (Error) Type() protoreflect.EnumType { + return &file_core_capabilities_remote_types_message_proto_enumTypes[0] +} + +func (x Error) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Error.Descriptor instead. +func (Error) EnumDescriptor() ([]byte, []int) { + return file_core_capabilities_remote_types_message_proto_rawDescGZIP(), []int{0} +} + +type Message struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Signature []byte `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"` + Body []byte `protobuf:"bytes,2,opt,name=body,proto3" json:"body,omitempty"` // proto-encoded MessageBody to sign +} + +func (x *Message) Reset() { + *x = Message{} + if protoimpl.UnsafeEnabled { + mi := &file_core_capabilities_remote_types_message_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Message) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Message) ProtoMessage() {} + +func (x *Message) ProtoReflect() protoreflect.Message { + mi := &file_core_capabilities_remote_types_message_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Message.ProtoReflect.Descriptor instead. +func (*Message) Descriptor() ([]byte, []int) { + return file_core_capabilities_remote_types_message_proto_rawDescGZIP(), []int{0} +} + +func (x *Message) GetSignature() []byte { + if x != nil { + return x.Signature + } + return nil +} + +func (x *Message) GetBody() []byte { + if x != nil { + return x.Body + } + return nil +} + +type MessageBody struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // header fields set and validated by the Dispatcher + Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + Sender []byte `protobuf:"bytes,2,opt,name=sender,proto3" json:"sender,omitempty"` + Receiver []byte `protobuf:"bytes,3,opt,name=receiver,proto3" json:"receiver,omitempty"` + Timestamp int64 `protobuf:"varint,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + MessageId []byte `protobuf:"bytes,5,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"` // scoped to sender + CapabilityId string `protobuf:"bytes,6,opt,name=capability_id,json=capabilityId,proto3" json:"capability_id,omitempty"` + CapabilityDonId string `protobuf:"bytes,7,opt,name=capability_don_id,json=capabilityDonId,proto3" json:"capability_don_id,omitempty"` + CallerDonId string `protobuf:"bytes,8,opt,name=caller_don_id,json=callerDonId,proto3" json:"caller_don_id,omitempty"` + Method string `protobuf:"bytes,9,opt,name=method,proto3" json:"method,omitempty"` + Error Error `protobuf:"varint,10,opt,name=error,proto3,enum=remote.Error" json:"error,omitempty"` + // payload contains a CapabilityRequest or CapabilityResponse + Payload []byte `protobuf:"bytes,11,opt,name=payload,proto3" json:"payload,omitempty"` + // Types that are assignable to Metadata: + // *MessageBody_TriggerRegistrationMetadata + // *MessageBody_TriggerEventMetadata + Metadata isMessageBody_Metadata `protobuf_oneof:"metadata"` +} + +func (x *MessageBody) Reset() { + *x = MessageBody{} + if protoimpl.UnsafeEnabled { + mi := &file_core_capabilities_remote_types_message_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MessageBody) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MessageBody) ProtoMessage() {} + +func (x *MessageBody) ProtoReflect() protoreflect.Message { + mi := &file_core_capabilities_remote_types_message_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MessageBody.ProtoReflect.Descriptor instead. +func (*MessageBody) Descriptor() ([]byte, []int) { + return file_core_capabilities_remote_types_message_proto_rawDescGZIP(), []int{1} +} + +func (x *MessageBody) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *MessageBody) GetSender() []byte { + if x != nil { + return x.Sender + } + return nil +} + +func (x *MessageBody) GetReceiver() []byte { + if x != nil { + return x.Receiver + } + return nil +} + +func (x *MessageBody) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *MessageBody) GetMessageId() []byte { + if x != nil { + return x.MessageId + } + return nil +} + +func (x *MessageBody) GetCapabilityId() string { + if x != nil { + return x.CapabilityId + } + return "" +} + +func (x *MessageBody) GetCapabilityDonId() string { + if x != nil { + return x.CapabilityDonId + } + return "" +} + +func (x *MessageBody) GetCallerDonId() string { + if x != nil { + return x.CallerDonId + } + return "" +} + +func (x *MessageBody) GetMethod() string { + if x != nil { + return x.Method + } + return "" +} + +func (x *MessageBody) GetError() Error { + if x != nil { + return x.Error + } + return Error_OK +} + +func (x *MessageBody) GetPayload() []byte { + if x != nil { + return x.Payload + } + return nil +} + +func (m *MessageBody) GetMetadata() isMessageBody_Metadata { + if m != nil { + return m.Metadata + } + return nil +} + +func (x *MessageBody) GetTriggerRegistrationMetadata() *TriggerRegistrationMetadata { + if x, ok := x.GetMetadata().(*MessageBody_TriggerRegistrationMetadata); ok { + return x.TriggerRegistrationMetadata + } + return nil +} + +func (x *MessageBody) GetTriggerEventMetadata() *TriggerEventMetadata { + if x, ok := x.GetMetadata().(*MessageBody_TriggerEventMetadata); ok { + return x.TriggerEventMetadata + } + return nil +} + +type isMessageBody_Metadata interface { + isMessageBody_Metadata() +} + +type MessageBody_TriggerRegistrationMetadata struct { + TriggerRegistrationMetadata *TriggerRegistrationMetadata `protobuf:"bytes,12,opt,name=trigger_registration_metadata,json=triggerRegistrationMetadata,proto3,oneof"` +} + +type MessageBody_TriggerEventMetadata struct { + TriggerEventMetadata *TriggerEventMetadata `protobuf:"bytes,13,opt,name=trigger_event_metadata,json=triggerEventMetadata,proto3,oneof"` +} + +func (*MessageBody_TriggerRegistrationMetadata) isMessageBody_Metadata() {} + +func (*MessageBody_TriggerEventMetadata) isMessageBody_Metadata() {} + +type TriggerRegistrationMetadata struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + LastReceivedEventId string `protobuf:"bytes,1,opt,name=last_received_event_id,json=lastReceivedEventId,proto3" json:"last_received_event_id,omitempty"` +} + +func (x *TriggerRegistrationMetadata) Reset() { + *x = TriggerRegistrationMetadata{} + if protoimpl.UnsafeEnabled { + mi := &file_core_capabilities_remote_types_message_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TriggerRegistrationMetadata) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TriggerRegistrationMetadata) ProtoMessage() {} + +func (x *TriggerRegistrationMetadata) ProtoReflect() protoreflect.Message { + mi := &file_core_capabilities_remote_types_message_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TriggerRegistrationMetadata.ProtoReflect.Descriptor instead. +func (*TriggerRegistrationMetadata) Descriptor() ([]byte, []int) { + return file_core_capabilities_remote_types_message_proto_rawDescGZIP(), []int{2} +} + +func (x *TriggerRegistrationMetadata) GetLastReceivedEventId() string { + if x != nil { + return x.LastReceivedEventId + } + return "" +} + +type TriggerEventMetadata struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TriggerEventId string `protobuf:"bytes,1,opt,name=trigger_event_id,json=triggerEventId,proto3" json:"trigger_event_id,omitempty"` + WorkflowIds []string `protobuf:"bytes,2,rep,name=workflow_ids,json=workflowIds,proto3" json:"workflow_ids,omitempty"` +} + +func (x *TriggerEventMetadata) Reset() { + *x = TriggerEventMetadata{} + if protoimpl.UnsafeEnabled { + mi := &file_core_capabilities_remote_types_message_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TriggerEventMetadata) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TriggerEventMetadata) ProtoMessage() {} + +func (x *TriggerEventMetadata) ProtoReflect() protoreflect.Message { + mi := &file_core_capabilities_remote_types_message_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TriggerEventMetadata.ProtoReflect.Descriptor instead. +func (*TriggerEventMetadata) Descriptor() ([]byte, []int) { + return file_core_capabilities_remote_types_message_proto_rawDescGZIP(), []int{3} +} + +func (x *TriggerEventMetadata) GetTriggerEventId() string { + if x != nil { + return x.TriggerEventId + } + return "" +} + +func (x *TriggerEventMetadata) GetWorkflowIds() []string { + if x != nil { + return x.WorkflowIds + } + return nil +} + +var File_core_capabilities_remote_types_message_proto protoreflect.FileDescriptor + +var file_core_capabilities_remote_types_message_proto_rawDesc = []byte{ + 0x0a, 0x2c, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, + 0x69, 0x65, 0x73, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, + 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x22, 0x3b, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, + 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x62, + 0x6f, 0x64, 0x79, 0x22, 0xb1, 0x04, 0x0a, 0x0b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, + 0x6f, 0x64, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, + 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, + 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, + 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, + 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, + 0x1d, 0x0a, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x23, + 0x0a, 0x0d, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, + 0x79, 0x49, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, + 0x79, 0x5f, 0x64, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, + 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6e, 0x49, 0x64, 0x12, + 0x22, 0x0a, 0x0d, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x64, 0x6f, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x44, 0x6f, + 0x6e, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x23, 0x0a, 0x05, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x72, 0x65, 0x6d, + 0x6f, 0x74, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x69, 0x0a, 0x1d, 0x74, 0x72, + 0x69, 0x67, 0x67, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0c, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x54, 0x72, 0x69, 0x67, 0x67, + 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x1b, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, + 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x54, 0x0a, 0x16, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, + 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, + 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x54, + 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x14, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x0a, 0x0a, 0x08, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x52, 0x0a, 0x1b, 0x54, 0x72, 0x69, 0x67, 0x67, + 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x33, 0x0a, 0x16, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x72, + 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x6c, 0x61, 0x73, 0x74, 0x52, 0x65, 0x63, 0x65, + 0x69, 0x76, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x63, 0x0a, 0x14, 0x54, + 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x5f, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, + 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x21, 0x0a, + 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x73, + 0x2a, 0x40, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x4b, 0x10, + 0x00, 0x12, 0x15, 0x0a, 0x11, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, + 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x43, 0x41, 0x50, 0x41, + 0x42, 0x49, 0x4c, 0x49, 0x54, 0x59, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x46, 0x4f, 0x55, 0x4e, 0x44, + 0x10, 0x02, 0x42, 0x20, 0x5a, 0x1e, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x61, 0x70, 0x61, 0x62, + 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2f, 0x74, + 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_core_capabilities_remote_types_message_proto_rawDescOnce sync.Once + file_core_capabilities_remote_types_message_proto_rawDescData = file_core_capabilities_remote_types_message_proto_rawDesc +) + +func file_core_capabilities_remote_types_message_proto_rawDescGZIP() []byte { + file_core_capabilities_remote_types_message_proto_rawDescOnce.Do(func() { + file_core_capabilities_remote_types_message_proto_rawDescData = protoimpl.X.CompressGZIP(file_core_capabilities_remote_types_message_proto_rawDescData) + }) + return file_core_capabilities_remote_types_message_proto_rawDescData +} + +var file_core_capabilities_remote_types_message_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_core_capabilities_remote_types_message_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_core_capabilities_remote_types_message_proto_goTypes = []interface{}{ + (Error)(0), // 0: remote.Error + (*Message)(nil), // 1: remote.Message + (*MessageBody)(nil), // 2: remote.MessageBody + (*TriggerRegistrationMetadata)(nil), // 3: remote.TriggerRegistrationMetadata + (*TriggerEventMetadata)(nil), // 4: remote.TriggerEventMetadata +} +var file_core_capabilities_remote_types_message_proto_depIdxs = []int32{ + 0, // 0: remote.MessageBody.error:type_name -> remote.Error + 3, // 1: remote.MessageBody.trigger_registration_metadata:type_name -> remote.TriggerRegistrationMetadata + 4, // 2: remote.MessageBody.trigger_event_metadata:type_name -> remote.TriggerEventMetadata + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_core_capabilities_remote_types_message_proto_init() } +func file_core_capabilities_remote_types_message_proto_init() { + if File_core_capabilities_remote_types_message_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_core_capabilities_remote_types_message_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Message); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_core_capabilities_remote_types_message_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MessageBody); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_core_capabilities_remote_types_message_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TriggerRegistrationMetadata); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_core_capabilities_remote_types_message_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TriggerEventMetadata); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_core_capabilities_remote_types_message_proto_msgTypes[1].OneofWrappers = []interface{}{ + (*MessageBody_TriggerRegistrationMetadata)(nil), + (*MessageBody_TriggerEventMetadata)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_core_capabilities_remote_types_message_proto_rawDesc, + NumEnums: 1, + NumMessages: 4, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_core_capabilities_remote_types_message_proto_goTypes, + DependencyIndexes: file_core_capabilities_remote_types_message_proto_depIdxs, + EnumInfos: file_core_capabilities_remote_types_message_proto_enumTypes, + MessageInfos: file_core_capabilities_remote_types_message_proto_msgTypes, + }.Build() + File_core_capabilities_remote_types_message_proto = out.File + file_core_capabilities_remote_types_message_proto_rawDesc = nil + file_core_capabilities_remote_types_message_proto_goTypes = nil + file_core_capabilities_remote_types_message_proto_depIdxs = nil +} diff --git a/core/capabilities/remote/types/message.proto b/core/capabilities/remote/types/message.proto new file mode 100644 index 00000000000..072accedbc0 --- /dev/null +++ b/core/capabilities/remote/types/message.proto @@ -0,0 +1,45 @@ +syntax = "proto3"; + +option go_package = "core/capabilities/remote/types"; + +package remote; + +enum Error { + OK = 0; + VALIDATION_FAILED = 1; + CAPABILITY_NOT_FOUND = 2; +} + +message Message { + bytes signature = 1; + bytes body = 2; // proto-encoded MessageBody to sign +} + +message MessageBody { + uint32 version = 1; + bytes sender = 2; + bytes receiver = 3; + int64 timestamp = 4; + bytes message_id = 5; // scoped to sender + string capability_id = 6; + string capability_don_id = 7; + string caller_don_id = 8; + string method = 9; + Error error = 10; + + // payload contains a CapabilityRequest or CapabilityResponse + bytes payload = 11; + oneof metadata { + TriggerRegistrationMetadata trigger_registration_metadata = 12; + TriggerEventMetadata trigger_event_metadata = 13; + } +} + +message TriggerRegistrationMetadata { + string last_received_event_id = 1; +} + +message TriggerEventMetadata { + string trigger_event_id = 1; + repeated string workflow_ids = 2; +} diff --git a/core/capabilities/remote/types/mocks/dispatcher.go b/core/capabilities/remote/types/mocks/dispatcher.go new file mode 100644 index 00000000000..8675e6153ac --- /dev/null +++ b/core/capabilities/remote/types/mocks/dispatcher.go @@ -0,0 +1,69 @@ +// Code generated by mockery v2.38.0. DO NOT EDIT. + +package mocks + +import ( + types "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" + ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" + mock "github.com/stretchr/testify/mock" +) + +// Dispatcher is an autogenerated mock type for the Dispatcher type +type Dispatcher struct { + mock.Mock +} + +// RemoveReceiver provides a mock function with given fields: capabilityId, donId +func (_m *Dispatcher) RemoveReceiver(capabilityId string, donId string) { + _m.Called(capabilityId, donId) +} + +// Send provides a mock function with given fields: peerID, msgBody +func (_m *Dispatcher) Send(peerID ragep2ptypes.PeerID, msgBody *types.MessageBody) error { + ret := _m.Called(peerID, msgBody) + + if len(ret) == 0 { + panic("no return value specified for Send") + } + + var r0 error + if rf, ok := ret.Get(0).(func(ragep2ptypes.PeerID, *types.MessageBody) error); ok { + r0 = rf(peerID, msgBody) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// SetReceiver provides a mock function with given fields: capabilityId, donId, receiver +func (_m *Dispatcher) SetReceiver(capabilityId string, donId string, receiver types.Receiver) error { + ret := _m.Called(capabilityId, donId, receiver) + + if len(ret) == 0 { + panic("no return value specified for SetReceiver") + } + + var r0 error + if rf, ok := ret.Get(0).(func(string, string, types.Receiver) error); ok { + r0 = rf(capabilityId, donId, receiver) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// NewDispatcher creates a new instance of Dispatcher. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewDispatcher(t interface { + mock.TestingT + Cleanup(func()) +}) *Dispatcher { + mock := &Dispatcher{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/capabilities/remote/types/mocks/receiver.go b/core/capabilities/remote/types/mocks/receiver.go new file mode 100644 index 00000000000..a15c464450e --- /dev/null +++ b/core/capabilities/remote/types/mocks/receiver.go @@ -0,0 +1,32 @@ +// Code generated by mockery v2.38.0. DO NOT EDIT. + +package mocks + +import ( + types "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" + mock "github.com/stretchr/testify/mock" +) + +// Receiver is an autogenerated mock type for the Receiver type +type Receiver struct { + mock.Mock +} + +// Receive provides a mock function with given fields: msg +func (_m *Receiver) Receive(msg *types.MessageBody) { + _m.Called(msg) +} + +// NewReceiver creates a new instance of Receiver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewReceiver(t interface { + mock.TestingT + Cleanup(func()) +}) *Receiver { + mock := &Receiver{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/capabilities/remote/types/types.go b/core/capabilities/remote/types/types.go new file mode 100644 index 00000000000..327c2b8d4c5 --- /dev/null +++ b/core/capabilities/remote/types/types.go @@ -0,0 +1,34 @@ +package types + +import ( + p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" +) + +const ( + MethodRegisterTrigger = "RegisterTrigger" + MethodUnRegisterTrigger = "UnregisterTrigger" + MethodTriggerEvent = "TriggerEvent" +) + +//go:generate mockery --quiet --name Dispatcher --output ./mocks/ --case=underscore +type Dispatcher interface { + SetReceiver(capabilityId string, donId string, receiver Receiver) error + RemoveReceiver(capabilityId string, donId string) + Send(peerID p2ptypes.PeerID, msgBody *MessageBody) error +} + +//go:generate mockery --quiet --name Receiver --output ./mocks/ --case=underscore +type Receiver interface { + Receive(msg *MessageBody) +} + +type Aggregator interface { + Aggregate(eventID string, responses [][]byte) ([]byte, error) +} + +// NOTE: this type will become part of the Registry (KS-108) +type DON struct { + ID string + Members []p2ptypes.PeerID + F uint8 +} diff --git a/core/capabilities/remote/utils.go b/core/capabilities/remote/utils.go new file mode 100644 index 00000000000..92c5e5447a5 --- /dev/null +++ b/core/capabilities/remote/utils.go @@ -0,0 +1,80 @@ +package remote + +import ( + "bytes" + "crypto/ed25519" + "crypto/sha256" + "encoding/hex" + "errors" + "fmt" + + "google.golang.org/protobuf/proto" + + remotetypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" + p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" +) + +func ValidateMessage(msg p2ptypes.Message, expectedReceiver p2ptypes.PeerID) (*remotetypes.MessageBody, error) { + var topLevelMessage remotetypes.Message + err := proto.Unmarshal(msg.Payload, &topLevelMessage) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal message, err: %v", err) + } + var body remotetypes.MessageBody + err = proto.Unmarshal(topLevelMessage.Body, &body) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal message body, err: %v", err) + } + if len(body.Sender) != p2ptypes.PeerIDLength || len(body.Receiver) != p2ptypes.PeerIDLength { + return &body, fmt.Errorf("invalid sender length (%d) or receiver length (%d)", len(body.Sender), len(body.Receiver)) + } + if !ed25519.Verify(body.Sender, topLevelMessage.Body, topLevelMessage.Signature) { + return &body, fmt.Errorf("failed to verify message signature") + } + // NOTE we currently don't support relaying messages so the p2p message sender needs to be the message author + if !bytes.Equal(body.Sender, msg.Sender[:]) { + return &body, fmt.Errorf("sender in message body does not match sender of p2p message") + } + if !bytes.Equal(body.Receiver, expectedReceiver[:]) { + return &body, fmt.Errorf("receiver in message body does not match expected receiver") + } + return &body, nil +} + +func ToPeerID(peerID []byte) p2ptypes.PeerID { + var id p2ptypes.PeerID + copy(id[:], peerID) + return id +} + +// Default MODE Aggregator needs a configurable number of identical responses for aggregation to succeed +type defaultModeAggregator struct { + minIdenticalResponses uint32 +} + +var _ remotetypes.Aggregator = &defaultModeAggregator{} + +func NewDefaultModeAggregator(minIdenticalResponses uint32) *defaultModeAggregator { + return &defaultModeAggregator{ + minIdenticalResponses: minIdenticalResponses, + } +} + +func (a *defaultModeAggregator) Aggregate(_ string, responses [][]byte) ([]byte, error) { + hashToCount := make(map[string]uint32) + var found []byte + for _, resp := range responses { + hasher := sha256.New() + hasher.Write(resp) + sha := hex.EncodeToString(hasher.Sum(nil)) + hashToCount[sha]++ + if hashToCount[sha] >= a.minIdenticalResponses { + found = resp + break + } + } + if found == nil { + return nil, errors.New("not enough identical responses found") + } + return found, nil +} diff --git a/core/capabilities/remote/utils_test.go b/core/capabilities/remote/utils_test.go new file mode 100644 index 00000000000..120cf5604ca --- /dev/null +++ b/core/capabilities/remote/utils_test.go @@ -0,0 +1,118 @@ +package remote_test + +import ( + "bytes" + "crypto/ed25519" + "crypto/rand" + "testing" + + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" + + ragetypes "github.com/smartcontractkit/libocr/ragep2p/types" + + commoncap "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" + "github.com/smartcontractkit/chainlink-common/pkg/values" + + "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote" + remotetypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" + p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" +) + +const ( + capId1 = "cap1" + capId2 = "cap2" + donId1 = "donA" + payload1 = "hello world" + payload2 = "goodbye world" +) + +func TestValidateMessage(t *testing.T) { + privKey1, peerId1 := newKeyPair(t) + _, peerId2 := newKeyPair(t) + + // valid + p2pMsg := encodeAndSign(t, privKey1, peerId1, peerId2, capId1, donId1, []byte(payload1)) + body, err := remote.ValidateMessage(p2pMsg, peerId2) + require.NoError(t, err) + require.Equal(t, peerId1[:], body.Sender) + require.Equal(t, payload1, string(body.Payload)) + + // invalid sender + p2pMsg = encodeAndSign(t, privKey1, peerId1, peerId2, capId1, donId1, []byte(payload1)) + p2pMsg.Sender = peerId2 + _, err = remote.ValidateMessage(p2pMsg, peerId2) + require.Error(t, err) + + // invalid receiver + p2pMsg = encodeAndSign(t, privKey1, peerId1, peerId2, capId1, donId1, []byte(payload1)) + _, err = remote.ValidateMessage(p2pMsg, peerId1) + require.Error(t, err) +} + +func newKeyPair(t *testing.T) (ed25519.PrivateKey, ragetypes.PeerID) { + _, privKey, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + peerID, err := ragetypes.PeerIDFromPrivateKey(privKey) + require.NoError(t, err) + return privKey, peerID +} + +func encodeAndSign(t *testing.T, senderPrivKey ed25519.PrivateKey, senderId p2ptypes.PeerID, receiverId p2ptypes.PeerID, capabilityId string, donId string, payload []byte) p2ptypes.Message { + body := remotetypes.MessageBody{ + Sender: senderId[:], + Receiver: receiverId[:], + CapabilityId: capabilityId, + CapabilityDonId: donId, + Payload: payload, + } + rawBody, err := proto.Marshal(&body) + require.NoError(t, err) + signature := ed25519.Sign(senderPrivKey, rawBody) + + msg := remotetypes.Message{ + Signature: signature, + Body: rawBody, + } + rawMsg, err := proto.Marshal(&msg) + require.NoError(t, err) + + return p2ptypes.Message{ + Sender: senderId, + Payload: rawMsg, + } +} + +func TestToPeerID(t *testing.T) { + id := remote.ToPeerID([]byte("12345678901234567890123456789012")) + require.Equal(t, "12D3KooWD8QYTQVYjB6oog4Ej8PcPpqTrPRnxLQap8yY8KUQRVvq", id.String()) +} + +func TestDefaultModeAggregator_Aggregate(t *testing.T) { + capResponse1 := marshalCapabilityResponse(t, triggerEvent1, nil) + capResponse2 := marshalCapabilityResponse(t, triggerEvent2, nil) + + agg := remote.NewDefaultModeAggregator(2) + _, err := agg.Aggregate("", [][]byte{capResponse1}) + require.Error(t, err) + + _, err = agg.Aggregate("", [][]byte{capResponse1, capResponse2}) + require.Error(t, err) + + res, err := agg.Aggregate("", [][]byte{capResponse1, capResponse2, capResponse1}) + require.NoError(t, err) + require.True(t, bytes.Equal(res, capResponse1)) +} + +func marshalCapabilityResponse(t *testing.T, capValue any, capError error) []byte { + val, err := values.Wrap(capValue) + require.NoError(t, err) + capResponse := commoncap.CapabilityResponse{ + Value: val, + Err: capError, + } + marshaled, err := pb.MarshalCapabilityResponse(capResponse) + require.NoError(t, err) + return marshaled +} diff --git a/core/capabilities/syncer.go b/core/capabilities/syncer.go index a8cfb2c56f8..748910c462b 100644 --- a/core/capabilities/syncer.go +++ b/core/capabilities/syncer.go @@ -2,13 +2,17 @@ package capabilities import ( "context" + "slices" + commoncap "github.com/smartcontractkit/chainlink-common/pkg/capabilities" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/libocr/ragep2p" ragetypes "github.com/smartcontractkit/libocr/ragep2p/types" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote" + remotetypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" "github.com/smartcontractkit/chainlink/v2/core/logger" p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" ) @@ -16,54 +20,134 @@ import ( type registrySyncer struct { peerWrapper p2ptypes.PeerWrapper registry types.CapabilitiesRegistry + dispatcher remotetypes.Dispatcher + subServices []services.Service lggr logger.Logger } var _ services.Service = ®istrySyncer{} +var defaultStreamConfig = p2ptypes.StreamConfig{ + IncomingMessageBufferSize: 1000000, + OutgoingMessageBufferSize: 1000000, + MaxMessageLenBytes: 100000, + MessageRateLimiter: ragep2p.TokenBucketParams{ + Rate: 10.0, + Capacity: 1000, + }, + BytesRateLimiter: ragep2p.TokenBucketParams{ + Rate: 10.0, + Capacity: 1000, + }, +} + // RegistrySyncer updates local Registry to match its onchain counterpart -func NewRegistrySyncer(peerWrapper p2ptypes.PeerWrapper, registry types.CapabilitiesRegistry, lggr logger.Logger) *registrySyncer { +func NewRegistrySyncer(peerWrapper p2ptypes.PeerWrapper, registry types.CapabilitiesRegistry, dispatcher remotetypes.Dispatcher, lggr logger.Logger) *registrySyncer { return ®istrySyncer{ peerWrapper: peerWrapper, registry: registry, + dispatcher: dispatcher, lggr: lggr, } } func (s *registrySyncer) Start(ctx context.Context) error { - // NOTE: temporary hard-coded values - defaultStreamConfig := p2ptypes.StreamConfig{ - IncomingMessageBufferSize: 1000000, - OutgoingMessageBufferSize: 1000000, - MaxMessageLenBytes: 100000, - MessageRateLimiter: ragep2p.TokenBucketParams{ - Rate: 10.0, - Capacity: 1000, - }, - BytesRateLimiter: ragep2p.TokenBucketParams{ - Rate: 10.0, - Capacity: 1000, - }, - } - peerIDs := []string{ + // NOTE: temporary hard-coded DONs + workflowDONPeers := []string{ "12D3KooWF3dVeJ6YoT5HFnYhmwQWWMoEwVFzJQ5kKCMX3ZityxMC", "12D3KooWQsmok6aD8PZqt3RnJhQRrNzKHLficq7zYFRp7kZ1hHP8", "12D3KooWJbZLiMuGeKw78s3LM5TNgBTJHcF39DraxLu14bucG9RN", "12D3KooWGqfSPhHKmQycfhRjgUDE2vg9YWZN27Eue8idb2ZUk6EH", } - peers := make(map[ragetypes.PeerID]p2ptypes.StreamConfig) - for _, peerID := range peerIDs { - var p ragetypes.PeerID - err := p.UnmarshalText([]byte(peerID)) + capabilityDONPeers := []string{ + "12D3KooWHCcyTPmYFB1ydNvNcXw5WyAomRzGSFu1B7hpB4yi8Smf", + "12D3KooWPv6eqJvYz7TcQWk4Y4XjZ1uQ7mUKahdDXj65ht95zH6a", + } + allPeers := make(map[ragetypes.PeerID]p2ptypes.StreamConfig) + addPeersToDONInfo := func(peers []string, donInfo *remotetypes.DON) error { + for _, peerID := range peers { + var p ragetypes.PeerID + err := p.UnmarshalText([]byte(peerID)) + if err != nil { + return err + } + allPeers[p] = defaultStreamConfig + donInfo.Members = append(donInfo.Members, p) + } + return nil + } + workflowDonInfo := remotetypes.DON{ID: "workflowDon1"} + if err := addPeersToDONInfo(workflowDONPeers, &workflowDonInfo); err != nil { + return err + } + capabilityDonInfo := remotetypes.DON{ID: "capabilityDon1"} + if err := addPeersToDONInfo(capabilityDONPeers, &capabilityDonInfo); err != nil { + return err + } + err := s.peerWrapper.GetPeer().UpdateConnections(allPeers) + if err != nil { + return err + } + // NOTE: temporary hard-coded capabilities + capId := "sample_remote_trigger" + triggerInfo := commoncap.CapabilityInfo{ + ID: capId, + CapabilityType: commoncap.CapabilityTypeTrigger, + Description: "Remote Trigger", + Version: "0.0.1", + } + myId := s.peerWrapper.GetPeer().ID().String() + config := remotetypes.RemoteTriggerConfig{ + RegistrationRefreshMs: 20000, + } + if slices.Contains(workflowDONPeers, myId) { + s.lggr.Info("member of a workflow DON - starting remote subscribers") + triggerCap := remote.NewTriggerSubscriber(config, triggerInfo, capabilityDonInfo, workflowDonInfo, s.dispatcher, nil, s.lggr) + err = s.registry.Add(ctx, triggerCap) + if err != nil { + s.lggr.Errorw("failed to add remote target capability to registry", "error", err) + return err + } + err = s.dispatcher.SetReceiver(capId, capabilityDonInfo.ID, triggerCap) + if err != nil { + s.lggr.Errorw("failed to set receiver", "capabilityId", capId, "donId", capabilityDonInfo.ID, "error", err) + return err + } + s.subServices = append(s.subServices, triggerCap) + } + if slices.Contains(capabilityDONPeers, myId) { + s.lggr.Info("member of a capability DON - starting remote publishers") + workflowDONs := map[string]remotetypes.DON{ + workflowDonInfo.ID: workflowDonInfo, + } + underlying := &noOpTrigger{info: triggerInfo, lggr: s.lggr} + triggerCap := remote.NewTriggerPublisher(config, underlying, triggerInfo, capabilityDonInfo, workflowDONs, s.dispatcher, s.lggr) + err = s.dispatcher.SetReceiver(capId, capabilityDonInfo.ID, triggerCap) if err != nil { + s.lggr.Errorw("failed to set receiver", "capabilityId", capId, "donId", capabilityDonInfo.ID, "error", err) return err } - peers[p] = defaultStreamConfig + s.subServices = append(s.subServices, triggerCap) } - return s.peerWrapper.GetPeer().UpdateConnections(peers) + // NOTE: temporary service start - should be managed by capability creation + for _, srv := range s.subServices { + err = srv.Start(ctx) + if err != nil { + s.lggr.Errorw("failed to start remote trigger caller", "error", err) + return err + } + } + s.lggr.Info("registry syncer started") + return nil } func (s *registrySyncer) Close() error { + for _, subService := range s.subServices { + err := subService.Close() + if err != nil { + s.lggr.Errorw("failed to close a sub-service", "name", subService.Name(), "error", err) + } + } return s.peerWrapper.GetPeer().UpdateConnections(map[ragetypes.PeerID]p2ptypes.StreamConfig{}) } @@ -78,3 +162,22 @@ func (s *registrySyncer) HealthReport() map[string]error { func (s *registrySyncer) Name() string { return "RegistrySyncer" } + +type noOpTrigger struct { + info commoncap.CapabilityInfo + lggr logger.Logger +} + +func (t *noOpTrigger) Info(_ context.Context) (commoncap.CapabilityInfo, error) { + return t.info, nil +} + +func (t *noOpTrigger) RegisterTrigger(_ context.Context, _ chan<- commoncap.CapabilityResponse, request commoncap.CapabilityRequest) error { + t.lggr.Infow("no-op trigger RegisterTrigger", "workflowID", request.Metadata.WorkflowID) + return nil +} + +func (t *noOpTrigger) UnregisterTrigger(_ context.Context, request commoncap.CapabilityRequest) error { + t.lggr.Infow("no-op trigger RegisterTrigger", "workflowID", request.Metadata.WorkflowID) + return nil +} diff --git a/core/capabilities/syncer_test.go b/core/capabilities/syncer_test.go index acfe0f00233..335b9774689 100644 --- a/core/capabilities/syncer_test.go +++ b/core/capabilities/syncer_test.go @@ -6,8 +6,11 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + ragetypes "github.com/smartcontractkit/libocr/ragep2p/types" + commonMocks "github.com/smartcontractkit/chainlink-common/pkg/types/mocks" coreCapabilities "github.com/smartcontractkit/chainlink/v2/core/capabilities" + remoteMocks "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types/mocks" @@ -16,13 +19,20 @@ import ( func TestSyncer_CleanStartClose(t *testing.T) { lggr := logger.TestLogger(t) ctx := testutils.Context(t) + var pid ragetypes.PeerID + err := pid.UnmarshalText([]byte("12D3KooWF3dVeJ6YoT5HFnYhmwQWWMoEwVFzJQ5kKCMX3ZityxMC")) + require.NoError(t, err) peer := mocks.NewPeer(t) peer.On("UpdateConnections", mock.Anything).Return(nil) + peer.On("ID").Return(pid) wrapper := mocks.NewPeerWrapper(t) wrapper.On("GetPeer").Return(peer) registry := commonMocks.NewCapabilitiesRegistry(t) + registry.On("Add", mock.Anything, mock.Anything).Return(nil) + dispatcher := remoteMocks.NewDispatcher(t) + dispatcher.On("SetReceiver", mock.Anything, mock.Anything, mock.Anything).Return(nil) - syncer := coreCapabilities.NewRegistrySyncer(wrapper, registry, lggr) + syncer := coreCapabilities.NewRegistrySyncer(wrapper, registry, dispatcher, lggr) require.NoError(t, syncer.Start(ctx)) require.NoError(t, syncer.Close()) } diff --git a/core/capabilities/targets/write_target_test.go b/core/capabilities/targets/write_target_test.go index c99e84beb75..c71c84e172e 100644 --- a/core/capabilities/targets/write_target_test.go +++ b/core/capabilities/targets/write_target_test.go @@ -9,7 +9,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/capabilities/targets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" - evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" evmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm/mocks" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/forwarder" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -17,13 +17,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) -var forwardABI = evmtypes.MustGetABI(forwarder.KeystoneForwarderMetaData.ABI) +var forwardABI = types.MustGetABI(forwarder.KeystoneForwarderMetaData.ABI) func TestEvmWrite(t *testing.T) { chain := evmmocks.NewChain(t) @@ -34,12 +33,12 @@ func TestEvmWrite(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { a := testutils.NewAddress() - addr, err := ethkey.NewEIP55Address(a.Hex()) + addr, err := types.NewEIP55Address(a.Hex()) require.NoError(t, err) c.EVM[0].ChainWriter.FromAddress = &addr forwarderA := testutils.NewAddress() - forwarderAddr, err := ethkey.NewEIP55Address(forwarderA.Hex()) + forwarderAddr, err := types.NewEIP55Address(forwarderA.Hex()) require.NoError(t, err) c.EVM[0].ChainWriter.ForwarderAddress = &forwarderAddr }) diff --git a/core/chains/evm/client/chain_client.go b/core/chains/evm/client/chain_client.go index 1eb2347c474..52bc1263c75 100644 --- a/core/chains/evm/client/chain_client.go +++ b/core/chains/evm/client/chain_client.go @@ -38,7 +38,8 @@ type chainClient struct { RPCClient, rpc.BatchElem, ] - logger logger.SugaredLogger + logger logger.SugaredLogger + chainType config.ChainType } func NewChainClient( @@ -269,3 +270,12 @@ func (c *chainClient) TransactionReceipt(ctx context.Context, txHash common.Hash func (c *chainClient) LatestFinalizedBlock(ctx context.Context) (*evmtypes.Head, error) { return c.multiNode.LatestFinalizedBlock(ctx) } + +func (c *chainClient) CheckTxValidity(ctx context.Context, from common.Address, to common.Address, data []byte) *SendError { + msg := ethereum.CallMsg{ + From: from, + To: &to, + Data: data, + } + return SimulateTransaction(ctx, c, c.logger, c.chainType, msg) +} diff --git a/core/chains/evm/client/client.go b/core/chains/evm/client/client.go index ee33db97fd6..2758c9cf0a4 100644 --- a/core/chains/evm/client/client.go +++ b/core/chains/evm/client/client.go @@ -95,6 +95,9 @@ type Client interface { PendingCallContract(ctx context.Context, msg ethereum.CallMsg) ([]byte, error) IsL2() bool + + // Simulate the transaction prior to sending to catch zk out-of-counters errors ahead of time + CheckTxValidity(ctx context.Context, from common.Address, to common.Address, data []byte) *SendError } func ContextWithDefaultTimeout() (ctx context.Context, cancel context.CancelFunc) { @@ -371,3 +374,7 @@ func (client *client) IsL2() bool { func (client *client) LatestFinalizedBlock(_ context.Context) (*evmtypes.Head, error) { return nil, pkgerrors.New("not implemented. client was deprecated. New methods are added only to satisfy type constraints while we are migrating to new alternatives") } + +func (client *client) CheckTxValidity(ctx context.Context, from common.Address, to common.Address, data []byte) *SendError { + return NewSendError(pkgerrors.New("not implemented. client was deprecated. New methods are added only to satisfy type constraints while we are migrating to new alternatives")) +} diff --git a/core/chains/evm/client/compatibility_helper.go b/core/chains/evm/client/compatibility_helper.go new file mode 100644 index 00000000000..c19c66b7442 --- /dev/null +++ b/core/chains/evm/client/compatibility_helper.go @@ -0,0 +1,57 @@ +package client + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/rpc" +) + +// Needed to support Geth servers < v1.11.0 + +// COPIED FROM go-ethereum/ethclient/gethclient - must be kept up to date! +func ToBackwardCompatibleBlockNumArg(number *big.Int) string { + if number == nil { + return "latest" + } + if number.Sign() >= 0 { + return hexutil.EncodeBig(number) + } + // It's negative. + if number.IsInt64() { + return rpc.BlockNumber(number.Int64()).String() + } + // It's negative and large, which is invalid. + return fmt.Sprintf("", number) +} + +// COPIED FROM go-ethereum/ethclient/gethclient - must be kept up to date! +// Modified to include legacy 'data' as well as 'input' in order to support non-compliant servers. +func ToBackwardCompatibleCallArg(msg ethereum.CallMsg) interface{} { + arg := map[string]interface{}{ + "from": msg.From, + "to": msg.To, + } + if len(msg.Data) > 0 { + arg["input"] = hexutil.Bytes(msg.Data) + arg["data"] = hexutil.Bytes(msg.Data) // duplicate legacy field for compatibility + } + if msg.Value != nil { + arg["value"] = (*hexutil.Big)(msg.Value) + } + if msg.Gas != 0 { + arg["gas"] = hexutil.Uint64(msg.Gas) + } + if msg.GasPrice != nil { + arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice) + } + if msg.GasFeeCap != nil { + arg["maxFeePerGas"] = (*hexutil.Big)(msg.GasFeeCap) + } + if msg.GasTipCap != nil { + arg["maxPriorityFeePerGas"] = (*hexutil.Big)(msg.GasTipCap) + } + return arg +} diff --git a/core/chains/evm/client/config_builder.go b/core/chains/evm/client/config_builder.go index c004bc4e9c6..d78a981b881 100644 --- a/core/chains/evm/client/config_builder.go +++ b/core/chains/evm/client/config_builder.go @@ -8,12 +8,13 @@ import ( "go.uber.org/multierr" commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" - "github.com/smartcontractkit/chainlink/v2/common/config" + + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" ) -type nodeConfig struct { +type NodeConfig struct { Name *string WSURL *string HTTPURL *string @@ -28,15 +29,19 @@ func NewClientConfigs( selectionMode *string, leaseDuration time.Duration, chainType string, - nodeCfgs []nodeConfig, + nodeCfgs []NodeConfig, pollFailureThreshold *uint32, pollInterval time.Duration, syncThreshold *uint32, nodeIsSyncingEnabled *bool, -) (evmconfig.NodePool, []*toml.Node, config.ChainType, error) { + noNewHeadsThreshold time.Duration, + finalityDepth *uint32, + finalityTagEnabled *bool, + +) (commonclient.ChainConfig, evmconfig.NodePool, []*toml.Node, error) { nodes, err := parseNodeConfigs(nodeCfgs) if err != nil { - return nil, nil, "", err + return nil, nil, nil, err } nodePool := toml.NodePool{ SelectionMode: selectionMode, @@ -47,10 +52,20 @@ func NewClientConfigs( NodeIsSyncingEnabled: nodeIsSyncingEnabled, } nodePoolCfg := &evmconfig.NodePoolConfig{C: nodePool} - return nodePoolCfg, nodes, config.ChainType(chainType), nil + chainConfig := &evmconfig.EVMConfig{ + C: &toml.EVMConfig{ + Chain: toml.Chain{ + ChainType: &chainType, + FinalityDepth: finalityDepth, + FinalityTagEnabled: finalityTagEnabled, + NoNewHeadsThreshold: commonconfig.MustNewDuration(noNewHeadsThreshold), + }, + }, + } + return chainConfig, nodePoolCfg, nodes, nil } -func parseNodeConfigs(nodeCfgs []nodeConfig) ([]*toml.Node, error) { +func parseNodeConfigs(nodeCfgs []NodeConfig) ([]*toml.Node, error) { nodes := make([]*toml.Node, len(nodeCfgs)) for i, nodeCfg := range nodeCfgs { if nodeCfg.WSURL == nil || nodeCfg.HTTPURL == nil { diff --git a/core/chains/evm/client/config_builder_test.go b/core/chains/evm/client/config_builder_test.go index cc00029d270..431cbc82353 100644 --- a/core/chains/evm/client/config_builder_test.go +++ b/core/chains/evm/client/config_builder_test.go @@ -1,11 +1,14 @@ package client_test import ( + "math/big" "testing" "time" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" ) @@ -19,14 +22,18 @@ func TestClientConfigBuilder(t *testing.T) { syncThreshold := ptr(uint32(5)) nodeIsSyncingEnabled := ptr(false) chainTypeStr := "" - nodeConfigs := []client.TestNodeConfig{ + nodeConfigs := []client.NodeConfig{ { Name: ptr("foo"), WSURL: ptr("ws://foo.test"), HTTPURL: ptr("http://foo.test"), }, } - nodePool, nodes, chainType, err := client.NewClientConfigs(selectionMode, leaseDuration, chainTypeStr, nodeConfigs, pollFailureThreshold, pollInterval, syncThreshold, nodeIsSyncingEnabled) + finalityDepth := ptr(uint32(10)) + finalityTagEnabled := ptr(true) + noNewHeadsThreshold := time.Second + chainCfg, nodePool, nodes, err := client.NewClientConfigs(selectionMode, leaseDuration, chainTypeStr, nodeConfigs, + pollFailureThreshold, pollInterval, syncThreshold, nodeIsSyncingEnabled, noNewHeadsThreshold, finalityDepth, finalityTagEnabled) require.NoError(t, err) // Validate node pool configs @@ -42,15 +49,21 @@ func TestClientConfigBuilder(t *testing.T) { require.Equal(t, *nodeConfigs[0].WSURL, (*nodes[0].WSURL).String()) require.Equal(t, *nodeConfigs[0].HTTPURL, (*nodes[0].HTTPURL).String()) - // Validate chain type - require.Equal(t, chainTypeStr, string(chainType)) + // Validate chain config + require.Equal(t, chainTypeStr, string(chainCfg.ChainType())) + require.Equal(t, noNewHeadsThreshold, chainCfg.NodeNoNewHeadsThreshold()) + require.Equal(t, *finalityDepth, chainCfg.FinalityDepth()) + require.Equal(t, *finalityTagEnabled, chainCfg.FinalityTagEnabled()) + + // let combiler tell us, when we do not have sufficient data to create evm client + _ = client.NewEvmClient(nodePool, chainCfg, logger.Test(t), big.NewInt(10), nodes) } func TestNodeConfigs(t *testing.T) { t.Parallel() t.Run("parsing unique node configs succeeds", func(t *testing.T) { - nodeConfigs := []client.TestNodeConfig{ + nodeConfigs := []client.NodeConfig{ { Name: ptr("foo1"), WSURL: ptr("ws://foo1.test"), @@ -68,7 +81,7 @@ func TestNodeConfigs(t *testing.T) { }) t.Run("parsing missing ws url fails", func(t *testing.T) { - nodeConfigs := []client.TestNodeConfig{ + nodeConfigs := []client.NodeConfig{ { Name: ptr("foo1"), HTTPURL: ptr("http://foo1.test"), @@ -79,7 +92,7 @@ func TestNodeConfigs(t *testing.T) { }) t.Run("parsing missing http url fails", func(t *testing.T) { - nodeConfigs := []client.TestNodeConfig{ + nodeConfigs := []client.NodeConfig{ { Name: ptr("foo1"), WSURL: ptr("ws://foo1.test"), @@ -90,7 +103,7 @@ func TestNodeConfigs(t *testing.T) { }) t.Run("parsing invalid ws url fails", func(t *testing.T) { - nodeConfigs := []client.TestNodeConfig{ + nodeConfigs := []client.NodeConfig{ { Name: ptr("foo1"), WSURL: ptr("http://foo1.test"), @@ -102,7 +115,7 @@ func TestNodeConfigs(t *testing.T) { }) t.Run("parsing duplicate http url fails", func(t *testing.T) { - nodeConfigs := []client.TestNodeConfig{ + nodeConfigs := []client.NodeConfig{ { Name: ptr("foo1"), WSURL: ptr("ws://foo1.test"), @@ -114,7 +127,7 @@ func TestNodeConfigs(t *testing.T) { }) t.Run("parsing duplicate node names fails", func(t *testing.T) { - nodeConfigs := []client.TestNodeConfig{ + nodeConfigs := []client.NodeConfig{ { Name: ptr("foo1"), WSURL: ptr("ws://foo1.test"), @@ -131,7 +144,7 @@ func TestNodeConfigs(t *testing.T) { }) t.Run("parsing duplicate node ws urls fails", func(t *testing.T) { - nodeConfigs := []client.TestNodeConfig{ + nodeConfigs := []client.NodeConfig{ { Name: ptr("foo1"), WSURL: ptr("ws://foo1.test"), @@ -148,7 +161,7 @@ func TestNodeConfigs(t *testing.T) { }) t.Run("parsing duplicate node http urls fails", func(t *testing.T) { - nodeConfigs := []client.TestNodeConfig{ + nodeConfigs := []client.NodeConfig{ { Name: ptr("foo1"), WSURL: ptr("ws://foo1.test"), @@ -165,7 +178,7 @@ func TestNodeConfigs(t *testing.T) { }) t.Run("parsing order too large fails", func(t *testing.T) { - nodeConfigs := []client.TestNodeConfig{ + nodeConfigs := []client.NodeConfig{ { Name: ptr("foo1"), WSURL: ptr("ws://foo1.test"), diff --git a/core/chains/evm/client/errors.go b/core/chains/evm/client/errors.go index 8095c122508..37572bc8643 100644 --- a/core/chains/evm/client/errors.go +++ b/core/chains/evm/client/errors.go @@ -63,6 +63,7 @@ const ( TransactionAlreadyMined Fatal ServiceUnavailable + OutOfCounters ) type ClientErrors = map[int]*regexp.Regexp @@ -224,10 +225,15 @@ var zkSync = ClientErrors{ // can't start a transaction from a non-account - trying to send from an invalid address, e.g. estimating a contract -> contract tx // max fee per gas higher than 2^64-1 - uint64 overflow // oversized data - data too large - Fatal: regexp.MustCompile(`(?:: |^)(?:exceeds block gas limit|intrinsic gas too low|Not enough gas for transaction validation|Failed to pay the fee to the operator|Error function_selector = 0x, data = 0x|invalid sender. can't start a transaction from a non-account|max(?: priority)? fee per (?:gas|pubdata byte) higher than 2\^64-1|oversized data. max: \d+; actual: \d+)$`), + Fatal: regexp.MustCompile(`(?:: |^)(?:exceeds block gas limit|intrinsic gas too low|Not enough gas for transaction validation|Failed to pay the fee to the operator|Error function_selector = 0x, data = 0x|invalid sender. can't start a transaction from a non-account|max(?: priority)? fee per (?:gas|pubdata byte) higher than 2\^64-1|oversized data. max: \d+; actual: \d+)$`), + TransactionAlreadyInMempool: regexp.MustCompile(`known transaction. transaction with hash .* is already in the system`), } -var clients = []ClientErrors{parity, geth, arbitrum, metis, substrate, avalanche, nethermind, harmony, besu, erigon, klaytn, celo, zkSync} +var zkEvm = ClientErrors{ + OutOfCounters: regexp.MustCompile(`(?:: |^)not enough .* counters to continue the execution$`), +} + +var clients = []ClientErrors{parity, geth, arbitrum, metis, substrate, avalanche, nethermind, harmony, besu, erigon, klaytn, celo, zkSync, zkEvm} func (s *SendError) is(errorType int) bool { if s == nil || s.err == nil { @@ -309,6 +315,11 @@ func (s *SendError) IsServiceUnavailable() bool { return s.is(ServiceUnavailable) } +// IsOutOfCounters is a zk chain specific error returned if the transaction is too complex to prove on zk circuits +func (s *SendError) IsOutOfCounters() bool { + return s.is(OutOfCounters) +} + // IsTimeout indicates if the error was caused by an exceeded context deadline func (s *SendError) IsTimeout() bool { if s == nil { diff --git a/core/chains/evm/client/errors_test.go b/core/chains/evm/client/errors_test.go index a59d3fbf719..5d1fa135725 100644 --- a/core/chains/evm/client/errors_test.go +++ b/core/chains/evm/client/errors_test.go @@ -127,6 +127,9 @@ func Test_Eth_Errors(t *testing.T) { {"call failed: AlreadyKnown", true, "Nethermind"}, {"call failed: OwnNonceAlreadyUsed", true, "Nethermind"}, {"known transaction", true, "Klaytn"}, + {"known transaction. transaction with hash 0x6013…3053 is already in the system", true, "zkSync"}, + // This seems to be an erroneous message from the zkSync client, we'll have to match it anyway + {"ErrorObject { code: ServerError(3), message: \\\"known transaction. transaction with hash 0xf016…ad63 is already in the system\\\", data: Some(RawValue(\\\"0x\\\")) }", true, "zkSync"}, } for _, test := range tests { err = evmclient.NewSendErrorS(test.message) diff --git a/core/chains/evm/client/evm_client.go b/core/chains/evm/client/evm_client.go index cd7d4a74b80..f60605bc88e 100644 --- a/core/chains/evm/client/evm_client.go +++ b/core/chains/evm/client/evm_client.go @@ -3,17 +3,16 @@ package client import ( "math/big" "net/url" - "time" "github.com/smartcontractkit/chainlink-common/pkg/logger" + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" - "github.com/smartcontractkit/chainlink/v2/common/config" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ) -func NewEvmClient(cfg evmconfig.NodePool, noNewHeadsThreshold time.Duration, lggr logger.Logger, chainID *big.Int, chainType config.ChainType, nodes []*toml.Node) Client { +func NewEvmClient(cfg evmconfig.NodePool, chainCfg commonclient.ChainConfig, lggr logger.Logger, chainID *big.Int, nodes []*toml.Node) Client { var empty url.URL var primaries []commonclient.Node[*big.Int, *evmtypes.Head, RPCClient] var sendonlys []commonclient.SendOnlyNode[*big.Int, RPCClient] @@ -27,11 +26,12 @@ func NewEvmClient(cfg evmconfig.NodePool, noNewHeadsThreshold time.Duration, lgg } else { rpc := NewRPCClient(lggr, (url.URL)(*node.WSURL), (*url.URL)(node.HTTPURL), *node.Name, int32(i), chainID, commonclient.Primary) - primaryNode := commonclient.NewNode(cfg, noNewHeadsThreshold, + primaryNode := commonclient.NewNode(cfg, chainCfg, lggr, (url.URL)(*node.WSURL), (*url.URL)(node.HTTPURL), *node.Name, int32(i), chainID, *node.Order, rpc, "EVM") primaries = append(primaries, primaryNode) } } - return NewChainClient(lggr, cfg.SelectionMode(), cfg.LeaseDuration(), noNewHeadsThreshold, primaries, sendonlys, chainID, chainType) + return NewChainClient(lggr, cfg.SelectionMode(), cfg.LeaseDuration(), chainCfg.NodeNoNewHeadsThreshold(), + primaries, sendonlys, chainID, chainCfg.ChainType()) } diff --git a/core/chains/evm/client/evm_client_test.go b/core/chains/evm/client/evm_client_test.go index 2764a2b3611..1317c365d38 100644 --- a/core/chains/evm/client/evm_client_test.go +++ b/core/chains/evm/client/evm_client_test.go @@ -6,9 +6,10 @@ import ( "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) func TestNewEvmClient(t *testing.T) { @@ -22,16 +23,19 @@ func TestNewEvmClient(t *testing.T) { syncThreshold := ptr(uint32(5)) nodeIsSyncingEnabled := ptr(false) chainTypeStr := "" - nodeConfigs := []client.TestNodeConfig{ + nodeConfigs := []client.NodeConfig{ { Name: ptr("foo"), WSURL: ptr("ws://foo.test"), HTTPURL: ptr("http://foo.test"), }, } - nodePool, nodes, chainType, err := client.NewClientConfigs(selectionMode, leaseDuration, chainTypeStr, nodeConfigs, pollFailureThreshold, pollInterval, syncThreshold, nodeIsSyncingEnabled) + finalityDepth := ptr(uint32(10)) + finalityTagEnabled := ptr(true) + chainCfg, nodePool, nodes, err := client.NewClientConfigs(selectionMode, leaseDuration, chainTypeStr, nodeConfigs, + pollFailureThreshold, pollInterval, syncThreshold, nodeIsSyncingEnabled, noNewHeadsThreshold, finalityDepth, finalityTagEnabled) require.NoError(t, err) - client := client.NewEvmClient(nodePool, noNewHeadsThreshold, logger.TestLogger(t), testutils.FixtureChainID, chainType, nodes) + client := client.NewEvmClient(nodePool, chainCfg, logger.Test(t), testutils.FixtureChainID, nodes) require.NotNil(t, client) } diff --git a/core/chains/evm/client/helpers_test.go b/core/chains/evm/client/helpers_test.go index 1decf3ed89d..2a360219046 100644 --- a/core/chains/evm/client/helpers_test.go +++ b/core/chains/evm/client/helpers_test.go @@ -12,6 +12,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" + clientMocks "github.com/smartcontractkit/chainlink/v2/common/client/mocks" commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" @@ -19,12 +20,13 @@ import ( ) type TestNodePoolConfig struct { - NodePollFailureThreshold uint32 - NodePollInterval time.Duration - NodeSelectionMode string - NodeSyncThreshold uint32 - NodeLeaseDuration time.Duration - NodeIsSyncingEnabledVal bool + NodePollFailureThreshold uint32 + NodePollInterval time.Duration + NodeSelectionMode string + NodeSyncThreshold uint32 + NodeLeaseDuration time.Duration + NodeIsSyncingEnabledVal bool + NodeFinalizedBlockPollInterval time.Duration } func (tc TestNodePoolConfig) PollFailureThreshold() uint32 { return tc.NodePollFailureThreshold } @@ -39,6 +41,10 @@ func (tc TestNodePoolConfig) NodeIsSyncingEnabled() bool { return tc.NodeIsSyncingEnabledVal } +func (tc TestNodePoolConfig) FinalizedBlockPollInterval() time.Duration { + return tc.NodeFinalizedBlockPollInterval +} + func NewClientWithTestNode(t *testing.T, nodePoolCfg config.NodePool, noNewHeadsThreshold time.Duration, rpcUrl string, rpcHTTPURL *url.URL, sendonlyRPCURLs []url.URL, id int32, chainID *big.Int) (*client, error) { parsed, err := url.ParseRequestURI(rpcUrl) if err != nil { @@ -97,7 +103,7 @@ func NewChainClientWithTestNode( rpc := NewRPCClient(lggr, *parsed, rpcHTTPURL, "eth-primary-rpc-0", id, chainID, commonclient.Primary) n := commonclient.NewNode[*big.Int, *evmtypes.Head, RPCClient]( - nodeCfg, noNewHeadsThreshold, lggr, *parsed, rpcHTTPURL, "eth-primary-node-0", id, chainID, 1, rpc, "EVM") + nodeCfg, clientMocks.ChainConfig{NoNewHeadsThresholdVal: noNewHeadsThreshold}, lggr, *parsed, rpcHTTPURL, "eth-primary-node-0", id, chainID, 1, rpc, "EVM") primaries := []commonclient.Node[*big.Int, *evmtypes.Head, RPCClient]{n} var sendonlys []commonclient.SendOnlyNode[*big.Int, RPCClient] @@ -153,7 +159,7 @@ func NewChainClientWithMockedRpc( parsed, _ := url.ParseRequestURI("ws://test") n := commonclient.NewNode[*big.Int, *evmtypes.Head, RPCClient]( - cfg, noNewHeadsThreshold, lggr, *parsed, nil, "eth-primary-node-0", 1, chainID, 1, rpc, "EVM") + cfg, clientMocks.ChainConfig{NoNewHeadsThresholdVal: noNewHeadsThreshold}, lggr, *parsed, nil, "eth-primary-node-0", 1, chainID, 1, rpc, "EVM") primaries := []commonclient.Node[*big.Int, *evmtypes.Head, RPCClient]{n} c := NewChainClient(lggr, selectionMode, leaseDuration, noNewHeadsThreshold, primaries, nil, chainID, chainType) t.Cleanup(c.Close) @@ -187,8 +193,6 @@ func (mes *mockSubscription) Unsubscribe() { close(mes.Errors) } -type TestNodeConfig = nodeConfig - -func ParseTestNodeConfigs(nodes []TestNodeConfig) ([]*toml.Node, error) { +func ParseTestNodeConfigs(nodes []NodeConfig) ([]*toml.Node, error) { return parseNodeConfigs(nodes) } diff --git a/core/chains/evm/client/mocks/client.go b/core/chains/evm/client/mocks/client.go index e6c9da1cbe9..b3cdac3a6b6 100644 --- a/core/chains/evm/client/mocks/client.go +++ b/core/chains/evm/client/mocks/client.go @@ -7,6 +7,8 @@ import ( assets "github.com/smartcontractkit/chainlink-common/pkg/assets" + client "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + common "github.com/ethereum/go-ethereum/common" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" @@ -236,6 +238,26 @@ func (_m *Client) ChainID() (*big.Int, error) { return r0, r1 } +// CheckTxValidity provides a mock function with given fields: ctx, from, to, data +func (_m *Client) CheckTxValidity(ctx context.Context, from common.Address, to common.Address, data []byte) *client.SendError { + ret := _m.Called(ctx, from, to, data) + + if len(ret) == 0 { + panic("no return value specified for CheckTxValidity") + } + + var r0 *client.SendError + if rf, ok := ret.Get(0).(func(context.Context, common.Address, common.Address, []byte) *client.SendError); ok { + r0 = rf(ctx, from, to, data) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*client.SendError) + } + } + + return r0 +} + // Close provides a mock function with given fields: func (_m *Client) Close() { _m.Called() diff --git a/core/chains/evm/client/null_client.go b/core/chains/evm/client/null_client.go index e4bd7d1dd9a..3129bcff9b0 100644 --- a/core/chains/evm/client/null_client.go +++ b/core/chains/evm/client/null_client.go @@ -231,3 +231,7 @@ func (nc *NullClient) IsL2() bool { func (nc *NullClient) LatestFinalizedBlock(_ context.Context) (*evmtypes.Head, error) { return nil, nil } + +func (nc *NullClient) CheckTxValidity(_ context.Context, _ common.Address, _ common.Address, _ []byte) *SendError { + return nil +} diff --git a/core/chains/evm/client/rpc_client.go b/core/chains/evm/client/rpc_client.go index f9745cfda11..255b038037a 100644 --- a/core/chains/evm/client/rpc_client.go +++ b/core/chains/evm/client/rpc_client.go @@ -785,10 +785,10 @@ func (r *rpcClient) CallContract(ctx context.Context, msg interface{}, blockNumb start := time.Now() var hex hexutil.Bytes if http != nil { - err = http.rpc.CallContext(ctx, &hex, "eth_call", toCallArg(message), toBlockNumArg(blockNumber)) + err = http.rpc.CallContext(ctx, &hex, "eth_call", ToBackwardCompatibleCallArg(message), ToBackwardCompatibleBlockNumArg(blockNumber)) err = r.wrapHTTP(err) } else { - err = ws.rpc.CallContext(ctx, &hex, "eth_call", toCallArg(message), toBlockNumArg(blockNumber)) + err = ws.rpc.CallContext(ctx, &hex, "eth_call", ToBackwardCompatibleCallArg(message), ToBackwardCompatibleBlockNumArg(blockNumber)) err = r.wrapWS(err) } if err == nil { @@ -816,10 +816,10 @@ func (r *rpcClient) PendingCallContract(ctx context.Context, msg interface{}) (v start := time.Now() var hex hexutil.Bytes if http != nil { - err = http.rpc.CallContext(ctx, &hex, "eth_call", toCallArg(message), "pending") + err = http.rpc.CallContext(ctx, &hex, "eth_call", ToBackwardCompatibleCallArg(message), "pending") err = r.wrapHTTP(err) } else { - err = ws.rpc.CallContext(ctx, &hex, "eth_call", toCallArg(message), "pending") + err = ws.rpc.CallContext(ctx, &hex, "eth_call", ToBackwardCompatibleCallArg(message), "pending") err = r.wrapWS(err) } if err == nil { @@ -834,51 +834,6 @@ func (r *rpcClient) PendingCallContract(ctx context.Context, msg interface{}) (v return } -// COPIED FROM go-ethereum/ethclient/gethclient - must be kept up to date! -func toBlockNumArg(number *big.Int) string { - if number == nil { - return "latest" - } - if number.Sign() >= 0 { - return hexutil.EncodeBig(number) - } - // It's negative. - if number.IsInt64() { - return rpc.BlockNumber(number.Int64()).String() - } - // It's negative and large, which is invalid. - return fmt.Sprintf("", number) -} - -// COPIED FROM go-ethereum/ethclient/gethclient - must be kept up to date! -// Modified to include legacy 'data' as well as 'input' in order to support non-compliant servers. -func toCallArg(msg ethereum.CallMsg) interface{} { - arg := map[string]interface{}{ - "from": msg.From, - "to": msg.To, - } - if len(msg.Data) > 0 { - arg["input"] = hexutil.Bytes(msg.Data) - arg["data"] = hexutil.Bytes(msg.Data) // duplicate legacy field for compatibility - } - if msg.Value != nil { - arg["value"] = (*hexutil.Big)(msg.Value) - } - if msg.Gas != 0 { - arg["gas"] = hexutil.Uint64(msg.Gas) - } - if msg.GasPrice != nil { - arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice) - } - if msg.GasFeeCap != nil { - arg["maxFeePerGas"] = (*hexutil.Big)(msg.GasFeeCap) - } - if msg.GasTipCap != nil { - arg["maxPriorityFeePerGas"] = (*hexutil.Big)(msg.GasTipCap) - } - return arg -} - func (r *rpcClient) LatestBlockHeight(ctx context.Context) (*big.Int, error) { var height big.Int h, err := r.BlockNumber(ctx) diff --git a/core/chains/evm/client/simulated_backend_client.go b/core/chains/evm/client/simulated_backend_client.go index 5750887126a..9fe2ff88ba7 100644 --- a/core/chains/evm/client/simulated_backend_client.go +++ b/core/chains/evm/client/simulated_backend_client.go @@ -774,6 +774,10 @@ func (c *SimulatedBackendClient) ethGetLogs(ctx context.Context, result interfac } } +func (c *SimulatedBackendClient) CheckTxValidity(ctx context.Context, from common.Address, to common.Address, data []byte) *SendError { + return nil +} + func toCallMsg(params map[string]interface{}) ethereum.CallMsg { var callMsg ethereum.CallMsg toAddr, err := interfaceToAddress(params["to"]) diff --git a/core/chains/evm/client/tx_simulator.go b/core/chains/evm/client/tx_simulator.go new file mode 100644 index 00000000000..65e108bd227 --- /dev/null +++ b/core/chains/evm/client/tx_simulator.go @@ -0,0 +1,55 @@ +package client + +import ( + "context" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common/hexutil" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/v2/common/config" +) + +type simulatorClient interface { + CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error +} + +// ZK chains can return an out-of-counters error +// This method allows a caller to determine if a tx would fail due to OOC error by simulating the transaction +// Used as an entry point in case custom simulation is required across different chains +func SimulateTransaction(ctx context.Context, client simulatorClient, lggr logger.SugaredLogger, chainType config.ChainType, msg ethereum.CallMsg) *SendError { + err := simulateTransactionDefault(ctx, client, msg) + return NewSendError(err) +} + +// eth_estimateGas returns out-of-counters (OOC) error if the transaction would result in an overflow +func simulateTransactionDefault(ctx context.Context, client simulatorClient, msg ethereum.CallMsg) error { + var result hexutil.Big + return client.CallContext(ctx, &result, "eth_estimateGas", toCallArg(msg), "pending") +} + +func toCallArg(msg ethereum.CallMsg) interface{} { + arg := map[string]interface{}{ + "from": msg.From, + "to": msg.To, + } + if len(msg.Data) > 0 { + arg["input"] = hexutil.Bytes(msg.Data) + } + if msg.Value != nil { + arg["value"] = (*hexutil.Big)(msg.Value) + } + if msg.Gas != 0 { + arg["gas"] = hexutil.Uint64(msg.Gas) + } + if msg.GasPrice != nil { + arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice) + } + if msg.GasFeeCap != nil { + arg["maxFeePerGas"] = (*hexutil.Big)(msg.GasFeeCap) + } + if msg.GasTipCap != nil { + arg["maxPriorityFeePerGas"] = (*hexutil.Big)(msg.GasTipCap) + } + return arg +} diff --git a/core/chains/evm/client/tx_simulator_test.go b/core/chains/evm/client/tx_simulator_test.go new file mode 100644 index 00000000000..4e270d401bf --- /dev/null +++ b/core/chains/evm/client/tx_simulator_test.go @@ -0,0 +1,113 @@ +package client_test + +import ( + "testing" + + "github.com/ethereum/go-ethereum" + "github.com/stretchr/testify/require" + "github.com/tidwall/gjson" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" +) + +func TestSimulateTx_Default(t *testing.T) { + t.Parallel() + + fromAddress := testutils.NewAddress() + toAddress := testutils.NewAddress() + ctx := testutils.Context(t) + + t.Run("returns without error if simulation passes", func(t *testing.T) { + wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + switch method { + case "eth_subscribe": + resp.Result = `"0x00"` + resp.Notify = headResult + return + case "eth_unsubscribe": + resp.Result = "true" + return + case "eth_estimateGas": + resp.Result = `"0x100"` + } + return + }).WSURL().String() + + ethClient := mustNewChainClient(t, wsURL) + err := ethClient.Dial(ctx) + require.NoError(t, err) + + msg := ethereum.CallMsg{ + From: fromAddress, + To: &toAddress, + Data: []byte("0x00"), + } + sendErr := client.SimulateTransaction(ctx, ethClient, logger.TestSugared(t), "", msg) + require.Empty(t, sendErr) + }) + + t.Run("returns error if simulation returns zk out-of-counters error", func(t *testing.T) { + wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + switch method { + case "eth_subscribe": + resp.Result = `"0x00"` + resp.Notify = headResult + return + case "eth_unsubscribe": + resp.Result = "true" + return + case "eth_estimateGas": + resp.Error.Code = -32000 + resp.Result = `"0x100"` + resp.Error.Message = "not enough keccak counters to continue the execution" + } + return + }).WSURL().String() + + ethClient := mustNewChainClient(t, wsURL) + err := ethClient.Dial(ctx) + require.NoError(t, err) + + msg := ethereum.CallMsg{ + From: fromAddress, + To: &toAddress, + Data: []byte("0x00"), + } + sendErr := client.SimulateTransaction(ctx, ethClient, logger.TestSugared(t), "", msg) + require.Equal(t, true, sendErr.IsOutOfCounters()) + }) + + t.Run("returns without error if simulation returns non-OOC error", func(t *testing.T) { + wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { + switch method { + case "eth_subscribe": + resp.Result = `"0x00"` + resp.Notify = headResult + return + case "eth_unsubscribe": + resp.Result = "true" + return + case "eth_estimateGas": + resp.Error.Code = -32000 + resp.Error.Message = "something went wrong" + } + return + }).WSURL().String() + + ethClient := mustNewChainClient(t, wsURL) + err := ethClient.Dial(ctx) + require.NoError(t, err) + + msg := ethereum.CallMsg{ + From: fromAddress, + To: &toAddress, + Data: []byte("0x00"), + } + sendErr := client.SimulateTransaction(ctx, ethClient, logger.TestSugared(t), "", msg) + require.Equal(t, false, sendErr.IsOutOfCounters()) + }) +} diff --git a/core/chains/evm/config/chain_scoped.go b/core/chains/evm/config/chain_scoped.go index aa13b9a2282..2201831feaf 100644 --- a/core/chains/evm/config/chain_scoped.go +++ b/core/chains/evm/config/chain_scoped.go @@ -20,7 +20,7 @@ import ( func NewTOMLChainScopedConfig(appCfg config.AppConfig, tomlConfig *toml.EVMConfig, lggr logger.Logger) *ChainScoped { return &ChainScoped{ AppConfig: appCfg, - evmConfig: &evmConfig{c: tomlConfig}, + evmConfig: &EVMConfig{C: tomlConfig}, lggr: lggr} } @@ -29,7 +29,7 @@ type ChainScoped struct { config.AppConfig lggr logger.Logger - evmConfig *evmConfig + evmConfig *EVMConfig } func (c *ChainScoped) EVM() EVM { @@ -37,7 +37,7 @@ func (c *ChainScoped) EVM() EVM { } func (c *ChainScoped) Nodes() toml.EVMNodes { - return c.evmConfig.c.Nodes + return c.evmConfig.C.Nodes } func (c *ChainScoped) BlockEmissionIdleWarningThreshold() time.Duration { @@ -62,142 +62,142 @@ func (c *ChainScoped) Validate() (err error) { return } -type evmConfig struct { - c *toml.EVMConfig +type EVMConfig struct { + C *toml.EVMConfig } -func (e *evmConfig) IsEnabled() bool { - return e.c.IsEnabled() +func (e *EVMConfig) IsEnabled() bool { + return e.C.IsEnabled() } -func (e *evmConfig) TOMLString() (string, error) { - return e.c.TOMLString() +func (e *EVMConfig) TOMLString() (string, error) { + return e.C.TOMLString() } -func (e *evmConfig) BalanceMonitor() BalanceMonitor { - return &balanceMonitorConfig{c: e.c.BalanceMonitor} +func (e *EVMConfig) BalanceMonitor() BalanceMonitor { + return &balanceMonitorConfig{c: e.C.BalanceMonitor} } -func (e *evmConfig) Transactions() Transactions { - return &transactionsConfig{c: e.c.Transactions} +func (e *EVMConfig) Transactions() Transactions { + return &transactionsConfig{c: e.C.Transactions} } -func (e *evmConfig) HeadTracker() HeadTracker { - return &headTrackerConfig{c: e.c.HeadTracker} +func (e *EVMConfig) HeadTracker() HeadTracker { + return &headTrackerConfig{c: e.C.HeadTracker} } -func (e *evmConfig) OCR() OCR { - return &ocrConfig{c: e.c.OCR} +func (e *EVMConfig) OCR() OCR { + return &ocrConfig{c: e.C.OCR} } -func (e *evmConfig) OCR2() OCR2 { - return &ocr2Config{c: e.c.OCR2} +func (e *EVMConfig) OCR2() OCR2 { + return &ocr2Config{c: e.C.OCR2} } -func (e *evmConfig) ChainWriter() ChainWriter { - return &chainWriterConfig{c: e.c.ChainWriter} +func (e *EVMConfig) ChainWriter() ChainWriter { + return &chainWriterConfig{c: e.C.ChainWriter} } -func (e *evmConfig) GasEstimator() GasEstimator { - return &gasEstimatorConfig{c: e.c.GasEstimator, blockDelay: e.c.RPCBlockQueryDelay, transactionsMaxInFlight: e.c.Transactions.MaxInFlight, k: e.c.KeySpecific} +func (e *EVMConfig) GasEstimator() GasEstimator { + return &gasEstimatorConfig{c: e.C.GasEstimator, blockDelay: e.C.RPCBlockQueryDelay, transactionsMaxInFlight: e.C.Transactions.MaxInFlight, k: e.C.KeySpecific} } -func (e *evmConfig) AutoCreateKey() bool { - return *e.c.AutoCreateKey +func (e *EVMConfig) AutoCreateKey() bool { + return *e.C.AutoCreateKey } -func (e *evmConfig) BlockBackfillDepth() uint64 { - return uint64(*e.c.BlockBackfillDepth) +func (e *EVMConfig) BlockBackfillDepth() uint64 { + return uint64(*e.C.BlockBackfillDepth) } -func (e *evmConfig) BlockBackfillSkip() bool { - return *e.c.BlockBackfillSkip +func (e *EVMConfig) BlockBackfillSkip() bool { + return *e.C.BlockBackfillSkip } -func (e *evmConfig) LogBackfillBatchSize() uint32 { - return *e.c.LogBackfillBatchSize +func (e *EVMConfig) LogBackfillBatchSize() uint32 { + return *e.C.LogBackfillBatchSize } -func (e *evmConfig) LogPollInterval() time.Duration { - return e.c.LogPollInterval.Duration() +func (e *EVMConfig) LogPollInterval() time.Duration { + return e.C.LogPollInterval.Duration() } -func (e *evmConfig) FinalityDepth() uint32 { - return *e.c.FinalityDepth +func (e *EVMConfig) FinalityDepth() uint32 { + return *e.C.FinalityDepth } -func (e *evmConfig) FinalityTagEnabled() bool { - return *e.c.FinalityTagEnabled +func (e *EVMConfig) FinalityTagEnabled() bool { + return *e.C.FinalityTagEnabled } -func (e *evmConfig) LogKeepBlocksDepth() uint32 { - return *e.c.LogKeepBlocksDepth +func (e *EVMConfig) LogKeepBlocksDepth() uint32 { + return *e.C.LogKeepBlocksDepth } -func (e *evmConfig) BackupLogPollerBlockDelay() uint64 { - return *e.c.BackupLogPollerBlockDelay +func (e *EVMConfig) BackupLogPollerBlockDelay() uint64 { + return *e.C.BackupLogPollerBlockDelay } -func (e *evmConfig) NonceAutoSync() bool { - return *e.c.NonceAutoSync +func (e *EVMConfig) NonceAutoSync() bool { + return *e.C.NonceAutoSync } -func (e *evmConfig) RPCDefaultBatchSize() uint32 { - return *e.c.RPCDefaultBatchSize +func (e *EVMConfig) RPCDefaultBatchSize() uint32 { + return *e.C.RPCDefaultBatchSize } -func (e *evmConfig) BlockEmissionIdleWarningThreshold() time.Duration { - return e.c.NoNewHeadsThreshold.Duration() +func (e *EVMConfig) BlockEmissionIdleWarningThreshold() time.Duration { + return e.C.NoNewHeadsThreshold.Duration() } -func (e *evmConfig) ChainType() commonconfig.ChainType { - if e.c.ChainType == nil { +func (e *EVMConfig) ChainType() commonconfig.ChainType { + if e.C.ChainType == nil { return "" } - return commonconfig.ChainType(*e.c.ChainType) + return commonconfig.ChainType(*e.C.ChainType) } -func (e *evmConfig) ChainID() *big.Int { - return e.c.ChainID.ToInt() +func (e *EVMConfig) ChainID() *big.Int { + return e.C.ChainID.ToInt() } -func (e *evmConfig) MinIncomingConfirmations() uint32 { - return *e.c.MinIncomingConfirmations +func (e *EVMConfig) MinIncomingConfirmations() uint32 { + return *e.C.MinIncomingConfirmations } -func (e *evmConfig) NodePool() NodePool { - return &NodePoolConfig{C: e.c.NodePool} +func (e *EVMConfig) NodePool() NodePool { + return &NodePoolConfig{C: e.C.NodePool} } -func (e *evmConfig) NodeNoNewHeadsThreshold() time.Duration { - return e.c.NoNewHeadsThreshold.Duration() +func (e *EVMConfig) NodeNoNewHeadsThreshold() time.Duration { + return e.C.NoNewHeadsThreshold.Duration() } -func (e *evmConfig) MinContractPayment() *assets.Link { - return e.c.MinContractPayment +func (e *EVMConfig) MinContractPayment() *assets.Link { + return e.C.MinContractPayment } -func (e *evmConfig) FlagsContractAddress() string { - if e.c.FlagsContractAddress == nil { +func (e *EVMConfig) FlagsContractAddress() string { + if e.C.FlagsContractAddress == nil { return "" } - return e.c.FlagsContractAddress.String() + return e.C.FlagsContractAddress.String() } -func (e *evmConfig) LinkContractAddress() string { - if e.c.LinkContractAddress == nil { +func (e *EVMConfig) LinkContractAddress() string { + if e.C.LinkContractAddress == nil { return "" } - return e.c.LinkContractAddress.String() + return e.C.LinkContractAddress.String() } -func (e *evmConfig) OperatorFactoryAddress() string { - if e.c.OperatorFactoryAddress == nil { +func (e *EVMConfig) OperatorFactoryAddress() string { + if e.C.OperatorFactoryAddress == nil { return "" } - return e.c.OperatorFactoryAddress.String() + return e.C.OperatorFactoryAddress.String() } -func (e *evmConfig) LogPrunePageSize() uint32 { - return *e.c.LogPrunePageSize +func (e *EVMConfig) LogPrunePageSize() uint32 { + return *e.C.LogPrunePageSize } diff --git a/core/chains/evm/config/chain_scoped_chain_writer.go b/core/chains/evm/config/chain_scoped_chain_writer.go index b84731314e1..1f1cdcecfa7 100644 --- a/core/chains/evm/config/chain_scoped_chain_writer.go +++ b/core/chains/evm/config/chain_scoped_chain_writer.go @@ -2,17 +2,17 @@ package config import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ) type chainWriterConfig struct { c toml.ChainWriter } -func (b *chainWriterConfig) FromAddress() *ethkey.EIP55Address { +func (b *chainWriterConfig) FromAddress() *types.EIP55Address { return b.c.FromAddress } -func (b *chainWriterConfig) ForwarderAddress() *ethkey.EIP55Address { +func (b *chainWriterConfig) ForwarderAddress() *types.EIP55Address { return b.c.ForwarderAddress } diff --git a/core/chains/evm/config/chain_scoped_gas_estimator.go b/core/chains/evm/config/chain_scoped_gas_estimator.go index 9d7d10356f7..689d5e38b81 100644 --- a/core/chains/evm/config/chain_scoped_gas_estimator.go +++ b/core/chains/evm/config/chain_scoped_gas_estimator.go @@ -76,7 +76,7 @@ func (g *gasEstimatorConfig) LimitMultiplier() float32 { return f } -func (g *gasEstimatorConfig) LimitTransfer() uint32 { +func (g *gasEstimatorConfig) LimitTransfer() uint64 { return *g.c.LimitTransfer } diff --git a/core/chains/evm/config/chain_scoped_node_pool.go b/core/chains/evm/config/chain_scoped_node_pool.go index 0796d004cae..6874b412f7f 100644 --- a/core/chains/evm/config/chain_scoped_node_pool.go +++ b/core/chains/evm/config/chain_scoped_node_pool.go @@ -33,3 +33,7 @@ func (n *NodePoolConfig) LeaseDuration() time.Duration { func (n *NodePoolConfig) NodeIsSyncingEnabled() bool { return *n.C.NodeIsSyncingEnabled } + +func (n *NodePoolConfig) FinalizedBlockPollInterval() time.Duration { + return n.C.FinalizedBlockPollInterval.Duration() +} diff --git a/core/chains/evm/config/config.go b/core/chains/evm/config/config.go index c9c3273f086..b9ff9ea9f8e 100644 --- a/core/chains/evm/config/config.go +++ b/core/chains/evm/config/config.go @@ -10,8 +10,8 @@ import ( commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/config" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" ) type EVM interface { @@ -100,7 +100,7 @@ type GasEstimator interface { LimitDefault() uint64 LimitMax() uint64 LimitMultiplier() float32 - LimitTransfer() uint32 + LimitTransfer() uint64 PriceDefault() *assets.Wei TipCapDefault() *assets.Wei TipCapMin() *assets.Wei @@ -130,8 +130,8 @@ type BlockHistory interface { } type ChainWriter interface { - FromAddress() *ethkey.EIP55Address - ForwarderAddress() *ethkey.EIP55Address + FromAddress() *types.EIP55Address + ForwarderAddress() *types.EIP55Address } type NodePool interface { @@ -141,6 +141,7 @@ type NodePool interface { SyncThreshold() uint32 LeaseDuration() time.Duration NodeIsSyncingEnabled() bool + FinalizedBlockPollInterval() time.Duration } // TODO BCF-2509 does the chainscopedconfig really need the entire app config? diff --git a/core/chains/evm/config/config_test.go b/core/chains/evm/config/config_test.go index 0f3e0a9a9f8..6fa491051c5 100644 --- a/core/chains/evm/config/config_test.go +++ b/core/chains/evm/config/config_test.go @@ -16,13 +16,13 @@ import ( commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" ) func TestChainScopedConfig(t *testing.T) { @@ -89,7 +89,7 @@ func TestChainScopedConfig(t *testing.T) { gcfg2 := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { overrides(c, s) c.EVM[0].KeySpecific = toml.KeySpecificConfig{ - {Key: ptr(ethkey.EIP55AddressFromAddress(randomOtherAddr)), + {Key: ptr(types.EIP55AddressFromAddress(randomOtherAddr)), GasEstimator: toml.KeySpecificGasEstimator{ PriceMax: assets.GWei(850), }, @@ -124,7 +124,7 @@ func TestChainScopedConfig(t *testing.T) { t.Run(tt.name, func(t *testing.T) { gcfg3 := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].KeySpecific = toml.KeySpecificConfig{ - {Key: ptr(ethkey.EIP55AddressFromAddress(addr)), + {Key: ptr(types.EIP55AddressFromAddress(addr)), GasEstimator: toml.KeySpecificGasEstimator{ PriceMax: tt.val, }, @@ -143,7 +143,7 @@ func TestChainScopedConfig(t *testing.T) { gcfg3 := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.PriceMax = chainSpecificPrice c.EVM[0].KeySpecific = toml.KeySpecificConfig{ - {Key: ptr(ethkey.EIP55AddressFromAddress(addr)), + {Key: ptr(types.EIP55AddressFromAddress(addr)), GasEstimator: toml.KeySpecificGasEstimator{ PriceMax: keySpecificPrice, }, @@ -160,7 +160,7 @@ func TestChainScopedConfig(t *testing.T) { gcfg3 := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.PriceMax = chainSpecificPrice c.EVM[0].KeySpecific = toml.KeySpecificConfig{ - {Key: ptr(ethkey.EIP55AddressFromAddress(addr)), + {Key: ptr(types.EIP55AddressFromAddress(addr)), GasEstimator: toml.KeySpecificGasEstimator{ PriceMax: keySpecificPrice, }, @@ -175,7 +175,7 @@ func TestChainScopedConfig(t *testing.T) { keySpecificPrice := assets.GWei(900) gcfg3 := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].KeySpecific = toml.KeySpecificConfig{ - {Key: ptr(ethkey.EIP55AddressFromAddress(addr)), + {Key: ptr(types.EIP55AddressFromAddress(addr)), GasEstimator: toml.KeySpecificGasEstimator{ PriceMax: keySpecificPrice, }, @@ -192,7 +192,7 @@ func TestChainScopedConfig(t *testing.T) { gcfg3 := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.PriceMax = chainSpecificPrice c.EVM[0].KeySpecific = toml.KeySpecificConfig{ - {Key: ptr(ethkey.EIP55AddressFromAddress(addr)), + {Key: ptr(types.EIP55AddressFromAddress(addr)), GasEstimator: toml.KeySpecificGasEstimator{ PriceMax: keySpecificPrice, }, @@ -224,7 +224,7 @@ func TestChainScopedConfig(t *testing.T) { val := testutils.NewAddress() gcfg3 := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].LinkContractAddress = ptr(ethkey.EIP55AddressFromAddress(val)) + c.EVM[0].LinkContractAddress = ptr(types.EIP55AddressFromAddress(val)) }) cfg3 := evmtest.NewChainScopedConfig(t, gcfg3) @@ -241,7 +241,7 @@ func TestChainScopedConfig(t *testing.T) { val := testutils.NewAddress() gcfg3 := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].OperatorFactoryAddress = ptr(ethkey.EIP55AddressFromAddress(val)) + c.EVM[0].OperatorFactoryAddress = ptr(types.EIP55AddressFromAddress(val)) }) cfg3 := evmtest.NewChainScopedConfig(t, gcfg3) @@ -280,7 +280,7 @@ func TestChainScopedConfig_GasEstimator(t *testing.T) { assert.Equal(t, uint64(500000), ge.LimitDefault()) assert.Equal(t, uint64(500000), ge.LimitMax()) assert.Equal(t, float32(1), ge.LimitMultiplier()) - assert.Equal(t, uint32(21000), ge.LimitTransfer()) + assert.Equal(t, uint64(21000), ge.LimitTransfer()) assert.Equal(t, assets.GWei(5), ge.BumpMin()) assert.Equal(t, uint16(20), ge.BumpPercent()) assert.Equal(t, uint64(3), ge.BumpThreshold()) diff --git a/core/chains/evm/config/mocks/gas_estimator.go b/core/chains/evm/config/mocks/gas_estimator.go index b1b25c0ee41..b1eb2b49b5c 100644 --- a/core/chains/evm/config/mocks/gas_estimator.go +++ b/core/chains/evm/config/mocks/gas_estimator.go @@ -223,18 +223,18 @@ func (_m *GasEstimator) LimitMultiplier() float32 { } // LimitTransfer provides a mock function with given fields: -func (_m *GasEstimator) LimitTransfer() uint32 { +func (_m *GasEstimator) LimitTransfer() uint64 { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for LimitTransfer") } - var r0 uint32 - if rf, ok := ret.Get(0).(func() uint32); ok { + var r0 uint64 + if rf, ok := ret.Get(0).(func() uint64); ok { r0 = rf() } else { - r0 = ret.Get(0).(uint32) + r0 = ret.Get(0).(uint64) } return r0 diff --git a/core/chains/evm/config/toml/config.go b/core/chains/evm/config/toml/config.go index b84993b28a6..0f647034162 100644 --- a/core/chains/evm/config/toml/config.go +++ b/core/chains/evm/config/toml/config.go @@ -1,6 +1,7 @@ package toml import ( + "errors" "fmt" "net/url" "slices" @@ -17,13 +18,13 @@ import ( commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/common/config" - "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" ) +var ErrNotFound = errors.New("not found") + type HasEVMConfigs interface { EVMConfigs() EVMConfigs } @@ -145,7 +146,7 @@ func (cs EVMConfigs) Node(name string) (types.Node, error) { } } } - return types.Node{}, fmt.Errorf("node %s: %w", name, chains.ErrNotFound) + return types.Node{}, fmt.Errorf("node %s: %w", name, ErrNotFound) } func (cs EVMConfigs) NodeStatus(name string) (commontypes.NodeStatus, error) { @@ -156,7 +157,7 @@ func (cs EVMConfigs) NodeStatus(name string) (commontypes.NodeStatus, error) { } } } - return commontypes.NodeStatus{}, fmt.Errorf("node %s: %w", name, chains.ErrNotFound) + return commontypes.NodeStatus{}, fmt.Errorf("node %s: %w", name, ErrNotFound) } func legacyNode(n *Node, chainID *big.Big) (v2 types.Node) { @@ -205,7 +206,7 @@ func (cs EVMConfigs) Nodes(chainID string) (ns []types.Node, err error) { } nodes := cs.nodes(chainID) if nodes == nil { - err = fmt.Errorf("no nodes: chain %q: %w", chainID, chains.ErrNotFound) + err = fmt.Errorf("no nodes: chain %q: %w", chainID, ErrNotFound) return } for _, n := range nodes { @@ -347,8 +348,8 @@ type Chain struct { ChainType *string FinalityDepth *uint32 FinalityTagEnabled *bool - FlagsContractAddress *ethkey.EIP55Address - LinkContractAddress *ethkey.EIP55Address + FlagsContractAddress *types.EIP55Address + LinkContractAddress *types.EIP55Address LogBackfillBatchSize *uint32 LogPollInterval *commonconfig.Duration LogKeepBlocksDepth *uint32 @@ -358,7 +359,7 @@ type Chain struct { MinContractPayment *commonassets.Link NonceAutoSync *bool NoNewHeadsThreshold *commonconfig.Duration - OperatorFactoryAddress *ethkey.EIP55Address + OperatorFactoryAddress *types.EIP55Address RPCDefaultBatchSize *uint32 RPCBlockQueryDelay *uint16 @@ -399,6 +400,7 @@ func (c *Chain) ValidateConfig() (err error) { err = multierr.Append(err, commonconfig.ErrInvalid{Name: "MinIncomingConfirmations", Value: *c.MinIncomingConfirmations, Msg: "must be greater than or equal to 1"}) } + return } @@ -451,8 +453,8 @@ func (a *Automation) setFrom(f *Automation) { } type ChainWriter struct { - FromAddress *ethkey.EIP55Address `toml:",omitempty"` - ForwarderAddress *ethkey.EIP55Address `toml:",omitempty"` + FromAddress *types.EIP55Address `toml:",omitempty"` + ForwarderAddress *types.EIP55Address `toml:",omitempty"` } func (m *ChainWriter) setFrom(f *ChainWriter) { @@ -484,7 +486,7 @@ type GasEstimator struct { LimitDefault *uint64 LimitMax *uint64 LimitMultiplier *decimal.Decimal - LimitTransfer *uint32 + LimitTransfer *uint64 LimitJobType GasLimitJobType `toml:",omitempty"` BumpMin *assets.Wei @@ -668,7 +670,7 @@ func (ks KeySpecificConfig) ValidateConfig() (err error) { } type KeySpecific struct { - Key *ethkey.EIP55Address + Key *types.EIP55Address GasEstimator KeySpecificGasEstimator `toml:",omitempty"` } @@ -701,12 +703,13 @@ func (t *HeadTracker) setFrom(f *HeadTracker) { } type NodePool struct { - PollFailureThreshold *uint32 - PollInterval *commonconfig.Duration - SelectionMode *string - SyncThreshold *uint32 - LeaseDuration *commonconfig.Duration - NodeIsSyncingEnabled *bool + PollFailureThreshold *uint32 + PollInterval *commonconfig.Duration + SelectionMode *string + SyncThreshold *uint32 + LeaseDuration *commonconfig.Duration + NodeIsSyncingEnabled *bool + FinalizedBlockPollInterval *commonconfig.Duration } func (p *NodePool) setFrom(f *NodePool) { @@ -728,6 +731,9 @@ func (p *NodePool) setFrom(f *NodePool) { if v := f.NodeIsSyncingEnabled; v != nil { p.NodeIsSyncingEnabled = v } + if v := f.FinalizedBlockPollInterval; v != nil { + p.FinalizedBlockPollInterval = v + } } type OCR struct { diff --git a/core/chains/evm/config/toml/defaults/Ethereum_Mainnet.toml b/core/chains/evm/config/toml/defaults/Ethereum_Mainnet.toml index 075d450ca22..fede762a663 100644 --- a/core/chains/evm/config/toml/defaults/Ethereum_Mainnet.toml +++ b/core/chains/evm/config/toml/defaults/Ethereum_Mainnet.toml @@ -11,3 +11,6 @@ BatchSize = 25 # EIP-1559 does well on a smaller block history size BlockHistorySize = 4 TransactionPercentile = 50 + +[OCR2.Automation] +GasLimit = 10500000 diff --git a/core/chains/evm/config/toml/defaults/Ethereum_Sepolia.toml b/core/chains/evm/config/toml/defaults/Ethereum_Sepolia.toml index 27dda602962..27acddeb721 100644 --- a/core/chains/evm/config/toml/defaults/Ethereum_Sepolia.toml +++ b/core/chains/evm/config/toml/defaults/Ethereum_Sepolia.toml @@ -9,3 +9,6 @@ EIP1559DynamicFees = true BatchSize = 25 BlockHistorySize = 4 TransactionPercentile = 50 + +[OCR2.Automation] +GasLimit = 10500000 diff --git a/core/chains/evm/config/toml/defaults/fallback.toml b/core/chains/evm/config/toml/defaults/fallback.toml index 1a1d9b69439..d65d0a1b0c1 100644 --- a/core/chains/evm/config/toml/defaults/fallback.toml +++ b/core/chains/evm/config/toml/defaults/fallback.toml @@ -62,6 +62,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 diff --git a/core/chains/evm/gas/arbitrum_estimator_test.go b/core/chains/evm/gas/arbitrum_estimator_test.go index afac9e03276..3c46b466e87 100644 --- a/core/chains/evm/gas/arbitrum_estimator_test.go +++ b/core/chains/evm/gas/arbitrum_estimator_test.go @@ -168,7 +168,7 @@ func TestArbitrumEstimator(t *testing.T) { rpcClient := mocks.NewRPCClient(t) ethClient := mocks.NewETHClient(t) o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{}, rpcClient, ethClient) - _, _, err := o.GetDynamicFee(testutils.Context(t), gasLimit, maxGasPrice) + _, err := o.GetDynamicFee(testutils.Context(t), maxGasPrice) assert.EqualError(t, err, "dynamic fees are not implemented for this estimator") }) @@ -180,7 +180,7 @@ func TestArbitrumEstimator(t *testing.T) { FeeCap: assets.NewWeiI(42), TipCap: assets.NewWeiI(5), } - _, _, err := o.BumpDynamicFee(testutils.Context(t), fee, gasLimit, maxGasPrice, nil) + _, err := o.BumpDynamicFee(testutils.Context(t), fee, maxGasPrice, nil) assert.EqualError(t, err, "dynamic fees are not implemented for this estimator") }) diff --git a/core/chains/evm/gas/block_history_estimator.go b/core/chains/evm/gas/block_history_estimator.go index fcd0d627063..295edc76eb1 100644 --- a/core/chains/evm/gas/block_history_estimator.go +++ b/core/chains/evm/gas/block_history_estimator.go @@ -86,7 +86,6 @@ type chainConfig interface { type estimatorGasEstimatorConfig interface { EIP1559DynamicFees() bool BumpThreshold() uint64 - LimitMultiplier() float32 PriceDefault() *assets.Wei TipCapDefault() *assets.Wei TipCapMin() *assets.Wei @@ -96,34 +95,32 @@ type estimatorGasEstimatorConfig interface { } //go:generate mockery --quiet --name Config --output ./mocks/ --case=underscore -type ( - BlockHistoryEstimator struct { - services.StateMachine - ethClient evmclient.Client - chainID big.Int - config chainConfig - eConfig estimatorGasEstimatorConfig - bhConfig BlockHistoryConfig - // NOTE: it is assumed that blocks will be kept sorted by - // block number ascending - blocks []evmtypes.Block - blocksMu sync.RWMutex - size int64 - mb *mailbox.Mailbox[*evmtypes.Head] - wg *sync.WaitGroup - ctx context.Context - ctxCancel context.CancelFunc - - gasPrice *assets.Wei - tipCap *assets.Wei - priceMu sync.RWMutex - latest *evmtypes.Head - latestMu sync.RWMutex - initialFetch atomic.Bool - - logger logger.SugaredLogger - } -) +type BlockHistoryEstimator struct { + services.StateMachine + ethClient evmclient.Client + chainID big.Int + config chainConfig + eConfig estimatorGasEstimatorConfig + bhConfig BlockHistoryConfig + // NOTE: it is assumed that blocks will be kept sorted by + // block number ascending + blocks []evmtypes.Block + blocksMu sync.RWMutex + size int64 + mb *mailbox.Mailbox[*evmtypes.Head] + wg *sync.WaitGroup + ctx context.Context + ctxCancel context.CancelFunc + + gasPrice *assets.Wei + tipCap *assets.Wei + priceMu sync.RWMutex + latest *evmtypes.Head + latestMu sync.RWMutex + initialFetch atomic.Bool + + logger logger.SugaredLogger +} // NewBlockHistoryEstimator returns a new BlockHistoryEstimator that listens // for new heads and updates the base gas price dynamically based on the @@ -264,7 +261,7 @@ func (b *BlockHistoryEstimator) GetLegacyGas(_ context.Context, _ []byte, gasLim gasPrice = b.eConfig.PriceDefault() } gasPrice = capGasPrice(gasPrice, maxGasPriceWei, b.eConfig.PriceMax()) - chainSpecificGasLimit, err = commonfee.ApplyMultiplier(gasLimit, b.eConfig.LimitMultiplier()) + chainSpecificGasLimit = gasLimit return } @@ -298,7 +295,11 @@ func (b *BlockHistoryEstimator) BumpLegacyGas(_ context.Context, originalGasPric return nil, 0, err } } - return BumpLegacyGasPriceOnly(b.eConfig, b.logger, b.getGasPrice(), originalGasPrice, gasLimit, maxGasPriceWei) + bumpedGasPrice, err = BumpLegacyGasPriceOnly(b.eConfig, b.logger, b.getGasPrice(), originalGasPrice, maxGasPriceWei) + if err != nil { + return nil, 0, err + } + return bumpedGasPrice, gasLimit, err } // checkConnectivity detects if the transaction is not being included due to @@ -388,18 +389,14 @@ func (b *BlockHistoryEstimator) checkConnectivity(attempts []EvmPriorAttempt) er return nil } -func (b *BlockHistoryEstimator) GetDynamicFee(_ context.Context, gasLimit uint64, maxGasPriceWei *assets.Wei) (fee DynamicFee, chainSpecificGasLimit uint64, err error) { +func (b *BlockHistoryEstimator) GetDynamicFee(_ context.Context, maxGasPriceWei *assets.Wei) (fee DynamicFee, err error) { if !b.eConfig.EIP1559DynamicFees() { - return fee, 0, pkgerrors.New("Can't get dynamic fee, EIP1559 is disabled") + return fee, pkgerrors.New("Can't get dynamic fee, EIP1559 is disabled") } var feeCap *assets.Wei var tipCap *assets.Wei ok := b.IfStarted(func() { - chainSpecificGasLimit, err = commonfee.ApplyMultiplier(gasLimit, b.eConfig.LimitMultiplier()) - if err != nil { - return - } b.priceMu.RLock() defer b.priceMu.RUnlock() tipCap = b.tipCap @@ -431,10 +428,10 @@ func (b *BlockHistoryEstimator) GetDynamicFee(_ context.Context, gasLimit uint64 } }) if !ok { - return fee, 0, pkgerrors.New("BlockHistoryEstimator is not started; cannot estimate gas") + return fee, pkgerrors.New("BlockHistoryEstimator is not started; cannot estimate gas") } if err != nil { - return fee, 0, err + return fee, err } fee.FeeCap = feeCap fee.TipCap = tipCap @@ -461,7 +458,7 @@ func calcFeeCap(latestAvailableBaseFeePerGas *assets.Wei, bufferBlocks int, tipC return feeCap } -func (b *BlockHistoryEstimator) BumpDynamicFee(_ context.Context, originalFee DynamicFee, originalGasLimit uint64, maxGasPriceWei *assets.Wei, attempts []EvmPriorAttempt) (bumped DynamicFee, chainSpecificGasLimit uint64, err error) { +func (b *BlockHistoryEstimator) BumpDynamicFee(_ context.Context, originalFee DynamicFee, maxGasPriceWei *assets.Wei, attempts []EvmPriorAttempt) (bumped DynamicFee, err error) { if b.bhConfig.CheckInclusionBlocks() > 0 { if err = b.checkConnectivity(attempts); err != nil { if pkgerrors.Is(err, commonfee.ErrConnectivity) { @@ -469,10 +466,10 @@ func (b *BlockHistoryEstimator) BumpDynamicFee(_ context.Context, originalFee Dy b.SvcErrBuffer.Append(err) promBlockHistoryEstimatorConnectivityFailureCount.WithLabelValues(b.chainID.String(), "eip1559").Inc() } - return bumped, 0, err + return bumped, err } } - return BumpDynamicFeeOnly(b.eConfig, b.bhConfig.EIP1559FeeCapBufferBlocks(), b.logger, b.getTipCap(), b.getCurrentBaseFee(), originalFee, originalGasLimit, maxGasPriceWei) + return BumpDynamicFeeOnly(b.eConfig, b.bhConfig.EIP1559FeeCapBufferBlocks(), b.logger, b.getTipCap(), b.getCurrentBaseFee(), originalFee, maxGasPriceWei) } func (b *BlockHistoryEstimator) runLoop() { diff --git a/core/chains/evm/gas/block_history_estimator_test.go b/core/chains/evm/gas/block_history_estimator_test.go index f5ab06fc913..5260a22bff3 100644 --- a/core/chains/evm/gas/block_history_estimator_test.go +++ b/core/chains/evm/gas/block_history_estimator_test.go @@ -67,7 +67,6 @@ func TestBlockHistoryEstimator_Start(t *testing.T) { minGasPrice := assets.NewWeiI(1) maxGasPrice := assets.NewWeiI(100) - geCfg.LimitMultiplierF = float32(1) geCfg.PriceMinF = minGasPrice geCfg.PriceMaxF = maxGasPrice @@ -112,7 +111,6 @@ func TestBlockHistoryEstimator_Start(t *testing.T) { t.Run("starts and loads partial history if fetch context times out", func(t *testing.T) { geCfg2 := &gas.MockGasEstimatorConfig{} geCfg2.EIP1559DynamicFeesF = true - geCfg2.LimitMultiplierF = float32(1) geCfg2.PriceMinF = minGasPrice bhCfg2 := newBlockHistoryConfig() @@ -188,7 +186,7 @@ func TestBlockHistoryEstimator_Start(t *testing.T) { require.Error(t, err) require.Contains(t, err.Error(), "has not finished the first gas estimation yet, likely because a failure on start") - _, _, err = bhe.GetDynamicFee(testutils.Context(t), 100, maxGasPrice) + _, err = bhe.GetDynamicFee(testutils.Context(t), maxGasPrice) require.Error(t, err) require.Contains(t, err.Error(), "has not finished the first gas estimation yet, likely because a failure on start") }) @@ -211,7 +209,7 @@ func TestBlockHistoryEstimator_Start(t *testing.T) { require.Error(t, err) require.Contains(t, err.Error(), "has not finished the first gas estimation yet, likely because a failure on start") - _, _, err = bhe.GetDynamicFee(testutils.Context(t), 100, maxGasPrice) + _, err = bhe.GetDynamicFee(testutils.Context(t), maxGasPrice) require.Error(t, err) require.Contains(t, err.Error(), "has not finished the first gas estimation yet, likely because a failure on start") }) @@ -252,7 +250,7 @@ func TestBlockHistoryEstimator_Start(t *testing.T) { require.Error(t, err) require.Contains(t, err.Error(), "has not finished the first gas estimation yet, likely because a failure on start") - _, _, err = bhe.GetDynamicFee(testutils.Context(t), 100, maxGasPrice) + _, err = bhe.GetDynamicFee(testutils.Context(t), maxGasPrice) require.Error(t, err) require.Contains(t, err.Error(), "has not finished the first gas estimation yet, likely because a failure on start") }) @@ -1785,7 +1783,6 @@ func TestBlockHistoryEstimator_GetLegacyGas(t *testing.T) { maxGasPrice := assets.NewWeiI(1000000) geCfg := &gas.MockGasEstimatorConfig{} geCfg.EIP1559DynamicFeesF = false - geCfg.LimitMultiplierF = float32(1) geCfg.PriceMaxF = maxGasPrice geCfg.PriceMinF = assets.NewWeiI(0) @@ -1828,7 +1825,6 @@ func TestBlockHistoryEstimator_GetLegacyGas(t *testing.T) { cfg = gas.NewMockConfig() - geCfg.LimitMultiplierF = float32(1) geCfg.PriceMaxF = assets.NewWeiI(700) geCfg.PriceMinF = assets.NewWeiI(0) @@ -1867,7 +1863,6 @@ func TestBlockHistoryEstimator_UseDefaultPriceAsFallback(t *testing.T) { geCfg := &gas.MockGasEstimatorConfig{} geCfg.EIP1559DynamicFeesF = false - geCfg.LimitMultiplierF = float32(1) geCfg.PriceMaxF = assets.NewWeiI(1000000) geCfg.PriceDefaultF = assets.NewWeiI(100) @@ -1917,7 +1912,6 @@ func TestBlockHistoryEstimator_UseDefaultPriceAsFallback(t *testing.T) { bhCfg.EIP1559FeeCapBufferBlocksF = uint16(4) geCfg := &gas.MockGasEstimatorConfig{} geCfg.EIP1559DynamicFeesF = true - geCfg.LimitMultiplierF = float32(1) geCfg.PriceMaxF = assets.NewWeiI(1000000) geCfg.PriceDefaultF = assets.NewWeiI(100) geCfg.TipCapDefaultF = assets.NewWeiI(50) @@ -1952,11 +1946,10 @@ func TestBlockHistoryEstimator_UseDefaultPriceAsFallback(t *testing.T) { err := bhe.Start(testutils.Context(t)) require.NoError(t, err) - fee, limit, err := bhe.GetDynamicFee(testutils.Context(t), 100000, assets.NewWeiI(200)) + fee, err := bhe.GetDynamicFee(testutils.Context(t), assets.NewWeiI(200)) require.NoError(t, err) assert.Equal(t, gas.DynamicFee{FeeCap: assets.NewWeiI(114), TipCap: geCfg.TipCapDefault()}, fee) - assert.Equal(t, 100000, int(limit)) }) } @@ -1970,7 +1963,6 @@ func TestBlockHistoryEstimator_GetDynamicFee(t *testing.T) { bhCfg.TransactionPercentileF = uint16(35) geCfg := &gas.MockGasEstimatorConfig{} geCfg.EIP1559DynamicFeesF = true - geCfg.LimitMultiplierF = float32(1) geCfg.PriceMaxF = maxGasPrice geCfg.TipCapMinF = assets.NewWeiI(0) geCfg.PriceMinF = assets.NewWeiI(0) @@ -1999,7 +1991,7 @@ func TestBlockHistoryEstimator_GetDynamicFee(t *testing.T) { t.Run("if estimator is missing base fee and gas bumping is enabled", func(t *testing.T) { geCfg.BumpThresholdF = uint64(1) - _, _, err := bhe.GetDynamicFee(testutils.Context(t), 100000, maxGasPrice) + _, err := bhe.GetDynamicFee(testutils.Context(t), maxGasPrice) require.Error(t, err) assert.Contains(t, err.Error(), "BlockHistoryEstimator: no value for latest block base fee; cannot estimate EIP-1559 base fee. Are you trying to run with EIP1559 enabled on a non-EIP1559 chain?") }) @@ -2007,10 +1999,9 @@ func TestBlockHistoryEstimator_GetDynamicFee(t *testing.T) { t.Run("if estimator is missing base fee and gas bumping is disabled", func(t *testing.T) { geCfg.BumpThresholdF = uint64(0) - fee, limit, err := bhe.GetDynamicFee(testutils.Context(t), 100000, maxGasPrice) + fee, err := bhe.GetDynamicFee(testutils.Context(t), maxGasPrice) require.NoError(t, err) assert.Equal(t, gas.DynamicFee{FeeCap: maxGasPrice, TipCap: assets.NewWeiI(6000)}, fee) - assert.Equal(t, 100000, int(limit)) }) h := cltest.Head(1) @@ -2020,41 +2011,37 @@ func TestBlockHistoryEstimator_GetDynamicFee(t *testing.T) { t.Run("if gas bumping is enabled", func(t *testing.T) { geCfg.BumpThresholdF = uint64(1) - fee, limit, err := bhe.GetDynamicFee(testutils.Context(t), 100000, maxGasPrice) + fee, err := bhe.GetDynamicFee(testutils.Context(t), maxGasPrice) require.NoError(t, err) assert.Equal(t, gas.DynamicFee{FeeCap: assets.NewWeiI(186203), TipCap: assets.NewWeiI(6000)}, fee) - assert.Equal(t, 100000, int(limit)) }) t.Run("if gas bumping is disabled", func(t *testing.T) { geCfg.BumpThresholdF = uint64(0) - fee, limit, err := bhe.GetDynamicFee(testutils.Context(t), 100000, maxGasPrice) + fee, err := bhe.GetDynamicFee(testutils.Context(t), maxGasPrice) require.NoError(t, err) assert.Equal(t, gas.DynamicFee{FeeCap: maxGasPrice, TipCap: assets.NewWeiI(6000)}, fee) - assert.Equal(t, 100000, int(limit)) }) t.Run("if gas bumping is enabled and local max gas price set", func(t *testing.T) { geCfg.BumpThresholdF = uint64(1) - fee, limit, err := bhe.GetDynamicFee(testutils.Context(t), 100000, assets.NewWeiI(180000)) + fee, err := bhe.GetDynamicFee(testutils.Context(t), assets.NewWeiI(180000)) require.NoError(t, err) assert.Equal(t, gas.DynamicFee{FeeCap: assets.NewWeiI(180000), TipCap: assets.NewWeiI(6000)}, fee) - assert.Equal(t, 100000, int(limit)) }) t.Run("if bump threshold is 0 and local max gas price set", func(t *testing.T) { geCfg.BumpThresholdF = uint64(0) - fee, limit, err := bhe.GetDynamicFee(testutils.Context(t), 100000, assets.NewWeiI(100)) + fee, err := bhe.GetDynamicFee(testutils.Context(t), assets.NewWeiI(100)) require.NoError(t, err) assert.Equal(t, gas.DynamicFee{FeeCap: assets.NewWeiI(100), TipCap: assets.NewWeiI(6000)}, fee) - assert.Equal(t, 100000, int(limit)) }) h = cltest.Head(1) @@ -2064,11 +2051,10 @@ func TestBlockHistoryEstimator_GetDynamicFee(t *testing.T) { t.Run("if gas bumping is enabled and global max gas price lower than local max gas price", func(t *testing.T) { geCfg.BumpThresholdF = uint64(1) - fee, limit, err := bhe.GetDynamicFee(testutils.Context(t), 100000, assets.NewWeiI(1200000)) + fee, err := bhe.GetDynamicFee(testutils.Context(t), assets.NewWeiI(1200000)) require.NoError(t, err) assert.Equal(t, gas.DynamicFee{FeeCap: assets.NewWeiI(1000000), TipCap: assets.NewWeiI(6000)}, fee) - assert.Equal(t, 100000, int(limit)) }) } @@ -2379,7 +2365,6 @@ func TestBlockHistoryEstimator_Bumps(t *testing.T) { geCfg.BumpPercentF = 10 geCfg.BumpMinF = assets.NewWeiI(150) geCfg.PriceMaxF = maxGasPrice - geCfg.LimitMultiplierF = float32(1.1) bhe := newBlockHistoryEstimator(t, nil, cfg, geCfg, bhCfg) @@ -2409,7 +2394,6 @@ func TestBlockHistoryEstimator_Bumps(t *testing.T) { geCfg.BumpPercentF = 10 geCfg.BumpMinF = assets.NewWeiI(150) geCfg.PriceMaxF = maxGasPrice - geCfg.LimitMultiplierF = float32(1.1) bhe := newBlockHistoryEstimator(t, nil, cfg, geCfg, bhCfg) @@ -2417,10 +2401,10 @@ func TestBlockHistoryEstimator_Bumps(t *testing.T) { gasPrice, gasLimit, err := bhe.BumpLegacyGas(testutils.Context(t), assets.NewWeiI(42), 100000, maxGasPrice, nil) require.NoError(t, err) - expectedGasPrice, expectedGasLimit, err := gas.BumpLegacyGasPriceOnly(geCfg, logger.TestSugared(t), nil, assets.NewWeiI(42), 100000, maxGasPrice) + expectedGasPrice, err := gas.BumpLegacyGasPriceOnly(geCfg, logger.TestSugared(t), nil, assets.NewWeiI(42), maxGasPrice) require.NoError(t, err) - assert.Equal(t, expectedGasLimit, gasLimit) + assert.Equal(t, 100000, int(gasLimit)) assert.Equal(t, expectedGasPrice, gasPrice) }) @@ -2431,10 +2415,10 @@ func TestBlockHistoryEstimator_Bumps(t *testing.T) { massive := assets.NewWeiI(100000000000000) gas.SetGasPrice(bhe, massive) - expectedGasPrice, expectedGasLimit, err := gas.BumpLegacyGasPriceOnly(geCfg, logger.TestSugared(t), massive, assets.NewWeiI(42), 100000, maxGasPrice) + expectedGasPrice, err := gas.BumpLegacyGasPriceOnly(geCfg, logger.TestSugared(t), massive, assets.NewWeiI(42), maxGasPrice) require.NoError(t, err) - assert.Equal(t, expectedGasLimit, gasLimit) + assert.Equal(t, 100000, int(gasLimit)) assert.Equal(t, expectedGasPrice, gasPrice) }) @@ -2444,7 +2428,7 @@ func TestBlockHistoryEstimator_Bumps(t *testing.T) { gasPrice, gasLimit, err := bhe.BumpLegacyGas(testutils.Context(t), assets.NewWeiI(42), 100000, maxGasPrice, nil) require.NoError(t, err) - assert.Equal(t, 110000, int(gasLimit)) + assert.Equal(t, 100000, int(gasLimit)) assert.Equal(t, assets.NewWeiI(192), gasPrice) }) @@ -2454,7 +2438,7 @@ func TestBlockHistoryEstimator_Bumps(t *testing.T) { gasPrice, gasLimit, err := bhe.BumpLegacyGas(testutils.Context(t), assets.NewWeiI(42), 100000, maxGasPrice, nil) require.NoError(t, err) - assert.Equal(t, 110000, int(gasLimit)) + assert.Equal(t, 100000, int(gasLimit)) assert.Equal(t, assets.NewWeiI(193), gasPrice) }) @@ -2491,7 +2475,6 @@ func TestBlockHistoryEstimator_Bumps(t *testing.T) { geCfg.BumpPercentF = 10 geCfg.BumpMinF = assets.NewWeiI(150) geCfg.PriceMaxF = maxGasPrice - geCfg.LimitMultiplierF = float32(1.1) bhe := newBlockHistoryEstimator(t, nil, cfg, geCfg, bhCfg) @@ -2509,7 +2492,7 @@ func TestBlockHistoryEstimator_Bumps(t *testing.T) { attempts := []gas.EvmPriorAttempt{ {TxType: 0x2, TxHash: NewEvmHash(), DynamicFee: gas.DynamicFee{TipCap: originalFee.TipCap, FeeCap: originalFee.FeeCap}, BroadcastBeforeBlockNum: testutils.Ptr(int64(0))}} - _, _, err := bhe.BumpDynamicFee(testutils.Context(t), originalFee, 100000, maxGasPrice, attempts) + _, err := bhe.BumpDynamicFee(testutils.Context(t), originalFee, maxGasPrice, attempts) require.Error(t, err) assert.True(t, pkgerrors.Is(err, commonfee.ErrConnectivity)) assert.Contains(t, err.Error(), fmt.Sprintf("transaction %s has tip cap of 25 wei, which is above percentile=10%% (percentile tip cap: 1 wei) for blocks 1 thru 1 (checking 1 blocks)", attempts[0].TxHash)) @@ -2524,47 +2507,42 @@ func TestBlockHistoryEstimator_Bumps(t *testing.T) { geCfg.BumpPercentF = 10 geCfg.BumpMinF = assets.NewWeiI(150) geCfg.PriceMaxF = maxGasPrice - geCfg.LimitMultiplierF = float32(1.1) geCfg.TipCapDefaultF = assets.NewWeiI(52) bhe := newBlockHistoryEstimator(t, nil, cfg, geCfg, bhCfg) t.Run("when current tip cap is nil", func(t *testing.T) { originalFee := gas.DynamicFee{FeeCap: assets.NewWeiI(100), TipCap: assets.NewWeiI(25)} - fee, gasLimit, err := bhe.BumpDynamicFee(testutils.Context(t), originalFee, 100000, maxGasPrice, nil) + fee, err := bhe.BumpDynamicFee(testutils.Context(t), originalFee, maxGasPrice, nil) require.NoError(t, err) - assert.Equal(t, 110000, int(gasLimit)) assert.Equal(t, gas.DynamicFee{FeeCap: assets.NewWeiI(250), TipCap: assets.NewWeiI(202)}, fee) }) t.Run("ignores current tip cap that is smaller than original fee with bump applied", func(t *testing.T) { gas.SetTipCap(bhe, assets.NewWeiI(201)) originalFee := gas.DynamicFee{FeeCap: assets.NewWeiI(100), TipCap: assets.NewWeiI(25)} - fee, gasLimit, err := bhe.BumpDynamicFee(testutils.Context(t), originalFee, 100000, maxGasPrice, nil) + fee, err := bhe.BumpDynamicFee(testutils.Context(t), originalFee, maxGasPrice, nil) require.NoError(t, err) - assert.Equal(t, 110000, int(gasLimit)) assert.Equal(t, gas.DynamicFee{FeeCap: assets.NewWeiI(250), TipCap: assets.NewWeiI(202)}, fee) }) t.Run("uses current tip cap that is larger than original fee with bump applied", func(t *testing.T) { gas.SetTipCap(bhe, assets.NewWeiI(203)) originalFee := gas.DynamicFee{FeeCap: assets.NewWeiI(100), TipCap: assets.NewWeiI(25)} - fee, gasLimit, err := bhe.BumpDynamicFee(testutils.Context(t), originalFee, 100000, maxGasPrice, nil) + fee, err := bhe.BumpDynamicFee(testutils.Context(t), originalFee, maxGasPrice, nil) require.NoError(t, err) - assert.Equal(t, 110000, int(gasLimit)) assert.Equal(t, gas.DynamicFee{FeeCap: assets.NewWeiI(250), TipCap: assets.NewWeiI(203)}, fee) }) t.Run("ignores absurdly large current tip cap", func(t *testing.T) { gas.SetTipCap(bhe, assets.NewWeiI(1000000000000000)) originalFee := gas.DynamicFee{FeeCap: assets.NewWeiI(100), TipCap: assets.NewWeiI(25)} - fee, gasLimit, err := bhe.BumpDynamicFee(testutils.Context(t), originalFee, 100000, maxGasPrice, nil) + fee, err := bhe.BumpDynamicFee(testutils.Context(t), originalFee, maxGasPrice, nil) require.NoError(t, err) - assert.Equal(t, 110000, int(gasLimit)) assert.Equal(t, gas.DynamicFee{FeeCap: assets.NewWeiI(250), TipCap: assets.NewWeiI(202)}, fee) }) @@ -2572,10 +2550,9 @@ func TestBlockHistoryEstimator_Bumps(t *testing.T) { gas.SetTipCap(bhe, assets.NewWeiI(203)) originalFee := gas.DynamicFee{FeeCap: assets.NewWeiI(100), TipCap: assets.NewWeiI(990000)} - fee, gasLimit, err := bhe.BumpDynamicFee(testutils.Context(t), originalFee, 100000, maxGasPrice, nil) + fee, err := bhe.BumpDynamicFee(testutils.Context(t), originalFee, maxGasPrice, nil) require.Error(t, err) - assert.Equal(t, 0, int(gasLimit)) assert.Equal(t, gas.DynamicFee{}, fee) assert.Contains(t, err.Error(), "bumped tip cap of 1.089 mwei would exceed configured max gas price of 1 mwei (original fee: tip cap 990 kwei, fee cap 100 wei)") }) @@ -2584,10 +2561,9 @@ func TestBlockHistoryEstimator_Bumps(t *testing.T) { gas.SetTipCap(bhe, assets.NewWeiI(203)) originalFee := gas.DynamicFee{FeeCap: assets.NewWeiI(990000), TipCap: assets.NewWeiI(25)} - fee, gasLimit, err := bhe.BumpDynamicFee(testutils.Context(t), originalFee, 100000, maxGasPrice, nil) + fee, err := bhe.BumpDynamicFee(testutils.Context(t), originalFee, maxGasPrice, nil) require.Error(t, err) - assert.Equal(t, 0, int(gasLimit)) assert.Equal(t, gas.DynamicFee{}, fee) assert.Contains(t, err.Error(), "bumped fee cap of 1.089 mwei would exceed configured max gas price of 1 mwei (original fee: tip cap 25 wei, fee cap 990 kwei)") }) diff --git a/core/chains/evm/gas/fixed_price_estimator.go b/core/chains/evm/gas/fixed_price_estimator.go index 53b7e93a871..fc65413d375 100644 --- a/core/chains/evm/gas/fixed_price_estimator.go +++ b/core/chains/evm/gas/fixed_price_estimator.go @@ -30,7 +30,6 @@ type bumpConfig interface { type fixedPriceEstimatorConfig interface { BumpThreshold() uint64 FeeCapDefault() *assets.Wei - LimitMultiplier() float32 PriceDefault() *assets.Wei TipCapDefault() *assets.Wei PriceMax() *assets.Wei @@ -60,10 +59,7 @@ func (f *fixedPriceEstimator) Start(context.Context) error { func (f *fixedPriceEstimator) GetLegacyGas(_ context.Context, _ []byte, gasLimit uint64, maxGasPriceWei *assets.Wei, _ ...feetypes.Opt) (*assets.Wei, uint64, error) { gasPrice := commonfee.CalculateFee(f.config.PriceDefault().ToInt(), maxGasPriceWei.ToInt(), f.config.PriceMax().ToInt()) - chainSpecificGasLimit, err := commonfee.ApplyMultiplier(gasLimit, f.config.LimitMultiplier()) - if err != nil { - return nil, 0, err - } + chainSpecificGasLimit := gasLimit return assets.NewWei(gasPrice), chainSpecificGasLimit, nil } @@ -88,22 +84,15 @@ func (f *fixedPriceEstimator) BumpLegacyGas( return nil, 0, err } - chainSpecificGasLimit, err := commonfee.ApplyMultiplier(originalGasLimit, f.config.LimitMultiplier()) - if err != nil { - return nil, 0, err - } + chainSpecificGasLimit := originalGasLimit return assets.NewWei(gasPrice), chainSpecificGasLimit, err } -func (f *fixedPriceEstimator) GetDynamicFee(_ context.Context, originalGasLimit uint64, maxGasPriceWei *assets.Wei) (d DynamicFee, chainSpecificGasLimit uint64, err error) { +func (f *fixedPriceEstimator) GetDynamicFee(_ context.Context, maxGasPriceWei *assets.Wei) (d DynamicFee, err error) { gasTipCap := f.config.TipCapDefault() if gasTipCap == nil { - return d, 0, pkgerrors.New("cannot calculate dynamic fee: EthGasTipCapDefault was not set") - } - chainSpecificGasLimit, err = commonfee.ApplyMultiplier(originalGasLimit, f.config.LimitMultiplier()) - if err != nil { - return d, 0, err + return d, pkgerrors.New("cannot calculate dynamic fee: EthGasTipCapDefault was not set") } var feeCap *assets.Wei @@ -118,16 +107,15 @@ func (f *fixedPriceEstimator) GetDynamicFee(_ context.Context, originalGasLimit return DynamicFee{ FeeCap: feeCap, TipCap: gasTipCap, - }, chainSpecificGasLimit, nil + }, nil } func (f *fixedPriceEstimator) BumpDynamicFee( _ context.Context, originalFee DynamicFee, - originalGasLimit uint64, maxGasPriceWei *assets.Wei, _ []EvmPriorAttempt, -) (bumped DynamicFee, chainSpecificGasLimit uint64, err error) { +) (bumped DynamicFee, err error) { return BumpDynamicFeeOnly( f.config, @@ -136,7 +124,6 @@ func (f *fixedPriceEstimator) BumpDynamicFee( f.config.TipCapDefault(), nil, originalFee, - originalGasLimit, maxGasPriceWei, ) } diff --git a/core/chains/evm/gas/fixed_price_estimator_test.go b/core/chains/evm/gas/fixed_price_estimator_test.go index 968275ace48..c31bd41aeee 100644 --- a/core/chains/evm/gas/fixed_price_estimator_test.go +++ b/core/chains/evm/gas/fixed_price_estimator_test.go @@ -24,50 +24,46 @@ func Test_FixedPriceEstimator(t *testing.T) { t.Parallel() maxGasPrice := assets.NewWeiI(1000000) - t.Run("GetLegacyGas returns EvmGasPriceDefault from config, with multiplier applied", func(t *testing.T) { + t.Run("GetLegacyGas returns EvmGasPriceDefault from config", func(t *testing.T) { config := &gas.MockGasEstimatorConfig{} f := gas.NewFixedPriceEstimator(config, &blockHistoryConfig{}, logger.Test(t)) config.PriceDefaultF = assets.NewWeiI(42) - config.LimitMultiplierF = float32(1.1) config.PriceMaxF = maxGasPrice gasPrice, gasLimit, err := f.GetLegacyGas(testutils.Context(t), nil, 100000, maxGasPrice) require.NoError(t, err) - assert.Equal(t, 110000, int(gasLimit)) + assert.Equal(t, 100000, int(gasLimit)) assert.Equal(t, assets.NewWeiI(42), gasPrice) }) t.Run("GetLegacyGas returns user specified maximum gas price", func(t *testing.T) { config := &gas.MockGasEstimatorConfig{} config.PriceDefaultF = assets.NewWeiI(42) - config.LimitMultiplierF = float32(1.1) config.PriceMaxF = assets.NewWeiI(35) f := gas.NewFixedPriceEstimator(config, &blockHistoryConfig{}, logger.Test(t)) gasPrice, gasLimit, err := f.GetLegacyGas(testutils.Context(t), nil, 100000, assets.NewWeiI(30)) require.NoError(t, err) - assert.Equal(t, 110000, int(gasLimit)) + assert.Equal(t, 100000, int(gasLimit)) assert.Equal(t, assets.NewWeiI(30), gasPrice) }) t.Run("GetLegacyGas returns global maximum gas price", func(t *testing.T) { config := &gas.MockGasEstimatorConfig{} config.PriceDefaultF = assets.NewWeiI(42) - config.LimitMultiplierF = float32(1.1) config.PriceMaxF = assets.NewWeiI(20) f := gas.NewFixedPriceEstimator(config, &blockHistoryConfig{}, logger.Test(t)) gasPrice, gasLimit, err := f.GetLegacyGas(testutils.Context(t), nil, 100000, assets.NewWeiI(30)) require.NoError(t, err) - assert.Equal(t, 110000, int(gasLimit)) + assert.Equal(t, 100000, int(gasLimit)) assert.Equal(t, assets.NewWeiI(20), gasPrice) }) t.Run("BumpLegacyGas calls BumpLegacyGasPriceOnly", func(t *testing.T) { config := &gas.MockGasEstimatorConfig{} config.PriceDefaultF = assets.NewWeiI(42) - config.LimitMultiplierF = float32(1.1) config.PriceMaxF = maxGasPrice config.BumpPercentF = uint16(10) config.BumpMinF = assets.NewWeiI(150) @@ -78,16 +74,15 @@ func Test_FixedPriceEstimator(t *testing.T) { gasPrice, gasLimit, err := f.BumpLegacyGas(testutils.Context(t), assets.NewWeiI(42), 100000, maxGasPrice, nil) require.NoError(t, err) - expectedGasPrice, expectedGasLimit, err := gas.BumpLegacyGasPriceOnly(config, lggr, nil, assets.NewWeiI(42), 100000, maxGasPrice) + expectedGasPrice, err := gas.BumpLegacyGasPriceOnly(config, lggr, nil, assets.NewWeiI(42), maxGasPrice) require.NoError(t, err) - assert.Equal(t, expectedGasLimit, gasLimit) + assert.Equal(t, 100000, int(gasLimit)) assert.Equal(t, expectedGasPrice, gasPrice) }) - t.Run("GetDynamicFee returns defaults from config, with multiplier applied", func(t *testing.T) { + t.Run("GetDynamicFee returns defaults from config", func(t *testing.T) { config := &gas.MockGasEstimatorConfig{} - config.LimitMultiplierF = float32(1.1) config.PriceMaxF = maxGasPrice config.TipCapDefaultF = assets.NewWeiI(52) config.FeeCapDefaultF = assets.NewWeiI(100) @@ -96,9 +91,8 @@ func Test_FixedPriceEstimator(t *testing.T) { lggr := logger.Test(t) f := gas.NewFixedPriceEstimator(config, &blockHistoryConfig{}, lggr) - fee, gasLimit, err := f.GetDynamicFee(testutils.Context(t), 100000, maxGasPrice) + fee, err := f.GetDynamicFee(testutils.Context(t), maxGasPrice) require.NoError(t, err) - assert.Equal(t, 110000, int(gasLimit)) assert.Equal(t, assets.NewWeiI(52), fee.TipCap) assert.Equal(t, assets.NewWeiI(100), fee.FeeCap) @@ -106,17 +100,15 @@ func Test_FixedPriceEstimator(t *testing.T) { // Gas bumping disabled config.BumpThresholdF = uint64(0) - fee, gasLimit, err = f.GetDynamicFee(testutils.Context(t), 100000, maxGasPrice) + fee, err = f.GetDynamicFee(testutils.Context(t), maxGasPrice) require.NoError(t, err) - assert.Equal(t, 110000, int(gasLimit)) assert.Equal(t, assets.NewWeiI(52), fee.TipCap) assert.Equal(t, maxGasPrice, fee.FeeCap) // override max gas price - fee, gasLimit, err = f.GetDynamicFee(testutils.Context(t), 100000, assets.NewWeiI(10)) + fee, err = f.GetDynamicFee(testutils.Context(t), assets.NewWeiI(10)) require.NoError(t, err) - assert.Equal(t, 110000, int(gasLimit)) assert.Equal(t, assets.NewWeiI(52), fee.TipCap) assert.Equal(t, assets.NewWeiI(10), fee.FeeCap) @@ -124,7 +116,6 @@ func Test_FixedPriceEstimator(t *testing.T) { t.Run("BumpDynamicFee calls BumpDynamicFeeOnly", func(t *testing.T) { config := &gas.MockGasEstimatorConfig{} - config.LimitMultiplierF = float32(1.1) config.PriceMaxF = maxGasPrice config.TipCapDefaultF = assets.NewWeiI(52) config.BumpMinF = assets.NewWeiI(150) @@ -134,13 +125,12 @@ func Test_FixedPriceEstimator(t *testing.T) { f := gas.NewFixedPriceEstimator(config, &blockHistoryConfig{}, lggr) originalFee := gas.DynamicFee{FeeCap: assets.NewWeiI(100), TipCap: assets.NewWeiI(25)} - fee, gasLimit, err := f.BumpDynamicFee(testutils.Context(t), originalFee, 100000, maxGasPrice, nil) + fee, err := f.BumpDynamicFee(testutils.Context(t), originalFee, maxGasPrice, nil) require.NoError(t, err) - expectedFee, expectedGasLimit, err := gas.BumpDynamicFeeOnly(config, 0, lggr, nil, nil, originalFee, 100000, maxGasPrice) + expectedFee, err := gas.BumpDynamicFeeOnly(config, 0, lggr, nil, nil, originalFee, maxGasPrice) require.NoError(t, err) - assert.Equal(t, expectedGasLimit, gasLimit) assert.Equal(t, expectedFee, fee) }) } diff --git a/core/chains/evm/gas/gas_test.go b/core/chains/evm/gas/gas_test.go index 43a1506bc24..8f3d56b54e7 100644 --- a/core/chains/evm/gas/gas_test.go +++ b/core/chains/evm/gas/gas_test.go @@ -5,7 +5,6 @@ import ( "math/big" "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -95,12 +94,11 @@ func Test_BumpLegacyGasPriceOnly(t *testing.T) { cfg.BumpMinF = test.bumpMin cfg.PriceMaxF = test.priceMax cfg.LimitMultiplierF = test.limitMultiplierPercent - actual, limit, err := gas.BumpLegacyGasPriceOnly(cfg, logger.TestSugared(t), test.currentGasPrice, test.originalGasPrice, test.originalLimit, test.priceMax) + actual, err := gas.BumpLegacyGasPriceOnly(cfg, logger.TestSugared(t), test.currentGasPrice, test.originalGasPrice, test.priceMax) require.NoError(t, err) if actual.Cmp(test.expectedGasPrice) != 0 { t.Fatalf("Expected %s but got %s", test.expectedGasPrice.String(), actual.String()) } - assert.Equal(t, int(test.expectedLimit), int(limit)) }) } } @@ -115,7 +113,7 @@ func Test_BumpLegacyGasPriceOnly_HitsMaxError(t *testing.T) { cfg.PriceMaxF = priceMax originalGasPrice := toWei("3e10") // 30 GWei - _, _, err := gas.BumpLegacyGasPriceOnly(cfg, logger.TestSugared(t), nil, originalGasPrice, 42, priceMax) + _, err := gas.BumpLegacyGasPriceOnly(cfg, logger.TestSugared(t), nil, originalGasPrice, priceMax) require.Error(t, err) require.Contains(t, err.Error(), "bumped gas price of 45 gwei would exceed configured max gas price of 40 gwei (original price was 30 gwei)") } @@ -132,13 +130,13 @@ func Test_BumpLegacyGasPriceOnly_NoBumpError(t *testing.T) { cfg.PriceMaxF = priceMax originalGasPrice := toWei("3e10") // 30 GWei - _, _, err := gas.BumpLegacyGasPriceOnly(cfg, lggr, nil, originalGasPrice, 42, priceMax) + _, err := gas.BumpLegacyGasPriceOnly(cfg, lggr, nil, originalGasPrice, priceMax) require.Error(t, err) require.Contains(t, err.Error(), "bumped gas price of 30 gwei is equal to original gas price of 30 gwei. ACTION REQUIRED: This is a configuration error, you must increase either EVM.GasEstimator.BumpPercent or EVM.GasEstimator.BumpMin") // Even if it's exactly the maximum originalGasPrice = toWei("4e10") // 40 GWei - _, _, err = gas.BumpLegacyGasPriceOnly(cfg, lggr, nil, originalGasPrice, 42, priceMax) + _, err = gas.BumpLegacyGasPriceOnly(cfg, lggr, nil, originalGasPrice, priceMax) require.Error(t, err) require.Contains(t, err.Error(), "bumped gas price of 40 gwei is equal to original gas price of 40 gwei. ACTION REQUIRED: This is a configuration error, you must increase either EVM.GasEstimator.BumpPercent or EVM.GasEstimator.BumpMin") } @@ -298,7 +296,7 @@ func Test_BumpDynamicFeeOnly(t *testing.T) { cfg.LimitMultiplierF = test.limitMultiplierPercent bufferBlocks := uint16(4) - actual, limit, err := gas.BumpDynamicFeeOnly(cfg, bufferBlocks, logger.TestSugared(t), test.currentTipCap, test.currentBaseFee, test.originalFee, test.originalLimit, test.priceMax) + actual, err := gas.BumpDynamicFeeOnly(cfg, bufferBlocks, logger.TestSugared(t), test.currentTipCap, test.currentBaseFee, test.originalFee, test.priceMax) require.NoError(t, err) if actual.TipCap.Cmp(test.expectedFee.TipCap) != 0 { t.Fatalf("TipCap not equal, expected %s but got %s", test.expectedFee.TipCap.String(), actual.TipCap.String()) @@ -306,7 +304,6 @@ func Test_BumpDynamicFeeOnly(t *testing.T) { if actual.FeeCap.Cmp(test.expectedFee.FeeCap) != 0 { t.Fatalf("FeeCap not equal, expected %s but got %s", test.expectedFee.FeeCap.String(), actual.FeeCap.String()) } - assert.Equal(t, int(test.expectedLimit), int(limit)) }) } } @@ -324,14 +321,14 @@ func Test_BumpDynamicFeeOnly_HitsMaxError(t *testing.T) { t.Run("tip cap hits max", func(t *testing.T) { originalFee := gas.DynamicFee{TipCap: assets.GWei(30), FeeCap: assets.GWei(100)} - _, _, err := gas.BumpDynamicFeeOnly(cfg, 0, logger.TestSugared(t), nil, nil, originalFee, 42, priceMax) + _, err := gas.BumpDynamicFeeOnly(cfg, 0, logger.TestSugared(t), nil, nil, originalFee, priceMax) require.Error(t, err) require.Contains(t, err.Error(), "bumped tip cap of 45 gwei would exceed configured max gas price of 40 gwei (original fee: tip cap 30 gwei, fee cap 100 gwei)") }) t.Run("fee cap hits max", func(t *testing.T) { originalFee := gas.DynamicFee{TipCap: assets.GWei(10), FeeCap: assets.GWei(100)} - _, _, err := gas.BumpDynamicFeeOnly(cfg, 0, logger.TestSugared(t), nil, nil, originalFee, 42, priceMax) + _, err := gas.BumpDynamicFeeOnly(cfg, 0, logger.TestSugared(t), nil, nil, originalFee, priceMax) require.Error(t, err) require.Contains(t, err.Error(), "bumped fee cap of 150 gwei would exceed configured max gas price of 40 gwei (original fee: tip cap 10 gwei, fee cap 100 gwei)") }) diff --git a/core/chains/evm/gas/helpers_test.go b/core/chains/evm/gas/helpers_test.go index 908674bbeeb..420c5060a90 100644 --- a/core/chains/evm/gas/helpers_test.go +++ b/core/chains/evm/gas/helpers_test.go @@ -147,6 +147,10 @@ type MockGasEstimatorConfig struct { ModeF string } +func NewMockGasConfig() *MockGasEstimatorConfig { + return &MockGasEstimatorConfig{} +} + func (m *MockGasEstimatorConfig) BumpPercent() uint16 { return m.BumpPercentF } diff --git a/core/chains/evm/gas/mocks/evm_estimator.go b/core/chains/evm/gas/mocks/evm_estimator.go index f9ea34b830d..a0b6fa62432 100644 --- a/core/chains/evm/gas/mocks/evm_estimator.go +++ b/core/chains/evm/gas/mocks/evm_estimator.go @@ -21,39 +21,32 @@ type EvmEstimator struct { mock.Mock } -// BumpDynamicFee provides a mock function with given fields: ctx, original, gasLimit, maxGasPriceWei, attempts -func (_m *EvmEstimator) BumpDynamicFee(ctx context.Context, original gas.DynamicFee, gasLimit uint64, maxGasPriceWei *assets.Wei, attempts []gas.EvmPriorAttempt) (gas.DynamicFee, uint64, error) { - ret := _m.Called(ctx, original, gasLimit, maxGasPriceWei, attempts) +// BumpDynamicFee provides a mock function with given fields: ctx, original, maxGasPriceWei, attempts +func (_m *EvmEstimator) BumpDynamicFee(ctx context.Context, original gas.DynamicFee, maxGasPriceWei *assets.Wei, attempts []gas.EvmPriorAttempt) (gas.DynamicFee, error) { + ret := _m.Called(ctx, original, maxGasPriceWei, attempts) if len(ret) == 0 { panic("no return value specified for BumpDynamicFee") } var r0 gas.DynamicFee - var r1 uint64 - var r2 error - if rf, ok := ret.Get(0).(func(context.Context, gas.DynamicFee, uint64, *assets.Wei, []gas.EvmPriorAttempt) (gas.DynamicFee, uint64, error)); ok { - return rf(ctx, original, gasLimit, maxGasPriceWei, attempts) + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, gas.DynamicFee, *assets.Wei, []gas.EvmPriorAttempt) (gas.DynamicFee, error)); ok { + return rf(ctx, original, maxGasPriceWei, attempts) } - if rf, ok := ret.Get(0).(func(context.Context, gas.DynamicFee, uint64, *assets.Wei, []gas.EvmPriorAttempt) gas.DynamicFee); ok { - r0 = rf(ctx, original, gasLimit, maxGasPriceWei, attempts) + if rf, ok := ret.Get(0).(func(context.Context, gas.DynamicFee, *assets.Wei, []gas.EvmPriorAttempt) gas.DynamicFee); ok { + r0 = rf(ctx, original, maxGasPriceWei, attempts) } else { r0 = ret.Get(0).(gas.DynamicFee) } - if rf, ok := ret.Get(1).(func(context.Context, gas.DynamicFee, uint64, *assets.Wei, []gas.EvmPriorAttempt) uint64); ok { - r1 = rf(ctx, original, gasLimit, maxGasPriceWei, attempts) - } else { - r1 = ret.Get(1).(uint64) - } - - if rf, ok := ret.Get(2).(func(context.Context, gas.DynamicFee, uint64, *assets.Wei, []gas.EvmPriorAttempt) error); ok { - r2 = rf(ctx, original, gasLimit, maxGasPriceWei, attempts) + if rf, ok := ret.Get(1).(func(context.Context, gas.DynamicFee, *assets.Wei, []gas.EvmPriorAttempt) error); ok { + r1 = rf(ctx, original, maxGasPriceWei, attempts) } else { - r2 = ret.Error(2) + r1 = ret.Error(1) } - return r0, r1, r2 + return r0, r1 } // BumpLegacyGas provides a mock function with given fields: ctx, originalGasPrice, gasLimit, maxGasPriceWei, attempts @@ -111,39 +104,32 @@ func (_m *EvmEstimator) Close() error { return r0 } -// GetDynamicFee provides a mock function with given fields: ctx, gasLimit, maxGasPriceWei -func (_m *EvmEstimator) GetDynamicFee(ctx context.Context, gasLimit uint64, maxGasPriceWei *assets.Wei) (gas.DynamicFee, uint64, error) { - ret := _m.Called(ctx, gasLimit, maxGasPriceWei) +// GetDynamicFee provides a mock function with given fields: ctx, maxGasPriceWei +func (_m *EvmEstimator) GetDynamicFee(ctx context.Context, maxGasPriceWei *assets.Wei) (gas.DynamicFee, error) { + ret := _m.Called(ctx, maxGasPriceWei) if len(ret) == 0 { panic("no return value specified for GetDynamicFee") } var r0 gas.DynamicFee - var r1 uint64 - var r2 error - if rf, ok := ret.Get(0).(func(context.Context, uint64, *assets.Wei) (gas.DynamicFee, uint64, error)); ok { - return rf(ctx, gasLimit, maxGasPriceWei) + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *assets.Wei) (gas.DynamicFee, error)); ok { + return rf(ctx, maxGasPriceWei) } - if rf, ok := ret.Get(0).(func(context.Context, uint64, *assets.Wei) gas.DynamicFee); ok { - r0 = rf(ctx, gasLimit, maxGasPriceWei) + if rf, ok := ret.Get(0).(func(context.Context, *assets.Wei) gas.DynamicFee); ok { + r0 = rf(ctx, maxGasPriceWei) } else { r0 = ret.Get(0).(gas.DynamicFee) } - if rf, ok := ret.Get(1).(func(context.Context, uint64, *assets.Wei) uint64); ok { - r1 = rf(ctx, gasLimit, maxGasPriceWei) - } else { - r1 = ret.Get(1).(uint64) - } - - if rf, ok := ret.Get(2).(func(context.Context, uint64, *assets.Wei) error); ok { - r2 = rf(ctx, gasLimit, maxGasPriceWei) + if rf, ok := ret.Get(1).(func(context.Context, *assets.Wei) error); ok { + r1 = rf(ctx, maxGasPriceWei) } else { - r2 = ret.Error(2) + r1 = ret.Error(1) } - return r0, r1, r2 + return r0, r1 } // GetLegacyGas provides a mock function with given fields: ctx, calldata, gasLimit, maxGasPriceWei, opts diff --git a/core/chains/evm/gas/models.go b/core/chains/evm/gas/models.go index ae041615f53..17ee6f6d405 100644 --- a/core/chains/evm/gas/models.go +++ b/core/chains/evm/gas/models.go @@ -95,7 +95,7 @@ func NewEstimator(lggr logger.Logger, ethClient evmclient.Client, cfg Config, ge return NewFixedPriceEstimator(geCfg, bh, lggr) } } - return NewWrappedEvmEstimator(lggr, newEstimator, df, l1Oracle) + return NewWrappedEvmEstimator(lggr, newEstimator, df, l1Oracle, geCfg) } // DynamicFee encompasses both FeeCap and TipCap for EIP1559 transactions @@ -131,13 +131,13 @@ type EvmEstimator interface { BumpLegacyGas(ctx context.Context, originalGasPrice *assets.Wei, gasLimit uint64, maxGasPriceWei *assets.Wei, attempts []EvmPriorAttempt) (bumpedGasPrice *assets.Wei, chainSpecificGasLimit uint64, err error) // GetDynamicFee Calculates initial gas fee for gas for EIP1559 transactions // maxGasPriceWei parameter is the highest possible gas fee cap that the function will return - GetDynamicFee(ctx context.Context, gasLimit uint64, maxGasPriceWei *assets.Wei) (fee DynamicFee, chainSpecificGasLimit uint64, err error) + GetDynamicFee(ctx context.Context, maxGasPriceWei *assets.Wei) (fee DynamicFee, err error) // BumpDynamicFee Increases gas price and/or limit for non-EIP1559 transactions // if the bumped gas fee or tip caps are greater than maxGasPriceWei, the method returns an error // attempts must: // - be sorted in order from highest price to lowest price // - all be of transaction type 0x2 - BumpDynamicFee(ctx context.Context, original DynamicFee, gasLimit uint64, maxGasPriceWei *assets.Wei, attempts []EvmPriorAttempt) (bumped DynamicFee, chainSpecificGasLimit uint64, err error) + BumpDynamicFee(ctx context.Context, original DynamicFee, maxGasPriceWei *assets.Wei, attempts []EvmPriorAttempt) (bumped DynamicFee, err error) } var _ feetypes.Fee = (*EvmFee)(nil) @@ -166,17 +166,19 @@ type WrappedEvmEstimator struct { EvmEstimator EIP1559Enabled bool l1Oracle rollups.L1Oracle + geCfg GasEstimatorConfig } var _ EvmFeeEstimator = (*WrappedEvmEstimator)(nil) -func NewWrappedEvmEstimator(lggr logger.Logger, newEstimator func(logger.Logger) EvmEstimator, eip1559Enabled bool, l1Oracle rollups.L1Oracle) EvmFeeEstimator { +func NewWrappedEvmEstimator(lggr logger.Logger, newEstimator func(logger.Logger) EvmEstimator, eip1559Enabled bool, l1Oracle rollups.L1Oracle, geCfg GasEstimatorConfig) EvmFeeEstimator { lggr = logger.Named(lggr, "WrappedEvmEstimator") return &WrappedEvmEstimator{ lggr: lggr, EvmEstimator: newEstimator(lggr), EIP1559Enabled: eip1559Enabled, l1Oracle: l1Oracle, + geCfg: geCfg, } } @@ -245,7 +247,11 @@ func (e *WrappedEvmEstimator) GetFee(ctx context.Context, calldata []byte, feeLi // get dynamic fee if e.EIP1559Enabled { var dynamicFee DynamicFee - dynamicFee, chainSpecificFeeLimit, err = e.EvmEstimator.GetDynamicFee(ctx, feeLimit, maxFeePrice) + dynamicFee, err = e.EvmEstimator.GetDynamicFee(ctx, maxFeePrice) + if err != nil { + return + } + chainSpecificFeeLimit, err = commonfee.ApplyMultiplier(feeLimit, e.geCfg.LimitMultiplier()) fee.DynamicFeeCap = dynamicFee.FeeCap fee.DynamicTipCap = dynamicFee.TipCap return @@ -253,6 +259,11 @@ func (e *WrappedEvmEstimator) GetFee(ctx context.Context, calldata []byte, feeLi // get legacy fee fee.Legacy, chainSpecificFeeLimit, err = e.EvmEstimator.GetLegacyGas(ctx, calldata, feeLimit, maxFeePrice, opts...) + if err != nil { + return + } + chainSpecificFeeLimit, err = commonfee.ApplyMultiplier(chainSpecificFeeLimit, e.geCfg.LimitMultiplier()) + return } @@ -285,11 +296,15 @@ func (e *WrappedEvmEstimator) BumpFee(ctx context.Context, originalFee EvmFee, f // bump dynamic original if originalFee.ValidDynamic() { var bumpedDynamic DynamicFee - bumpedDynamic, chainSpecificFeeLimit, err = e.EvmEstimator.BumpDynamicFee(ctx, + bumpedDynamic, err = e.EvmEstimator.BumpDynamicFee(ctx, DynamicFee{ TipCap: originalFee.DynamicTipCap, FeeCap: originalFee.DynamicFeeCap, - }, feeLimit, maxFeePrice, attempts) + }, maxFeePrice, attempts) + if err != nil { + return + } + chainSpecificFeeLimit, err = commonfee.ApplyMultiplier(feeLimit, e.geCfg.LimitMultiplier()) bumpedFee.DynamicFeeCap = bumpedDynamic.FeeCap bumpedFee.DynamicTipCap = bumpedDynamic.TipCap return @@ -297,6 +312,10 @@ func (e *WrappedEvmEstimator) BumpFee(ctx context.Context, originalFee EvmFee, f // bump legacy fee bumpedFee.Legacy, chainSpecificFeeLimit, err = e.EvmEstimator.BumpLegacyGas(ctx, originalFee.Legacy, feeLimit, maxFeePrice, attempts) + if err != nil { + return + } + chainSpecificFeeLimit, err = commonfee.ApplyMultiplier(chainSpecificFeeLimit, e.geCfg.LimitMultiplier()) return } @@ -355,13 +374,12 @@ func HexToInt64(input interface{}) int64 { } } -// BumpLegacyGasPriceOnly will increase the price and apply multiplier to the gas limit -func BumpLegacyGasPriceOnly(cfg bumpConfig, lggr logger.SugaredLogger, currentGasPrice, originalGasPrice *assets.Wei, originalGasLimit uint64, maxGasPriceWei *assets.Wei) (gasPrice *assets.Wei, chainSpecificGasLimit uint64, err error) { +// BumpLegacyGasPriceOnly will increase the price +func BumpLegacyGasPriceOnly(cfg bumpConfig, lggr logger.SugaredLogger, currentGasPrice, originalGasPrice *assets.Wei, maxGasPriceWei *assets.Wei) (gasPrice *assets.Wei, err error) { gasPrice, err = bumpGasPrice(cfg, lggr, currentGasPrice, originalGasPrice, maxGasPriceWei) if err != nil { - return nil, 0, err + return nil, err } - chainSpecificGasLimit, err = commonfee.ApplyMultiplier(originalGasLimit, cfg.LimitMultiplier()) return } @@ -391,12 +409,11 @@ func bumpGasPrice(cfg bumpConfig, lggr logger.SugaredLogger, currentGasPrice, or } // BumpDynamicFeeOnly bumps the tip cap and max gas price if necessary -func BumpDynamicFeeOnly(config bumpConfig, feeCapBufferBlocks uint16, lggr logger.SugaredLogger, currentTipCap, currentBaseFee *assets.Wei, originalFee DynamicFee, originalGasLimit uint64, maxGasPriceWei *assets.Wei) (bumped DynamicFee, chainSpecificGasLimit uint64, err error) { +func BumpDynamicFeeOnly(config bumpConfig, feeCapBufferBlocks uint16, lggr logger.SugaredLogger, currentTipCap, currentBaseFee *assets.Wei, originalFee DynamicFee, maxGasPriceWei *assets.Wei) (bumped DynamicFee, err error) { bumped, err = bumpDynamicFee(config, feeCapBufferBlocks, lggr, currentTipCap, currentBaseFee, originalFee, maxGasPriceWei) if err != nil { - return bumped, 0, err + return bumped, err } - chainSpecificGasLimit, err = commonfee.ApplyMultiplier(originalGasLimit, config.LimitMultiplier()) return } diff --git a/core/chains/evm/gas/models_test.go b/core/chains/evm/gas/models_test.go index 76666143189..ec9542b4040 100644 --- a/core/chains/evm/gas/models_test.go +++ b/core/chains/evm/gas/models_test.go @@ -28,16 +28,20 @@ func TestWrappedEvmEstimator(t *testing.T) { FeeCap: assets.NewWeiI(20), TipCap: assets.NewWeiI(1), } + limitMultiplier := float32(1.5) + est := mocks.NewEvmEstimator(t) - est.On("GetDynamicFee", mock.Anything, mock.Anything, mock.Anything). - Return(dynamicFee, gasLimit, nil).Twice() + est.On("GetDynamicFee", mock.Anything, mock.Anything). + Return(dynamicFee, nil).Twice() est.On("GetLegacyGas", mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(legacyFee, gasLimit, nil).Twice() - est.On("BumpDynamicFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). - Return(dynamicFee, gasLimit, nil).Once() + est.On("BumpDynamicFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything). + Return(dynamicFee, nil).Once() est.On("BumpLegacyGas", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(legacyFee, gasLimit, nil).Once() getRootEst := func(logger.Logger) gas.EvmEstimator { return est } + geCfg := gas.NewMockGasConfig() + geCfg.LimitMultiplierF = limitMultiplier mockEstimatorName := "WrappedEvmEstimator" mockEvmEstimatorName := "WrappedEvmEstimator.MockEstimator" @@ -46,13 +50,13 @@ func TestWrappedEvmEstimator(t *testing.T) { t.Run("L1Oracle", func(t *testing.T) { lggr := logger.Test(t) // expect nil - estimator := gas.NewWrappedEvmEstimator(lggr, getRootEst, false, nil) + estimator := gas.NewWrappedEvmEstimator(lggr, getRootEst, false, nil, nil) l1Oracle := estimator.L1Oracle() assert.Nil(t, l1Oracle) // expect l1Oracle oracle := rollupMocks.NewL1Oracle(t) - estimator = gas.NewWrappedEvmEstimator(lggr, getRootEst, false, oracle) + estimator = gas.NewWrappedEvmEstimator(lggr, getRootEst, false, oracle, geCfg) l1Oracle = estimator.L1Oracle() assert.Equal(t, oracle, l1Oracle) }) @@ -62,20 +66,20 @@ func TestWrappedEvmEstimator(t *testing.T) { lggr := logger.Test(t) // expect legacy fee data dynamicFees := false - estimator := gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil) + estimator := gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil, geCfg) fee, max, err := estimator.GetFee(ctx, nil, 0, nil) require.NoError(t, err) - assert.Equal(t, gasLimit, max) + assert.Equal(t, uint64(float32(gasLimit)*limitMultiplier), max) assert.True(t, legacyFee.Equal(fee.Legacy)) assert.Nil(t, fee.DynamicTipCap) assert.Nil(t, fee.DynamicFeeCap) // expect dynamic fee data dynamicFees = true - estimator = gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil) - fee, max, err = estimator.GetFee(ctx, nil, 0, nil) + estimator = gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil, geCfg) + fee, max, err = estimator.GetFee(ctx, nil, gasLimit, nil) require.NoError(t, err) - assert.Equal(t, gasLimit, max) + assert.Equal(t, uint64(float32(gasLimit)*limitMultiplier), max) assert.True(t, dynamicFee.FeeCap.Equal(fee.DynamicFeeCap)) assert.True(t, dynamicFee.TipCap.Equal(fee.DynamicTipCap)) assert.Nil(t, fee.Legacy) @@ -85,12 +89,12 @@ func TestWrappedEvmEstimator(t *testing.T) { t.Run("BumpFee", func(t *testing.T) { lggr := logger.Test(t) dynamicFees := false - estimator := gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil) + estimator := gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil, geCfg) // expect legacy fee data fee, max, err := estimator.BumpFee(ctx, gas.EvmFee{Legacy: assets.NewWeiI(0)}, 0, nil, nil) require.NoError(t, err) - assert.Equal(t, gasLimit, max) + assert.Equal(t, uint64(float32(gasLimit)*limitMultiplier), max) assert.True(t, legacyFee.Equal(fee.Legacy)) assert.Nil(t, fee.DynamicTipCap) assert.Nil(t, fee.DynamicFeeCap) @@ -99,9 +103,9 @@ func TestWrappedEvmEstimator(t *testing.T) { fee, max, err = estimator.BumpFee(ctx, gas.EvmFee{ DynamicFeeCap: assets.NewWeiI(0), DynamicTipCap: assets.NewWeiI(0), - }, 0, nil, nil) + }, gasLimit, nil, nil) require.NoError(t, err) - assert.Equal(t, gasLimit, max) + assert.Equal(t, uint64(float32(gasLimit)*limitMultiplier), max) assert.True(t, dynamicFee.FeeCap.Equal(fee.DynamicFeeCap)) assert.True(t, dynamicFee.TipCap.Equal(fee.DynamicTipCap)) assert.Nil(t, fee.Legacy) @@ -123,18 +127,20 @@ func TestWrappedEvmEstimator(t *testing.T) { // expect legacy fee data dynamicFees := false - estimator := gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil) + estimator := gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil, geCfg) total, err := estimator.GetMaxCost(ctx, val, nil, gasLimit, nil) require.NoError(t, err) fee := new(big.Int).Mul(legacyFee.ToInt(), big.NewInt(int64(gasLimit))) + fee, _ = new(big.Float).Mul(new(big.Float).SetInt(fee), big.NewFloat(float64(limitMultiplier))).Int(nil) assert.Equal(t, new(big.Int).Add(val.ToInt(), fee), total) // expect dynamic fee data dynamicFees = true - estimator = gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil) + estimator = gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil, geCfg) total, err = estimator.GetMaxCost(ctx, val, nil, gasLimit, nil) require.NoError(t, err) fee = new(big.Int).Mul(dynamicFee.FeeCap.ToInt(), big.NewInt(int64(gasLimit))) + fee, _ = new(big.Float).Mul(new(big.Float).SetInt(fee), big.NewFloat(float64(limitMultiplier))).Int(nil) assert.Equal(t, new(big.Int).Add(val.ToInt(), fee), total) }) @@ -147,7 +153,7 @@ func TestWrappedEvmEstimator(t *testing.T) { estimator := gas.NewWrappedEvmEstimator(lggr, func(logger.Logger) gas.EvmEstimator { return evmEstimator - }, false, oracle) + }, false, oracle, geCfg) require.Equal(t, mockEstimatorName, estimator.Name()) require.Equal(t, mockEvmEstimatorName, evmEstimator.Name()) @@ -164,13 +170,13 @@ func TestWrappedEvmEstimator(t *testing.T) { oracle.On("Close").Return(nil).Once() getEst := func(logger.Logger) gas.EvmEstimator { return evmEstimator } - estimator := gas.NewWrappedEvmEstimator(lggr, getEst, false, nil) + estimator := gas.NewWrappedEvmEstimator(lggr, getEst, false, nil, geCfg) err := estimator.Start(ctx) require.NoError(t, err) err = estimator.Close() require.NoError(t, err) - estimator = gas.NewWrappedEvmEstimator(lggr, getEst, false, oracle) + estimator = gas.NewWrappedEvmEstimator(lggr, getEst, false, oracle, geCfg) err = estimator.Start(ctx) require.NoError(t, err) err = estimator.Close() @@ -186,11 +192,11 @@ func TestWrappedEvmEstimator(t *testing.T) { oracle.On("Ready").Return(nil).Once() getEst := func(logger.Logger) gas.EvmEstimator { return evmEstimator } - estimator := gas.NewWrappedEvmEstimator(lggr, getEst, false, nil) + estimator := gas.NewWrappedEvmEstimator(lggr, getEst, false, nil, geCfg) err := estimator.Ready() require.NoError(t, err) - estimator = gas.NewWrappedEvmEstimator(lggr, getEst, false, oracle) + estimator = gas.NewWrappedEvmEstimator(lggr, getEst, false, oracle, geCfg) err = estimator.Ready() require.NoError(t, err) }) @@ -209,13 +215,13 @@ func TestWrappedEvmEstimator(t *testing.T) { oracle.On("HealthReport").Return(map[string]error{oracleKey: oracleError}).Once() getEst := func(logger.Logger) gas.EvmEstimator { return evmEstimator } - estimator := gas.NewWrappedEvmEstimator(lggr, getEst, false, nil) + estimator := gas.NewWrappedEvmEstimator(lggr, getEst, false, nil, geCfg) report := estimator.HealthReport() require.True(t, pkgerrors.Is(report[evmEstimatorKey], evmEstimatorError)) require.Nil(t, report[oracleKey]) require.NotNil(t, report[mockEstimatorName]) - estimator = gas.NewWrappedEvmEstimator(lggr, getEst, false, oracle) + estimator = gas.NewWrappedEvmEstimator(lggr, getEst, false, oracle, geCfg) report = estimator.HealthReport() require.True(t, pkgerrors.Is(report[evmEstimatorKey], evmEstimatorError)) require.True(t, pkgerrors.Is(report[oracleKey], oracleError)) diff --git a/core/chains/evm/gas/rollups/l1_oracle.go b/core/chains/evm/gas/rollups/l1_oracle.go index e9cdc6b73b1..ae46071cf0d 100644 --- a/core/chains/evm/gas/rollups/l1_oracle.go +++ b/core/chains/evm/gas/rollups/l1_oracle.go @@ -12,6 +12,7 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rpc" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" @@ -28,6 +29,12 @@ import ( //go:generate mockery --quiet --name ethClient --output ./mocks/ --case=underscore --structname ETHClient type ethClient interface { CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) + BatchCallContext(ctx context.Context, b []rpc.BatchElem) error +} + +//go:generate mockery --quiet --name daPriceReader --output ./mocks/ --case=underscore --structname DAPriceReader +type daPriceReader interface { + GetDAGasPrice(ctx context.Context) (*big.Int, error) } type priceEntry struct { @@ -53,6 +60,8 @@ type l1Oracle struct { gasCostMethod string l1GasCostMethodAbi abi.ABI + priceReader daPriceReader + chInitialised chan struct{} chStop services.StopChan chDone chan struct{} @@ -109,9 +118,23 @@ func IsRollupWithL1Support(chainType config.ChainType) bool { } func NewL1GasOracle(lggr logger.Logger, ethClient ethClient, chainType config.ChainType) L1Oracle { + var priceReader daPriceReader + switch chainType { + case config.ChainOptimismBedrock: + priceReader = newOPPriceReader(lggr, ethClient, chainType, OPGasOracleAddress) + case config.ChainKroma: + priceReader = newOPPriceReader(lggr, ethClient, chainType, KromaGasOracleAddress) + default: + priceReader = nil + } + return newL1GasOracle(lggr, ethClient, chainType, priceReader) +} + +func newL1GasOracle(lggr logger.Logger, ethClient ethClient, chainType config.ChainType, priceReader daPriceReader) L1Oracle { var l1GasPriceAddress, gasPriceMethod, l1GasCostAddress, gasCostMethod string var l1GasPriceMethodAbi, l1GasCostMethodAbi abi.ABI var gasPriceErr, gasCostErr error + switch chainType { case config.ChainArbitrum: l1GasPriceAddress = ArbGasInfoAddress @@ -164,6 +187,8 @@ func NewL1GasOracle(lggr logger.Logger, ethClient ethClient, chainType config.Ch gasCostMethod: gasCostMethod, l1GasCostMethodAbi: l1GasCostMethodAbi, + priceReader: priceReader, + chInitialised: make(chan struct{}), chStop: make(chan struct{}), chDone: make(chan struct{}), @@ -222,13 +247,30 @@ func (o *l1Oracle) refreshWithError() (t *time.Timer, err error) { ctx, cancel := o.chStop.CtxCancel(evmclient.ContextWithDefaultTimeout()) defer cancel() + price, err := o.fetchL1GasPrice(ctx) + if err != nil { + return t, err + } + + o.l1GasPriceMu.Lock() + defer o.l1GasPriceMu.Unlock() + o.l1GasPrice = priceEntry{price: assets.NewWei(price), timestamp: time.Now()} + return +} + +func (o *l1Oracle) fetchL1GasPrice(ctx context.Context) (price *big.Int, err error) { + // if dedicated priceReader exists, use the reader + if o.priceReader != nil { + return o.priceReader.GetDAGasPrice(ctx) + } + var callData, b []byte precompile := common.HexToAddress(o.l1GasPriceAddress) callData, err = o.l1GasPriceMethodAbi.Pack(o.gasPriceMethod) if err != nil { errMsg := fmt.Sprintf("failed to pack calldata for %s L1 gas price method", o.chainType) o.logger.Errorf(errMsg) - return t, fmt.Errorf("%s: %w", errMsg, err) + return nil, fmt.Errorf("%s: %w", errMsg, err) } b, err = o.client.CallContract(ctx, ethereum.CallMsg{ To: &precompile, @@ -237,20 +279,16 @@ func (o *l1Oracle) refreshWithError() (t *time.Timer, err error) { if err != nil { errMsg := "gas oracle contract call failed" o.logger.Errorf(errMsg) - return t, fmt.Errorf("%s: %w", errMsg, err) + return nil, fmt.Errorf("%s: %w", errMsg, err) } if len(b) != 32 { // returns uint256; errMsg := fmt.Sprintf("return data length (%d) different than expected (%d)", len(b), 32) o.logger.Criticalf(errMsg) - return t, fmt.Errorf(errMsg) + return nil, fmt.Errorf(errMsg) } - price := new(big.Int).SetBytes(b) - - o.l1GasPriceMu.Lock() - defer o.l1GasPriceMu.Unlock() - o.l1GasPrice = priceEntry{price: assets.NewWei(price), timestamp: time.Now()} - return + price = new(big.Int).SetBytes(b) + return price, nil } func (o *l1Oracle) GasPrice(_ context.Context) (l1GasPrice *assets.Wei, err error) { diff --git a/core/chains/evm/gas/rollups/l1_oracle_abi.go b/core/chains/evm/gas/rollups/l1_oracle_abi.go index 77ef4d49f3c..dc18e43c98e 100644 --- a/core/chains/evm/gas/rollups/l1_oracle_abi.go +++ b/core/chains/evm/gas/rollups/l1_oracle_abi.go @@ -11,3 +11,7 @@ const GasEstimateL1ComponentAbiString = `[{"inputs":[{"internalType":"address"," // All ABIs found at https://optimistic.etherscan.io/address/0xc0d3c0d3c0d3c0d3c0d3c0d3c0d3c0d3c0d3000f#code const L1BaseFeeAbiString = `[{"inputs":[],"name":"l1BaseFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]` const GetL1FeeAbiString = `[{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"getL1Fee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]` + +// ABIs for OP Stack Ecotone GasPriceOracle methods needed to calculated encoded gas price +const OPIsEcotoneAbiString = `[{"inputs":[],"name":"isEcotone","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]` +const OPGetL1GasUsedAbiString = `[{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"getL1GasUsed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]` diff --git a/core/chains/evm/gas/rollups/l1_oracle_test.go b/core/chains/evm/gas/rollups/l1_oracle_test.go index 8415e4d7805..4f3b67e2ecf 100644 --- a/core/chains/evm/gas/rollups/l1_oracle_test.go +++ b/core/chains/evm/gas/rollups/l1_oracle_test.go @@ -72,21 +72,11 @@ func TestL1Oracle_GasPrice(t *testing.T) { t.Run("Calling GasPrice on started Kroma L1Oracle returns Kroma l1GasPrice", func(t *testing.T) { l1BaseFee := big.NewInt(100) - l1GasPriceMethodAbi, err := abi.JSON(strings.NewReader(L1BaseFeeAbiString)) - require.NoError(t, err) - ethClient := mocks.NewETHClient(t) - ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { - callMsg := args.Get(1).(ethereum.CallMsg) - blockNumber := args.Get(2).(*big.Int) - var payload []byte - payload, err = l1GasPriceMethodAbi.Pack("l1BaseFee") - require.NoError(t, err) - require.Equal(t, payload, callMsg.Data) - assert.Nil(t, blockNumber) - }).Return(common.BigToHash(l1BaseFee).Bytes(), nil) + priceReader := mocks.NewDAPriceReader(t) + priceReader.On("GetDAGasPrice", mock.Anything).Return(l1BaseFee, nil) - oracle := NewL1GasOracle(logger.Test(t), ethClient, config.ChainKroma) + oracle := newL1GasOracle(logger.Test(t), nil, config.ChainKroma, priceReader) servicetest.RunHealthy(t, oracle) gasPrice, err := oracle.GasPrice(testutils.Context(t)) @@ -97,21 +87,11 @@ func TestL1Oracle_GasPrice(t *testing.T) { t.Run("Calling GasPrice on started OPStack L1Oracle returns OPStack l1GasPrice", func(t *testing.T) { l1BaseFee := big.NewInt(100) - l1GasPriceMethodAbi, err := abi.JSON(strings.NewReader(L1BaseFeeAbiString)) - require.NoError(t, err) - ethClient := mocks.NewETHClient(t) - ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { - callMsg := args.Get(1).(ethereum.CallMsg) - blockNumber := args.Get(2).(*big.Int) - var payload []byte - payload, err = l1GasPriceMethodAbi.Pack("l1BaseFee") - require.NoError(t, err) - require.Equal(t, payload, callMsg.Data) - assert.Nil(t, blockNumber) - }).Return(common.BigToHash(l1BaseFee).Bytes(), nil) + priceReader := mocks.NewDAPriceReader(t) + priceReader.On("GetDAGasPrice", mock.Anything).Return(l1BaseFee, nil) - oracle := NewL1GasOracle(logger.Test(t), ethClient, config.ChainOptimismBedrock) + oracle := newL1GasOracle(logger.Test(t), nil, config.ChainOptimismBedrock, priceReader) servicetest.RunHealthy(t, oracle) gasPrice, err := oracle.GasPrice(testutils.Context(t)) diff --git a/core/chains/evm/gas/rollups/mocks/da_price_reader.go b/core/chains/evm/gas/rollups/mocks/da_price_reader.go new file mode 100644 index 00000000000..7758f53e436 --- /dev/null +++ b/core/chains/evm/gas/rollups/mocks/da_price_reader.go @@ -0,0 +1,59 @@ +// Code generated by mockery v2.38.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + big "math/big" + + mock "github.com/stretchr/testify/mock" +) + +// DAPriceReader is an autogenerated mock type for the daPriceReader type +type DAPriceReader struct { + mock.Mock +} + +// GetDAGasPrice provides a mock function with given fields: ctx +func (_m *DAPriceReader) GetDAGasPrice(ctx context.Context) (*big.Int, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetDAGasPrice") + } + + var r0 *big.Int + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) *big.Int); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*big.Int) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewDAPriceReader creates a new instance of DAPriceReader. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewDAPriceReader(t interface { + mock.TestingT + Cleanup(func()) +}) *DAPriceReader { + mock := &DAPriceReader{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/chains/evm/gas/rollups/mocks/eth_client.go b/core/chains/evm/gas/rollups/mocks/eth_client.go index bb0784f8515..e5a28f715ad 100644 --- a/core/chains/evm/gas/rollups/mocks/eth_client.go +++ b/core/chains/evm/gas/rollups/mocks/eth_client.go @@ -9,6 +9,8 @@ import ( ethereum "github.com/ethereum/go-ethereum" mock "github.com/stretchr/testify/mock" + + rpc "github.com/ethereum/go-ethereum/rpc" ) // ETHClient is an autogenerated mock type for the ethClient type @@ -16,6 +18,24 @@ type ETHClient struct { mock.Mock } +// BatchCallContext provides a mock function with given fields: ctx, b +func (_m *ETHClient) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error { + ret := _m.Called(ctx, b) + + if len(ret) == 0 { + panic("no return value specified for BatchCallContext") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, []rpc.BatchElem) error); ok { + r0 = rf(ctx, b) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // CallContract provides a mock function with given fields: ctx, msg, blockNumber func (_m *ETHClient) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { ret := _m.Called(ctx, msg, blockNumber) diff --git a/core/chains/evm/gas/rollups/models.go b/core/chains/evm/gas/rollups/models.go index 8158ba2b906..7aa3d4059dd 100644 --- a/core/chains/evm/gas/rollups/models.go +++ b/core/chains/evm/gas/rollups/models.go @@ -6,8 +6,8 @@ import ( "github.com/ethereum/go-ethereum/core/types" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" - "github.com/smartcontractkit/chainlink/v2/core/services" ) // L1Oracle provides interface for fetching L1-specific fee components if the chain is an L2. @@ -15,7 +15,7 @@ import ( // //go:generate mockery --quiet --name L1Oracle --output ./mocks/ --case=underscore type L1Oracle interface { - services.ServiceCtx + services.Service GasPrice(ctx context.Context) (*assets.Wei, error) GetGasCost(ctx context.Context, tx *types.Transaction, blockNum *big.Int) (*assets.Wei, error) diff --git a/core/chains/evm/gas/rollups/op_price_reader.go b/core/chains/evm/gas/rollups/op_price_reader.go new file mode 100644 index 00000000000..2d3d668ad8b --- /dev/null +++ b/core/chains/evm/gas/rollups/op_price_reader.go @@ -0,0 +1,228 @@ +package rollups + +import ( + "context" + "fmt" + "math/big" + "strings" + "time" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/rpc" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + + "github.com/smartcontractkit/chainlink/v2/common/config" +) + +const ( + // OPStackGasOracle_l1BaseFee fetches the l1 base fee set in the OP Stack GasPriceOracle contract + OPStackGasOracle_l1BaseFee = "l1BaseFee" + + // OPStackGasOracle_isEcotone fetches if the OP Stack GasPriceOracle contract has upgraded to Ecotone + OPStackGasOracle_isEcotone = "isEcotone" + + // OPStackGasOracle_getL1GasUsed fetches the l1 gas used for given tx bytes + OPStackGasOracle_getL1GasUsed = "getL1GasUsed" + + // OPStackGasOracle_getL1Fee fetches the l1 fee for given tx bytes + OPStackGasOracle_getL1Fee = "getL1Fee" + + // OPStackGasOracle_isEcotonePollingPeriod is the interval to poll if chain has upgraded to Ecotone + // Set to poll every 4 hours + OPStackGasOracle_isEcotonePollingPeriod = 14400 +) + +type opStackGasPriceReader struct { + client ethClient + logger logger.SugaredLogger + + oracleAddress common.Address + isEcotoneMethodAbi abi.ABI + + l1BaseFeeCalldata []byte + isEcotoneCalldata []byte + getL1GasUsedCalldata []byte + getL1FeeCalldata []byte + + isEcotone bool + isEcotoneCheckTs int64 +} + +func newOPPriceReader(lggr logger.Logger, ethClient ethClient, chainType config.ChainType, oracleAddress string) daPriceReader { + // encode calldata for each method; these calldata will remain the same for each call, we can encode them just once + l1BaseFeeMethodAbi, err := abi.JSON(strings.NewReader(L1BaseFeeAbiString)) + if err != nil { + panic(fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", OPStackGasOracle_l1BaseFee, chainType, err)) + } + l1BaseFeeCalldata, err := l1BaseFeeMethodAbi.Pack(OPStackGasOracle_l1BaseFee) + if err != nil { + panic(fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", OPStackGasOracle_l1BaseFee, chainType, err)) + } + + isEcotoneMethodAbi, err := abi.JSON(strings.NewReader(OPIsEcotoneAbiString)) + if err != nil { + panic(fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", OPStackGasOracle_isEcotone, chainType, err)) + } + isEcotoneCalldata, err := isEcotoneMethodAbi.Pack(OPStackGasOracle_isEcotone) + if err != nil { + panic(fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", OPStackGasOracle_isEcotone, chainType, err)) + } + + getL1GasUsedMethodAbi, err := abi.JSON(strings.NewReader(OPGetL1GasUsedAbiString)) + if err != nil { + panic(fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", OPStackGasOracle_getL1GasUsed, chainType, err)) + } + getL1GasUsedCalldata, err := getL1GasUsedMethodAbi.Pack(OPStackGasOracle_getL1GasUsed, []byte{0x1}) + if err != nil { + panic(fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", OPStackGasOracle_getL1GasUsed, chainType, err)) + } + + getL1FeeMethodAbi, err := abi.JSON(strings.NewReader(GetL1FeeAbiString)) + if err != nil { + panic(fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", OPStackGasOracle_getL1Fee, chainType, err)) + } + getL1FeeCalldata, err := getL1FeeMethodAbi.Pack(OPStackGasOracle_getL1Fee, []byte{0x1}) + if err != nil { + panic(fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", OPStackGasOracle_getL1Fee, chainType, err)) + } + + return &opStackGasPriceReader{ + client: ethClient, + logger: logger.Sugared(logger.Named(lggr, fmt.Sprintf("OPStackGasOracle(%s)", chainType))), + + oracleAddress: common.HexToAddress(oracleAddress), + isEcotoneMethodAbi: isEcotoneMethodAbi, + + l1BaseFeeCalldata: l1BaseFeeCalldata, + isEcotoneCalldata: isEcotoneCalldata, + getL1GasUsedCalldata: getL1GasUsedCalldata, + getL1FeeCalldata: getL1FeeCalldata, + + isEcotone: false, + isEcotoneCheckTs: 0, + } +} + +func (o *opStackGasPriceReader) GetDAGasPrice(ctx context.Context) (*big.Int, error) { + isEcotone, err := o.checkIsEcotone(ctx) + if err != nil { + return nil, err + } + + o.logger.Infof("Chain isEcotone result: %t", isEcotone) + + if isEcotone { + return o.getEcotoneGasPrice(ctx) + } + + return o.getV1GasPrice(ctx) +} + +func (o *opStackGasPriceReader) checkIsEcotone(ctx context.Context) (bool, error) { + // if chain is already Ecotone, NOOP + if o.isEcotone { + return true, nil + } + // if time since last check has not exceeded polling period, NOOP + if time.Now().Unix()-o.isEcotoneCheckTs < OPStackGasOracle_isEcotonePollingPeriod { + return false, nil + } + o.isEcotoneCheckTs = time.Now().Unix() + + // confirmed with OP team that isEcotone() is the canonical way to check if the chain has upgraded + b, err := o.client.CallContract(ctx, ethereum.CallMsg{ + To: &o.oracleAddress, + Data: o.isEcotoneCalldata, + }, nil) + + // if the chain has not upgraded to Ecotone, the isEcotone call will revert, this would be expected + if err != nil { + o.logger.Infof("isEcotone() call failed, this can happen if chain has not upgraded: %w", err) + return false, nil + } + + res, err := o.isEcotoneMethodAbi.Unpack(OPStackGasOracle_isEcotone, b) + if err != nil { + return false, fmt.Errorf("failed to unpack isEcotone() return data: %w", err) + } + o.isEcotone = res[0].(bool) + return o.isEcotone, nil +} + +func (o *opStackGasPriceReader) getV1GasPrice(ctx context.Context) (*big.Int, error) { + b, err := o.client.CallContract(ctx, ethereum.CallMsg{ + To: &o.oracleAddress, + Data: o.l1BaseFeeCalldata, + }, nil) + if err != nil { + return nil, fmt.Errorf("l1BaseFee() call failed: %w", err) + } + + if len(b) != 32 { + return nil, fmt.Errorf("l1BaseFee() return data length (%d) different than expected (%d)", len(b), 32) + } + return new(big.Int).SetBytes(b), nil +} + +func (o *opStackGasPriceReader) getEcotoneGasPrice(ctx context.Context) (*big.Int, error) { + rpcBatchCalls := []rpc.BatchElem{ + { + Method: "eth_call", + Args: []any{ + map[string]interface{}{ + "from": common.Address{}, + "to": o.oracleAddress, + "data": hexutil.Bytes(o.getL1GasUsedCalldata), + }, + "latest", + }, + Result: new(string), + }, + { + Method: "eth_call", + Args: []any{ + map[string]interface{}{ + "from": common.Address{}, + "to": o.oracleAddress, + "data": hexutil.Bytes(o.getL1FeeCalldata), + }, + "latest", + }, + Result: new(string), + }, + } + + err := o.client.BatchCallContext(ctx, rpcBatchCalls) + if err != nil { + return nil, fmt.Errorf("getEcotoneGasPrice batch call failed: %w", err) + } + if rpcBatchCalls[0].Error != nil { + return nil, fmt.Errorf("%s call failed in a batch: %w", OPStackGasOracle_getL1GasUsed, err) + } + if rpcBatchCalls[1].Error != nil { + return nil, fmt.Errorf("%s call failed in a batch: %w", OPStackGasOracle_getL1Fee, err) + } + + l1GasUsedResult := *(rpcBatchCalls[0].Result.(*string)) + l1FeeResult := *(rpcBatchCalls[1].Result.(*string)) + + l1GasUsedBytes, err := hexutil.Decode(l1GasUsedResult) + if err != nil { + return nil, fmt.Errorf("failed to decode %s rpc result: %w", OPStackGasOracle_getL1GasUsed, err) + } + l1FeeBytes, err := hexutil.Decode(l1FeeResult) + if err != nil { + return nil, fmt.Errorf("failed to decode %s rpc result: %w", OPStackGasOracle_getL1Fee, err) + } + + l1GasUsed := new(big.Int).SetBytes(l1GasUsedBytes) + l1Fee := new(big.Int).SetBytes(l1FeeBytes) + + // for the same tx byte, l1Fee / l1GasUsed will give the l1 gas price + // note this price is per l1 gas, not l1 data byte + return new(big.Int).Div(l1Fee, l1GasUsed), nil +} diff --git a/core/chains/evm/gas/rollups/op_price_reader_test.go b/core/chains/evm/gas/rollups/op_price_reader_test.go new file mode 100644 index 00000000000..dad12a16366 --- /dev/null +++ b/core/chains/evm/gas/rollups/op_price_reader_test.go @@ -0,0 +1,200 @@ +package rollups + +import ( + "fmt" + "math/big" + "strings" + "testing" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/rpc" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + + "github.com/smartcontractkit/chainlink/v2/common/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups/mocks" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" +) + +func TestDAPriceReader_ReadV1GasPrice(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + isEcotoneError bool + returnBadData bool + }{ + { + name: "calling isEcotone returns false, fetches l1BaseFee", + isEcotoneError: false, + }, + { + name: "calling isEcotone when chain has not made Ecotone upgrade, fetches l1BaseFee", + isEcotoneError: true, + }, + { + name: "calling isEcotone returns bad data, returns error", + isEcotoneError: false, + returnBadData: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + l1BaseFee := big.NewInt(100) + oracleAddress := common.HexToAddress("0x1234").String() + + l1BaseFeeMethodAbi, err := abi.JSON(strings.NewReader(L1BaseFeeAbiString)) + require.NoError(t, err) + l1BaseFeeCalldata, err := l1BaseFeeMethodAbi.Pack(OPStackGasOracle_l1BaseFee) + require.NoError(t, err) + + isEcotoneMethodAbi, err := abi.JSON(strings.NewReader(OPIsEcotoneAbiString)) + require.NoError(t, err) + isEcotoneCalldata, err := isEcotoneMethodAbi.Pack(OPStackGasOracle_isEcotone) + require.NoError(t, err) + + ethClient := mocks.NewETHClient(t) + call := ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { + callMsg := args.Get(1).(ethereum.CallMsg) + blockNumber := args.Get(2).(*big.Int) + require.Equal(t, isEcotoneCalldata, callMsg.Data) + require.Equal(t, oracleAddress, callMsg.To.String()) + assert.Nil(t, blockNumber) + }) + + if tc.returnBadData { + call.Return([]byte{0x2, 0x2}, nil).Once() + } else if tc.isEcotoneError { + call.Return(nil, fmt.Errorf("test error")).Once() + } else { + call.Return(isEcotoneMethodAbi.Methods["isEcotone"].Outputs.Pack(false)).Once() + } + + if !tc.returnBadData { + ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { + callMsg := args.Get(1).(ethereum.CallMsg) + blockNumber := args.Get(2).(*big.Int) + require.Equal(t, l1BaseFeeCalldata, callMsg.Data) + require.Equal(t, oracleAddress, callMsg.To.String()) + assert.Nil(t, blockNumber) + }).Return(common.BigToHash(l1BaseFee).Bytes(), nil).Once() + } + + oracle := newOPPriceReader(logger.Test(t), ethClient, config.ChainOptimismBedrock, oracleAddress) + gasPrice, err := oracle.GetDAGasPrice(testutils.Context(t)) + + if tc.returnBadData { + assert.Error(t, err) + } else { + require.NoError(t, err) + assert.Equal(t, l1BaseFee, gasPrice) + } + }) + } +} + +func setupIsEcotone(t *testing.T, oracleAddress string) *mocks.ETHClient { + isEcotoneMethodAbi, err := abi.JSON(strings.NewReader(OPIsEcotoneAbiString)) + require.NoError(t, err) + isEcotoneCalldata, err := isEcotoneMethodAbi.Pack(OPStackGasOracle_isEcotone) + require.NoError(t, err) + + ethClient := mocks.NewETHClient(t) + ethClient.On("CallContract", mock.Anything, mock.IsType(ethereum.CallMsg{}), mock.IsType(&big.Int{})).Run(func(args mock.Arguments) { + callMsg := args.Get(1).(ethereum.CallMsg) + blockNumber := args.Get(2).(*big.Int) + require.Equal(t, isEcotoneCalldata, callMsg.Data) + require.Equal(t, oracleAddress, callMsg.To.String()) + assert.Nil(t, blockNumber) + }).Return(isEcotoneMethodAbi.Methods["isEcotone"].Outputs.Pack(true)).Once() + + return ethClient +} + +func TestDAPriceReader_ReadEcotoneGasPrice(t *testing.T) { + l1BaseFee := big.NewInt(100) + oracleAddress := common.HexToAddress("0x1234").String() + + t.Parallel() + + t.Run("correctly fetches weighted gas price if chain has upgraded to Ecotone", func(t *testing.T) { + ethClient := setupIsEcotone(t, oracleAddress) + getL1GasUsedMethodAbi, err := abi.JSON(strings.NewReader(OPGetL1GasUsedAbiString)) + require.NoError(t, err) + getL1GasUsedCalldata, err := getL1GasUsedMethodAbi.Pack(OPStackGasOracle_getL1GasUsed, []byte{0x1}) + require.NoError(t, err) + + getL1FeeMethodAbi, err := abi.JSON(strings.NewReader(GetL1FeeAbiString)) + require.NoError(t, err) + getL1FeeCalldata, err := getL1FeeMethodAbi.Pack(OPStackGasOracle_getL1Fee, []byte{0x1}) + require.NoError(t, err) + + ethClient.On("BatchCallContext", mock.Anything, mock.IsType([]rpc.BatchElem{})).Run(func(args mock.Arguments) { + rpcElements := args.Get(1).([]rpc.BatchElem) + require.Equal(t, 2, len(rpcElements)) + + for _, rE := range rpcElements { + require.Equal(t, "eth_call", rE.Method) + require.Equal(t, oracleAddress, rE.Args[0].(map[string]interface{})["to"].(common.Address).String()) + require.Equal(t, "latest", rE.Args[1]) + } + + require.Equal(t, hexutil.Bytes(getL1GasUsedCalldata), rpcElements[0].Args[0].(map[string]interface{})["data"]) + require.Equal(t, hexutil.Bytes(getL1FeeCalldata), rpcElements[1].Args[0].(map[string]interface{})["data"]) + + res1 := common.BigToHash(big.NewInt(1)).Hex() + res2 := common.BigToHash(l1BaseFee).Hex() + rpcElements[0].Result = &res1 + rpcElements[1].Result = &res2 + }).Return(nil).Once() + + oracle := newOPPriceReader(logger.Test(t), ethClient, config.ChainOptimismBedrock, oracleAddress) + gasPrice, err := oracle.GetDAGasPrice(testutils.Context(t)) + require.NoError(t, err) + assert.Equal(t, l1BaseFee, gasPrice) + }) + + t.Run("fetching Ecotone price but rpc returns bad data", func(t *testing.T) { + ethClient := setupIsEcotone(t, oracleAddress) + ethClient.On("BatchCallContext", mock.Anything, mock.IsType([]rpc.BatchElem{})).Run(func(args mock.Arguments) { + rpcElements := args.Get(1).([]rpc.BatchElem) + var badData = "zzz" + rpcElements[0].Result = &badData + rpcElements[1].Result = &badData + }).Return(nil).Once() + + oracle := newOPPriceReader(logger.Test(t), ethClient, config.ChainOptimismBedrock, oracleAddress) + _, err := oracle.GetDAGasPrice(testutils.Context(t)) + assert.Error(t, err) + }) + + t.Run("fetching Ecotone price but rpc parent call errors", func(t *testing.T) { + ethClient := setupIsEcotone(t, oracleAddress) + ethClient.On("BatchCallContext", mock.Anything, mock.IsType([]rpc.BatchElem{})).Return(fmt.Errorf("revert")).Once() + + oracle := newOPPriceReader(logger.Test(t), ethClient, config.ChainOptimismBedrock, oracleAddress) + _, err := oracle.GetDAGasPrice(testutils.Context(t)) + assert.Error(t, err) + }) + + t.Run("fetching Ecotone price but one of the sub rpc call errors", func(t *testing.T) { + ethClient := setupIsEcotone(t, oracleAddress) + ethClient.On("BatchCallContext", mock.Anything, mock.IsType([]rpc.BatchElem{})).Run(func(args mock.Arguments) { + rpcElements := args.Get(1).([]rpc.BatchElem) + res := common.BigToHash(l1BaseFee).Hex() + rpcElements[0].Result = &res + rpcElements[1].Error = fmt.Errorf("revert") + }).Return(nil).Once() + + oracle := newOPPriceReader(logger.Test(t), ethClient, config.ChainOptimismBedrock, oracleAddress) + _, err := oracle.GetDAGasPrice(testutils.Context(t)) + assert.Error(t, err) + }) +} diff --git a/core/chains/evm/gas/suggested_price_estimator.go b/core/chains/evm/gas/suggested_price_estimator.go index 89e497edbd3..edc1b0f92fa 100644 --- a/core/chains/evm/gas/suggested_price_estimator.go +++ b/core/chains/evm/gas/suggested_price_estimator.go @@ -154,12 +154,12 @@ func (o *SuggestedPriceEstimator) forceRefresh(ctx context.Context) (err error) func (o *SuggestedPriceEstimator) OnNewLongestChain(context.Context, *evmtypes.Head) {} -func (*SuggestedPriceEstimator) GetDynamicFee(_ context.Context, _ uint64, _ *assets.Wei) (fee DynamicFee, chainSpecificGasLimit uint64, err error) { +func (*SuggestedPriceEstimator) GetDynamicFee(_ context.Context, _ *assets.Wei) (fee DynamicFee, err error) { err = pkgerrors.New("dynamic fees are not implemented for this estimator") return } -func (*SuggestedPriceEstimator) BumpDynamicFee(_ context.Context, _ DynamicFee, _ uint64, _ *assets.Wei, _ []EvmPriorAttempt) (bumped DynamicFee, chainSpecificGasLimit uint64, err error) { +func (*SuggestedPriceEstimator) BumpDynamicFee(_ context.Context, _ DynamicFee, _ *assets.Wei, _ []EvmPriorAttempt) (bumped DynamicFee, err error) { err = pkgerrors.New("dynamic fees are not implemented for this estimator") return } @@ -223,7 +223,6 @@ func (o *SuggestedPriceEstimator) BumpLegacyGas(ctx context.Context, originalFee // If the new suggested price is less than or equal to the max and the buffer puts the new price over the max, return the max price instead // The buffer is added on top of the suggested price during bumping as just a precaution. It is better to resubmit the transaction with the max gas price instead of erroring. newGasPrice = assets.NewWei(bigmath.Min(bufferedPrice, maxGasPriceWei.ToInt())) - // Return the original price if the refreshed price with the buffer is lower to ensure the bumped gas price is always equal or higher to the previous attempt if originalFee != nil && originalFee.Cmp(newGasPrice) > 0 { return originalFee, chainSpecificGasLimit, nil diff --git a/core/chains/evm/gas/suggested_price_estimator_test.go b/core/chains/evm/gas/suggested_price_estimator_test.go index ff5e004031b..0d52d6ab1b9 100644 --- a/core/chains/evm/gas/suggested_price_estimator_test.go +++ b/core/chains/evm/gas/suggested_price_estimator_test.go @@ -98,7 +98,7 @@ func TestSuggestedPriceEstimator(t *testing.T) { t.Run("calling GetDynamicFee always returns error", func(t *testing.T) { client := mocks.NewRPCClient(t) o := gas.NewSuggestedPriceEstimator(logger.Test(t), client, cfg) - _, _, err := o.GetDynamicFee(testutils.Context(t), gasLimit, maxGasPrice) + _, err := o.GetDynamicFee(testutils.Context(t), maxGasPrice) assert.EqualError(t, err, "dynamic fees are not implemented for this estimator") }) @@ -116,7 +116,7 @@ func TestSuggestedPriceEstimator(t *testing.T) { FeeCap: assets.NewWeiI(42), TipCap: assets.NewWeiI(5), } - _, _, err := o.BumpDynamicFee(testutils.Context(t), fee, gasLimit, maxGasPrice, nil) + _, err := o.BumpDynamicFee(testutils.Context(t), fee, maxGasPrice, nil) assert.EqualError(t, err, "dynamic fees are not implemented for this estimator") }) diff --git a/core/chains/evm/keystore/eth.go b/core/chains/evm/keystore/eth.go new file mode 100644 index 00000000000..1e2b0c439bc --- /dev/null +++ b/core/chains/evm/keystore/eth.go @@ -0,0 +1,19 @@ +package keystore + +import ( + "context" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +// Eth is the external interface for EthKeyStore +// +//go:generate mockery --quiet --name Eth --output mocks/ --case=underscore +type Eth interface { + CheckEnabled(ctx context.Context, address common.Address, chainID *big.Int) error + EnabledAddressesForChain(ctx context.Context, chainID *big.Int) (addresses []common.Address, err error) + SignTx(ctx context.Context, fromAddress common.Address, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) + SubscribeToKeyChanges(ctx context.Context) (ch chan struct{}, unsub func()) +} diff --git a/core/chains/evm/keystore/mocks/eth.go b/core/chains/evm/keystore/mocks/eth.go new file mode 100644 index 00000000000..48bd738fdbe --- /dev/null +++ b/core/chains/evm/keystore/mocks/eth.go @@ -0,0 +1,143 @@ +// Code generated by mockery v2.38.0. DO NOT EDIT. + +package mocks + +import ( + context "context" + big "math/big" + + common "github.com/ethereum/go-ethereum/common" + + mock "github.com/stretchr/testify/mock" + + types "github.com/ethereum/go-ethereum/core/types" +) + +// Eth is an autogenerated mock type for the Eth type +type Eth struct { + mock.Mock +} + +// CheckEnabled provides a mock function with given fields: ctx, address, chainID +func (_m *Eth) CheckEnabled(ctx context.Context, address common.Address, chainID *big.Int) error { + ret := _m.Called(ctx, address, chainID) + + if len(ret) == 0 { + panic("no return value specified for CheckEnabled") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) error); ok { + r0 = rf(ctx, address, chainID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// EnabledAddressesForChain provides a mock function with given fields: ctx, chainID +func (_m *Eth) EnabledAddressesForChain(ctx context.Context, chainID *big.Int) ([]common.Address, error) { + ret := _m.Called(ctx, chainID) + + if len(ret) == 0 { + panic("no return value specified for EnabledAddressesForChain") + } + + var r0 []common.Address + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) ([]common.Address, error)); ok { + return rf(ctx, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) []common.Address); ok { + r0 = rf(ctx, chainID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]common.Address) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *big.Int) error); ok { + r1 = rf(ctx, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// SignTx provides a mock function with given fields: ctx, fromAddress, tx, chainID +func (_m *Eth) SignTx(ctx context.Context, fromAddress common.Address, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { + ret := _m.Called(ctx, fromAddress, tx, chainID) + + if len(ret) == 0 { + panic("no return value specified for SignTx") + } + + var r0 *types.Transaction + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *types.Transaction, *big.Int) (*types.Transaction, error)); ok { + return rf(ctx, fromAddress, tx, chainID) + } + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *types.Transaction, *big.Int) *types.Transaction); ok { + r0 = rf(ctx, fromAddress, tx, chainID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Transaction) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, common.Address, *types.Transaction, *big.Int) error); ok { + r1 = rf(ctx, fromAddress, tx, chainID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// SubscribeToKeyChanges provides a mock function with given fields: ctx +func (_m *Eth) SubscribeToKeyChanges(ctx context.Context) (chan struct{}, func()) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for SubscribeToKeyChanges") + } + + var r0 chan struct{} + var r1 func() + if rf, ok := ret.Get(0).(func(context.Context) (chan struct{}, func())); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) chan struct{}); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(chan struct{}) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) func()); ok { + r1 = rf(ctx) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(func()) + } + } + + return r0, r1 +} + +// NewEth creates a new instance of Eth. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewEth(t interface { + mock.TestingT + Cleanup(func()) +}) *Eth { + mock := &Eth{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/chains/evm/log/broadcaster.go b/core/chains/evm/log/broadcaster.go index c4db2a4826c..a96474c0f78 100644 --- a/core/chains/evm/log/broadcaster.go +++ b/core/chains/evm/log/broadcaster.go @@ -2,12 +2,15 @@ package log import ( "context" + "database/sql" "fmt" "math/big" "sync" "sync/atomic" "time" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" pkgerrors "github.com/pkg/errors" @@ -22,8 +25,6 @@ import ( evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" evmutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" - "github.com/smartcontractkit/chainlink/v2/core/null" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) //go:generate mockery --quiet --name Broadcaster --output ./mocks/ --case=underscore --structname Broadcaster --filename broadcaster.go @@ -58,18 +59,18 @@ type ( IsConnected() bool Register(listener Listener, opts ListenerOpts) (unsubscribe func()) - WasAlreadyConsumed(lb Broadcast, qopts ...pg.QOpt) (bool, error) - MarkConsumed(lb Broadcast, qopts ...pg.QOpt) error + WasAlreadyConsumed(ctx context.Context, lb Broadcast) (bool, error) + MarkConsumed(ctx context.Context, lb Broadcast) error // MarkManyConsumed marks all the provided log broadcasts as consumed. - MarkManyConsumed(lbs []Broadcast, qopts ...pg.QOpt) error + MarkManyConsumed(ctx context.Context, lbs []Broadcast) error // NOTE: WasAlreadyConsumed, MarkConsumed and MarkManyConsumed MUST be used within a single goroutine in order for WasAlreadyConsumed to be accurate } BroadcasterInTest interface { Broadcaster - BackfillBlockNumber() null.Int64 + BackfillBlockNumber() sql.NullInt64 TrackedAddressesCount() uint32 // Pause pauses the eventLoop until Resume is called. Pause() @@ -98,7 +99,7 @@ type ( evmChainID big.Int // a block number to start backfill from - backfillBlockNumber null.Int64 + backfillBlockNumber sql.NullInt64 ethSubscriber *ethSubscriber registrations *registrations @@ -327,7 +328,7 @@ func (b *broadcaster) startResubscribeLoop() { if from < 0 { from = 0 } - b.backfillBlockNumber = null.NewInt64(from, true) + b.backfillBlockNumber = sql.NullInt64{Int64: from, Valid: true} } // Remove leftover unconsumed logs, maybe update pending broadcasts, and backfill sooner if necessary. @@ -337,7 +338,8 @@ func (b *broadcaster) startResubscribeLoop() { // No need to worry about r.highestNumConfirmations here because it's // already at minimum this deep due to the latest seen head check above if !b.backfillBlockNumber.Valid || *backfillStart < b.backfillBlockNumber.Int64 { - b.backfillBlockNumber.SetValid(*backfillStart) + b.backfillBlockNumber.Int64 = *backfillStart + b.backfillBlockNumber.Valid = true } } @@ -397,7 +399,7 @@ func (b *broadcaster) reinitialize() (backfillStart *int64, abort bool) { evmutils.RetryWithBackoff(ctx, func() bool { var err error - backfillStart, err = b.orm.Reinitialize(pg.WithParentCtx(ctx)) + backfillStart, err = b.orm.Reinitialize(ctx) if err != nil { b.logger.Errorw("Failed to reinitialize database", "err", err) return true @@ -490,14 +492,15 @@ func (b *broadcaster) onReplayRequest(replayReq replayRequest) { // NOTE: This ignores r.highestNumConfirmations, but it is // generally assumed that this will only be performed rarely and // manually by someone who knows what he is doing - b.backfillBlockNumber.SetValid(replayReq.fromBlock) + b.backfillBlockNumber.Int64 = replayReq.fromBlock + b.backfillBlockNumber.Valid = true if replayReq.forceBroadcast { - ctx, cancel := b.chStop.NewCtx() + ctx, cancel := b.chStop.CtxCancel(context.WithTimeout(context.Background(), time.Minute)) + ctx = sqlutil.WithoutDefaultTimeout(ctx) defer cancel() - // Use a longer timeout in the event that a very large amount of logs need to be marked // as consumed. - err := b.orm.MarkBroadcastsUnconsumed(replayReq.fromBlock, pg.WithParentCtx(ctx), pg.WithLongQueryTimeout()) + err := b.orm.MarkBroadcastsUnconsumed(ctx, replayReq.fromBlock) if err != nil { b.logger.Errorw("Error marking broadcasts as unconsumed", "err", err, "fromBlock", replayReq.fromBlock) @@ -515,7 +518,8 @@ func (b *broadcaster) invalidatePool() int64 { b.logPool = newLogPool(b.logger) // Note: even if we crash right now, PendingMinBlock is preserved in the database and we will backfill the same. blockNum := int64(min.(Uint64)) - b.backfillBlockNumber.SetValid(blockNum) + b.backfillBlockNumber.Int64 = blockNum + b.backfillBlockNumber.Valid = true return blockNum } return -1 @@ -538,7 +542,7 @@ func (b *broadcaster) onNewLog(log types.Log) { ctx, cancel := b.chStop.NewCtx() defer cancel() blockNumber := int64(log.BlockNumber) - if err := b.orm.SetPendingMinBlock(&blockNumber, pg.WithParentCtx(ctx)); err != nil { + if err := b.orm.SetPendingMinBlock(ctx, &blockNumber); err != nil { b.logger.Errorw("Failed to set pending broadcasts number", "blockNumber", log.BlockNumber, "err", err) } } @@ -583,13 +587,13 @@ func (b *broadcaster) onNewHeads() { if b.registrations.highestNumConfirmations == 0 { logs, lowest, highest := b.logPool.getAndDeleteAll() if len(logs) > 0 { - broadcasts, err := b.orm.FindBroadcasts(lowest, highest) + broadcasts, err := b.orm.FindBroadcasts(ctx, lowest, highest) if err != nil { b.logger.Errorf("Failed to query for log broadcasts, %v", err) return } - b.registrations.sendLogs(logs, *latestHead, broadcasts, b.orm) - if err := b.orm.SetPendingMinBlock(nil, pg.WithParentCtx(ctx)); err != nil { + b.registrations.sendLogs(ctx, logs, *latestHead, broadcasts, b.orm) + if err := b.orm.SetPendingMinBlock(ctx, nil); err != nil { b.logger.Errorw("Failed to set pending broadcasts number null", "err", err) } } @@ -597,16 +601,16 @@ func (b *broadcaster) onNewHeads() { logs, minBlockNum := b.logPool.getLogsToSend(latestBlockNum) if len(logs) > 0 { - broadcasts, err := b.orm.FindBroadcasts(minBlockNum, latestBlockNum) + broadcasts, err := b.orm.FindBroadcasts(ctx, minBlockNum, latestBlockNum) if err != nil { b.logger.Errorf("Failed to query for log broadcasts, %v", err) return } - b.registrations.sendLogs(logs, *latestHead, broadcasts, b.orm) + b.registrations.sendLogs(ctx, logs, *latestHead, broadcasts, b.orm) } newMin := b.logPool.deleteOlderLogs(keptDepth) - if err := b.orm.SetPendingMinBlock(newMin); err != nil { + if err := b.orm.SetPendingMinBlock(ctx, newMin); err != nil { b.logger.Errorw("Failed to set pending broadcasts number", "blockNumber", keptDepth, "err", err) } } @@ -685,17 +689,17 @@ func (b *broadcaster) maybeWarnOnLargeBlockNumberDifference(logBlockNumber int64 } // WasAlreadyConsumed reports whether the given consumer had already consumed the given log -func (b *broadcaster) WasAlreadyConsumed(lb Broadcast, qopts ...pg.QOpt) (bool, error) { - return b.orm.WasBroadcastConsumed(lb.RawLog().BlockHash, lb.RawLog().Index, lb.JobID(), qopts...) +func (b *broadcaster) WasAlreadyConsumed(ctx context.Context, lb Broadcast) (bool, error) { + return b.orm.WasBroadcastConsumed(ctx, lb.RawLog().BlockHash, lb.RawLog().Index, lb.JobID()) } // MarkConsumed marks the log as having been successfully consumed by the subscriber -func (b *broadcaster) MarkConsumed(lb Broadcast, qopts ...pg.QOpt) error { - return b.orm.MarkBroadcastConsumed(lb.RawLog().BlockHash, lb.RawLog().BlockNumber, lb.RawLog().Index, lb.JobID(), qopts...) +func (b *broadcaster) MarkConsumed(ctx context.Context, lb Broadcast) error { + return b.orm.MarkBroadcastConsumed(ctx, lb.RawLog().BlockHash, lb.RawLog().BlockNumber, lb.RawLog().Index, lb.JobID()) } // MarkManyConsumed marks the logs as having been successfully consumed by the subscriber -func (b *broadcaster) MarkManyConsumed(lbs []Broadcast, qopts ...pg.QOpt) (err error) { +func (b *broadcaster) MarkManyConsumed(ctx context.Context, lbs []Broadcast) (err error) { var ( blockHashes = make([]common.Hash, len(lbs)) blockNumbers = make([]uint64, len(lbs)) @@ -708,7 +712,7 @@ func (b *broadcaster) MarkManyConsumed(lbs []Broadcast, qopts ...pg.QOpt) (err e logIndexes[i] = lbs[i].RawLog().Index jobIDs[i] = lbs[i].JobID() } - return b.orm.MarkBroadcastsConsumed(blockHashes, blockNumbers, logIndexes, jobIDs, qopts...) + return b.orm.MarkBroadcastsConsumed(ctx, blockHashes, blockNumbers, logIndexes, jobIDs) } // test only @@ -717,7 +721,7 @@ func (b *broadcaster) TrackedAddressesCount() uint32 { } // test only -func (b *broadcaster) BackfillBlockNumber() null.Int64 { +func (b *broadcaster) BackfillBlockNumber() sql.NullInt64 { return b.backfillBlockNumber } @@ -766,19 +770,19 @@ func (n *NullBroadcaster) Register(listener Listener, opts ListenerOpts) (unsubs // ReplayFromBlock implements the Broadcaster interface. func (n *NullBroadcaster) ReplayFromBlock(number int64, forceBroadcast bool) {} -func (n *NullBroadcaster) BackfillBlockNumber() null.Int64 { - return null.NewInt64(0, false) +func (n *NullBroadcaster) BackfillBlockNumber() sql.NullInt64 { + return sql.NullInt64{Int64: 0, Valid: false} } func (n *NullBroadcaster) TrackedAddressesCount() uint32 { return 0 } -func (n *NullBroadcaster) WasAlreadyConsumed(lb Broadcast, qopts ...pg.QOpt) (bool, error) { +func (n *NullBroadcaster) WasAlreadyConsumed(ctx context.Context, lb Broadcast) (bool, error) { return false, pkgerrors.New(n.ErrMsg) } -func (n *NullBroadcaster) MarkConsumed(lb Broadcast, qopts ...pg.QOpt) error { +func (n *NullBroadcaster) MarkConsumed(ctx context.Context, lb Broadcast) error { return pkgerrors.New(n.ErrMsg) } -func (n *NullBroadcaster) MarkManyConsumed(lbs []Broadcast, qopts ...pg.QOpt) error { +func (n *NullBroadcaster) MarkManyConsumed(ctx context.Context, lbs []Broadcast) error { return pkgerrors.New(n.ErrMsg) } diff --git a/core/chains/evm/log/eth_subscriber.go b/core/chains/evm/log/eth_subscriber.go index ff20a6e74e8..e5ba202dbf2 100644 --- a/core/chains/evm/log/eth_subscriber.go +++ b/core/chains/evm/log/eth_subscriber.go @@ -2,6 +2,7 @@ package log import ( "context" + "database/sql" "fmt" "math/big" "time" @@ -15,7 +16,6 @@ import ( evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" - "github.com/smartcontractkit/chainlink/v2/core/null" ) type ( @@ -39,7 +39,7 @@ func newEthSubscriber(ethClient evmclient.Client, config Config, lggr logger.Log // backfillLogs - fetches earlier logs either from a relatively recent block (latest minus BlockBackfillDepth) or from the given fromBlockOverride // note that the whole operation has no timeout - it relies on BlockBackfillSkip (set outside) to optionally prevent very deep, long backfills // Max runtime is: (10 sec + 1 min * numBlocks/batchSize) * 3 retries -func (sub *ethSubscriber) backfillLogs(fromBlockOverride null.Int64, addresses []common.Address, topics []common.Hash) (chBackfilledLogs chan types.Log, abort bool) { +func (sub *ethSubscriber) backfillLogs(fromBlockOverride sql.NullInt64, addresses []common.Address, topics []common.Hash) (chBackfilledLogs chan types.Log, abort bool) { sub.logger.Infow("backfilling logs", "from", fromBlockOverride, "addresses", addresses) if len(addresses) == 0 { sub.logger.Debug("LogBroadcaster: No addresses to backfill for, returning") diff --git a/core/chains/evm/log/helpers_test.go b/core/chains/evm/log/helpers_test.go index 35db8f7f7bf..18f396fab9d 100644 --- a/core/chains/evm/log/helpers_test.go +++ b/core/chains/evm/log/helpers_test.go @@ -41,7 +41,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" ) @@ -93,7 +92,7 @@ func newBroadcasterHelperWithEthClient(t *testing.T, ethClient evmclient.Client, mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) db := pgtest.NewSqlxDB(t) - orm := log.NewORM(db, lggr, config.Database(), cltest.FixtureChainID) + orm := log.NewORM(db, cltest.FixtureChainID) lb := log.NewTestBroadcaster(orm, ethClient, config.EVM(), lggr, highestSeenHead, mailMon) kst := cltest.NewKeyStore(t, db, globalConfig.Database()) @@ -247,7 +246,6 @@ func (rec *received) logsOnBlocks() []logOnBlock { type simpleLogListener struct { name string lggr logger.SugaredLogger - cfg pg.QConfig received *received t *testing.T db *sqlx.DB @@ -272,7 +270,6 @@ func (helper *broadcasterHelper) newLogListenerWithJob(name string) *simpleLogLi return &simpleLogListener{ db: db, lggr: logger.Sugared(logger.Test(t)), - cfg: helper.config.Database(), name: name, received: &rec, t: t, @@ -326,16 +323,17 @@ func (listener *simpleLogListener) requireAllReceived(t *testing.T, expectedStat func (listener *simpleLogListener) handleLogBroadcast(lb log.Broadcast) bool { t := listener.t - consumed, err := listener.WasAlreadyConsumed(lb) + ctx := testutils.Context(t) + consumed, err := listener.WasAlreadyConsumed(ctx, lb) if !assert.NoError(t, err) { return false } if !consumed && !listener.skipMarkingConsumed.Load() { - err = listener.MarkConsumed(lb) + err = listener.MarkConsumed(ctx, lb) if assert.NoError(t, err) { - consumed2, err := listener.WasAlreadyConsumed(lb) + consumed2, err := listener.WasAlreadyConsumed(ctx, lb) if assert.NoError(t, err) { assert.True(t, consumed2) } @@ -344,12 +342,12 @@ func (listener *simpleLogListener) handleLogBroadcast(lb log.Broadcast) bool { return consumed } -func (listener *simpleLogListener) WasAlreadyConsumed(broadcast log.Broadcast) (bool, error) { - return log.NewORM(listener.db, listener.lggr, listener.cfg, cltest.FixtureChainID).WasBroadcastConsumed(broadcast.RawLog().BlockHash, broadcast.RawLog().Index, listener.jobID) +func (listener *simpleLogListener) WasAlreadyConsumed(ctx context.Context, broadcast log.Broadcast) (bool, error) { + return log.NewORM(listener.db, cltest.FixtureChainID).WasBroadcastConsumed(ctx, broadcast.RawLog().BlockHash, broadcast.RawLog().Index, listener.jobID) } -func (listener *simpleLogListener) MarkConsumed(broadcast log.Broadcast) error { - return log.NewORM(listener.db, listener.lggr, listener.cfg, cltest.FixtureChainID).MarkBroadcastConsumed(broadcast.RawLog().BlockHash, broadcast.RawLog().BlockNumber, broadcast.RawLog().Index, listener.jobID) +func (listener *simpleLogListener) MarkConsumed(ctx context.Context, broadcast log.Broadcast) error { + return log.NewORM(listener.db, cltest.FixtureChainID).MarkBroadcastConsumed(ctx, broadcast.RawLog().BlockHash, broadcast.RawLog().BlockNumber, broadcast.RawLog().Index, listener.jobID) } type mockListener struct { diff --git a/core/chains/evm/log/integration_test.go b/core/chains/evm/log/integration_test.go index 02a30c6d93f..4bdb43d9521 100644 --- a/core/chains/evm/log/integration_test.go +++ b/core/chains/evm/log/integration_test.go @@ -250,6 +250,7 @@ func TestBroadcaster_ReplaysLogs(t *testing.T) { func TestBroadcaster_BackfillUnconsumedAfterCrash(t *testing.T) { contract1 := newMockContract(t) contract2 := newMockContract(t) + ctx := testutils.Context(t) blocks := cltest.NewBlocks(t, 10) const ( @@ -268,8 +269,7 @@ func TestBroadcaster_BackfillUnconsumedAfterCrash(t *testing.T) { helper := newBroadcasterHelper(t, 0, 1, logs, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FinalityDepth = ptr[uint32](confs) }) - lggr := logger.Test(t) - orm := log.NewORM(helper.db, lggr, helper.config.Database(), cltest.FixtureChainID) + orm := log.NewORM(helper.db, cltest.FixtureChainID) listener := helper.newLogListenerWithJob("one") listener.SkipMarkingConsumed(true) @@ -282,7 +282,7 @@ func TestBroadcaster_BackfillUnconsumedAfterCrash(t *testing.T) { chRawLogs.TrySend(log2) }) // Pool min block in DB and neither listener received a broadcast - blockNum, err := orm.GetPendingMinBlock() + blockNum, err := orm.GetPendingMinBlock(ctx) require.NoError(t, err) require.NotNil(t, blockNum) require.Equal(t, int64(log1.BlockNumber), *blockNum) @@ -294,8 +294,7 @@ func TestBroadcaster_BackfillUnconsumedAfterCrash(t *testing.T) { helper := newBroadcasterHelper(t, 2, 1, logs, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FinalityDepth = ptr[uint32](confs) }) - lggr := logger.Test(t) - orm := log.NewORM(helper.db, lggr, helper.config.Database(), cltest.FixtureChainID) + orm := log.NewORM(helper.db, cltest.FixtureChainID) listener := helper.newLogListenerWithJob("one") listener.SkipMarkingConsumed(true) @@ -305,13 +304,13 @@ func TestBroadcaster_BackfillUnconsumedAfterCrash(t *testing.T) { helper.simulateHeads(t, listener, listener2, contract1, contract2, confs, blocks.Slice(2, 5), orm, &expBlock, nil) // Pool min block in DB and one listener received but didn't consume - blockNum, err := orm.GetPendingMinBlock() + blockNum, err := orm.GetPendingMinBlock(ctx) require.NoError(t, err) require.NotNil(t, blockNum) require.Equal(t, int64(log2.BlockNumber), *blockNum) require.NotEmpty(t, listener.getUniqueLogs()) require.Empty(t, listener2.getUniqueLogs()) - c, err := orm.WasBroadcastConsumed(log1.BlockHash, log1.Index, listener.JobID()) + c, err := orm.WasBroadcastConsumed(ctx, log1.BlockHash, log1.Index, listener.JobID()) require.NoError(t, err) require.False(t, c) }) @@ -319,8 +318,7 @@ func TestBroadcaster_BackfillUnconsumedAfterCrash(t *testing.T) { helper := newBroadcasterHelper(t, 4, 1, logs, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FinalityDepth = ptr[uint32](confs) }) - lggr := logger.Test(t) - orm := log.NewORM(helper.db, lggr, helper.config.Database(), cltest.FixtureChainID) + orm := log.NewORM(helper.db, cltest.FixtureChainID) listener := helper.newLogListenerWithJob("one") listener2 := helper.newLogListenerWithJob("two") @@ -328,15 +326,15 @@ func TestBroadcaster_BackfillUnconsumedAfterCrash(t *testing.T) { helper.simulateHeads(t, listener, listener2, contract1, contract2, confs, blocks.Slice(5, 8), orm, nil, nil) // Pool empty and one consumed but other didn't - blockNum, err := orm.GetPendingMinBlock() + blockNum, err := orm.GetPendingMinBlock(ctx) require.NoError(t, err) require.Nil(t, blockNum) require.NotEmpty(t, listener.getUniqueLogs()) require.NotEmpty(t, listener2.getUniqueLogs()) - c, err := orm.WasBroadcastConsumed(log1.BlockHash, log1.Index, listener.JobID()) + c, err := orm.WasBroadcastConsumed(ctx, log1.BlockHash, log1.Index, listener.JobID()) require.NoError(t, err) require.True(t, c) - c, err = orm.WasBroadcastConsumed(log2.BlockHash, log2.Index, listener2.JobID()) + c, err = orm.WasBroadcastConsumed(ctx, log2.BlockHash, log2.Index, listener2.JobID()) require.NoError(t, err) require.False(t, c) }) @@ -344,19 +342,18 @@ func TestBroadcaster_BackfillUnconsumedAfterCrash(t *testing.T) { helper := newBroadcasterHelper(t, 7, 1, logs[1:], func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FinalityDepth = ptr[uint32](confs) }) - lggr := logger.Test(t) - orm := log.NewORM(helper.db, lggr, helper.config.Database(), cltest.FixtureChainID) + orm := log.NewORM(helper.db, cltest.FixtureChainID) listener := helper.newLogListenerWithJob("one") listener2 := helper.newLogListenerWithJob("two") helper.simulateHeads(t, listener, listener2, contract1, contract2, confs, blocks.Slice(8, 9), orm, nil, nil) // Pool empty, one broadcasted and consumed - blockNum, err := orm.GetPendingMinBlock() + blockNum, err := orm.GetPendingMinBlock(ctx) require.NoError(t, err) require.Nil(t, blockNum) require.Empty(t, listener.getUniqueLogs()) require.NotEmpty(t, listener2.getUniqueLogs()) - c, err := orm.WasBroadcastConsumed(log2.BlockHash, log2.Index, listener2.JobID()) + c, err := orm.WasBroadcastConsumed(ctx, log2.BlockHash, log2.Index, listener2.JobID()) require.NoError(t, err) require.True(t, c) }) @@ -381,7 +378,7 @@ func (helper *broadcasterHelper) simulateHeads(t *testing.T, listener, listener2 <-headsDone require.Eventually(t, func() bool { - blockNum, err := orm.GetPendingMinBlock() + blockNum, err := orm.GetPendingMinBlock(testutils.Context(t)) if !assert.NoError(t, err) { return false } diff --git a/core/chains/evm/log/mocks/broadcaster.go b/core/chains/evm/log/mocks/broadcaster.go index 031bdaaa7d9..26fe1a35101 100644 --- a/core/chains/evm/log/mocks/broadcaster.go +++ b/core/chains/evm/log/mocks/broadcaster.go @@ -8,8 +8,6 @@ import ( log "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" mock "github.com/stretchr/testify/mock" - pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" - types "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ) @@ -104,24 +102,17 @@ func (_m *Broadcaster) IsConnected() bool { return r0 } -// MarkConsumed provides a mock function with given fields: lb, qopts -func (_m *Broadcaster) MarkConsumed(lb log.Broadcast, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, lb) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// MarkConsumed provides a mock function with given fields: ctx, lb +func (_m *Broadcaster) MarkConsumed(ctx context.Context, lb log.Broadcast) error { + ret := _m.Called(ctx, lb) if len(ret) == 0 { panic("no return value specified for MarkConsumed") } var r0 error - if rf, ok := ret.Get(0).(func(log.Broadcast, ...pg.QOpt) error); ok { - r0 = rf(lb, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, log.Broadcast) error); ok { + r0 = rf(ctx, lb) } else { r0 = ret.Error(0) } @@ -129,24 +120,17 @@ func (_m *Broadcaster) MarkConsumed(lb log.Broadcast, qopts ...pg.QOpt) error { return r0 } -// MarkManyConsumed provides a mock function with given fields: lbs, qopts -func (_m *Broadcaster) MarkManyConsumed(lbs []log.Broadcast, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, lbs) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// MarkManyConsumed provides a mock function with given fields: ctx, lbs +func (_m *Broadcaster) MarkManyConsumed(ctx context.Context, lbs []log.Broadcast) error { + ret := _m.Called(ctx, lbs) if len(ret) == 0 { panic("no return value specified for MarkManyConsumed") } var r0 error - if rf, ok := ret.Get(0).(func([]log.Broadcast, ...pg.QOpt) error); ok { - r0 = rf(lbs, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, []log.Broadcast) error); ok { + r0 = rf(ctx, lbs) } else { r0 = ret.Error(0) } @@ -238,16 +222,9 @@ func (_m *Broadcaster) Start(_a0 context.Context) error { return r0 } -// WasAlreadyConsumed provides a mock function with given fields: lb, qopts -func (_m *Broadcaster) WasAlreadyConsumed(lb log.Broadcast, qopts ...pg.QOpt) (bool, error) { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, lb) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// WasAlreadyConsumed provides a mock function with given fields: ctx, lb +func (_m *Broadcaster) WasAlreadyConsumed(ctx context.Context, lb log.Broadcast) (bool, error) { + ret := _m.Called(ctx, lb) if len(ret) == 0 { panic("no return value specified for WasAlreadyConsumed") @@ -255,17 +232,17 @@ func (_m *Broadcaster) WasAlreadyConsumed(lb log.Broadcast, qopts ...pg.QOpt) (b var r0 bool var r1 error - if rf, ok := ret.Get(0).(func(log.Broadcast, ...pg.QOpt) (bool, error)); ok { - return rf(lb, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, log.Broadcast) (bool, error)); ok { + return rf(ctx, lb) } - if rf, ok := ret.Get(0).(func(log.Broadcast, ...pg.QOpt) bool); ok { - r0 = rf(lb, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, log.Broadcast) bool); ok { + r0 = rf(ctx, lb) } else { r0 = ret.Get(0).(bool) } - if rf, ok := ret.Get(1).(func(log.Broadcast, ...pg.QOpt) error); ok { - r1 = rf(lb, qopts...) + if rf, ok := ret.Get(1).(func(context.Context, log.Broadcast) error); ok { + r1 = rf(ctx, lb) } else { r1 = ret.Error(1) } diff --git a/core/chains/evm/log/orm.go b/core/chains/evm/log/orm.go index 25012d5c8e0..71c9675d6fd 100644 --- a/core/chains/evm/log/orm.go +++ b/core/chains/evm/log/orm.go @@ -1,21 +1,20 @@ package log import ( + "context" "database/sql" "fmt" "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - pkgerrors "github.com/pkg/errors" - "github.com/jmoiron/sqlx" + pkgerrors "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-common/pkg/utils" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) // ORM is the interface for log broadcasts. @@ -25,41 +24,44 @@ import ( // entries are removed and the pending broadcasts number updated. type ORM interface { // FindBroadcasts returns broadcasts for a range of block numbers, both consumed and unconsumed. - FindBroadcasts(fromBlockNum int64, toBlockNum int64) ([]LogBroadcast, error) + FindBroadcasts(ctx context.Context, fromBlockNum int64, toBlockNum int64) ([]LogBroadcast, error) // CreateBroadcast inserts an unconsumed log broadcast for jobID. - CreateBroadcast(blockHash common.Hash, blockNumber uint64, logIndex uint, jobID int32, qopts ...pg.QOpt) error + CreateBroadcast(ctx context.Context, blockHash common.Hash, blockNumber uint64, logIndex uint, jobID int32) error // WasBroadcastConsumed returns true if jobID consumed the log broadcast. - WasBroadcastConsumed(blockHash common.Hash, logIndex uint, jobID int32, qopts ...pg.QOpt) (bool, error) + WasBroadcastConsumed(ctx context.Context, blockHash common.Hash, logIndex uint, jobID int32) (bool, error) // MarkBroadcastConsumed marks the log broadcast as consumed by jobID. - MarkBroadcastConsumed(blockHash common.Hash, blockNumber uint64, logIndex uint, jobID int32, qopts ...pg.QOpt) error + MarkBroadcastConsumed(ctx context.Context, blockHash common.Hash, blockNumber uint64, logIndex uint, jobID int32) error // MarkBroadcastsConsumed marks the log broadcasts as consumed by jobID. - MarkBroadcastsConsumed(blockHashes []common.Hash, blockNumbers []uint64, logIndexes []uint, jobIDs []int32, qopts ...pg.QOpt) error + MarkBroadcastsConsumed(ctx context.Context, blockHashes []common.Hash, blockNumbers []uint64, logIndexes []uint, jobIDs []int32) error // MarkBroadcastsUnconsumed marks all log broadcasts from all jobs on or after fromBlock as // unconsumed. - MarkBroadcastsUnconsumed(fromBlock int64, qopts ...pg.QOpt) error + MarkBroadcastsUnconsumed(ctx context.Context, fromBlock int64) error // SetPendingMinBlock sets the minimum block number for which there are pending broadcasts in the pool, or nil if empty. - SetPendingMinBlock(blockNum *int64, qopts ...pg.QOpt) error + SetPendingMinBlock(ctx context.Context, blockNum *int64) error // GetPendingMinBlock returns the minimum block number for which there were pending broadcasts in the pool, or nil if it was empty. - GetPendingMinBlock(qopts ...pg.QOpt) (blockNumber *int64, err error) + GetPendingMinBlock(ctx context.Context) (blockNumber *int64, err error) // Reinitialize cleans up the database by removing any unconsumed broadcasts, then updating (if necessary) and // returning the pending minimum block number. - Reinitialize(qopts ...pg.QOpt) (blockNumber *int64, err error) + Reinitialize(ctx context.Context) (blockNumber *int64, err error) } type orm struct { - q pg.Q + db sqlutil.DataSource evmChainID ubig.Big } var _ ORM = (*orm)(nil) -func NewORM(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig, evmChainID big.Int) *orm { - return &orm{pg.NewQ(db, lggr, cfg), *ubig.New(&evmChainID)} +func NewORM(db sqlutil.DataSource, evmChainID big.Int) *orm { + return &orm{ + db: db, + evmChainID: *ubig.New(&evmChainID), + } } -func (o *orm) WasBroadcastConsumed(blockHash common.Hash, logIndex uint, jobID int32, qopts ...pg.QOpt) (consumed bool, err error) { +func (o *orm) WasBroadcastConsumed(ctx context.Context, blockHash common.Hash, logIndex uint, jobID int32) (consumed bool, err error) { query := ` SELECT consumed FROM log_broadcasts WHERE block_hash = $1 @@ -73,15 +75,14 @@ func (o *orm) WasBroadcastConsumed(blockHash common.Hash, logIndex uint, jobID i jobID, o.evmChainID, } - q := o.q.WithOpts(qopts...) - err = q.Get(&consumed, query, args...) + err = o.db.GetContext(ctx, &consumed, query, args...) if pkgerrors.Is(err, sql.ErrNoRows) { return false, nil } return consumed, err } -func (o *orm) FindBroadcasts(fromBlockNum int64, toBlockNum int64) ([]LogBroadcast, error) { +func (o *orm) FindBroadcasts(ctx context.Context, fromBlockNum int64, toBlockNum int64) ([]LogBroadcast, error) { var broadcasts []LogBroadcast query := ` SELECT block_hash, consumed, log_index, job_id FROM log_broadcasts @@ -89,25 +90,23 @@ func (o *orm) FindBroadcasts(fromBlockNum int64, toBlockNum int64) ([]LogBroadca AND block_number <= $2 AND evm_chain_id = $3 ` - err := o.q.Select(&broadcasts, query, fromBlockNum, toBlockNum, o.evmChainID) + err := o.db.SelectContext(ctx, &broadcasts, query, fromBlockNum, toBlockNum, o.evmChainID) if err != nil { return nil, pkgerrors.Wrap(err, "failed to find log broadcasts") } return broadcasts, err } -func (o *orm) CreateBroadcast(blockHash common.Hash, blockNumber uint64, logIndex uint, jobID int32, qopts ...pg.QOpt) error { - q := o.q.WithOpts(qopts...) - err := q.ExecQ(` +func (o *orm) CreateBroadcast(ctx context.Context, blockHash common.Hash, blockNumber uint64, logIndex uint, jobID int32) error { + _, err := o.db.ExecContext(ctx, ` INSERT INTO log_broadcasts (block_hash, block_number, log_index, job_id, created_at, updated_at, consumed, evm_chain_id) VALUES ($1, $2, $3, $4, NOW(), NOW(), false, $5) `, blockHash, blockNumber, logIndex, jobID, o.evmChainID) return pkgerrors.Wrap(err, "failed to create log broadcast") } -func (o *orm) MarkBroadcastConsumed(blockHash common.Hash, blockNumber uint64, logIndex uint, jobID int32, qopts ...pg.QOpt) error { - q := o.q.WithOpts(qopts...) - err := q.ExecQ(` +func (o *orm) MarkBroadcastConsumed(ctx context.Context, blockHash common.Hash, blockNumber uint64, logIndex uint, jobID int32) error { + _, err := o.db.ExecContext(ctx, ` INSERT INTO log_broadcasts (block_hash, block_number, log_index, job_id, created_at, updated_at, consumed, evm_chain_id) VALUES ($1, $2, $3, $4, NOW(), NOW(), true, $5) ON CONFLICT (job_id, block_hash, log_index, evm_chain_id) DO UPDATE @@ -118,7 +117,7 @@ func (o *orm) MarkBroadcastConsumed(blockHash common.Hash, blockNumber uint64, l // MarkBroadcastsConsumed marks many broadcasts as consumed. // The lengths of all the provided slices must be equal, otherwise an error is returned. -func (o *orm) MarkBroadcastsConsumed(blockHashes []common.Hash, blockNumbers []uint64, logIndexes []uint, jobIDs []int32, qopts ...pg.QOpt) error { +func (o *orm) MarkBroadcastsConsumed(ctx context.Context, blockHashes []common.Hash, blockNumbers []uint64, logIndexes []uint, jobIDs []int32) error { if !utils.AllEqual(len(blockHashes), len(blockNumbers), len(logIndexes), len(jobIDs)) { return fmt.Errorf("all arg slice lengths must be equal, got: %d %d %d %d", len(blockHashes), len(blockNumbers), len(logIndexes), len(jobIDs), @@ -148,15 +147,13 @@ SET consumed = true, updated_at = NOW(); ChainID: o.evmChainID, } } - q := o.q.WithOpts(qopts...) - _, err := q.NamedExec(query, inputs) + _, err := o.db.(*sqlx.DB).NamedExecContext(ctx, query, inputs) return pkgerrors.Wrap(err, "mark broadcasts consumed") } // MarkBroadcastsUnconsumed implements the ORM interface. -func (o *orm) MarkBroadcastsUnconsumed(fromBlock int64, qopts ...pg.QOpt) error { - q := o.q.WithOpts(qopts...) - err := q.ExecQ(` +func (o *orm) MarkBroadcastsUnconsumed(ctx context.Context, fromBlock int64) error { + _, err := o.db.ExecContext(ctx, ` UPDATE log_broadcasts SET consumed = false WHERE block_number >= $1 @@ -165,14 +162,14 @@ func (o *orm) MarkBroadcastsUnconsumed(fromBlock int64, qopts ...pg.QOpt) error return pkgerrors.Wrap(err, "failed to mark broadcasts unconsumed") } -func (o *orm) Reinitialize(qopts ...pg.QOpt) (*int64, error) { +func (o *orm) Reinitialize(ctx context.Context) (*int64, error) { // Minimum block number from the set of unconsumed logs, which we'll remove later. - minUnconsumed, err := o.getUnconsumedMinBlock(qopts...) + minUnconsumed, err := o.getUnconsumedMinBlock(ctx) if err != nil { return nil, err } // Minimum block number from the set of pending logs in the pool. - minPending, err := o.GetPendingMinBlock(qopts...) + minPending, err := o.GetPendingMinBlock(ctx) if err != nil { return nil, err } @@ -184,30 +181,28 @@ func (o *orm) Reinitialize(qopts ...pg.QOpt) (*int64, error) { // Use the lesser minUnconsumed. minPending = minUnconsumed // Update the db so that we can safely delete the unconsumed entries. - if err := o.SetPendingMinBlock(minPending, qopts...); err != nil { + if err := o.SetPendingMinBlock(ctx, minPending); err != nil { return nil, err } } // Safe to delete old unconsumed entries since the pending minimum block covers this range. - if err := o.removeUnconsumed(qopts...); err != nil { + if err := o.removeUnconsumed(ctx); err != nil { return nil, err } return minPending, nil } -func (o *orm) SetPendingMinBlock(blockNumber *int64, qopts ...pg.QOpt) error { - q := o.q.WithOpts(qopts...) - err := q.ExecQ(` +func (o *orm) SetPendingMinBlock(ctx context.Context, blockNumber *int64) error { + _, err := o.db.ExecContext(ctx, ` INSERT INTO log_broadcasts_pending (evm_chain_id, block_number, created_at, updated_at) VALUES ($1, $2, NOW(), NOW()) ON CONFLICT (evm_chain_id) DO UPDATE SET block_number = $3, updated_at = NOW() `, o.evmChainID, blockNumber, blockNumber) return pkgerrors.Wrap(err, "failed to set pending broadcast block number") } -func (o *orm) GetPendingMinBlock(qopts ...pg.QOpt) (*int64, error) { - q := o.q.WithOpts(qopts...) +func (o *orm) GetPendingMinBlock(ctx context.Context) (*int64, error) { var blockNumber *int64 - err := q.Get(&blockNumber, ` + err := o.db.GetContext(ctx, &blockNumber, ` SELECT block_number FROM log_broadcasts_pending WHERE evm_chain_id = $1 `, o.evmChainID) if pkgerrors.Is(err, sql.ErrNoRows) { @@ -218,10 +213,9 @@ func (o *orm) GetPendingMinBlock(qopts ...pg.QOpt) (*int64, error) { return blockNumber, nil } -func (o *orm) getUnconsumedMinBlock(qopts ...pg.QOpt) (*int64, error) { - q := o.q.WithOpts(qopts...) +func (o *orm) getUnconsumedMinBlock(ctx context.Context) (*int64, error) { var blockNumber *int64 - err := q.Get(&blockNumber, ` + err := o.db.GetContext(ctx, &blockNumber, ` SELECT min(block_number) FROM log_broadcasts WHERE evm_chain_id = $1 AND consumed = false @@ -235,9 +229,8 @@ func (o *orm) getUnconsumedMinBlock(qopts ...pg.QOpt) (*int64, error) { return blockNumber, nil } -func (o *orm) removeUnconsumed(qopts ...pg.QOpt) error { - q := o.q.WithOpts(qopts...) - err := q.ExecQ(` +func (o *orm) removeUnconsumed(ctx context.Context) error { + _, err := o.db.ExecContext(ctx, ` DELETE FROM log_broadcasts WHERE evm_chain_id = $1 AND consumed = false diff --git a/core/chains/evm/log/orm_test.go b/core/chains/evm/log/orm_test.go index 758cfa1d690..ba9509d4518 100644 --- a/core/chains/evm/log/orm_test.go +++ b/core/chains/evm/log/orm_test.go @@ -10,21 +10,20 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" - "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) func TestORM_broadcasts(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - lggr := logger.Test(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ctx := testutils.Context(t) - orm := log.NewORM(db, lggr, cfg.Database(), cltest.FixtureChainID) + orm := log.NewORM(db, cltest.FixtureChainID) _, addr := cltest.MustInsertRandomKey(t, ethKeyStore) specV2 := cltest.MustInsertV2JobSpec(t, db, addr) @@ -45,12 +44,12 @@ func TestORM_broadcasts(t *testing.T) { require.Zero(t, rowsAffected) t.Run("WasBroadcastConsumed_DNE", func(t *testing.T) { - _, err := orm.WasBroadcastConsumed(rawLog.BlockHash, rawLog.Index, listener.JobID()) + _, err := orm.WasBroadcastConsumed(ctx, rawLog.BlockHash, rawLog.Index, listener.JobID()) require.NoError(t, err) }) require.True(t, t.Run("CreateBroadcast", func(t *testing.T) { - err := orm.CreateBroadcast(rawLog.BlockHash, rawLog.BlockNumber, rawLog.Index, listener.JobID()) + err := orm.CreateBroadcast(ctx, rawLog.BlockHash, rawLog.BlockNumber, rawLog.Index, listener.JobID()) require.NoError(t, err) var consumed null.Bool @@ -60,13 +59,13 @@ func TestORM_broadcasts(t *testing.T) { })) t.Run("WasBroadcastConsumed_false", func(t *testing.T) { - was, err := orm.WasBroadcastConsumed(rawLog.BlockHash, rawLog.Index, listener.JobID()) + was, err := orm.WasBroadcastConsumed(ctx, rawLog.BlockHash, rawLog.Index, listener.JobID()) require.NoError(t, err) require.False(t, was) }) require.True(t, t.Run("MarkBroadcastConsumed", func(t *testing.T) { - err := orm.MarkBroadcastConsumed(rawLog.BlockHash, rawLog.BlockNumber, rawLog.Index, listener.JobID()) + err := orm.MarkBroadcastConsumed(ctx, rawLog.BlockHash, rawLog.BlockNumber, rawLog.Index, listener.JobID()) require.NoError(t, err) var consumed null.Bool @@ -85,7 +84,7 @@ func TestORM_broadcasts(t *testing.T) { ) for i := 0; i < 3; i++ { l := cltest.RandomLog(t) - err = orm.CreateBroadcast(l.BlockHash, l.BlockNumber, l.Index, listener.JobID()) + err = orm.CreateBroadcast(ctx, l.BlockHash, l.BlockNumber, l.Index, listener.JobID()) require.NoError(t, err) blockHashes = append(blockHashes, l.BlockHash) blockNumbers = append(blockNumbers, l.BlockNumber) @@ -93,11 +92,11 @@ func TestORM_broadcasts(t *testing.T) { jobIDs = append(jobIDs, listener.JobID()) } - err = orm.MarkBroadcastsConsumed(blockHashes, blockNumbers, logIndexes, jobIDs, pg.WithLongQueryTimeout()) + err = orm.MarkBroadcastsConsumed(ctx, blockHashes, blockNumbers, logIndexes, jobIDs) require.NoError(t, err) for i := range blockHashes { - was, err := orm.WasBroadcastConsumed(blockHashes[i], logIndexes[i], jobIDs[i]) + was, err := orm.WasBroadcastConsumed(ctx, blockHashes[i], logIndexes[i], jobIDs[i]) require.NoError(t, err) require.True(t, was) } @@ -113,19 +112,19 @@ func TestORM_broadcasts(t *testing.T) { ) for i := 0; i < 5; i++ { l := cltest.RandomLog(t) - err = orm.CreateBroadcast(l.BlockHash, l.BlockNumber, l.Index, listener.JobID()) + err = orm.CreateBroadcast(ctx, l.BlockHash, l.BlockNumber, l.Index, listener.JobID()) require.NoError(t, err) blockHashes = append(blockHashes, l.BlockHash) blockNumbers = append(blockNumbers, l.BlockNumber) logIndexes = append(logIndexes, l.Index) jobIDs = append(jobIDs, listener.JobID()) } - err = orm.MarkBroadcastsConsumed(blockHashes[:len(blockHashes)-2], blockNumbers, logIndexes, jobIDs, pg.WithLongQueryTimeout()) + err = orm.MarkBroadcastsConsumed(ctx, blockHashes[:len(blockHashes)-2], blockNumbers, logIndexes, jobIDs) require.Error(t, err) }) t.Run("WasBroadcastConsumed_true", func(t *testing.T) { - was, err := orm.WasBroadcastConsumed(rawLog.BlockHash, rawLog.Index, listener.JobID()) + was, err := orm.WasBroadcastConsumed(ctx, rawLog.BlockHash, rawLog.Index, listener.JobID()) require.NoError(t, err) require.True(t, was) }) @@ -133,26 +132,25 @@ func TestORM_broadcasts(t *testing.T) { func TestORM_pending(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) - lggr := logger.Test(t) - orm := log.NewORM(db, lggr, cfg.Database(), cltest.FixtureChainID) + orm := log.NewORM(db, cltest.FixtureChainID) + ctx := testutils.Context(t) - num, err := orm.GetPendingMinBlock() + num, err := orm.GetPendingMinBlock(ctx) require.NoError(t, err) require.Nil(t, num) var num10 int64 = 10 - err = orm.SetPendingMinBlock(&num10) + err = orm.SetPendingMinBlock(ctx, &num10) require.NoError(t, err) - num, err = orm.GetPendingMinBlock() + num, err = orm.GetPendingMinBlock(ctx) require.NoError(t, err) require.Equal(t, num10, *num) - err = orm.SetPendingMinBlock(nil) + err = orm.SetPendingMinBlock(ctx, nil) require.NoError(t, err) - num, err = orm.GetPendingMinBlock() + num, err = orm.GetPendingMinBlock(ctx) require.NoError(t, err) require.Nil(t, num) } @@ -160,10 +158,10 @@ func TestORM_pending(t *testing.T) { func TestORM_MarkUnconsumed(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - lggr := logger.Test(t) + ctx := testutils.Context(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - orm := log.NewORM(db, lggr, cfg.Database(), cltest.FixtureChainID) + orm := log.NewORM(db, cltest.FixtureChainID) _, addr1 := cltest.MustInsertRandomKey(t, ethKeyStore) job1 := cltest.MustInsertV2JobSpec(t, db, addr1) @@ -174,36 +172,36 @@ func TestORM_MarkUnconsumed(t *testing.T) { logBefore := cltest.RandomLog(t) logBefore.BlockNumber = 34 require.NoError(t, - orm.CreateBroadcast(logBefore.BlockHash, logBefore.BlockNumber, logBefore.Index, job1.ID)) + orm.CreateBroadcast(ctx, logBefore.BlockHash, logBefore.BlockNumber, logBefore.Index, job1.ID)) require.NoError(t, - orm.MarkBroadcastConsumed(logBefore.BlockHash, logBefore.BlockNumber, logBefore.Index, job1.ID)) + orm.MarkBroadcastConsumed(ctx, logBefore.BlockHash, logBefore.BlockNumber, logBefore.Index, job1.ID)) logAt := cltest.RandomLog(t) logAt.BlockNumber = 38 require.NoError(t, - orm.CreateBroadcast(logAt.BlockHash, logAt.BlockNumber, logAt.Index, job1.ID)) + orm.CreateBroadcast(ctx, logAt.BlockHash, logAt.BlockNumber, logAt.Index, job1.ID)) require.NoError(t, - orm.MarkBroadcastConsumed(logAt.BlockHash, logAt.BlockNumber, logAt.Index, job1.ID)) + orm.MarkBroadcastConsumed(ctx, logAt.BlockHash, logAt.BlockNumber, logAt.Index, job1.ID)) logAfter := cltest.RandomLog(t) logAfter.BlockNumber = 40 require.NoError(t, - orm.CreateBroadcast(logAfter.BlockHash, logAfter.BlockNumber, logAfter.Index, job2.ID)) + orm.CreateBroadcast(ctx, logAfter.BlockHash, logAfter.BlockNumber, logAfter.Index, job2.ID)) require.NoError(t, - orm.MarkBroadcastConsumed(logAfter.BlockHash, logAfter.BlockNumber, logAfter.Index, job2.ID)) + orm.MarkBroadcastConsumed(ctx, logAfter.BlockHash, logAfter.BlockNumber, logAfter.Index, job2.ID)) // logAt and logAfter should now be marked unconsumed. logBefore is still consumed. - require.NoError(t, orm.MarkBroadcastsUnconsumed(38)) + require.NoError(t, orm.MarkBroadcastsUnconsumed(ctx, 38)) - consumed, err := orm.WasBroadcastConsumed(logBefore.BlockHash, logBefore.Index, job1.ID) + consumed, err := orm.WasBroadcastConsumed(ctx, logBefore.BlockHash, logBefore.Index, job1.ID) require.NoError(t, err) require.True(t, consumed) - consumed, err = orm.WasBroadcastConsumed(logAt.BlockHash, logAt.Index, job1.ID) + consumed, err = orm.WasBroadcastConsumed(ctx, logAt.BlockHash, logAt.Index, job1.ID) require.NoError(t, err) require.False(t, consumed) - consumed, err = orm.WasBroadcastConsumed(logAfter.BlockHash, logAfter.Index, job2.ID) + consumed, err = orm.WasBroadcastConsumed(ctx, logAfter.BlockHash, logAfter.Index, job2.ID) require.NoError(t, err) require.False(t, consumed) } @@ -258,35 +256,34 @@ func TestORM_Reinitialize(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) - lggr := logger.Test(t) - orm := log.NewORM(db, lggr, cfg.Database(), cltest.FixtureChainID) + orm := log.NewORM(db, cltest.FixtureChainID) + ctx := testutils.Context(t) jobID := cltest.MustInsertV2JobSpec(t, db, common.BigToAddress(big.NewInt(rand.Int63()))).ID for _, b := range tt.broadcasts { if b.Consumed { - err := orm.MarkBroadcastConsumed(b.BlockHash, b.BlockNumber.Uint64(), b.LogIndex, jobID) + err := orm.MarkBroadcastConsumed(ctx, b.BlockHash, b.BlockNumber.Uint64(), b.LogIndex, jobID) require.NoError(t, err) } else { - err := orm.CreateBroadcast(b.BlockHash, b.BlockNumber.Uint64(), b.LogIndex, jobID) + err := orm.CreateBroadcast(ctx, b.BlockHash, b.BlockNumber.Uint64(), b.LogIndex, jobID) require.NoError(t, err) } } if tt.pendingBlockNum != nil { - require.NoError(t, orm.SetPendingMinBlock(tt.pendingBlockNum)) + require.NoError(t, orm.SetPendingMinBlock(ctx, tt.pendingBlockNum)) } - pendingBlockNum, err := orm.Reinitialize() + pendingBlockNum, err := orm.Reinitialize(ctx) require.NoError(t, err) assert.Equal(t, tt.expPendingBlockNum, pendingBlockNum) - pendingBlockNum, err = orm.GetPendingMinBlock() + pendingBlockNum, err = orm.GetPendingMinBlock(ctx) if assert.NoError(t, err) { assert.Equal(t, tt.expPendingBlockNum, pendingBlockNum) } - bs, err := orm.FindBroadcasts(0, 20) + bs, err := orm.FindBroadcasts(ctx, 0, 20) if assert.NoError(t, err) { for _, b := range bs { assert.True(t, b.Consumed) diff --git a/core/chains/evm/log/registrations.go b/core/chains/evm/log/registrations.go index 1bb6c8c59c0..b56d3f4aaaa 100644 --- a/core/chains/evm/log/registrations.go +++ b/core/chains/evm/log/registrations.go @@ -1,6 +1,7 @@ package log import ( + "context" "fmt" "math/big" "sync" @@ -13,7 +14,6 @@ import ( evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) // 1. Each listener being registered can specify a custom NumConfirmations - number of block confirmations required for any log being sent to it. @@ -215,7 +215,7 @@ func (r *registrations) isAddressRegistered(address common.Address) bool { return false } -func (r *registrations) sendLogs(logsToSend []logsOnBlock, latestHead evmtypes.Head, broadcasts []LogBroadcast, bc broadcastCreator) { +func (r *registrations) sendLogs(ctx context.Context, logsToSend []logsOnBlock, latestHead evmtypes.Head, broadcasts []LogBroadcast, bc broadcastCreator) { broadcastsExisting := make(map[LogBroadcastAsKey]bool) for _, b := range broadcasts { broadcastsExisting[b.AsKey()] = b.Consumed @@ -239,7 +239,7 @@ func (r *registrations) sendLogs(logsToSend []logsOnBlock, latestHead evmtypes.H } for _, log := range logsPerBlock.Logs { - handlers.sendLog(log, latestHead, broadcastsExisting, bc, r.logger) + handlers.sendLog(ctx, log, latestHead, broadcastsExisting, bc, r.logger) } } } @@ -382,10 +382,10 @@ func (r *handler) isAddressRegistered(addr common.Address) bool { var _ broadcastCreator = &orm{} type broadcastCreator interface { - CreateBroadcast(blockHash common.Hash, blockNumber uint64, logIndex uint, jobID int32, pqOpts ...pg.QOpt) error + CreateBroadcast(ctx context.Context, blockHash common.Hash, blockNumber uint64, logIndex uint, jobID int32) error } -func (r *handler) sendLog(log types.Log, latestHead evmtypes.Head, +func (r *handler) sendLog(ctx context.Context, log types.Log, latestHead evmtypes.Head, broadcasts map[LogBroadcastAsKey]bool, bc broadcastCreator, logger logger.Logger) { @@ -425,7 +425,7 @@ func (r *handler) sendLog(log types.Log, latestHead evmtypes.Head, jobID := sub.listener.JobID() if !exists { // Create unconsumed broadcast - if err := bc.CreateBroadcast(log.BlockHash, log.BlockNumber, log.Index, jobID); err != nil { + if err := bc.CreateBroadcast(ctx, log.BlockHash, log.BlockNumber, log.Index, jobID); err != nil { logger.Errorw("Could not create broadcast log", "blockNumber", log.BlockNumber, "blockHash", log.BlockHash, "address", log.Address, "jobID", jobID, "err", err) continue diff --git a/core/chains/evm/logpoller/disabled.go b/core/chains/evm/logpoller/disabled.go index 8287aed22a4..f3e64378384 100644 --- a/core/chains/evm/logpoller/disabled.go +++ b/core/chains/evm/logpoller/disabled.go @@ -21,6 +21,10 @@ func (disabled) Start(ctx context.Context) error { return ErrDisabled } func (disabled) Close() error { return ErrDisabled } +func (disabled) Healthy() error { + return ErrDisabled +} + func (disabled) Ready() error { return ErrDisabled } func (disabled) HealthReport() map[string]error { @@ -37,6 +41,8 @@ func (disabled) UnregisterFilter(ctx context.Context, name string) error { retur func (disabled) HasFilter(name string) bool { return false } +func (disabled) GetFilters() map[string]Filter { return nil } + func (disabled) LatestBlock(ctx context.Context) (LogPollerBlock, error) { return LogPollerBlock{}, ErrDisabled } diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index f4a235b3c70..de2a182bbce 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -5,11 +5,13 @@ import ( "context" "database/sql" "encoding/binary" + "errors" "fmt" "math/big" "sort" "strings" "sync" + "sync/atomic" "time" "github.com/ethereum/go-ethereum" @@ -33,11 +35,13 @@ import ( //go:generate mockery --quiet --name LogPoller --output ./mocks/ --case=underscore --structname LogPoller --filename log_poller.go type LogPoller interface { services.Service + Healthy() error Replay(ctx context.Context, fromBlock int64) error ReplayAsync(fromBlock int64) RegisterFilter(ctx context.Context, filter Filter) error UnregisterFilter(ctx context.Context, name string) error HasFilter(name string) bool + GetFilters() map[string]Filter LatestBlock(ctx context.Context) (LogPollerBlock, error) GetBlocksRange(ctx context.Context, numbers []uint64) ([]LogPollerBlock, error) @@ -91,6 +95,7 @@ var ( ErrReplayRequestAborted = pkgerrors.New("aborted, replay request cancelled") ErrReplayInProgress = pkgerrors.New("replay request cancelled, but replay is already in progress") ErrLogPollerShutdown = pkgerrors.New("replay aborted due to log poller shutdown") + ErrFinalityViolated = pkgerrors.New("finality violated") ) type logPoller struct { @@ -119,6 +124,12 @@ type logPoller struct { ctx context.Context cancel context.CancelFunc wg sync.WaitGroup + // This flag is raised whenever the log poller detects that the chain's finality has been violated. + // It can happen when reorg is deeper than the latest finalized block that LogPoller saw in a previous PollAndSave tick. + // Usually the only way to recover is to manually remove the offending logs and block from the database. + // LogPoller keeps running in infinite loop, so whenever the invalid state is removed from the database it should + // recover automatically without needing to restart the LogPoller. + finalityViolated *atomic.Bool } type Opts struct { @@ -162,6 +173,7 @@ func NewLogPoller(orm ORM, ec Client, lggr logger.Logger, opts Opts) *logPoller logPrunePageSize: opts.LogPrunePageSize, filters: make(map[string]Filter), filterDirty: true, // Always build Filter on first call to cache an empty filter if nothing registered yet. + finalityViolated: new(atomic.Bool), } } @@ -305,6 +317,35 @@ func (lp *logPoller) HasFilter(name string) bool { return ok } +// GetFilters returns a deep copy of the filters map. +func (lp *logPoller) GetFilters() map[string]Filter { + lp.filterMu.RLock() + defer lp.filterMu.RUnlock() + + filters := make(map[string]Filter) + for k, v := range lp.filters { + deepCopyFilter := Filter{ + Name: v.Name, + Addresses: make(evmtypes.AddressArray, len(v.Addresses)), + EventSigs: make(evmtypes.HashArray, len(v.EventSigs)), + Topic2: make(evmtypes.HashArray, len(v.Topic2)), + Topic3: make(evmtypes.HashArray, len(v.Topic3)), + Topic4: make(evmtypes.HashArray, len(v.Topic4)), + Retention: v.Retention, + MaxLogsKept: v.MaxLogsKept, + LogsPerBlock: v.LogsPerBlock, + } + copy(deepCopyFilter.Addresses, v.Addresses) + copy(deepCopyFilter.EventSigs, v.EventSigs) + copy(deepCopyFilter.Topic2, v.Topic2) + copy(deepCopyFilter.Topic3, v.Topic3) + copy(deepCopyFilter.Topic4, v.Topic4) + + filters[k] = deepCopyFilter + } + return filters +} + func (lp *logPoller) Filter(from, to *big.Int, bh *common.Hash) ethereum.FilterQuery { lp.filterMu.Lock() defer lp.filterMu.Unlock() @@ -357,7 +398,13 @@ func (lp *logPoller) Filter(from, to *big.Int, bh *common.Hash) ethereum.FilterQ // If ctx is cancelled before the replay request has been initiated, ErrReplayRequestAborted is returned. If the replay // is already in progress, the replay will continue and ErrReplayInProgress will be returned. If the client needs a // guarantee that the replay is complete before proceeding, it should either avoid cancelling or retry until nil is returned -func (lp *logPoller) Replay(ctx context.Context, fromBlock int64) error { +func (lp *logPoller) Replay(ctx context.Context, fromBlock int64) (err error) { + defer func() { + if errors.Is(err, context.Canceled) { + err = ErrReplayRequestAborted + } + }() + lp.lggr.Debugf("Replaying from block %d", fromBlock) latest, err := lp.ec.HeadByNumber(ctx, nil) if err != nil { @@ -366,6 +413,27 @@ func (lp *logPoller) Replay(ctx context.Context, fromBlock int64) error { if fromBlock < 1 || fromBlock > latest.Number { return pkgerrors.Errorf("Invalid replay block number %v, acceptable range [1, %v]", fromBlock, latest.Number) } + + // Backfill all logs up to the latest saved finalized block outside the LogPoller's main loop. + // This is safe, because chain cannot be rewinded deeper than that, so there must not be any race conditions. + savedFinalizedBlockNumber, err := lp.savedFinalizedBlockNumber(ctx) + if err != nil { + return err + } + if fromBlock <= savedFinalizedBlockNumber { + err = lp.backfill(ctx, fromBlock, savedFinalizedBlockNumber) + if err != nil { + return err + } + } + + // Poll everything after latest finalized block in main loop to avoid concurrent writes during reorg + // We assume that number of logs between saved finalized block and current head is small enough to be processed in main loop + fromBlock = mathutil.Max(fromBlock, savedFinalizedBlockNumber+1) + // Don't continue if latest block number is the same as saved finalized block number + if fromBlock > latest.Number { + return nil + } // Block until replay notification accepted or cancelled. select { case lp.replayStart <- fromBlock: @@ -384,6 +452,20 @@ func (lp *logPoller) Replay(ctx context.Context, fromBlock int64) error { } } +// savedFinalizedBlockNumber returns the FinalizedBlockNumber saved with the last processed block in the db +// (latestFinalizedBlock at the time the last processed block was saved) +// If this is the first poll and no blocks are in the db, it returns 0 +func (lp *logPoller) savedFinalizedBlockNumber(ctx context.Context) (int64, error) { + latestProcessed, err := lp.LatestBlock(ctx) + if err == nil { + return latestProcessed.FinalizedBlockNumber, nil + } + if errors.Is(err, sql.ErrNoRows) { + return 0, nil + } + return 0, err +} + func (lp *logPoller) recvReplayComplete() { err := <-lp.replayComplete if err != nil { @@ -424,6 +506,13 @@ func (lp *logPoller) Close() error { }) } +func (lp *logPoller) Healthy() error { + if lp.finalityViolated.Load() { + return ErrFinalityViolated + } + return nil +} + func (lp *logPoller) Name() string { return lp.lggr.Name() } @@ -744,7 +833,13 @@ func (lp *logPoller) backfill(ctx context.Context, start, end int64) error { // 1. Find the LCA by following parent hashes. // 2. Delete all logs and blocks after the LCA // 3. Return the LCA+1, i.e. our new current (unprocessed) block. -func (lp *logPoller) getCurrentBlockMaybeHandleReorg(ctx context.Context, currentBlockNumber int64, currentBlock *evmtypes.Head) (*evmtypes.Head, error) { +func (lp *logPoller) getCurrentBlockMaybeHandleReorg(ctx context.Context, currentBlockNumber int64, currentBlock *evmtypes.Head) (head *evmtypes.Head, err error) { + defer func() { + if err == nil { + lp.finalityViolated.Store(false) + } + }() + var err1 error if currentBlock == nil { // If we don't have the current block already, lets get it. @@ -970,6 +1065,7 @@ func (lp *logPoller) findBlockAfterLCA(ctx context.Context, current *evmtypes.He lp.lggr.Criticalw("Reorg greater than finality depth detected", "finalityTag", lp.useFinalityTag, "current", current.Number, "latestFinalized", latestFinalizedBlockNumber) rerr := pkgerrors.New("Reorg greater than finality depth") lp.SvcErrBuffer.Append(rerr) + lp.finalityViolated.Store(true) return nil, rerr } diff --git a/core/chains/evm/logpoller/log_poller_internal_test.go b/core/chains/evm/logpoller/log_poller_internal_test.go index 7ad48b6a349..b6af0f7de5c 100644 --- a/core/chains/evm/logpoller/log_poller_internal_test.go +++ b/core/chains/evm/logpoller/log_poller_internal_test.go @@ -270,7 +270,7 @@ func TestLogPoller_Replay(t *testing.T) { ec := evmclimocks.NewClient(t) ec.On("HeadByNumber", mock.Anything, mock.Anything).Return(&head, nil) - ec.On("FilterLogs", mock.Anything, mock.Anything).Return([]types.Log{log1}, nil).Once() + ec.On("FilterLogs", mock.Anything, mock.Anything).Return([]types.Log{log1}, nil).Twice() ec.On("ConfiguredChainID").Return(chainID, nil) lpOpts := Opts{ PollPeriod: time.Hour, @@ -287,12 +287,13 @@ func TestLogPoller_Replay(t *testing.T) { latest, err := lp.LatestBlock(ctx) require.NoError(t, err) require.Equal(t, int64(4), latest.BlockNumber) + require.Equal(t, int64(1), latest.FinalizedBlockNumber) t.Run("abort before replayStart received", func(t *testing.T) { // Replay() should abort immediately if caller's context is cancelled before request signal is read - ctx, cancel := context.WithCancel(testutils.Context(t)) + cancelCtx, cancel := context.WithCancel(testutils.Context(t)) cancel() - err = lp.Replay(ctx, 3) + err = lp.Replay(cancelCtx, 3) assert.ErrorIs(t, err, ErrReplayRequestAborted) }) @@ -307,12 +308,11 @@ func TestLogPoller_Replay(t *testing.T) { // Replay() should return error code received from replayComplete t.Run("returns error code on replay complete", func(t *testing.T) { - ctx := testutils.Context(t) anyErr := pkgerrors.New("any error") done := make(chan struct{}) go func() { defer close(done) - recvStartReplay(ctx, 1) + recvStartReplay(ctx, 2) lp.replayComplete <- anyErr }() assert.ErrorIs(t, lp.Replay(ctx, 1), anyErr) @@ -321,14 +321,14 @@ func TestLogPoller_Replay(t *testing.T) { // Replay() should return ErrReplayInProgress if caller's context is cancelled after replay has begun t.Run("late abort returns ErrReplayInProgress", func(t *testing.T) { - ctx, cancel := context.WithTimeout(testutils.Context(t), time.Second) // Intentionally abort replay after 1s + cancelCtx, cancel := context.WithTimeout(testutils.Context(t), time.Second) // Intentionally abort replay after 1s done := make(chan struct{}) go func() { defer close(done) - recvStartReplay(ctx, 4) + recvStartReplay(cancelCtx, 4) cancel() }() - assert.ErrorIs(t, lp.Replay(ctx, 4), ErrReplayInProgress) + assert.ErrorIs(t, lp.Replay(cancelCtx, 4), ErrReplayInProgress) <-done lp.replayComplete <- nil lp.wg.Wait() @@ -338,8 +338,6 @@ func TestLogPoller_Replay(t *testing.T) { t.Run("client abort doesnt hang run loop", func(t *testing.T) { lp.backupPollerNextBlock = 0 - ctx := testutils.Context(t) - pass := make(chan struct{}) cancelled := make(chan struct{}) @@ -394,7 +392,6 @@ func TestLogPoller_Replay(t *testing.T) { done := make(chan struct{}) defer func() { <-done }() - ctx := testutils.Context(t) ec.On("FilterLogs", mock.Anything, mock.Anything).Once().Return([]types.Log{log1}, nil).Run(func(args mock.Arguments) { go func() { defer close(done) @@ -427,7 +424,7 @@ func TestLogPoller_Replay(t *testing.T) { lp.ReplayAsync(1) - recvStartReplay(testutils.Context(t), 1) + recvStartReplay(testutils.Context(t), 2) }) t.Run("ReplayAsync error", func(t *testing.T) { @@ -449,6 +446,25 @@ func TestLogPoller_Replay(t *testing.T) { require.Equal(t, 1, observedLogs.Len()) assert.Equal(t, observedLogs.All()[0].Message, anyErr.Error()) }) + + t.Run("run regular replay when there are not blocks in db", func(t *testing.T) { + err := lp.orm.DeleteLogsAndBlocksAfter(ctx, 0) + require.NoError(t, err) + + lp.ReplayAsync(1) + recvStartReplay(testutils.Context(t), 1) + }) + + t.Run("run only backfill when everything is finalized", func(t *testing.T) { + err := lp.orm.DeleteLogsAndBlocksAfter(ctx, 0) + require.NoError(t, err) + + err = lp.orm.InsertBlock(ctx, head.Hash, head.Number, head.Timestamp, head.Number) + require.NoError(t, err) + + err = lp.Replay(ctx, 1) + require.NoError(t, err) + }) } func (lp *logPoller) reset() { diff --git a/core/chains/evm/logpoller/log_poller_test.go b/core/chains/evm/logpoller/log_poller_test.go index 9ee7cfa85cd..2096ccf3cf4 100644 --- a/core/chains/evm/logpoller/log_poller_test.go +++ b/core/chains/evm/logpoller/log_poller_test.go @@ -1040,6 +1040,93 @@ func TestLogPoller_PollAndSaveLogs(t *testing.T) { } } +func TestLogPoller_ReorgDeeperThanFinality(t *testing.T) { + tests := []struct { + name string + finalityDepth int64 + finalityTag bool + }{ + { + name: "fixed finality depth without finality tag", + finalityDepth: 1, + finalityTag: false, + }, + { + name: "chain finality in use", + finalityDepth: 0, + finalityTag: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + th := SetupTH(t, logpoller.Opts{ + UseFinalityTag: tt.finalityTag, + FinalityDepth: tt.finalityDepth, + BackfillBatchSize: 3, + RpcBatchSize: 2, + KeepFinalizedBlocksDepth: 1000, + BackupPollerBlockDelay: 100, + }) + // Set up a log poller listening for log emitter logs. + err := th.LogPoller.RegisterFilter(testutils.Context(t), logpoller.Filter{ + Name: "Test Emitter", + EventSigs: []common.Hash{EmitterABI.Events["Log1"].ID}, + Addresses: []common.Address{th.EmitterAddress1}, + }) + require.NoError(t, err) + + // Test scenario + // Chain gen <- 1 <- 2 <- 3 (finalized) <- 4 (L1_1) + _, err = th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(1)}) + require.NoError(t, err) + th.Client.Commit() + th.Client.Commit() + th.Client.Commit() + markBlockAsFinalized(t, th, 3) + + // Polling should get us the L1 log. + firstPoll := th.PollAndSaveLogs(testutils.Context(t), 1) + assert.Equal(t, int64(5), firstPoll) + assert.NoError(t, th.LogPoller.Healthy()) + + // Fork deeper than finality depth + // Chain gen <- 1 <- 2 <- 3 (finalized) <- 4 (L1_1) + // \ 2' <- 3' <- 4' <- 5' <- 6' (finalized) <- 7' <- 8' <- 9' <- 10' (L1_2) + lca, err := th.Client.BlockByNumber(testutils.Context(t), big.NewInt(1)) + require.NoError(t, err) + require.NoError(t, th.Client.Fork(testutils.Context(t), lca.Hash())) + + // Create 2' + _, err = th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(2)}) + require.NoError(t, err) + th.Client.Commit() + + // Create 3-10 + for i := 3; i < 10; i++ { + _, err = th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err) + th.Client.Commit() + } + markBlockAsFinalized(t, th, 6) + + secondPoll := th.PollAndSaveLogs(testutils.Context(t), firstPoll) + assert.Equal(t, firstPoll, secondPoll) + assert.Equal(t, logpoller.ErrFinalityViolated, th.LogPoller.Healthy()) + + // Manually remove latest block from the log poller to bring it back to life + // LogPoller should be healthy again after first poll + // Chain gen <- 1 + // \ 2' <- 3' <- 4' <- 5' <- 6' (finalized) <- 7' <- 8' <- 9' <- 10' (L1_2) + require.NoError(t, th.ORM.DeleteLogsAndBlocksAfter(testutils.Context(t), 2)) + // Poll from latest + recoveryPoll := th.PollAndSaveLogs(testutils.Context(t), 1) + assert.Equal(t, int64(10), recoveryPoll) + assert.NoError(t, th.LogPoller.Healthy()) + }) + } +} + func TestLogPoller_PollAndSaveLogsDeepReorg(t *testing.T) { t.Parallel() @@ -1089,6 +1176,7 @@ func TestLogPoller_PollAndSaveLogsDeepReorg(t *testing.T) { // Polling should get us the L1 log. newStart := th.PollAndSaveLogs(testutils.Context(t), 1) + assert.NoError(t, th.LogPoller.Healthy()) assert.Equal(t, int64(3), newStart) // Check that L1_1 has a proper data payload lgs, err := th.ORM.SelectLogsByBlockRange(testutils.Context(t), 2, 2) @@ -1115,6 +1203,7 @@ func TestLogPoller_PollAndSaveLogsDeepReorg(t *testing.T) { newStart = th.PollAndSaveLogs(testutils.Context(t), newStart) assert.Equal(t, int64(10), newStart) + assert.NoError(t, th.LogPoller.Healthy()) // Expect L1_2 to be properly updated lgs, err = th.ORM.SelectLogsByBlockRange(testutils.Context(t), 2, 2) @@ -1194,6 +1283,20 @@ func TestLogPoller_LoadFilters(t *testing.T) { assert.True(t, th.LogPoller.HasFilter("third Filter")) assert.False(t, th.LogPoller.HasFilter("fourth Filter")) }) + + t.Run("GetFilters", func(t *testing.T) { + filters := th.LogPoller.GetFilters() + assert.Equal(t, 3, len(filters)) + assert.Equal(t, filters["first Filter"].Name, "first Filter") + assert.Equal(t, filters["first Filter"].EventSigs, filter1.EventSigs) + assert.Equal(t, filters["first Filter"].Addresses, filter1.Addresses) + assert.Equal(t, filters["second Filter"].Name, "second Filter") + assert.Equal(t, filters["second Filter"].EventSigs, filter2.EventSigs) + assert.Equal(t, filters["second Filter"].Addresses, filter2.Addresses) + assert.Equal(t, filters["third Filter"].Name, "third Filter") + assert.Equal(t, filters["third Filter"].EventSigs, filter3.EventSigs) + assert.Equal(t, filters["third Filter"].Addresses, filter3.Addresses) + }) } func TestLogPoller_GetBlocks_Range(t *testing.T) { @@ -1405,7 +1508,7 @@ func TestLogPoller_DBErrorHandling(t *testing.T) { time.Sleep(100 * time.Millisecond) require.NoError(t, lp.Start(ctx)) require.Eventually(t, func() bool { - return observedLogs.Len() >= 2 + return observedLogs.Len() >= 1 }, 2*time.Second, 20*time.Millisecond) err = lp.Close() require.NoError(t, err) @@ -1421,7 +1524,6 @@ func TestLogPoller_DBErrorHandling(t *testing.T) { } assert.Contains(t, logMsgs, "Failed loading filters in main logpoller loop, retrying later") - assert.Contains(t, logMsgs, "Error executing replay, could not get fromBlock") } type getLogErrData struct { diff --git a/core/chains/evm/logpoller/mocks/log_poller.go b/core/chains/evm/logpoller/mocks/log_poller.go index 2bf24881405..a8eabaff115 100644 --- a/core/chains/evm/logpoller/mocks/log_poller.go +++ b/core/chains/evm/logpoller/mocks/log_poller.go @@ -67,6 +67,26 @@ func (_m *LogPoller) GetBlocksRange(ctx context.Context, numbers []uint64) ([]lo return r0, r1 } +// GetFilters provides a mock function with given fields: +func (_m *LogPoller) GetFilters() map[string]logpoller.Filter { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetFilters") + } + + var r0 map[string]logpoller.Filter + if rf, ok := ret.Get(0).(func() map[string]logpoller.Filter); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[string]logpoller.Filter) + } + } + + return r0 +} + // HasFilter provides a mock function with given fields: name func (_m *LogPoller) HasFilter(name string) bool { ret := _m.Called(name) @@ -105,6 +125,24 @@ func (_m *LogPoller) HealthReport() map[string]error { return r0 } +// Healthy provides a mock function with given fields: +func (_m *LogPoller) Healthy() error { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Healthy") + } + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + // IndexedLogs provides a mock function with given fields: ctx, eventSig, address, topicIndex, topicValues, confs func (_m *LogPoller) IndexedLogs(ctx context.Context, eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs logpoller.Confirmations) ([]logpoller.Log, error) { ret := _m.Called(ctx, eventSig, address, topicIndex, topicValues, confs) diff --git a/core/chains/evm/monitor/balance.go b/core/chains/evm/monitor/balance.go index 16e2fd527bf..28bcdd9abdf 100644 --- a/core/chains/evm/monitor/balance.go +++ b/core/chains/evm/monitor/balance.go @@ -20,8 +20,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/keystore" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ) //go:generate mockery --quiet --name BalanceMonitor --output ../mocks/ --case=underscore diff --git a/core/chains/evm/txmgr/attempts_test.go b/core/chains/evm/txmgr/attempts_test.go index ab8a5831b20..d5c8f577ce1 100644 --- a/core/chains/evm/txmgr/attempts_test.go +++ b/core/chains/evm/txmgr/attempts_test.go @@ -18,13 +18,13 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" gasmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" + ksmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/keystore/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" ) func NewEvmAddress() gethcommon.Address { diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index 0b76f7fc6d1..d9e9364fdf0 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -35,10 +35,10 @@ import ( evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" gasmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/keystore" + ksmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/keystore/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" - ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -46,8 +46,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" ) // NewEthBroadcaster creates a new txmgr.EthBroadcaster for use in testing. @@ -59,17 +57,18 @@ func NewTestEthBroadcaster( config evmconfig.ChainScopedConfig, checkerFactory txmgr.TransmitCheckerFactory, nonceAutoSync bool, + nonceTracker txmgr.NonceTracker, ) *txmgr.Broadcaster { t.Helper() lggr := logger.Test(t) ge := config.EVM().GasEstimator() + estimator := gas.NewWrappedEvmEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator { return gas.NewFixedPriceEstimator(config.EVM().GasEstimator(), ge.BlockHistory(), lggr) - }, ge.EIP1559DynamicFees(), nil) + }, ge.EIP1559DynamicFees(), nil, ge) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, keyStore, estimator) - txNonceSyncer := txmgr.NewNonceSyncer(txStore, lggr, ethClient) - ethBroadcaster := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(config.EVM().GasEstimator()), config.EVM().Transactions(), config.Database().Listener(), keyStore, txBuilder, txNonceSyncer, lggr, checkerFactory, nonceAutoSync) + ethBroadcaster := txmgrcommon.NewBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(config.EVM().GasEstimator()), config.EVM().Transactions(), config.Database().Listener(), keyStore, txBuilder, nonceTracker, lggr, checkerFactory, nonceAutoSync) // Mark instance as test ethBroadcaster.XXXTestDisableUnstartedTxAutoProcessing() @@ -79,24 +78,24 @@ func NewTestEthBroadcaster( func TestEthBroadcaster_Lifecycle(t *testing.T) { cfg, db := heavyweight.FullTestDBV2(t, nil) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) evmcfg := evmtest.NewChainScopedConfig(t, cfg) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) estimator := gasmocks.NewEvmFeeEstimator(t) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) + txmClient := txmgr.NewEvmTxmClient(ethClient) ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) eb := txmgr.NewEvmBroadcaster( txStore, - txmgr.NewEvmTxmClient(ethClient), + txmClient, txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), evmcfg.Database().Listener(), ethKeyStore, txBuilder, - nil, logger.Test(t), &testCheckerFactory{}, false, @@ -137,7 +136,7 @@ func TestEthBroadcaster_Lifecycle(t *testing.T) { func TestEthBroadcaster_LoadNextSequenceMapFailure_StartupSuccess(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) evmcfg := evmtest.NewChainScopedConfig(t, cfg) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() @@ -145,16 +144,16 @@ func TestEthBroadcaster_LoadNextSequenceMapFailure_StartupSuccess(t *testing.T) estimator := gasmocks.NewEvmFeeEstimator(t) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), errors.New("Getting on-chain nonce failed")) + txmClient := txmgr.NewEvmTxmClient(ethClient) eb := txmgr.NewEvmBroadcaster( txStore, - txmgr.NewEvmTxmClient(ethClient), + txmClient, txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), evmcfg.Database().Listener(), ethKeyStore, txBuilder, - nil, logger.Test(t), &testCheckerFactory{}, false, @@ -169,7 +168,8 @@ func TestEthBroadcaster_LoadNextSequenceMapFailure_StartupSuccess(t *testing.T) func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ctx := testutils.Context(t) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) _, otherAddress := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -180,7 +180,9 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() ethClient.On("PendingNonceAt", mock.Anything, otherAddress).Return(uint64(0), nil).Once() - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, checkerFactory, false) + lggr := logger.Test(t) + nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient)) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, checkerFactory, false, nonceTracker) toAddress := gethCommon.HexToAddress("0x6C03DDA95a2AEd917EeCc6eddD4b9D16E6380411") timeNow := time.Now() @@ -232,8 +234,8 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { State: txmgrcommon.TxFatalError, } - require.NoError(t, txStore.InsertTx(&etxUnconfirmed)) - require.NoError(t, txStore.InsertTx(&etxWithError)) + require.NoError(t, txStore.InsertTx(ctx, &etxUnconfirmed)) + require.NoError(t, txStore.InsertTx(ctx, &etxWithError)) retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) assert.NoError(t, err) @@ -307,9 +309,9 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { }), fromAddress).Return(commonclient.Successful, nil).Once() // Insertion order deliberately reversed to test ordering - require.NoError(t, txStore.InsertTx(&expensiveEthTx)) - require.NoError(t, txStore.InsertTx(&laterEthTx)) - require.NoError(t, txStore.InsertTx(&earlierEthTx)) + require.NoError(t, txStore.InsertTx(ctx, &expensiveEthTx)) + require.NoError(t, txStore.InsertTx(ctx, &laterEthTx)) + require.NoError(t, txStore.InsertTx(ctx, &earlierEthTx)) // Do the thing retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) @@ -318,7 +320,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { // Check earlierEthTx and it's attempt // This was the earlier one sent so it has the lower nonce - earlierTransaction, err := txStore.FindTxWithAttempts(earlierEthTx.ID) + earlierTransaction, err := txStore.FindTxWithAttempts(ctx, earlierEthTx.ID) require.NoError(t, err) assert.False(t, earlierTransaction.Error.Valid) require.NotNil(t, earlierTransaction.FromAddress) @@ -349,7 +351,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { // Check laterEthTx and it's attempt // This was the later one sent so it has the higher nonce - laterTransaction, err := txStore.FindTxWithAttempts(laterEthTx.ID) + laterTransaction, err := txStore.FindTxWithAttempts(ctx, laterEthTx.ID) require.NoError(t, err) assert.False(t, earlierTransaction.Error.Valid) require.NotNil(t, laterTransaction.FromAddress) @@ -380,7 +382,8 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { }) evmcfg = evmtest.NewChainScopedConfig(t, cfg) ethClient.On("PendingNonceAt", mock.Anything, otherAddress).Return(uint64(1), nil).Once() - eb = NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, checkerFactory, false) + nonceTracker = txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient)) + eb = NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, checkerFactory, false, nonceTracker) t.Run("sends transactions with type 0x2 in EIP-1559 mode", func(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -397,7 +400,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { // Check eipTxWithAl and it's attempt // This was the earlier one sent so it has the lower nonce - etx, err := txStore.FindTxWithAttempts(etx.ID) + etx, err := txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.False(t, etx.Error.Valid) require.NotNil(t, etx.FromAddress) @@ -461,7 +464,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { } // Check ethtx was sent - ethTx, err := txStore.FindTxWithAttempts(ethTx.ID) + ethTx, err := txStore.FindTxWithAttempts(ctx, ethTx.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, ethTx.State) }) @@ -484,7 +487,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { assert.False(t, retryable) } - ethTx, err := txStore.FindTxWithAttempts(ethTx.ID) + ethTx, err := txStore.FindTxWithAttempts(ctx, ethTx.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, ethTx.State) }) @@ -508,7 +511,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { assert.False(t, retryable) } - ethTx, err := txStore.FindTxWithAttempts(ethTx.ID) + ethTx, err := txStore.FindTxWithAttempts(ctx, ethTx.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxFatalError, ethTx.State) assert.True(t, ethTx.Error.Valid) @@ -520,7 +523,8 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { func TestEthBroadcaster_TransmitChecking(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ctx := testutils.Context(t) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -528,7 +532,8 @@ func TestEthBroadcaster_TransmitChecking(t *testing.T) { evmcfg := evmtest.NewChainScopedConfig(t, cfg) checkerFactory := &testCheckerFactory{} ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, checkerFactory, false) + nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient)) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, checkerFactory, false, nonceTracker) checker := txmgr.TransmitCheckerSpec{ CheckerType: txmgr.TransmitCheckerTypeSimulate, @@ -551,7 +556,7 @@ func TestEthBroadcaster_TransmitChecking(t *testing.T) { } // Check ethtx was sent - ethTx, err := txStore.FindTxWithAttempts(ethTx.ID) + ethTx, err := txStore.FindTxWithAttempts(ctx, ethTx.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, ethTx.State) }) @@ -574,7 +579,7 @@ func TestEthBroadcaster_TransmitChecking(t *testing.T) { } // Check ethtx was sent - ethTx, err := txStore.FindTxWithAttempts(ethTx.ID) + ethTx, err := txStore.FindTxWithAttempts(ctx, ethTx.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, ethTx.State) }) @@ -591,7 +596,7 @@ func TestEthBroadcaster_TransmitChecking(t *testing.T) { } // Check ethtx was sent - ethTx, err := txStore.FindTxWithAttempts(ethTx.ID) + ethTx, err := txStore.FindTxWithAttempts(ctx, ethTx.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxFatalError, ethTx.State) assert.True(t, ethTx.Error.Valid) @@ -602,7 +607,7 @@ func TestEthBroadcaster_TransmitChecking(t *testing.T) { func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testing.T) { // non-transactional DB needed because we deliberately test for FK violation cfg, db := heavyweight.FullTestDBV2(t, nil) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ccfg := evmtest.NewChainScopedConfig(t, cfg) evmcfg := txmgr.NewEvmTxmConfig(ccfg.EVM()) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) @@ -619,16 +624,16 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testi <-chBlock }).Once() ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil) + txmClient := txmgr.NewEvmTxmClient(ethClient) eb := txmgr.NewEvmBroadcaster( txStore, - txmgr.NewEvmTxmClient(ethClient), + txmClient, evmcfg, txmgr.NewEvmTxmFeeConfig(ccfg.EVM().GasEstimator()), ccfg.EVM().Transactions(), cfg.Database().Listener(), ethKeyStore, txBuilder, - nil, logger.Test(t), &testCheckerFactory{}, false, @@ -667,7 +672,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success_WithMultiplier(t *testing lm := decimal.RequireFromString("1.3") c.EVM[0].GasEstimator.LimitMultiplier = &lm }) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -676,7 +681,8 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success_WithMultiplier(t *testing ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) + nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient)) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false, nonceTracker) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { assert.Equal(t, int(1600), int(tx.Gas())) @@ -711,10 +717,11 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { secondNonce := nextNonce + 1 cfg := configtest.NewGeneralConfig(t, nil) evmcfg := evmtest.NewChainScopedConfig(t, cfg) + ctx := testutils.Context(t) t.Run("cannot be more than one transaction per address in an unfinished state", func(t *testing.T) { db := pgtest.NewSqlxDB(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) @@ -741,22 +748,23 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { State: txmgrcommon.TxInProgress, } - require.NoError(t, txStore.InsertTx(&firstInProgress)) - err := txStore.InsertTx(&secondInProgress) + require.NoError(t, txStore.InsertTx(ctx, &firstInProgress)) + err := txStore.InsertTx(ctx, &secondInProgress) require.Error(t, err) assert.Contains(t, err.Error(), "ERROR: duplicate key value violates unique constraint \"idx_only_one_in_progress_tx_per_account_id_per_evm_chain_id\" (SQLSTATE 23505)") }) t.Run("previous run assigned nonce but never broadcast", func(t *testing.T) { db := pgtest.NewSqlxDB(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) + nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient)) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved // the nonce to the eth_tx so evm.key_states.next_nonce has not been @@ -775,7 +783,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { } // Check it was saved correctly with its attempt - etx, err := txStore.FindTxWithAttempts(inProgressEthTx.ID) + etx, err := txStore.FindTxWithAttempts(ctx, inProgressEthTx.ID) require.NoError(t, err) assert.NotNil(t, etx.BroadcastAt) @@ -787,14 +795,15 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { t.Run("previous run assigned nonce and broadcast but it fatally errored before we could save", func(t *testing.T) { db := pgtest.NewSqlxDB(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) + nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient)) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) @@ -811,7 +820,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { } // Check it was saved correctly with its attempt - etx, err := txStore.FindTxWithAttempts(inProgressEthTx.ID) + etx, err := txStore.FindTxWithAttempts(ctx, inProgressEthTx.ID) require.NoError(t, err) assert.Nil(t, etx.BroadcastAt) @@ -823,14 +832,15 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { t.Run("previous run assigned nonce and broadcast and is now in mempool", func(t *testing.T) { db := pgtest.NewSqlxDB(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) + nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient)) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) @@ -847,7 +857,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { } // Check it was saved correctly with its attempt - etx, err := txStore.FindTxWithAttempts(inProgressEthTx.ID) + etx, err := txStore.FindTxWithAttempts(ctx, inProgressEthTx.ID) require.NoError(t, err) assert.NotNil(t, etx.BroadcastAt) @@ -858,14 +868,15 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { t.Run("previous run assigned nonce and broadcast and now the transaction has been confirmed", func(t *testing.T) { db := pgtest.NewSqlxDB(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) + nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient)) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) @@ -882,7 +893,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { } // Check it was saved correctly with its attempt - etx, err := txStore.FindTxWithAttempts(inProgressEthTx.ID) + etx, err := txStore.FindTxWithAttempts(ctx, inProgressEthTx.ID) require.NoError(t, err) require.NotNil(t, etx.BroadcastAt) @@ -895,14 +906,15 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { t.Run("previous run assigned nonce and then failed to reach node for some reason and node is still down", func(t *testing.T) { failedToReachNodeError := context.DeadlineExceeded db := pgtest.NewSqlxDB(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) + nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient)) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) @@ -918,7 +930,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { assert.True(t, retryable) // Check it was left in the unfinished state - etx, err := txStore.FindTxWithAttempts(inProgressEthTx.ID) + etx, err := txStore.FindTxWithAttempts(ctx, inProgressEthTx.ID) require.NoError(t, err) assert.Nil(t, etx.BroadcastAt) @@ -930,7 +942,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { t.Run("previous run assigned nonce and broadcast transaction then crashed and rebooted with a different configured gas price", func(t *testing.T) { db := pgtest.NewSqlxDB(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) @@ -943,7 +955,8 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) + nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient)) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false, nonceTracker) // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := mustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) @@ -965,7 +978,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { } // Check it was saved correctly with its attempt - etx, err := txStore.FindTxWithAttempts(inProgressEthTx.ID) + etx, err := txStore.FindTxWithAttempts(ctx, inProgressEthTx.ID) require.NoError(t, err) assert.NotNil(t, etx.BroadcastAt) @@ -980,8 +993,8 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { }) } -func getLocalNextNonce(t *testing.T, eb *txmgr.Broadcaster, fromAddress gethCommon.Address) uint64 { - n, err := eb.GetNextSequence(testutils.Context(t), fromAddress) +func getLocalNextNonce(t *testing.T, nonceTracker txmgr.NonceTracker, fromAddress gethCommon.Address) uint64 { + n, err := nonceTracker.GetNextSequence(testutils.Context(t), fromAddress) require.NoError(t, err) require.NotNil(t, n) return uint64(n) @@ -998,7 +1011,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -1006,7 +1019,10 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { evmcfg := evmtest.NewChainScopedConfig(t, cfg) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() - eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) + lggr := logger.Test(t) + txmClient := txmgr.NewEvmTxmClient(ethClient) + nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmClient) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false, nonceTracker) ctx := testutils.Context(t) require.NoError(t, commonutils.JustError(db.Exec(`SET CONSTRAINTS pipeline_runs_pipeline_spec_id_fkey DEFERRED`))) @@ -1028,7 +1044,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { var latestID int64 var etx1 txmgr.Tx require.NoError(t, db.Get(&latestID, "SELECT max(id) FROM evm.txes")) - etx1, err = txStore.FindTxWithAttempts(latestID) + etx1, err = txStore.FindTxWithAttempts(ctx, latestID) require.NoError(t, err) require.NotNil(t, etx1.BroadcastAt) assert.NotEqual(t, etx1.CreatedAt, *etx1.BroadcastAt) @@ -1039,7 +1055,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.Len(t, etx1.TxAttempts, 1) // Check that the local nonce was incremented by one - finalNextNonce := getLocalNextNonce(t, eb, fromAddress) + finalNextNonce := getLocalNextNonce(t, nonceTracker, fromAddress) require.NoError(t, err) require.NotNil(t, finalNextNonce) require.Equal(t, int64(1), int64(finalNextNonce)) @@ -1047,7 +1063,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("geth Client returns an error in the fatal errors category", func(t *testing.T) { fatalErrorExample := "exceeds block gas limit" - localNextNonce := getLocalNextNonce(t, eb, fromAddress) + localNextNonce := getLocalNextNonce(t, nonceTracker, fromAddress) t.Run("without callback", func(t *testing.T) { etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) @@ -1060,7 +1076,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.False(t, retryable) // Check it was saved correctly with its attempt - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.Nil(t, etx.BroadcastAt) @@ -1072,7 +1088,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // Check that the key had its nonce reset var nonce evmtypes.Nonce - nonce, err = eb.GetNextSequence(ctx, fromAddress) + nonce, err = nonceTracker.GetNextSequence(ctx, fromAddress) require.NoError(t, err) // Saved NextNonce must be the same as before because this transaction // was not accepted by the eth node and never can be @@ -1095,7 +1111,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { } t.Run("with erroring callback bails out", func(t *testing.T) { - require.NoError(t, txStore.InsertTx(&etx)) + require.NoError(t, txStore.InsertTx(ctx, &etx)) fn := func(id uuid.UUID, result interface{}, err error) error { return errors.New("something exploded in the callback") } @@ -1135,14 +1151,12 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // same as the parent test, but callback is set by ctor t.Run("callback set by ctor", func(t *testing.T) { - lggr := logger.Test(t) estimator := gas.NewWrappedEvmEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator { return gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), evmcfg.EVM().GasEstimator().BlockHistory(), lggr) - }, evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), nil) + }, evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), nil, evmcfg.EVM().GasEstimator()) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) - localNextNonce = getLocalNextNonce(t, eb, fromAddress) - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() - eb2 := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), evmcfg.Database().Listener(), ethKeyStore, txBuilder, nil, lggr, &testCheckerFactory{}, false) + localNextNonce = getLocalNextNonce(t, nonceTracker, fromAddress) + eb2 := txmgr.NewEvmBroadcaster(txStore, txmClient, txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), evmcfg.Database().Listener(), ethKeyStore, txBuilder, lggr, &testCheckerFactory{}, false) retryable, err := eb2.ProcessUnstartedTxs(ctx, fromAddress) assert.NoError(t, err) assert.False(t, retryable) @@ -1155,7 +1169,8 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("geth Client fails with error indicating that the transaction was too expensive", func(t *testing.T) { TxFeeExceedsCapError := "tx fee (1.10 ether) exceeds the configured cap (1.00 ether)" - localNextNonce := getLocalNextNonce(t, eb, fromAddress) + localNextNonce := getLocalNextNonce(t, nonceTracker, fromAddress) + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce @@ -1172,7 +1187,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.True(t, retryable) // Check it was saved with its attempt - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.Nil(t, etx.BroadcastAt) @@ -1185,7 +1200,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // Check that the key had its nonce reset var nonce evmtypes.Nonce - nonce, err = eb.GetNextSequence(ctx, fromAddress) + nonce, err = nonceTracker.GetNextSequence(ctx, fromAddress) require.NoError(t, err) // Saved NextNonce must be the same as before because this transaction // was not accepted by the eth node and never can be @@ -1199,7 +1214,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.False(t, retryable) // Check it was saved with its attempt - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.NotNil(t, etx.BroadcastAt) @@ -1213,7 +1228,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("eth Client call fails with an unexpected random error, and transaction was not accepted into mempool", func(t *testing.T) { retryableErrorExample := "some unknown error" - localNextNonce := getLocalNextNonce(t, eb, fromAddress) + localNextNonce := getLocalNextNonce(t, nonceTracker, fromAddress) etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce @@ -1228,7 +1243,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.True(t, retryable) // Check it was saved correctly with its attempt - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.Nil(t, etx.BroadcastAt) @@ -1250,7 +1265,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.False(t, retryable) // Check it was saved correctly with its attempt - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.NotNil(t, etx.BroadcastAt) @@ -1265,7 +1280,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("eth client call fails with an unexpected random error, and the nonce check also subsequently fails", func(t *testing.T) { retryableErrorExample := "some unknown error" - localNextNonce := getLocalNextNonce(t, eb, fromAddress) + localNextNonce := getLocalNextNonce(t, nonceTracker, fromAddress) etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce @@ -1280,7 +1295,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.True(t, retryable) // Check it was saved correctly with its attempt - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.Nil(t, etx.BroadcastAt) @@ -1302,7 +1317,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.False(t, retryable) // Check it was saved correctly with its attempt - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.NotNil(t, etx.BroadcastAt) @@ -1317,7 +1332,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("eth Client call fails with an unexpected random error, and transaction was accepted into mempool", func(t *testing.T) { retryableErrorExample := "some strange RPC returns an unexpected thing" - localNextNonce := getLocalNextNonce(t, eb, fromAddress) + localNextNonce := getLocalNextNonce(t, nonceTracker, fromAddress) etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce @@ -1331,7 +1346,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.False(t, retryable) // Check it was saved correctly with its attempt, in a broadcast state - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.NotNil(t, etx.BroadcastAt) @@ -1349,7 +1364,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // configured for the transaction pool. // This is a configuration error by the node operator, since it means they set the base gas level too low. underpricedError := "transaction underpriced" - localNextNonce := getLocalNextNonce(t, eb, fromAddress) + localNextNonce := getLocalNextNonce(t, nonceTracker, fromAddress) etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) // First was underpriced @@ -1373,7 +1388,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.False(t, retryable) // Check it was saved correctly with its attempt - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.NotNil(t, etx.BroadcastAt) @@ -1393,11 +1408,11 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { FeeLimit: gasLimit, State: txmgrcommon.TxUnstarted, } - require.NoError(t, txStore.InsertTx(&etxUnfinished)) + require.NoError(t, txStore.InsertTx(ctx, &etxUnfinished)) t.Run("failed to reach node for some reason", func(t *testing.T) { failedToReachNodeError := context.DeadlineExceeded - localNextNonce := getLocalNextNonce(t, eb, fromAddress) + localNextNonce := getLocalNextNonce(t, nonceTracker, fromAddress) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce @@ -1410,7 +1425,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.True(t, retryable) // Check it was left in the unfinished state - etx, err := txStore.FindTxWithAttempts(etxUnfinished.ID) + etx, err := txStore.FindTxWithAttempts(ctx, etxUnfinished.ID) require.NoError(t, err) assert.Nil(t, etx.BroadcastAt) @@ -1426,7 +1441,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // This happens if parity is rejecting transactions that are not priced high enough to even get into the mempool at all // It should pretend it was accepted into the mempool and hand off to ethConfirmer to bump gas as normal temporarilyUnderpricedError := "There are too many transactions in the queue. Your transaction was dropped due to limit. Try increasing the fee." - localNextNonce := getLocalNextNonce(t, eb, fromAddress) + localNextNonce := getLocalNextNonce(t, nonceTracker, fromAddress) // Re-use the previously unfinished transaction, no need to insert new @@ -1440,7 +1455,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.False(t, retryable) // Check it was saved correctly with its attempt - etx, err := txStore.FindTxWithAttempts(etxUnfinished.ID) + etx, err := txStore.FindTxWithAttempts(ctx, etxUnfinished.ID) require.NoError(t, err) assert.NotNil(t, etx.BroadcastAt) @@ -1457,7 +1472,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // configured for the transaction pool. // This is a configuration error by the node operator, since it means they set the base gas level too low. underpricedError := "transaction underpriced" - localNextNonce := getLocalNextNonce(t, eb, fromAddress) + localNextNonce := getLocalNextNonce(t, nonceTracker, fromAddress) // In this scenario the node operator REALLY fucked up and set the bump // to zero (even though that should not be possible due to config // validation) @@ -1465,8 +1480,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { c.EVM[0].GasEstimator.BumpMin = assets.NewWeiI(0) c.EVM[0].GasEstimator.BumpPercent = ptr[uint16](0) })) - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() - eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) + eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false, nonceTracker) mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) // First was underpriced @@ -1486,7 +1500,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("eth tx is left in progress if eth node returns insufficient eth", func(t *testing.T) { insufficientEthError := "insufficient funds for transfer" - localNextNonce := getLocalNextNonce(t, eb, fromAddress) + localNextNonce := getLocalNextNonce(t, nonceTracker, fromAddress) etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce @@ -1498,7 +1512,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.True(t, retryable) // Check it was saved correctly with its attempt - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.Nil(t, etx.BroadcastAt) @@ -1515,7 +1529,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { pgtest.MustExec(t, db, `DELETE FROM evm.txes`) t.Run("eth tx is left in progress if nonce is too high", func(t *testing.T) { - localNextNonce := getLocalNextNonce(t, eb, fromAddress) + localNextNonce := getLocalNextNonce(t, nonceTracker, fromAddress) nonceGapError := "NonceGap, Future nonce. Expected nonce: " + strconv.FormatUint(localNextNonce, 10) etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -1527,7 +1541,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.Contains(t, err.Error(), nonceGapError) assert.True(t, retryable) - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.Nil(t, etx.BroadcastAt) @@ -1556,12 +1570,12 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { c.EVM[0].GasEstimator.BumpMin = assets.NewWeiI(0) c.EVM[0].GasEstimator.BumpPercent = ptr[uint16](0) })) - localNextNonce := getLocalNextNonce(t, eb, fromAddress) + localNextNonce := getLocalNextNonce(t, nonceTracker, fromAddress) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() - eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) + eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false, nonceTracker) mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) underpricedError := "transaction underpriced" - localNextNonce = getLocalNextNonce(t, eb, fromAddress) + localNextNonce = getLocalNextNonce(t, nonceTracker, fromAddress) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce && tx.GasTipCap().Cmp(big.NewInt(1)) == 0 }), fromAddress).Return(commonclient.Underpriced, errors.New(underpricedError)).Once() @@ -1580,7 +1594,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // configured for the transaction pool. // This is a configuration error by the node operator, since it means they set the base gas level too low. underpricedError := "transaction underpriced" - localNextNonce := getLocalNextNonce(t, eb, fromAddress) + localNextNonce := getLocalNextNonce(t, nonceTracker, fromAddress) mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) // Check gas tip cap verification @@ -1589,7 +1603,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { c.EVM[0].GasEstimator.TipCapDefault = assets.NewWeiI(0) })) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() - eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) + eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false, nonceTracker) retryable, err := eb2.ProcessUnstartedTxs(ctx, fromAddress) require.Error(t, err) @@ -1602,8 +1616,9 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) c.EVM[0].GasEstimator.TipCapDefault = gasTipCapDefault })) - localNextNonce = getLocalNextNonce(t, eb, fromAddress) - eb2 = NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) + localNextNonce = getLocalNextNonce(t, nonceTracker, fromAddress) + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() + eb2 = NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false, nonceTracker) // Second was underpriced but above minimum ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -1637,7 +1652,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) realKeystore := cltest.NewKeyStore(t, db, cfg.Database()) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, realKeystore.Eth()) @@ -1649,9 +1664,11 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) { addresses := []gethCommon.Address{fromAddress} kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Once() ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() - eb := NewTestEthBroadcaster(t, txStore, ethClient, kst, evmcfg, &testCheckerFactory{}, false) + lggr := logger.Test(t) + nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient)) + eb := NewTestEthBroadcaster(t, txStore, ethClient, kst, evmcfg, &testCheckerFactory{}, false, nonceTracker) ctx := testutils.Context(t) - _, err := eb.GetNextSequence(ctx, fromAddress) + _, err := nonceTracker.GetNextSequence(ctx, fromAddress) require.NoError(t, err) t.Run("tx signing fails", func(t *testing.T) { @@ -1671,7 +1688,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) { assert.True(t, retryable) // Check that the transaction is left in unstarted state - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnstarted, etx.State) @@ -1679,55 +1696,12 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) { // Check that the key did not have its nonce incremented var nonce evmtypes.Nonce - nonce, err = eb.GetNextSequence(ctx, fromAddress) + nonce, err = nonceTracker.GetNextSequence(ctx, fromAddress) require.NoError(t, err) require.Equal(t, int64(localNonce), int64(nonce)) }) } -func TestEthBroadcaster_GetNextNonce(t *testing.T) { - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) - fromAddress := testutils.NewAddress() - evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - - kst := ksmocks.NewEth(t) - addresses := []gethCommon.Address{fromAddress} - kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Once() - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() - eb := NewTestEthBroadcaster(t, txStore, ethClient, kst, evmcfg, &testCheckerFactory{}, false) - nonce := getLocalNextNonce(t, eb, fromAddress) - require.NotNil(t, nonce) - assert.Equal(t, int64(0), int64(nonce)) -} - -func TestEthBroadcaster_IncrementNextNonce(t *testing.T) { - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) - kst := ksmocks.NewEth(t) - fromAddress := testutils.NewAddress() - evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - - addresses := []gethCommon.Address{fromAddress} - kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Once() - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() - eb := NewTestEthBroadcaster(t, txStore, ethClient, kst, evmcfg, &testCheckerFactory{}, false) - - ctx := testutils.Context(t) - nonce, err := eb.GetNextSequence(ctx, fromAddress) - require.NoError(t, err) - eb.IncrementNextSequence(fromAddress, nonce) - - // Nonce bumped to 1 - nonce, err = eb.GetNextSequence(ctx, fromAddress) - require.NoError(t, err) - require.Equal(t, int64(1), int64(nonce)) -} - func TestEthBroadcaster_Trigger(t *testing.T) { t.Parallel() @@ -1735,10 +1709,13 @@ func TestEthBroadcaster_Trigger(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) evmcfg := evmtest.NewChainScopedConfig(t, cfg) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - eb := NewTestEthBroadcaster(t, txStore, evmtest.NewEthClientMockWithDefaultChain(t), ethKeyStore, evmcfg, &testCheckerFactory{}, false) + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + lggr := logger.Test(t) + nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient)) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false, nonceTracker) eb.Trigger(testutils.NewAddress()) eb.Trigger(testutils.NewAddress()) @@ -1755,17 +1732,14 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { }) evmcfg := evmtest.NewChainScopedConfig(t, cfg) evmTxmCfg := txmgr.NewEvmTxmConfig(evmcfg.EVM()) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) kst := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.RandomKey{Disabled: false}.MustInsertWithState(t, kst) - _, disabledAddress := cltest.RandomKey{Disabled: true}.MustInsertWithState(t, kst) - - ethNodeNonce := uint64(22) estimator := gas.NewWrappedEvmEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator { return gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), evmcfg.EVM().GasEstimator().BlockHistory(), lggr) - }, evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), nil) + }, evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), nil, evmcfg.EVM().GasEstimator()) checkerFactory := &testCheckerFactory{} ge := evmcfg.EVM().GasEstimator() @@ -1778,7 +1752,8 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { addresses := []gethCommon.Address{fromAddress} kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Once() ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() - eb := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), evmTxmCfg, txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, txBuilder, nil, lggr, checkerFactory, false) + txmClient := txmgr.NewEvmTxmClient(ethClient) + eb := txmgr.NewEvmBroadcaster(txStore, txmClient, evmTxmCfg, txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, txBuilder, lggr, checkerFactory, false) err := eb.Start(ctx) assert.NoError(t, err) @@ -1786,236 +1761,44 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { testutils.WaitForLogMessage(t, observed, "Skipping sequence auto-sync") }) - - t.Run("when nonce syncer returns new nonce, successfully sets nonce", func(t *testing.T) { - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, estimator) - - txNonceSyncer := txmgr.NewNonceSyncer(txStore, lggr, ethClient) - kst := ksmocks.NewEth(t) - addresses := []gethCommon.Address{fromAddress} - kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Once() - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() - eb := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), evmTxmCfg, txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, txBuilder, txNonceSyncer, lggr, checkerFactory, true) - - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(ethNodeNonce, nil).Once() - servicetest.Run(t, eb) - - testutils.WaitForLogMessage(t, observed, "Fast-forward sequence") - - // Check nextSequenceMap to make sure it has correct nonce assigned - nonce, err := eb.GetNextSequence(ctx, fromAddress) - require.NoError(t, err) - require.Equal(t, strconv.FormatUint(ethNodeNonce, 10), nonce.String()) - - // The disabled key did not get updated - _, err = eb.GetNextSequence(ctx, disabledAddress) - require.Error(t, err) - }) - - ethNodeNonce++ - observed.TakeAll() - - t.Run("when nonce syncer returns error, retries and successfully sets nonce", func(t *testing.T) { - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, estimator) - txNonceSyncer := txmgr.NewNonceSyncer(txStore, lggr, ethClient) - - kst := ksmocks.NewEth(t) - addresses := []gethCommon.Address{fromAddress} - kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Once() - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() - - eb := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), evmTxmCfg, txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, txBuilder, txNonceSyncer, lggr, checkerFactory, true) - eb.XXXTestDisableUnstartedTxAutoProcessing() - - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), errors.New("something exploded")).Once() - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(ethNodeNonce, nil) - - servicetest.Run(t, eb) - - testutils.WaitForLogMessage(t, observed, "Fast-forward sequence") - - // Check keyState to make sure it has correct nonce assigned - nonce, err := eb.GetNextSequence(ctx, fromAddress) - require.NoError(t, err) - assert.Equal(t, int64(ethNodeNonce), int64(nonce)) - - // The disabled key did not get updated - _, err = eb.GetNextSequence(ctx, disabledAddress) - require.Error(t, err) - }) -} - -func Test_LoadSequenceMap(t *testing.T) { - t.Parallel() - ctx := testutils.Context(t) - t.Run("set next nonce using entries from tx table", func(t *testing.T) { - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) - ks := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) - checkerFactory := &txmgr.CheckerFactory{Client: ethClient} - _, fromAddress := cltest.MustInsertRandomKey(t, ks) - cltest.MustInsertUnconfirmedEthTx(t, txStore, int64(0), fromAddress) - cltest.MustInsertUnconfirmedEthTx(t, txStore, int64(1), fromAddress) - eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) - - nonce, err := eb.GetNextSequence(ctx, fromAddress) - require.NoError(t, err) - require.Equal(t, int64(2), int64(nonce)) - }) - - t.Run("set next nonce using client when not found in tx table", func(t *testing.T) { - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) - ks := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) - checkerFactory := &txmgr.CheckerFactory{Client: ethClient} - _, fromAddress := cltest.MustInsertRandomKey(t, ks) - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(10), nil).Once() - eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) - - nonce, err := eb.GetNextSequence(ctx, fromAddress) - require.NoError(t, err) - require.Equal(t, int64(10), int64(nonce)) - }) -} - -func Test_NextNonce(t *testing.T) { - t.Parallel() - - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) - ks := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) - checkerFactory := &txmgr.CheckerFactory{Client: ethClient} - randNonce := testutils.NewRandomPositiveInt64() - _, addr1 := cltest.MustInsertRandomKey(t, ks) - ethClient.On("PendingNonceAt", mock.Anything, addr1).Return(uint64(randNonce), nil).Once() - eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) - ctx := testutils.Context(t) - cltest.MustInsertRandomKey(t, ks, *ubig.New(testutils.FixtureChainID)) - - nonce, err := eb.GetNextSequence(ctx, addr1) - require.NoError(t, err) - require.Equal(t, randNonce, int64(nonce)) - - randAddr1 := utils.RandomAddress() - _, err = eb.GetNextSequence(ctx, randAddr1) - require.Error(t, err) - require.Contains(t, err.Error(), fmt.Sprintf("address disabled: %s", randAddr1.Hex())) - - randAddr2 := utils.RandomAddress() - _, err = eb.GetNextSequence(ctx, randAddr2) - require.Error(t, err) - require.Contains(t, err.Error(), fmt.Sprintf("address disabled: %s", randAddr2.Hex())) - } -func Test_SetNonceAfterInit(t *testing.T) { +func TestEthBroadcaster_NonceTracker_InProgressTx(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) - ks := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) - checkerFactory := &txmgr.CheckerFactory{Client: ethClient} - randNonce := testutils.NewRandomPositiveInt64() - _, addr1 := cltest.MustInsertRandomKey(t, ks) - ethClient.On("PendingNonceAt", mock.Anything, addr1).Return(uint64(0), errors.New("failed to retrieve nonce at startup")).Once() - ethClient.On("PendingNonceAt", mock.Anything, addr1).Return(uint64(randNonce), nil).Once() - eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) - - ctx := testutils.Context(t) - nonce, err := eb.GetNextSequence(ctx, addr1) - require.NoError(t, err) - require.Equal(t, randNonce, int64(nonce)) - - // Test that the new nonce is set in the map and does not need a client call to retrieve on subsequent calls - nonce, err = eb.GetNextSequence(ctx, addr1) - require.NoError(t, err) - require.Equal(t, randNonce, int64(nonce)) -} - -func Test_IncrementNextNonce(t *testing.T) { - t.Parallel() - - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) - ks := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + txStore := cltest.NewTestTxStore(t, db) + ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) evmcfg := evmtest.NewChainScopedConfig(t, cfg) checkerFactory := &txmgr.CheckerFactory{Client: ethClient} - randNonce := testutils.NewRandomPositiveInt64() - _, addr1 := cltest.MustInsertRandomKey(t, ks) - ethClient.On("PendingNonceAt", mock.Anything, addr1).Return(uint64(randNonce), nil).Once() - eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) - + lggr := logger.Test(t) ctx := testutils.Context(t) - nonce, err := eb.GetNextSequence(ctx, addr1) - require.NoError(t, err) - eb.IncrementNextSequence(addr1, nonce) - - nonce, err = eb.GetNextSequence(ctx, addr1) - require.NoError(t, err) - assert.Equal(t, randNonce+1, int64(nonce)) - eb.IncrementNextSequence(addr1, nonce) - nonce, err = eb.GetNextSequence(ctx, addr1) - require.NoError(t, err) - assert.Equal(t, randNonce+2, int64(nonce)) - - randAddr1 := utils.RandomAddress() - _, err = eb.GetNextSequence(ctx, randAddr1) - require.Error(t, err) - assert.Contains(t, err.Error(), fmt.Sprintf("address disabled: %s", randAddr1.Hex())) - - // verify it didnt get changed by any erroring calls - nonce, err = eb.GetNextSequence(ctx, addr1) - require.NoError(t, err) - assert.Equal(t, randNonce+2, int64(nonce)) -} - -func Test_SetNextNonce(t *testing.T) { - t.Parallel() + t.Run("maintains the proper nonce if there is an in-progress tx during startup", func(t *testing.T) { + inProgressTxNonce := uint64(0) + ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { + return tx.Nonce() == inProgressTxNonce + }), fromAddress).Return(commonclient.Successful, nil).Once() - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) - ks := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + // Tx with nonce 0 in DB will set local nonce map to value to 1 + mustInsertInProgressEthTxWithAttempt(t, txStore, evmtypes.Nonce(inProgressTxNonce), fromAddress) + nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient)) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, checkerFactory, false, nonceTracker) - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - evmcfg := evmtest.NewChainScopedConfig(t, cfg) - checkerFactory := &txmgr.CheckerFactory{Client: ethClient} - _, fromAddress := cltest.MustInsertRandomKey(t, ks) - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() - eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) - ctx := testutils.Context(t) + // Check the local nonce map was set to 1 higher than in-progress tx nonce + nonce := getLocalNextNonce(t, nonceTracker, fromAddress) + require.Equal(t, inProgressTxNonce+1, nonce) - t.Run("update next nonce", func(t *testing.T) { - nonce, err := eb.GetNextSequence(ctx, fromAddress) + _, err := eb.ProcessUnstartedTxs(ctx, fromAddress) require.NoError(t, err) - assert.Equal(t, int64(0), int64(nonce)) - eb.SetNextSequence(fromAddress, evmtypes.Nonce(24)) - newNextNonce, err := eb.GetNextSequence(ctx, fromAddress) - require.NoError(t, err) - assert.Equal(t, int64(24), int64(newNextNonce)) + // Check the local nonce map maintained nonce 1 higher than in-progress tx nonce + nonce = getLocalNextNonce(t, nonceTracker, fromAddress) + require.Equal(t, inProgressTxNonce+1, nonce) }) } diff --git a/core/chains/evm/txmgr/builder.go b/core/chains/evm/txmgr/builder.go index 58e37d633d9..b345f48a671 100644 --- a/core/chains/evm/txmgr/builder.go +++ b/core/chains/evm/txmgr/builder.go @@ -14,9 +14,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/keystore" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ) // NewTxm constructs the necessary dependencies for the EvmTxm (broadcaster, confirmer, etc) and returns a new EvmTxManager @@ -46,21 +46,19 @@ func NewTxm( checker := &CheckerFactory{Client: client} // create tx attempt builder txAttemptBuilder := NewEvmTxAttemptBuilder(*client.ConfiguredChainID(), fCfg, keyStore, estimator) - txStore := NewTxStore(sqlxDB, lggr, dbConfig) - txNonceSyncer := NewNonceSyncer(txStore, lggr, client) - + txStore := NewTxStore(sqlxDB, lggr) txmCfg := NewEvmTxmConfig(chainConfig) // wrap Evm specific config feeCfg := NewEvmTxmFeeConfig(fCfg) // wrap Evm specific config txmClient := NewEvmTxmClient(client) // wrap Evm specific client chainID := txmClient.ConfiguredChainID() - evmBroadcaster := NewEvmBroadcaster(txStore, txmClient, txmCfg, feeCfg, txConfig, listenerConfig, keyStore, txAttemptBuilder, txNonceSyncer, lggr, checker, chainConfig.NonceAutoSync()) + evmBroadcaster := NewEvmBroadcaster(txStore, txmClient, txmCfg, feeCfg, txConfig, listenerConfig, keyStore, txAttemptBuilder, lggr, checker, chainConfig.NonceAutoSync()) evmTracker := NewEvmTracker(txStore, keyStore, chainID, lggr) evmConfirmer := NewEvmConfirmer(txStore, txmClient, txmCfg, feeCfg, txConfig, dbConfig, keyStore, txAttemptBuilder, lggr) var evmResender *Resender if txConfig.ResendAfterThreshold() > 0 { evmResender = NewEvmResender(lggr, txStore, txmClient, evmTracker, keyStore, txmgr.DefaultResenderPollInterval, chainConfig, txConfig) } - txm = NewEvmTxm(chainID, txmCfg, txConfig, keyStore, lggr, checker, fwdMgr, txAttemptBuilder, txStore, txNonceSyncer, evmBroadcaster, evmConfirmer, evmResender, evmTracker) + txm = NewEvmTxm(chainID, txmCfg, txConfig, keyStore, lggr, checker, fwdMgr, txAttemptBuilder, txStore, evmBroadcaster, evmConfirmer, evmResender, evmTracker) return txm, nil } @@ -75,13 +73,12 @@ func NewEvmTxm( fwdMgr FwdMgr, txAttemptBuilder TxAttemptBuilder, txStore TxStore, - nonceSyncer NonceSyncer, broadcaster *Broadcaster, confirmer *Confirmer, resender *Resender, tracker *Tracker, ) *Txm { - return txmgr.NewTxm(chainId, cfg, txCfg, keyStore, lggr, checkerFactory, fwdMgr, txAttemptBuilder, txStore, nonceSyncer, broadcaster, confirmer, resender, tracker) + return txmgr.NewTxm(chainId, cfg, txCfg, keyStore, lggr, checkerFactory, fwdMgr, txAttemptBuilder, txStore, broadcaster, confirmer, resender, tracker) } // NewEvmResender creates a new concrete EvmResender @@ -138,10 +135,10 @@ func NewEvmBroadcaster( listenerConfig txmgrtypes.BroadcasterListenerConfig, keystore KeyStore, txAttemptBuilder TxAttemptBuilder, - nonceSyncer NonceSyncer, logger logger.Logger, checkerFactory TransmitCheckerFactory, autoSyncNonce bool, ) *Broadcaster { - return txmgr.NewBroadcaster(txStore, client, chainConfig, feeConfig, txConfig, listenerConfig, keystore, txAttemptBuilder, nonceSyncer, logger, checkerFactory, autoSyncNonce, evmtypes.GenerateNextNonce) + nonceTracker := NewNonceTracker(logger, txStore, client) + return txmgr.NewBroadcaster(txStore, client, chainConfig, feeConfig, txConfig, listenerConfig, keystore, txAttemptBuilder, nonceTracker, logger, checkerFactory, autoSyncNonce) } diff --git a/core/chains/evm/txmgr/confirmer_test.go b/core/chains/evm/txmgr/confirmer_test.go index ec09085bc44..3e200d66818 100644 --- a/core/chains/evm/txmgr/confirmer_test.go +++ b/core/chains/evm/txmgr/confirmer_test.go @@ -31,6 +31,8 @@ import ( evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" gasmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/keystore" + ksmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/keystore/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" @@ -40,8 +42,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" ) func newTestChainScopedConfig(t *testing.T) evmconfig.ChainScopedConfig { @@ -60,7 +60,7 @@ func newBroadcastLegacyEthTxAttempt(t *testing.T, etxID int64, gasPrice ...int64 } func mustTxBeInState(t *testing.T, txStore txmgr.TestEvmTxStore, tx txmgr.Tx, expectedState txmgrtypes.TxState) { - etx, err := txStore.FindTxWithAttempts(tx.ID) + etx, err := txStore.FindTxWithAttempts(testutils.Context(t), tx.ID) require.NoError(t, err) require.Equal(t, expectedState, etx.State) } @@ -90,7 +90,7 @@ func mustInsertInProgressEthTx(t *testing.T, txStore txmgr.TestEvmTxStore, nonce etx.State = txmgrcommon.TxInProgress n := evmtypes.Nonce(nonce) etx.Sequence = &n - require.NoError(t, txStore.InsertTx(&etx)) + require.NoError(t, txStore.InsertTx(testutils.Context(t), &etx)) return etx } @@ -103,7 +103,7 @@ func mustInsertConfirmedEthTx(t *testing.T, txStore txmgr.TestEvmTxStore, nonce now := time.Now() etx.BroadcastAt = &now etx.InitialBroadcastAt = &now - require.NoError(t, txStore.InsertTx(&etx)) + require.NoError(t, txStore.InsertTx(testutils.Context(t), &etx)) return etx } @@ -113,7 +113,7 @@ func TestEthConfirmer_Lifecycle(t *testing.T) { db := pgtest.NewSqlxDB(t) config := newTestChainScopedConfig(t) - txStore := newTxStore(t, db, config.Database()) + txStore := newTxStore(t, db) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() @@ -125,7 +125,7 @@ func TestEthConfirmer_Lifecycle(t *testing.T) { newEst := func(logger.Logger) gas.EvmEstimator { return estimator } lggr := logger.Test(t) ge := config.EVM().GasEstimator() - feeEstimator := gas.NewWrappedEvmEstimator(lggr, newEst, ge.EIP1559DynamicFees(), nil) + feeEstimator := gas.NewWrappedEvmEstimator(lggr, newEst, ge.EIP1559DynamicFees(), nil, ge) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ethKeyStore, feeEstimator) ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), config.Database(), ethKeyStore, txBuilder, lggr) ctx := testutils.Context(t) @@ -183,7 +183,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) { db := pgtest.NewSqlxDB(t) config := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, config.Database()) + txStore := cltest.NewTestTxStore(t, db) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() @@ -231,7 +231,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) { require.NoError(t, ec.CheckForReceipts(ctx, blockNum)) var err error - etx1, err = txStore.FindTxWithAttempts(etx1.ID) + etx1, err = txStore.FindTxWithAttempts(ctx, etx1.ID) assert.NoError(t, err) require.Len(t, etx1.TxAttempts, 1) attempt1_1 = etx1.TxAttempts[0] @@ -259,7 +259,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) { // No error because it is merely logged require.NoError(t, ec.CheckForReceipts(ctx, blockNum)) - etx, err := txStore.FindTxWithAttempts(etx1.ID) + etx, err := txStore.FindTxWithAttempts(ctx, etx1.ID) require.NoError(t, err) require.Len(t, etx.TxAttempts, 1) @@ -287,7 +287,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) { // No error because it is merely logged require.NoError(t, ec.CheckForReceipts(ctx, blockNum)) - etx, err := txStore.FindTxWithAttempts(etx1.ID) + etx, err := txStore.FindTxWithAttempts(ctx, etx1.ID) require.NoError(t, err) require.Len(t, etx.TxAttempts, 1) require.Len(t, etx.TxAttempts[0].Receipts, 0) @@ -326,7 +326,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) { require.NoError(t, ec.CheckForReceipts(ctx, blockNum)) // Check that the receipt was saved - etx, err := txStore.FindTxWithAttempts(etx1.ID) + etx, err := txStore.FindTxWithAttempts(ctx, etx1.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxConfirmed, etx.State) @@ -357,8 +357,8 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) { attempt2_3.TxFee = gas.EvmFee{Legacy: assets.NewWeiI(20)} // Insert order deliberately reversed to test sorting by gas price - require.NoError(t, txStore.InsertTxAttempt(&attempt2_3)) - require.NoError(t, txStore.InsertTxAttempt(&attempt2_2)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt2_3)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt2_2)) txmReceipt := evmtypes.Receipt{ TxHash: attempt2_2.Hash, @@ -389,7 +389,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) { require.NoError(t, ec.CheckForReceipts(ctx, blockNum)) // Check that the state was updated - etx, err := txStore.FindTxWithAttempts(etx2.ID) + etx, err := txStore.FindTxWithAttempts(ctx, etx2.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmed, etx.State) @@ -417,7 +417,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) { require.NoError(t, ec.CheckForReceipts(ctx, blockNum)) // No receipt, but no error either - etx, err := txStore.FindTxWithAttempts(etx3.ID) + etx, err := txStore.FindTxWithAttempts(ctx, etx3.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx.State) @@ -444,7 +444,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) { require.NoError(t, ec.CheckForReceipts(ctx, blockNum)) // No receipt, but no error either - etx, err := txStore.FindTxWithAttempts(etx3.ID) + etx, err := txStore.FindTxWithAttempts(ctx, etx3.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx.State) @@ -473,7 +473,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) { require.NoError(t, ec.CheckForReceipts(ctx, blockNum)) // Check that the receipt was unchanged - etx, err := txStore.FindTxWithAttempts(etx3.ID) + etx, err := txStore.FindTxWithAttempts(ctx, etx3.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxConfirmed, etx.State) @@ -497,7 +497,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) { attempt4_2 := newInProgressLegacyEthTxAttempt(t, etx4.ID) attempt4_2.TxFee = gas.EvmFee{Legacy: assets.NewWeiI(10)} - require.NoError(t, txStore.InsertTxAttempt(&attempt4_2)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt4_2)) txmReceipt := evmtypes.Receipt{ TxHash: attempt4_2.Hash, @@ -525,7 +525,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) { // Check that the state was updated var err error - etx4, err = txStore.FindTxWithAttempts(etx4.ID) + etx4, err = txStore.FindTxWithAttempts(ctx, etx4.ID) require.NoError(t, err) attempt4_1 = etx4.TxAttempts[1] @@ -577,7 +577,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) { require.NoError(t, ec.CheckForReceipts(ctx, blockNum)) // Check that the state was updated - etx5, err = txStore.FindTxWithAttempts(etx5.ID) + etx5, err = txStore.FindTxWithAttempts(ctx, etx5.ID) require.NoError(t, err) attempt5_1 = etx5.TxAttempts[0] @@ -597,7 +597,7 @@ func TestEthConfirmer_CheckForReceipts_batching(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].RPCDefaultBatchSize = ptr[uint32](2) }) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() @@ -616,7 +616,7 @@ func TestEthConfirmer_CheckForReceipts_batching(t *testing.T) { // Total of 5 attempts should lead to 3 batched fetches (2, 2, 1) for i := 0; i < 5; i++ { attempt := newBroadcastLegacyEthTxAttempt(t, etx.ID, int64(i+2)) - require.NoError(t, txStore.InsertTxAttempt(&attempt)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt)) attempts = append(attempts, attempt) } @@ -661,7 +661,7 @@ func TestEthConfirmer_CheckForReceipts_HandlesNonFwdTxsWithForwardingEnabled(t * c.EVM[0].Transactions.ForwardersEnabled = ptr(true) }) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) evmcfg := evmtest.NewChainScopedConfig(t, cfg) @@ -673,8 +673,8 @@ func TestEthConfirmer_CheckForReceipts_HandlesNonFwdTxsWithForwardingEnabled(t * etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, 0, fromAddress) attempt := newBroadcastLegacyEthTxAttempt(t, etx.ID, 2) attempt.Tx.Meta = nil - require.NoError(t, txStore.InsertTxAttempt(&attempt)) - dbtx, err := txStore.FindTxWithAttempts(etx.ID) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt)) + dbtx, err := txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) require.Equal(t, 0, len(dbtx.TxAttempts[0].Receipts)) @@ -698,7 +698,7 @@ func TestEthConfirmer_CheckForReceipts_HandlesNonFwdTxsWithForwardingEnabled(t * require.NoError(t, ec.CheckForReceipts(ctx, 42)) // Check receipt is inserted correctly. - dbtx, err = txStore.FindTxWithAttempts(etx.ID) + dbtx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) require.Equal(t, 1, len(dbtx.TxAttempts[0].Receipts)) } @@ -710,7 +710,7 @@ func TestEthConfirmer_CheckForReceipts_only_likely_confirmed(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].RPCDefaultBatchSize = ptr[uint32](6) }) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() @@ -728,12 +728,12 @@ func TestEthConfirmer_CheckForReceipts_only_likely_confirmed(t *testing.T) { etx2 := cltest.MustInsertUnconfirmedEthTx(t, txStore, 1, fromAddress) for i := 0; i < 4; i++ { attempt := newBroadcastLegacyEthTxAttempt(t, etx2.ID, int64(100-i)) - require.NoError(t, txStore.InsertTxAttempt(&attempt)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt)) } etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, 0, fromAddress) for i := 0; i < 4; i++ { attempt := newBroadcastLegacyEthTxAttempt(t, etx.ID, int64(100-i)) - require.NoError(t, txStore.InsertTxAttempt(&attempt)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt)) // only adding these because a batch for only those attempts should be sent attempts = append(attempts, attempt) @@ -766,7 +766,7 @@ func TestEthConfirmer_CheckForReceipts_should_not_check_for_likely_unconfirmed(t db := pgtest.NewSqlxDB(t) config := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, config.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() @@ -780,7 +780,7 @@ func TestEthConfirmer_CheckForReceipts_should_not_check_for_likely_unconfirmed(t etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, 1, fromAddress) for i := 0; i < 4; i++ { attempt := newBroadcastLegacyEthTxAttempt(t, etx.ID, int64(100-i)) - require.NoError(t, txStore.InsertTxAttempt(&attempt)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt)) } // latest nonce is lower that all attempts' nonces @@ -794,7 +794,7 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt_scoped_to_key(t db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress1_1 := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -820,7 +820,7 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt_scoped_to_key(t pgtest.MustExec(t, db, `UPDATE evm.txes SET state='confirmed' WHERE id = $1`, etx_other_chain.ID) attempt2_9 := newBroadcastLegacyEthTxAttempt(t, etx2_9.ID, int64(1)) - require.NoError(t, txStore.InsertTxAttempt(&attempt2_9)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt2_9)) txmReceipt2_9 := newTxReceipt(attempt2_9.Hash, 10, 1) ethClient.On("BatchCallContext", mock.Anything, mock.MatchedBy(func(b []rpc.BatchElem) bool { @@ -838,7 +838,7 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt_scoped_to_key(t // Now etx1_1 gets a receipt in block 11, which should mark etx1_0 as confirmed_missing_receipt attempt1_1 := newBroadcastLegacyEthTxAttempt(t, etx1_1.ID, int64(2)) - require.NoError(t, txStore.InsertTxAttempt(&attempt1_1)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt1_1)) txmReceipt1_1 := newTxReceipt(attempt1_1.Hash, 11, 1) ethClient.On("BatchCallContext", mock.Anything, mock.MatchedBy(func(b []rpc.BatchElem) bool { @@ -862,7 +862,7 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FinalityDepth = ptr[uint32](50) }) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() @@ -887,23 +887,23 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) { attempt0_1 := newBroadcastLegacyEthTxAttempt(t, etx0.ID, int64(1)) attempt0_2 := newBroadcastLegacyEthTxAttempt(t, etx0.ID, int64(2)) attempt0_2.BroadcastBeforeBlockNum = &b - require.NoError(t, txStore.InsertTxAttempt(&attempt0_1)) - require.NoError(t, txStore.InsertTxAttempt(&attempt0_2)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt0_1)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt0_2)) etx1 := cltest.MustInsertUnconfirmedEthTx(t, txStore, 1, fromAddress) attempt1_1 := newBroadcastLegacyEthTxAttempt(t, etx1.ID, int64(1)) attempt1_2 := newBroadcastLegacyEthTxAttempt(t, etx1.ID, int64(2)) attempt1_2.BroadcastBeforeBlockNum = &b - require.NoError(t, txStore.InsertTxAttempt(&attempt1_1)) - require.NoError(t, txStore.InsertTxAttempt(&attempt1_2)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt1_1)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt1_2)) etx2 := cltest.MustInsertUnconfirmedEthTx(t, txStore, 2, fromAddress) attempt2_1 := newBroadcastLegacyEthTxAttempt(t, etx2.ID, int64(1)) - require.NoError(t, txStore.InsertTxAttempt(&attempt2_1)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt2_1)) etx3 := cltest.MustInsertUnconfirmedEthTx(t, txStore, 3, fromAddress) attempt3_1 := newBroadcastLegacyEthTxAttempt(t, etx3.ID, int64(1)) - require.NoError(t, txStore.InsertTxAttempt(&attempt3_1)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt3_1)) pgtest.MustExec(t, db, `UPDATE evm.tx_attempts SET broadcast_before_block_num = 41 WHERE broadcast_before_block_num IS NULL`) @@ -953,21 +953,21 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) { // Expected state is that the "top" eth_tx is now confirmed, with the // two below it "confirmed_missing_receipt" and the "bottom" eth_tx also confirmed var err error - etx3, err = txStore.FindTxWithAttempts(etx3.ID) + etx3, err = txStore.FindTxWithAttempts(ctx, etx3.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmed, etx3.State) ethReceipt := etx3.TxAttempts[0].Receipts[0] require.Equal(t, txmReceipt3.BlockHash, ethReceipt.GetBlockHash()) - etx2, err = txStore.FindTxWithAttempts(etx2.ID) + etx2, err = txStore.FindTxWithAttempts(ctx, etx2.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmedMissingReceipt, etx2.State) - etx1, err = txStore.FindTxWithAttempts(etx1.ID) + etx1, err = txStore.FindTxWithAttempts(ctx, etx1.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmedMissingReceipt, etx1.State) - etx0, err = txStore.FindTxWithAttempts(etx0.ID) + etx0, err = txStore.FindTxWithAttempts(ctx, etx0.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmed, etx0.State) @@ -1014,20 +1014,20 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) { // Expected state is that the "top" two eth_txes are now confirmed, with the // one below it still "confirmed_missing_receipt" and the bottom one remains confirmed var err error - etx3, err = txStore.FindTxWithAttempts(etx3.ID) + etx3, err = txStore.FindTxWithAttempts(ctx, etx3.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmed, etx3.State) - etx2, err = txStore.FindTxWithAttempts(etx2.ID) + etx2, err = txStore.FindTxWithAttempts(ctx, etx2.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmed, etx2.State) ethReceipt := etx2.TxAttempts[0].Receipts[0] require.Equal(t, txmReceipt.BlockHash, ethReceipt.GetBlockHash()) - etx1, err = txStore.FindTxWithAttempts(etx1.ID) + etx1, err = txStore.FindTxWithAttempts(ctx, etx1.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmedMissingReceipt, etx1.State) - etx0, err = txStore.FindTxWithAttempts(etx0.ID) + etx0, err = txStore.FindTxWithAttempts(ctx, etx0.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmed, etx0.State) }) @@ -1059,16 +1059,16 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) { // Expected state is that the "top" two eth_txes are now confirmed, with the // one below it still "confirmed_missing_receipt" and the bottom one remains confirmed var err error - etx3, err = txStore.FindTxWithAttempts(etx3.ID) + etx3, err = txStore.FindTxWithAttempts(ctx, etx3.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmed, etx3.State) - etx2, err = txStore.FindTxWithAttempts(etx2.ID) + etx2, err = txStore.FindTxWithAttempts(ctx, etx2.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmed, etx2.State) - etx1, err = txStore.FindTxWithAttempts(etx1.ID) + etx1, err = txStore.FindTxWithAttempts(ctx, etx1.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmedMissingReceipt, etx1.State) - etx0, err = txStore.FindTxWithAttempts(etx0.ID) + etx0, err = txStore.FindTxWithAttempts(ctx, etx0.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmed, etx0.State) }) @@ -1100,16 +1100,16 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) { // Expected state is that the "top" two eth_txes are now confirmed, with the // one below it marked as "fatal_error" and the bottom one remains confirmed var err error - etx3, err = txStore.FindTxWithAttempts(etx3.ID) + etx3, err = txStore.FindTxWithAttempts(ctx, etx3.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmed, etx3.State) - etx2, err = txStore.FindTxWithAttempts(etx2.ID) + etx2, err = txStore.FindTxWithAttempts(ctx, etx2.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmed, etx2.State) - etx1, err = txStore.FindTxWithAttempts(etx1.ID) + etx1, err = txStore.FindTxWithAttempts(ctx, etx1.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxFatalError, etx1.State) - etx0, err = txStore.FindTxWithAttempts(etx0.ID) + etx0, err = txStore.FindTxWithAttempts(ctx, etx0.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmed, etx0.State) }) @@ -1122,7 +1122,7 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FinalityDepth = ptr[uint32](50) }) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() @@ -1143,11 +1143,11 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt(t *testing.T) { etx0 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 0, 1, originalBroadcastAt, fromAddress) attempt0_2 := newBroadcastLegacyEthTxAttempt(t, etx0.ID, int64(2)) - require.NoError(t, txStore.InsertTxAttempt(&attempt0_2)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt0_2)) etx1 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 1, 1, originalBroadcastAt, fromAddress) attempt1_2 := newBroadcastLegacyEthTxAttempt(t, etx1.ID, int64(2)) - require.NoError(t, txStore.InsertTxAttempt(&attempt1_2)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt1_2)) etx2 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 2, 1, originalBroadcastAt, fromAddress) attempt2_1 := etx2.TxAttempts[0] @@ -1176,19 +1176,19 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt(t *testing.T) { // Expected state is that the "top" eth_tx is untouched but the other two // are marked as unconfirmed var err error - etx0, err = txStore.FindTxWithAttempts(etx0.ID) + etx0, err = txStore.FindTxWithAttempts(ctx, etx0.ID) assert.NoError(t, err) assert.Equal(t, txmgrcommon.TxConfirmedMissingReceipt, etx0.State) assert.Greater(t, etx0.BroadcastAt.Unix(), originalBroadcastAt.Unix()) - etx1, err = txStore.FindTxWithAttempts(etx1.ID) + etx1, err = txStore.FindTxWithAttempts(ctx, etx1.ID) assert.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx1.State) assert.Greater(t, etx1.BroadcastAt.Unix(), originalBroadcastAt.Unix()) - etx2, err = txStore.FindTxWithAttempts(etx2.ID) + etx2, err = txStore.FindTxWithAttempts(ctx, etx2.ID) assert.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx2.State) assert.Greater(t, etx2.BroadcastAt.Unix(), originalBroadcastAt.Unix()) - etx3, err = txStore.FindTxWithAttempts(etx3.ID) + etx3, err = txStore.FindTxWithAttempts(ctx, etx3.ID) assert.NoError(t, err) assert.Equal(t, txmgrcommon.TxConfirmedMissingReceipt, etx3.State) assert.Greater(t, etx3.BroadcastAt.Unix(), originalBroadcastAt.Unix()) @@ -1201,7 +1201,7 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_batchSendTransactions_fails(t cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FinalityDepth = ptr[uint32](50) }) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() @@ -1222,11 +1222,11 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_batchSendTransactions_fails(t etx0 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 0, 1, originalBroadcastAt, fromAddress) attempt0_2 := newBroadcastLegacyEthTxAttempt(t, etx0.ID, int64(2)) - require.NoError(t, txStore.InsertTxAttempt(&attempt0_2)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt0_2)) etx1 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 1, 1, originalBroadcastAt, fromAddress) attempt1_2 := newBroadcastLegacyEthTxAttempt(t, etx1.ID, int64(2)) - require.NoError(t, txStore.InsertTxAttempt(&attempt1_2)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt1_2)) etx2 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 2, 1, originalBroadcastAt, fromAddress) attempt2_1 := etx2.TxAttempts[0] @@ -1243,15 +1243,15 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_batchSendTransactions_fails(t // Expected state is that all txes are marked as unconfirmed, since the batch call had failed var err error - etx0, err = txStore.FindTxWithAttempts(etx0.ID) + etx0, err = txStore.FindTxWithAttempts(ctx, etx0.ID) assert.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx0.State) assert.Equal(t, etx0.BroadcastAt.Unix(), originalBroadcastAt.Unix()) - etx1, err = txStore.FindTxWithAttempts(etx1.ID) + etx1, err = txStore.FindTxWithAttempts(ctx, etx1.ID) assert.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx1.State) assert.Equal(t, etx1.BroadcastAt.Unix(), originalBroadcastAt.Unix()) - etx2, err = txStore.FindTxWithAttempts(etx2.ID) + etx2, err = txStore.FindTxWithAttempts(ctx, etx2.ID) assert.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx2.State) assert.Equal(t, etx2.BroadcastAt.Unix(), originalBroadcastAt.Unix()) @@ -1265,7 +1265,7 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_smallEvmRPCBatchSize_middleBa c.EVM[0].FinalityDepth = ptr[uint32](50) c.EVM[0].RPCDefaultBatchSize = ptr[uint32](1) }) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() @@ -1286,11 +1286,11 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_smallEvmRPCBatchSize_middleBa etx0 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 0, 1, originalBroadcastAt, fromAddress) attempt0_2 := newBroadcastLegacyEthTxAttempt(t, etx0.ID, int64(2)) - require.NoError(t, txStore.InsertTxAttempt(&attempt0_2)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt0_2)) etx1 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 1, 1, originalBroadcastAt, fromAddress) attempt1_2 := newBroadcastLegacyEthTxAttempt(t, etx1.ID, int64(2)) - require.NoError(t, txStore.InsertTxAttempt(&attempt1_2)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt1_2)) etx2 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 2, 1, originalBroadcastAt, fromAddress) @@ -1313,15 +1313,15 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_smallEvmRPCBatchSize_middleBa // Expected state is that all transactions since failed batch will be unconfirmed var err error - etx0, err = txStore.FindTxWithAttempts(etx0.ID) + etx0, err = txStore.FindTxWithAttempts(ctx, etx0.ID) assert.NoError(t, err) assert.Equal(t, txmgrcommon.TxConfirmedMissingReceipt, etx0.State) assert.Greater(t, etx0.BroadcastAt.Unix(), originalBroadcastAt.Unix()) - etx1, err = txStore.FindTxWithAttempts(etx1.ID) + etx1, err = txStore.FindTxWithAttempts(ctx, etx1.ID) assert.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx1.State) assert.Equal(t, etx1.BroadcastAt.Unix(), originalBroadcastAt.Unix()) - etx2, err = txStore.FindTxWithAttempts(etx2.ID) + etx2, err = txStore.FindTxWithAttempts(ctx, etx2.ID) assert.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx2.State) assert.Equal(t, etx2.BroadcastAt.Unix(), originalBroadcastAt.Unix()) @@ -1332,7 +1332,8 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) + ctx := testutils.Context(t) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) @@ -1396,7 +1397,7 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { attempt1_2 := newBroadcastLegacyEthTxAttempt(t, etx1.ID) attempt1_2.BroadcastBeforeBlockNum = &onTheMoney attempt1_2.TxFee = gas.EvmFee{Legacy: assets.NewWeiI(30000)} - require.NoError(t, txStore.InsertTxAttempt(&attempt1_2)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt1_2)) t.Run("returns nothing when the transaction is unconfirmed with an attempt that is recent", func(t *testing.T) { etxs, err := ec.FindTxsRequiringRebroadcast(testutils.Context(t), lggr, evmFromAddress, currentHead, gasBumpThreshold, 10, 0, &cltest.FixtureChainID) @@ -1428,7 +1429,7 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { etxWithoutAttempts.BroadcastAt = &now etxWithoutAttempts.InitialBroadcastAt = &now etxWithoutAttempts.State = txmgrcommon.TxUnconfirmed - require.NoError(t, txStore.InsertTx(&etxWithoutAttempts)) + require.NoError(t, txStore.InsertTx(ctx, &etxWithoutAttempts)) nonce++ t.Run("does nothing if the transaction is from a different address than the one given", func(t *testing.T) { @@ -1538,7 +1539,7 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { attempt3_2 := newBroadcastLegacyEthTxAttempt(t, etx3.ID) attempt3_2.BroadcastBeforeBlockNum = &oldEnough attempt3_2.TxFee = gas.EvmFee{Legacy: assets.NewWeiI(30000)} - require.NoError(t, txStore.InsertTxAttempt(&attempt3_2)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt3_2)) t.Run("returns the transaction if it is unconfirmed with two attempts that are older than gasBumpThreshold blocks", func(t *testing.T) { etxs, err := ec.FindTxsRequiringRebroadcast(testutils.Context(t), lggr, evmFromAddress, currentHead, gasBumpThreshold, 10, 0, &cltest.FixtureChainID) @@ -1553,7 +1554,7 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { attempt3_3 := newBroadcastLegacyEthTxAttempt(t, etx3.ID) attempt3_3.BroadcastBeforeBlockNum = &tooNew attempt3_3.TxFee = gas.EvmFee{Legacy: assets.NewWeiI(40000)} - require.NoError(t, txStore.InsertTxAttempt(&attempt3_3)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt3_3)) t.Run("does not return the transaction if it has some older but one newer attempt", func(t *testing.T) { etxs, err := ec.FindTxsRequiringRebroadcast(testutils.Context(t), lggr, evmFromAddress, currentHead, gasBumpThreshold, 10, 0, &cltest.FixtureChainID) @@ -1570,7 +1571,7 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { attempt0_1 := newBroadcastLegacyEthTxAttempt(t, etxWithoutAttempts.ID) attempt0_1.State = txmgrtypes.TxAttemptInsufficientFunds - require.NoError(t, txStore.InsertTxAttempt(&attempt0_1)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt0_1)) // This attempt has insufficient_eth, but there is also another attempt4_1 // which is old enough, so this will be caught by both queries and should @@ -1578,7 +1579,7 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { attempt4_2 := cltest.NewLegacyEthTxAttempt(t, etx4.ID) attempt4_2.State = txmgrtypes.TxAttemptInsufficientFunds attempt4_2.TxFee = gas.EvmFee{Legacy: assets.NewWeiI(40000)} - require.NoError(t, txStore.InsertTxAttempt(&attempt4_2)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt4_2)) etx5 := mustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, nonce, fromAddress) nonce++ @@ -1590,7 +1591,7 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { attempt6_2 := newBroadcastLegacyEthTxAttempt(t, etx3.ID) attempt6_2.BroadcastBeforeBlockNum = &tooNew attempt6_2.TxFee = gas.EvmFee{Legacy: assets.NewWeiI(30001)} - require.NoError(t, txStore.InsertTxAttempt(&attempt6_2)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt6_2)) t.Run("returns unique attempts requiring resubmission due to insufficient eth, ordered by nonce asc", func(t *testing.T) { etxs, err := ec.FindTxsRequiringRebroadcast(testutils.Context(t), lggr, evmFromAddress, currentHead, gasBumpThreshold, 10, 0, &cltest.FixtureChainID) @@ -1634,7 +1635,8 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing }) ccfg := evmtest.NewChainScopedConfig(t, cfg) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ctx := testutils.Context(t) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) kst := ksmocks.NewEth(t) @@ -1643,7 +1645,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing newEst := func(logger.Logger) gas.EvmEstimator { return estimator } estimator.On("BumpLegacyGas", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, uint64(0), pkgerrors.Wrapf(commonfee.ErrConnectivity, "transaction...")) ge := ccfg.EVM().GasEstimator() - feeEstimator := gas.NewWrappedEvmEstimator(lggr, newEst, ge.EIP1559DynamicFees(), nil) + feeEstimator := gas.NewWrappedEvmEstimator(lggr, newEst, ge.EIP1559DynamicFees(), nil, ge) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, feeEstimator) addresses := []gethCommon.Address{fromAddress} kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Maybe() @@ -1667,7 +1669,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing err := ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead) require.NoError(t, err) - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) require.Len(t, etx.TxAttempts, 1) }) @@ -1680,17 +1682,18 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing }) ccfg := evmtest.NewChainScopedConfig(t, cfg) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ctx := testutils.Context(t) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) kst := ksmocks.NewEth(t) estimator := gasmocks.NewEvmEstimator(t) - estimator.On("BumpDynamicFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.DynamicFee{}, uint64(0), pkgerrors.Wrapf(commonfee.ErrConnectivity, "transaction...")) + estimator.On("BumpDynamicFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.DynamicFee{}, pkgerrors.Wrapf(commonfee.ErrConnectivity, "transaction...")) newEst := func(logger.Logger) gas.EvmEstimator { return estimator } // Create confirmer with necessary state ge := ccfg.EVM().GasEstimator() - feeEstimator := gas.NewWrappedEvmEstimator(lggr, newEst, ge.EIP1559DynamicFees(), nil) + feeEstimator := gas.NewWrappedEvmEstimator(lggr, newEst, ge.EIP1559DynamicFees(), nil, ge) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, feeEstimator) addresses := []gethCommon.Address{fromAddress} kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Maybe() @@ -1713,7 +1716,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing err := ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead) require.NoError(t, err) - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) require.Len(t, etx.TxAttempts, 1) }) @@ -1726,7 +1729,8 @@ func TestEthConfirmer_RebroadcastWhereNecessary_MaxFeeScenario(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.PriceMax = assets.GWei(500) }) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) + ctx := testutils.Context(t) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() @@ -1774,7 +1778,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_MaxFeeScenario(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) var err error - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) // Check that the attempt is saved @@ -1793,7 +1797,8 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.PriceMax = assets.GWei(500) }) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) + ctx := testutils.Context(t) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() @@ -1836,7 +1841,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { require.Error(t, err) require.Contains(t, err.Error(), "signing error") - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxUnconfirmed, etx.State) @@ -1864,7 +1869,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) var err error - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) require.Len(t, etx.TxAttempts, 1) @@ -1898,7 +1903,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) var err error - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) require.Len(t, etx.TxAttempts, 2) @@ -1914,7 +1919,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) var err error - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) require.Len(t, etx.TxAttempts, 2) @@ -1944,7 +1949,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) var err error - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) require.Len(t, etx.TxAttempts, 3) @@ -1984,7 +1989,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) var err error - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxConfirmedMissingReceipt, etx.State) @@ -2038,7 +2043,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { require.Error(t, err) require.Contains(t, err.Error(), "some network error") - etx2, err = txStore.FindTxWithAttempts(etx2.ID) + etx2, err = txStore.FindTxWithAttempts(ctx, etx2.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx2.State) @@ -2064,7 +2069,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) // Attempt marked "broadcast" - etx2, err = txStore.FindTxWithAttempts(etx2.ID) + etx2, err = txStore.FindTxWithAttempts(ctx, etx2.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx2.State) @@ -2103,7 +2108,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Creates new attempt as normal if currentHead is not high enough require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) var err error - etx2, err = txStore.FindTxWithAttempts(etx2.ID) + etx2, err = txStore.FindTxWithAttempts(ctx, etx2.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxConfirmedMissingReceipt, etx2.State) @@ -2144,7 +2149,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) var err error - etx3, err = txStore.FindTxWithAttempts(etx3.ID) + etx3, err = txStore.FindTxWithAttempts(ctx, etx3.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx3.State) @@ -2181,7 +2186,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) var err error - etx3, err = txStore.FindTxWithAttempts(etx3.ID) + etx3, err = txStore.FindTxWithAttempts(ctx, etx3.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx3.State) @@ -2220,7 +2225,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) var err error - etx3, err = txStore.FindTxWithAttempts(etx3.ID) + etx3, err = txStore.FindTxWithAttempts(ctx, etx3.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx3.State) @@ -2249,7 +2254,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec2.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) var err error - etx3, err = txStore.FindTxWithAttempts(etx3.ID) + etx3, err = txStore.FindTxWithAttempts(ctx, etx3.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx3.State) @@ -2279,7 +2284,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec2.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) var err error - etx3, err = txStore.FindTxWithAttempts(etx3.ID) + etx3, err = txStore.FindTxWithAttempts(ctx, etx3.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx3.State) @@ -2316,7 +2321,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { }), fromAddress).Return(commonclient.Successful, nil).Once() require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) var err error - etx4, err = txStore.FindTxWithAttempts(etx4.ID) + etx4, err = txStore.FindTxWithAttempts(ctx, etx4.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx4.State) @@ -2347,7 +2352,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { require.NoError(t, ec2.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) var err error - etx4, err = txStore.FindTxWithAttempts(etx4.ID) + etx4, err = txStore.FindTxWithAttempts(ctx, etx4.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx4.State) @@ -2384,7 +2389,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do it require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) var err error - etx4, err = txStore.FindTxWithAttempts(etx4.ID) + etx4, err = txStore.FindTxWithAttempts(ctx, etx4.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx4.State) @@ -2405,7 +2410,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.PriceMax = assets.GWei(500) }) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() @@ -2515,7 +2520,8 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) + ctx := testutils.Context(t) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() @@ -2556,7 +2562,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) require.Len(t, etx.TxAttempts, 2) @@ -2582,7 +2588,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) // New attempt was NOT created @@ -2607,7 +2613,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) // New attempt was NOT created @@ -2653,7 +2659,8 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) + ctx := testutils.Context(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() @@ -2688,7 +2695,7 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) { // Do the thing require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(testutils.Context(t), &head)) - etx, err := txStore.FindTxWithAttempts(etx.ID) + etx, err := txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx.State) }) @@ -2700,7 +2707,7 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) { // Do the thing require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(testutils.Context(t), &head)) - etx, err := txStore.FindTxWithAttempts(etx.ID) + etx, err := txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxConfirmed, etx.State) }) @@ -2713,7 +2720,7 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) { // Do the thing require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(testutils.Context(t), &head)) - etx, err := txStore.FindTxWithAttempts(etx.ID) + etx, err := txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxConfirmed, etx.State) }) @@ -2734,7 +2741,7 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) { // Do the thing require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(testutils.Context(t), &head)) - etx, err := txStore.FindTxWithAttempts(etx.ID) + etx, err := txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx.State) require.Len(t, etx.TxAttempts, 1) @@ -2757,7 +2764,7 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) { // Do the thing require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(testutils.Context(t), &head)) - etx, err := txStore.FindTxWithAttempts(etx.ID) + etx, err := txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx.State) require.Len(t, etx.TxAttempts, 1) @@ -2775,8 +2782,8 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) { attempt2.SignedRawTx = hexutil.MustDecode("0xf88c8301f3a98503b9aca000832ab98094f5fff180082d6017036b771ba883025c654bc93580a4daa6d556000000000000000000000000000000000000000000000000000000000000000026a0f25601065ee369b6470c0399a2334afcfbeb0b5c8f3d9a9042e448ed29b5bcbda05b676e00248b85faf4dd889f0e2dcf91eb867e23ac9eeb14a73f9e4c14972cdf") attempt3 := newBroadcastLegacyEthTxAttempt(t, etx.ID, 40000) attempt3.SignedRawTx = hexutil.MustDecode("0xf88c8301f3a88503b9aca0008316e36094151445852b0cfdf6a4cc81440f2af99176e8ad0880a4daa6d556000000000000000000000000000000000000000000000000000000000000000026a0dcb5a7ad52b96a866257134429f944c505820716567f070e64abb74899803855a04c13eff2a22c218e68da80111e1bb6dc665d3dea7104ab40ff8a0275a99f630d") - require.NoError(t, txStore.InsertTxAttempt(&attempt2)) - require.NoError(t, txStore.InsertTxAttempt(&attempt3)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt2)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt3)) // Receipt is within head height but a different block hash mustInsertEthReceipt(t, txStore, head.Parent.Number, utils.NewHash(), attempt2.Hash) @@ -2792,7 +2799,7 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) { // Do the thing require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(testutils.Context(t), &head)) - etx, err := txStore.FindTxWithAttempts(etx.ID) + etx, err := txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx.State) require.Len(t, etx.TxAttempts, 3) @@ -2812,7 +2819,7 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) { require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(testutils.Context(t), &head)) - etx, err := txStore.FindTxWithAttempts(etx.ID) + etx, err := txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxConfirmed, etx.State) require.Len(t, etx.TxAttempts, 1) @@ -2827,7 +2834,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -2928,7 +2935,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { db := pgtest.NewSqlxDB(t) config := configtest.NewTestGeneralConfig(t) - txStore := cltest.NewTestTxStore(t, db, config.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() @@ -3125,7 +3132,7 @@ func newEthConfirmer(t testing.TB, txStore txmgr.EvmTxStore, ethClient client.Cl ge := config.EVM().GasEstimator() estimator := gas.NewWrappedEvmEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator { return gas.NewFixedPriceEstimator(ge, ge.BlockHistory(), lggr) - }, ge.EIP1559DynamicFees(), nil) + }, ge.EIP1559DynamicFees(), nil, ge) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ks, estimator) ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), config.Database(), ks, txBuilder, lggr) ec.SetResumeCallback(fn) diff --git a/core/chains/evm/txmgr/evm_tx_store.go b/core/chains/evm/txmgr/evm_tx_store.go index 8187a390878..55f650e934b 100644 --- a/core/chains/evm/txmgr/evm_tx_store.go +++ b/core/chains/evm/txmgr/evm_tx_store.go @@ -29,19 +29,16 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/label" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) var ( ErrKeyNotUpdated = errors.New("evmTxStore: Key not updated") - ErrInvalidQOpt = errors.New("evmTxStore: Invalid QOpt") - // ErrCouldNotGetReceipt is the error string we save if we reach our finality depth for a confirmed transaction without ever getting a receipt // This most likely happened because an external wallet used the account for this nonce ErrCouldNotGetReceipt = "could not get receipt" ) -// EvmTxStore combines the txmgr tx store interface and the interface needed for the the API to read from the tx DB +// EvmTxStore combines the txmgr tx store interface and the interface needed for the API to read from the tx DB // //go:generate mockery --quiet --name EvmTxStore --output ./mocks/ --case=underscore type EvmTxStore interface { @@ -52,24 +49,24 @@ type EvmTxStore interface { // TxStoreWebApi encapsulates the methods that are not used by the txmgr and only used by the various web controllers and readers type TxStoreWebApi interface { - FindTxAttemptConfirmedByTxIDs(ids []int64) ([]TxAttempt, error) - FindTxByHash(hash common.Hash) (*Tx, error) - Transactions(offset, limit int) ([]Tx, int, error) - TxAttempts(offset, limit int) ([]TxAttempt, int, error) - TransactionsWithAttempts(offset, limit int) ([]Tx, int, error) - FindTxAttempt(hash common.Hash) (*TxAttempt, error) - FindTxWithAttempts(etxID int64) (etx Tx, err error) + FindTxAttemptConfirmedByTxIDs(ctx context.Context, ids []int64) ([]TxAttempt, error) + FindTxByHash(ctx context.Context, hash common.Hash) (*Tx, error) + Transactions(ctx context.Context, offset, limit int) ([]Tx, int, error) + TxAttempts(ctx context.Context, offset, limit int) ([]TxAttempt, int, error) + TransactionsWithAttempts(ctx context.Context, offset, limit int) ([]Tx, int, error) + FindTxAttempt(ctx context.Context, hash common.Hash) (*TxAttempt, error) + FindTxWithAttempts(ctx context.Context, etxID int64) (etx Tx, err error) } type TestEvmTxStore interface { EvmTxStore // methods only used for testing purposes - InsertReceipt(receipt *evmtypes.Receipt) (int64, error) - InsertTx(etx *Tx) error - FindTxAttemptsByTxIDs(ids []int64) ([]TxAttempt, error) - InsertTxAttempt(attempt *TxAttempt) error - LoadTxesAttempts(etxs []*Tx, qopts ...pg.QOpt) error + InsertReceipt(ctx context.Context, receipt *evmtypes.Receipt) (int64, error) + InsertTx(ctx context.Context, etx *Tx) error + FindTxAttemptsByTxIDs(ctx context.Context, ids []int64) ([]TxAttempt, error) + InsertTxAttempt(ctx context.Context, attempt *TxAttempt) error + LoadTxesAttempts(ctx context.Context, etxs []*Tx) error GetFatalTransactions(ctx context.Context) (txes []*Tx, err error) GetAllTxes(ctx context.Context) (txes []*Tx, err error) GetAllTxAttempts(ctx context.Context) (attempts []TxAttempt, err error) @@ -79,7 +76,7 @@ type TestEvmTxStore interface { } type evmTxStore struct { - q pg.Q + q sqlutil.DataSource logger logger.SugaredLogger ctx context.Context ctxCancel context.CancelFunc @@ -118,6 +115,14 @@ func DbReceiptToEvmReceipt(receipt *dbReceipt) *evmtypes.Receipt { // Directly maps to onchain receipt schema. type rawOnchainReceipt = evmtypes.Receipt +func (o *evmTxStore) Transaction(ctx context.Context, readOnly bool, fn func(*evmTxStore) error) (err error) { + opts := &sqlutil.TxOptions{TxOptions: sql.TxOptions{ReadOnly: readOnly}} + return sqlutil.Transact(ctx, o.new, o.q, opts, fn) +} + +// new returns a NewORM like o, but backed by q. +func (o *evmTxStore) new(q sqlutil.DataSource) *evmTxStore { return NewTxStore(q, o.logger) } + // Directly maps to some columns of few database tables. // Does not map to a single database table. // It's comprised of fields from different tables. @@ -336,15 +341,13 @@ func dbEthTxAttemptsToEthTxAttempts(dbEthTxAttempt []DbEthTxAttempt) []TxAttempt } func NewTxStore( - db *sqlx.DB, + db sqlutil.DataSource, lggr logger.Logger, - cfg pg.QConfig, ) *evmTxStore { namedLogger := logger.Named(lggr, "TxmStore") ctx, cancel := context.WithCancel(context.Background()) - q := pg.NewQ(db, namedLogger, cfg, pg.WithParentCtx(ctx)) return &evmTxStore{ - q: q, + q: db, logger: logger.Sugared(namedLogger), ctx: ctx, ctxCancel: cancel, @@ -357,13 +360,11 @@ VALUES (:eth_tx_id, :gas_price, :signed_raw_tx, :hash, :broadcast_before_block_n RETURNING *; ` -// TODO: create method to pass in new context to evmTxStore (which will also create a new pg.Q) - func (o *evmTxStore) Close() { o.ctxCancel() } -func (o *evmTxStore) preloadTxAttempts(txs []Tx) error { +func (o *evmTxStore) preloadTxAttempts(ctx context.Context, txs []Tx) error { // Preload TxAttempts var ids []int64 for _, tx := range txs { @@ -379,7 +380,7 @@ func (o *evmTxStore) preloadTxAttempts(txs []Tx) error { return err } query = o.q.Rebind(query) - if err = o.q.Select(&dbAttempts, query, args...); err != nil { + if err = o.q.SelectContext(ctx, &dbAttempts, query, args...); err != nil { return err } // fill in attempts @@ -399,11 +400,11 @@ func (o *evmTxStore) PreloadTxes(ctx context.Context, attempts []TxAttempt) erro var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - return o.preloadTxesAtomic(attempts, pg.WithParentCtx(ctx)) + return o.preloadTxesAtomic(ctx, attempts) } // Only to be used for atomic transactions internal to the tx store -func (o *evmTxStore) preloadTxesAtomic(attempts []TxAttempt, qopts ...pg.QOpt) error { +func (o *evmTxStore) preloadTxesAtomic(ctx context.Context, attempts []TxAttempt) error { ethTxM := make(map[int64]Tx) for _, attempt := range attempts { ethTxM[attempt.TxID] = Tx{} @@ -415,8 +416,7 @@ func (o *evmTxStore) preloadTxesAtomic(attempts []TxAttempt, qopts ...pg.QOpt) e i++ } dbEthTxs := make([]DbEthTx, len(ethTxIDs)) - qq := o.q.WithOpts(qopts...) - if err := qq.Select(&dbEthTxs, `SELECT * FROM evm.txes WHERE id = ANY($1)`, pq.Array(ethTxIDs)); err != nil { + if err := o.q.SelectContext(ctx, &dbEthTxs, `SELECT * FROM evm.txes WHERE id = ANY($1)`, pq.Array(ethTxIDs)); err != nil { return pkgerrors.Wrap(err, "loadEthTxes failed") } for _, dbEtx := range dbEthTxs { @@ -432,15 +432,15 @@ func (o *evmTxStore) preloadTxesAtomic(attempts []TxAttempt, qopts ...pg.QOpt) e // Transactions returns all eth transactions without loaded relations // limited by passed parameters. -func (o *evmTxStore) Transactions(offset, limit int) (txs []Tx, count int, err error) { +func (o *evmTxStore) Transactions(ctx context.Context, offset, limit int) (txs []Tx, count int, err error) { sql := `SELECT count(*) FROM evm.txes WHERE id IN (SELECT DISTINCT eth_tx_id FROM evm.tx_attempts)` - if err = o.q.Get(&count, sql); err != nil { + if err = o.q.GetContext(ctx, &count, sql); err != nil { return } sql = `SELECT * FROM evm.txes WHERE id IN (SELECT DISTINCT eth_tx_id FROM evm.tx_attempts) ORDER BY id desc LIMIT $1 OFFSET $2` var dbEthTxs []DbEthTx - if err = o.q.Select(&dbEthTxs, sql, limit, offset); err != nil { + if err = o.q.SelectContext(ctx, &dbEthTxs, sql, limit, offset); err != nil { return } txs = dbEthTxsToEvmEthTxs(dbEthTxs) @@ -449,73 +449,73 @@ func (o *evmTxStore) Transactions(offset, limit int) (txs []Tx, count int, err e // TransactionsWithAttempts returns all eth transactions with at least one attempt // limited by passed parameters. Attempts are sorted by id. -func (o *evmTxStore) TransactionsWithAttempts(offset, limit int) (txs []Tx, count int, err error) { +func (o *evmTxStore) TransactionsWithAttempts(ctx context.Context, offset, limit int) (txs []Tx, count int, err error) { sql := `SELECT count(*) FROM evm.txes WHERE id IN (SELECT DISTINCT eth_tx_id FROM evm.tx_attempts)` - if err = o.q.Get(&count, sql); err != nil { + if err = o.q.GetContext(ctx, &count, sql); err != nil { return } sql = `SELECT * FROM evm.txes WHERE id IN (SELECT DISTINCT eth_tx_id FROM evm.tx_attempts) ORDER BY id desc LIMIT $1 OFFSET $2` var dbTxs []DbEthTx - if err = o.q.Select(&dbTxs, sql, limit, offset); err != nil { + if err = o.q.SelectContext(ctx, &dbTxs, sql, limit, offset); err != nil { return } txs = dbEthTxsToEvmEthTxs(dbTxs) - err = o.preloadTxAttempts(txs) + err = o.preloadTxAttempts(ctx, txs) return } // TxAttempts returns the last tx attempts sorted by created_at descending. -func (o *evmTxStore) TxAttempts(offset, limit int) (txs []TxAttempt, count int, err error) { +func (o *evmTxStore) TxAttempts(ctx context.Context, offset, limit int) (txs []TxAttempt, count int, err error) { sql := `SELECT count(*) FROM evm.tx_attempts` - if err = o.q.Get(&count, sql); err != nil { + if err = o.q.GetContext(ctx, &count, sql); err != nil { return } sql = `SELECT * FROM evm.tx_attempts ORDER BY created_at DESC, id DESC LIMIT $1 OFFSET $2` var dbTxs []DbEthTxAttempt - if err = o.q.Select(&dbTxs, sql, limit, offset); err != nil { + if err = o.q.SelectContext(ctx, &dbTxs, sql, limit, offset); err != nil { return } txs = dbEthTxAttemptsToEthTxAttempts(dbTxs) - err = o.preloadTxesAtomic(txs) + err = o.preloadTxesAtomic(ctx, txs) return } // FindTxAttempt returns an individual TxAttempt -func (o *evmTxStore) FindTxAttempt(hash common.Hash) (*TxAttempt, error) { +func (o *evmTxStore) FindTxAttempt(ctx context.Context, hash common.Hash) (*TxAttempt, error) { dbTxAttempt := DbEthTxAttempt{} sql := `SELECT * FROM evm.tx_attempts WHERE hash = $1` - if err := o.q.Get(&dbTxAttempt, sql, hash); err != nil { + if err := o.q.GetContext(ctx, &dbTxAttempt, sql, hash); err != nil { return nil, err } // reuse the preload var attempt TxAttempt dbTxAttempt.ToTxAttempt(&attempt) attempts := []TxAttempt{attempt} - err := o.preloadTxesAtomic(attempts) + err := o.preloadTxesAtomic(ctx, attempts) return &attempts[0], err } // FindTxAttemptsByTxIDs returns a list of attempts by ETH Tx IDs -func (o *evmTxStore) FindTxAttemptsByTxIDs(ids []int64) ([]TxAttempt, error) { +func (o *evmTxStore) FindTxAttemptsByTxIDs(ctx context.Context, ids []int64) ([]TxAttempt, error) { sql := `SELECT * FROM evm.tx_attempts WHERE eth_tx_id = ANY($1)` var dbTxAttempts []DbEthTxAttempt - if err := o.q.Select(&dbTxAttempts, sql, ids); err != nil { + if err := o.q.SelectContext(ctx, &dbTxAttempts, sql, ids); err != nil { return nil, err } return dbEthTxAttemptsToEthTxAttempts(dbTxAttempts), nil } -func (o *evmTxStore) FindTxByHash(hash common.Hash) (*Tx, error) { +func (o *evmTxStore) FindTxByHash(ctx context.Context, hash common.Hash) (*Tx, error) { var dbEtx DbEthTx - err := o.q.Transaction(func(tx pg.Queryer) error { + err := o.Transaction(ctx, true, func(orm *evmTxStore) error { sql := `SELECT evm.txes.* FROM evm.txes WHERE id IN (SELECT DISTINCT eth_tx_id FROM evm.tx_attempts WHERE hash = $1)` - if err := tx.Get(&dbEtx, sql, hash); err != nil { + if err := orm.q.GetContext(ctx, &dbEtx, sql, hash); err != nil { return pkgerrors.Wrapf(err, "failed to find eth_tx with hash %d", hash) } return nil - }, pg.OptReadOnlyTx()) + }) var etx Tx dbEtx.ToTx(&etx) @@ -523,7 +523,7 @@ func (o *evmTxStore) FindTxByHash(hash common.Hash) (*Tx, error) { } // InsertTx inserts a new evm tx into the database -func (o *evmTxStore) InsertTx(etx *Tx) error { +func (o *evmTxStore) InsertTx(ctx context.Context, etx *Tx) error { if etx.CreatedAt == (time.Time{}) { etx.CreatedAt = time.Now() } @@ -532,30 +532,42 @@ func (o *evmTxStore) InsertTx(etx *Tx) error { ) RETURNING *` var dbTx DbEthTx dbTx.FromTx(etx) - err := o.q.GetNamed(insertEthTxSQL, &dbTx, &dbTx) + + query, args, err := o.q.BindNamed(insertEthTxSQL, &dbTx) + if err != nil { + return pkgerrors.Wrap(err, "InsertTx failed to bind named") + } + err = o.q.GetContext(ctx, &dbTx, query, args...) dbTx.ToTx(etx) return pkgerrors.Wrap(err, "InsertTx failed") } // InsertTxAttempt inserts a new txAttempt into the database -func (o *evmTxStore) InsertTxAttempt(attempt *TxAttempt) error { +func (o *evmTxStore) InsertTxAttempt(ctx context.Context, attempt *TxAttempt) error { var dbTxAttempt DbEthTxAttempt dbTxAttempt.FromTxAttempt(attempt) - err := o.q.GetNamed(insertIntoEthTxAttemptsQuery, &dbTxAttempt, &dbTxAttempt) + query, args, err := o.q.BindNamed(insertIntoEthTxAttemptsQuery, &dbTxAttempt) + if err != nil { + return pkgerrors.Wrap(err, "InsertTxAttempt failed to bind named") + } + err = o.q.GetContext(ctx, &dbTxAttempt, query, args...) dbTxAttempt.ToTxAttempt(attempt) return pkgerrors.Wrap(err, "InsertTxAttempt failed") } // InsertReceipt only used in tests. Use SaveFetchedReceipts instead -func (o *evmTxStore) InsertReceipt(receipt *evmtypes.Receipt) (int64, error) { +func (o *evmTxStore) InsertReceipt(ctx context.Context, receipt *evmtypes.Receipt) (int64, error) { // convert to database representation r := DbReceiptFromEvmReceipt(receipt) const insertEthReceiptSQL = `INSERT INTO evm.receipts (tx_hash, block_hash, block_number, transaction_index, receipt, created_at) VALUES ( :tx_hash, :block_hash, :block_number, :transaction_index, :receipt, NOW() ) RETURNING *` - err := o.q.GetNamed(insertEthReceiptSQL, &r, &r) - + query, args, err := o.q.BindNamed(insertEthReceiptSQL, &r) + if err != nil { + return 0, pkgerrors.Wrap(err, "InsertReceipt failed to bind named") + } + err = o.q.GetContext(ctx, &r, query, args...) return r.ID, pkgerrors.Wrap(err, "InsertReceipt failed") } @@ -563,62 +575,60 @@ func (o *evmTxStore) GetFatalTransactions(ctx context.Context) (txes []*Tx, err var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - err = qq.Transaction(func(tx pg.Queryer) error { + err = o.Transaction(ctx, true, func(orm *evmTxStore) error { stmt := `SELECT * FROM evm.txes WHERE state = 'fatal_error'` var dbEtxs []DbEthTx - if err = tx.Select(&dbEtxs, stmt); err != nil { + if err = orm.q.SelectContext(ctx, &dbEtxs, stmt); err != nil { return fmt.Errorf("failed to load evm.txes: %w", err) } txes = make([]*Tx, len(dbEtxs)) dbEthTxsToEvmEthTxPtrs(dbEtxs, txes) - err = o.LoadTxesAttempts(txes, pg.WithParentCtx(ctx), pg.WithQueryer(tx)) + err = orm.LoadTxesAttempts(ctx, txes) if err != nil { return fmt.Errorf("failed to load evm.tx_attempts: %w", err) } return nil - }, pg.OptReadOnlyTx()) + }) return txes, nil } // FindTxWithAttempts finds the Tx with its attempts and receipts preloaded -func (o *evmTxStore) FindTxWithAttempts(etxID int64) (etx Tx, err error) { - err = o.q.Transaction(func(tx pg.Queryer) error { +func (o *evmTxStore) FindTxWithAttempts(ctx context.Context, etxID int64) (etx Tx, err error) { + err = o.Transaction(ctx, true, func(orm *evmTxStore) error { var dbEtx DbEthTx - if err = tx.Get(&dbEtx, `SELECT * FROM evm.txes WHERE id = $1 ORDER BY created_at ASC, id ASC`, etxID); err != nil { + if err = orm.q.GetContext(ctx, &dbEtx, `SELECT * FROM evm.txes WHERE id = $1 ORDER BY created_at ASC, id ASC`, etxID); err != nil { return pkgerrors.Wrapf(err, "failed to find evm.tx with id %d", etxID) } dbEtx.ToTx(&etx) - if err = o.loadTxAttemptsAtomic(&etx, pg.WithQueryer(tx)); err != nil { + if err = orm.loadTxAttemptsAtomic(ctx, &etx); err != nil { return pkgerrors.Wrapf(err, "failed to load evm.tx_attempts for evm.tx with id %d", etxID) } - if err = loadEthTxAttemptsReceipts(tx, &etx); err != nil { + if err = orm.loadEthTxAttemptsReceipts(ctx, &etx); err != nil { return pkgerrors.Wrapf(err, "failed to load evm.receipts for evm.tx with id %d", etxID) } return nil - }, pg.OptReadOnlyTx()) + }) return etx, pkgerrors.Wrap(err, "FindTxWithAttempts failed") } -func (o *evmTxStore) FindTxAttemptConfirmedByTxIDs(ids []int64) ([]TxAttempt, error) { +func (o *evmTxStore) FindTxAttemptConfirmedByTxIDs(ctx context.Context, ids []int64) ([]TxAttempt, error) { var txAttempts []TxAttempt - err := o.q.Transaction(func(tx pg.Queryer) error { + err := o.Transaction(ctx, true, func(orm *evmTxStore) error { var dbAttempts []DbEthTxAttempt - if err := tx.Select(&dbAttempts, `SELECT eta.* + if err := orm.q.SelectContext(ctx, &dbAttempts, `SELECT eta.* FROM evm.tx_attempts eta join evm.receipts er on eta.hash = er.tx_hash where eta.eth_tx_id = ANY($1) ORDER BY eta.gas_price DESC, eta.gas_tip_cap DESC`, ids); err != nil { return err } txAttempts = dbEthTxAttemptsToEthTxAttempts(dbAttempts) - return loadConfirmedAttemptsReceipts(tx, txAttempts) - }, pg.OptReadOnlyTx()) + return loadConfirmedAttemptsReceipts(ctx, orm.q, txAttempts) + }) return txAttempts, pkgerrors.Wrap(err, "FindTxAttemptConfirmedByTxIDs failed") } // Only used internally for atomic transactions -func (o *evmTxStore) LoadTxesAttempts(etxs []*Tx, qopts ...pg.QOpt) error { - qq := o.q.WithOpts(qopts...) +func (o *evmTxStore) LoadTxesAttempts(ctx context.Context, etxs []*Tx) error { ethTxIDs := make([]int64, len(etxs)) ethTxesM := make(map[int64]*Tx, len(etxs)) for i, etx := range etxs { @@ -627,7 +637,7 @@ func (o *evmTxStore) LoadTxesAttempts(etxs []*Tx, qopts ...pg.QOpt) error { ethTxesM[etx.ID] = etxs[i] } var dbTxAttempts []DbEthTxAttempt - if err := qq.Select(&dbTxAttempts, `SELECT * FROM evm.tx_attempts WHERE eth_tx_id = ANY($1) ORDER BY evm.tx_attempts.gas_price DESC, evm.tx_attempts.gas_tip_cap DESC`, pq.Array(ethTxIDs)); err != nil { + if err := o.q.SelectContext(ctx, &dbTxAttempts, `SELECT * FROM evm.tx_attempts WHERE eth_tx_id = ANY($1) ORDER BY evm.tx_attempts.gas_price DESC, evm.tx_attempts.gas_tip_cap DESC`, pq.Array(ethTxIDs)); err != nil { return pkgerrors.Wrap(err, "loadEthTxesAttempts failed to load evm.tx_attempts") } for _, dbAttempt := range dbTxAttempts { @@ -643,19 +653,19 @@ func (o *evmTxStore) LoadTxAttempts(ctx context.Context, etx *Tx) error { var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - return o.loadTxAttemptsAtomic(etx, pg.WithParentCtx(ctx)) + return o.loadTxAttemptsAtomic(ctx, etx) } // Only to be used for atomic transactions internal to the tx store -func (o *evmTxStore) loadTxAttemptsAtomic(etx *Tx, qopts ...pg.QOpt) error { - return o.LoadTxesAttempts([]*Tx{etx}, qopts...) +func (o *evmTxStore) loadTxAttemptsAtomic(ctx context.Context, etx *Tx) error { + return o.LoadTxesAttempts(ctx, []*Tx{etx}) } -func loadEthTxAttemptsReceipts(q pg.Queryer, etx *Tx) (err error) { - return loadEthTxesAttemptsReceipts(q, []*Tx{etx}) +func (o *evmTxStore) loadEthTxAttemptsReceipts(ctx context.Context, etx *Tx) (err error) { + return o.loadEthTxesAttemptsReceipts(ctx, []*Tx{etx}) } -func loadEthTxesAttemptsReceipts(q pg.Queryer, etxs []*Tx) (err error) { +func (o *evmTxStore) loadEthTxesAttemptsReceipts(ctx context.Context, etxs []*Tx) (err error) { if len(etxs) == 0 { return nil } @@ -668,7 +678,7 @@ func loadEthTxesAttemptsReceipts(q pg.Queryer, etxs []*Tx) (err error) { } } var rs []dbReceipt - if err = q.Select(&rs, `SELECT * FROM evm.receipts WHERE tx_hash = ANY($1)`, pq.Array(attemptHashes)); err != nil { + if err = o.q.SelectContext(ctx, &rs, `SELECT * FROM evm.receipts WHERE tx_hash = ANY($1)`, pq.Array(attemptHashes)); err != nil { return pkgerrors.Wrap(err, "loadEthTxesAttemptsReceipts failed to load evm.receipts") } @@ -683,7 +693,7 @@ func loadEthTxesAttemptsReceipts(q pg.Queryer, etxs []*Tx) (err error) { return nil } -func loadConfirmedAttemptsReceipts(q pg.Queryer, attempts []TxAttempt) error { +func loadConfirmedAttemptsReceipts(ctx context.Context, q sqlutil.DataSource, attempts []TxAttempt) error { byHash := make(map[string]*TxAttempt, len(attempts)) hashes := make([][]byte, len(attempts)) for i, attempt := range attempts { @@ -691,7 +701,7 @@ func loadConfirmedAttemptsReceipts(q pg.Queryer, attempts []TxAttempt) error { hashes = append(hashes, attempt.Hash.Bytes()) } var rs []dbReceipt - if err := q.Select(&rs, `SELECT * FROM evm.receipts WHERE tx_hash = ANY($1)`, pq.Array(hashes)); err != nil { + if err := q.SelectContext(ctx, &rs, `SELECT * FROM evm.receipts WHERE tx_hash = ANY($1)`, pq.Array(hashes)); err != nil { return pkgerrors.Wrap(err, "loadConfirmedAttemptsReceipts failed to load evm.receipts") } var receipts []*evmtypes.Receipt = fromDBReceipts(rs) @@ -708,7 +718,6 @@ func (o *evmTxStore) FindTxAttemptsRequiringResend(ctx context.Context, olderTha var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) var limit null.Uint32 if maxInFlightTransactions > 0 { limit = null.Uint32From(maxInFlightTransactions) @@ -716,7 +725,7 @@ func (o *evmTxStore) FindTxAttemptsRequiringResend(ctx context.Context, olderTha var dbAttempts []DbEthTxAttempt // this select distinct works because of unique index on evm.txes // (evm_chain_id, from_address, nonce) - err = qq.Select(&dbAttempts, ` + err = o.q.SelectContext(ctx, &dbAttempts, ` SELECT DISTINCT ON (evm.txes.nonce) evm.tx_attempts.* FROM evm.tx_attempts JOIN evm.txes ON evm.txes.id = evm.tx_attempts.eth_tx_id AND evm.txes.state IN ('unconfirmed', 'confirmed_missing_receipt') @@ -733,7 +742,6 @@ func (o *evmTxStore) UpdateBroadcastAts(ctx context.Context, now time.Time, etxI var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) // Deliberately do nothing on NULL broadcast_at because that indicates the // tx has been moved into a state where broadcast_at is not relevant, e.g. // fatally errored. @@ -741,7 +749,7 @@ func (o *evmTxStore) UpdateBroadcastAts(ctx context.Context, now time.Time, etxI // Since EthConfirmer/EthResender can race (totally OK since highest // priced transaction always wins) we only want to update broadcast_at if // our version is later. - _, err := qq.Exec(`UPDATE evm.txes SET broadcast_at = $1 WHERE id = ANY($2) AND broadcast_at < $1`, now, pq.Array(etxIDs)) + _, err := o.q.ExecContext(ctx, `UPDATE evm.txes SET broadcast_at = $1 WHERE id = ANY($2) AND broadcast_at < $1`, now, pq.Array(etxIDs)) return pkgerrors.Wrap(err, "updateBroadcastAts failed to update evm.txes") } @@ -752,8 +760,7 @@ func (o *evmTxStore) SetBroadcastBeforeBlockNum(ctx context.Context, blockNum in var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - _, err := qq.Exec( + _, err := o.q.ExecContext(ctx, `UPDATE evm.tx_attempts SET broadcast_before_block_num = $1 FROM evm.txes @@ -768,9 +775,8 @@ func (o *evmTxStore) FindTxAttemptsConfirmedMissingReceipt(ctx context.Context, var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) var dbAttempts []DbEthTxAttempt - err = qq.Select(&dbAttempts, + err = o.q.SelectContext(ctx, &dbAttempts, `SELECT DISTINCT ON (evm.tx_attempts.eth_tx_id) evm.tx_attempts.* FROM evm.tx_attempts JOIN evm.txes ON evm.txes.id = evm.tx_attempts.eth_tx_id AND evm.txes.state = 'confirmed_missing_receipt' @@ -788,8 +794,7 @@ func (o *evmTxStore) UpdateTxsUnconfirmed(ctx context.Context, ids []int64) erro var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - _, err := qq.Exec(`UPDATE evm.txes SET state='unconfirmed' WHERE id = ANY($1)`, pq.Array(ids)) + _, err := o.q.ExecContext(ctx, `UPDATE evm.txes SET state='unconfirmed' WHERE id = ANY($1)`, pq.Array(ids)) if err != nil { return pkgerrors.Wrap(err, "UpdateEthTxsUnconfirmed failed to execute") @@ -801,10 +806,9 @@ func (o *evmTxStore) FindTxAttemptsRequiringReceiptFetch(ctx context.Context, ch var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - err = qq.Transaction(func(tx pg.Queryer) error { + err = o.Transaction(ctx, true, func(orm *evmTxStore) error { var dbAttempts []DbEthTxAttempt - err = tx.Select(&dbAttempts, ` + err = orm.q.SelectContext(ctx, &dbAttempts, ` SELECT evm.tx_attempts.* FROM evm.tx_attempts JOIN evm.txes ON evm.txes.id = evm.tx_attempts.eth_tx_id AND evm.txes.state IN ('unconfirmed', 'confirmed_missing_receipt') AND evm.txes.evm_chain_id = $1 WHERE evm.tx_attempts.state != 'insufficient_eth' @@ -814,9 +818,9 @@ ORDER BY evm.txes.nonce ASC, evm.tx_attempts.gas_price DESC, evm.tx_attempts.gas return pkgerrors.Wrap(err, "FindEthTxAttemptsRequiringReceiptFetch failed to load evm.tx_attempts") } attempts = dbEthTxAttemptsToEthTxAttempts(dbAttempts) - err = o.preloadTxesAtomic(attempts, pg.WithParentCtx(ctx), pg.WithQueryer(tx)) + err = orm.preloadTxesAtomic(ctx, attempts) return pkgerrors.Wrap(err, "FindEthTxAttemptsRequiringReceiptFetch failed to load evm.txes") - }, pg.OptReadOnlyTx()) + }) return } @@ -824,7 +828,6 @@ func (o *evmTxStore) SaveFetchedReceipts(ctx context.Context, r []*evmtypes.Rece var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) receipts := toOnchainReceipt(r) if len(receipts) == 0 { return nil @@ -901,7 +904,7 @@ func (o *evmTxStore) SaveFetchedReceipts(ctx context.Context, r []*evmtypes.Rece stmt = sqlx.Rebind(sqlx.DOLLAR, stmt) - err = qq.ExecQ(stmt, valueArgs...) + _, err = o.q.ExecContext(ctx, stmt, valueArgs...) return pkgerrors.Wrap(err, "SaveFetchedReceipts failed to save receipts") } @@ -929,8 +932,7 @@ func (o *evmTxStore) MarkAllConfirmedMissingReceipt(ctx context.Context, chainID var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - res, err := qq.Exec(` + res, err := o.q.ExecContext(ctx, ` UPDATE evm.txes SET state = 'confirmed_missing_receipt' FROM ( @@ -961,10 +963,9 @@ func (o *evmTxStore) GetInProgressTxAttempts(ctx context.Context, address common var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - err = qq.Transaction(func(tx pg.Queryer) error { + err = o.Transaction(ctx, true, func(orm *evmTxStore) error { var dbAttempts []DbEthTxAttempt - err = tx.Select(&dbAttempts, ` + err = orm.q.SelectContext(ctx, &dbAttempts, ` SELECT evm.tx_attempts.* FROM evm.tx_attempts INNER JOIN evm.txes ON evm.txes.id = evm.tx_attempts.eth_tx_id AND evm.txes.state in ('confirmed', 'confirmed_missing_receipt', 'unconfirmed') WHERE evm.tx_attempts.state = 'in_progress' AND evm.txes.from_address = $1 AND evm.txes.evm_chain_id = $2 @@ -973,9 +974,9 @@ WHERE evm.tx_attempts.state = 'in_progress' AND evm.txes.from_address = $1 AND e return pkgerrors.Wrap(err, "getInProgressEthTxAttempts failed to load evm.tx_attempts") } attempts = dbEthTxAttemptsToEthTxAttempts(dbAttempts) - err = o.preloadTxesAtomic(attempts, pg.WithParentCtx(ctx), pg.WithQueryer(tx)) + err = orm.preloadTxesAtomic(ctx, attempts) return pkgerrors.Wrap(err, "getInProgressEthTxAttempts failed to load evm.txes") - }, pg.OptReadOnlyTx()) + }) return attempts, pkgerrors.Wrap(err, "getInProgressEthTxAttempts failed") } @@ -1005,8 +1006,7 @@ func (o *evmTxStore) UpdateTxCallbackCompleted(ctx context.Context, pipelineTask var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - _, err := qq.Exec(`UPDATE evm.txes SET callback_completed = TRUE WHERE pipeline_task_run_id = $1 AND evm_chain_id = $2`, pipelineTaskRunId, chainId.String()) + _, err := o.q.ExecContext(ctx, `UPDATE evm.txes SET callback_completed = TRUE WHERE pipeline_task_run_id = $1 AND evm_chain_id = $2`, pipelineTaskRunId, chainId.String()) if err != nil { return fmt.Errorf("failed to mark callback completed for transaction: %w", err) } @@ -1017,9 +1017,8 @@ func (o *evmTxStore) FindLatestSequence(ctx context.Context, fromAddress common. var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) sql := `SELECT nonce FROM evm.txes WHERE from_address = $1 AND evm_chain_id = $2 AND nonce IS NOT NULL ORDER BY nonce DESC LIMIT 1` - err = qq.Get(&nonce, sql, fromAddress, chainId.String()) + err = o.q.GetContext(ctx, &nonce, sql, fromAddress, chainId.String()) return } @@ -1028,9 +1027,8 @@ func (o *evmTxStore) FindTxWithIdempotencyKey(ctx context.Context, idempotencyKe var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) var dbEtx DbEthTx - err = qq.Get(&dbEtx, `SELECT * FROM evm.txes WHERE idempotency_key = $1 and evm_chain_id = $2`, idempotencyKey, chainID.String()) + err = o.q.GetContext(ctx, &dbEtx, `SELECT * FROM evm.txes WHERE idempotency_key = $1 and evm_chain_id = $2`, idempotencyKey, chainID.String()) if err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, nil @@ -1047,44 +1045,43 @@ func (o *evmTxStore) FindTxWithSequence(ctx context.Context, fromAddress common. var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) etx = new(Tx) - err = qq.Transaction(func(tx pg.Queryer) error { + err = o.Transaction(ctx, true, func(orm *evmTxStore) error { var dbEtx DbEthTx - err = tx.Get(&dbEtx, ` + err = orm.q.GetContext(ctx, &dbEtx, ` SELECT * FROM evm.txes WHERE from_address = $1 AND nonce = $2 AND state IN ('confirmed', 'confirmed_missing_receipt', 'unconfirmed') `, fromAddress, nonce.Int64()) if err != nil { return pkgerrors.Wrap(err, "FindEthTxWithNonce failed to load evm.txes") } dbEtx.ToTx(etx) - err = o.loadTxAttemptsAtomic(etx, pg.WithParentCtx(ctx), pg.WithQueryer(tx)) + err = orm.loadTxAttemptsAtomic(ctx, etx) return pkgerrors.Wrap(err, "FindEthTxWithNonce failed to load evm.tx_attempts") - }, pg.OptReadOnlyTx()) + }) if errors.Is(err, sql.ErrNoRows) { return nil, nil } return } -func updateEthTxAttemptUnbroadcast(q pg.Queryer, attempt TxAttempt) error { +func updateEthTxAttemptUnbroadcast(ctx context.Context, orm *evmTxStore, attempt TxAttempt) error { if attempt.State != txmgrtypes.TxAttemptBroadcast { return errors.New("expected eth_tx_attempt to be broadcast") } - _, err := q.Exec(`UPDATE evm.tx_attempts SET broadcast_before_block_num = NULL, state = 'in_progress' WHERE id = $1`, attempt.ID) + _, err := orm.q.ExecContext(ctx, `UPDATE evm.tx_attempts SET broadcast_before_block_num = NULL, state = 'in_progress' WHERE id = $1`, attempt.ID) return pkgerrors.Wrap(err, "updateEthTxAttemptUnbroadcast failed") } -func updateEthTxUnconfirm(q pg.Queryer, etx Tx) error { +func updateEthTxUnconfirm(ctx context.Context, orm *evmTxStore, etx Tx) error { if etx.State != txmgr.TxConfirmed { return errors.New("expected eth_tx state to be confirmed") } - _, err := q.Exec(`UPDATE evm.txes SET state = 'unconfirmed' WHERE id = $1`, etx.ID) + _, err := orm.q.ExecContext(ctx, `UPDATE evm.txes SET state = 'unconfirmed' WHERE id = $1`, etx.ID) return pkgerrors.Wrap(err, "updateEthTxUnconfirm failed") } -func deleteEthReceipts(q pg.Queryer, etxID int64) (err error) { - _, err = q.Exec(` +func deleteEthReceipts(ctx context.Context, orm *evmTxStore, etxID int64) (err error) { + _, err = orm.q.ExecContext(ctx, ` DELETE FROM evm.receipts USING evm.tx_attempts WHERE evm.receipts.tx_hash = evm.tx_attempts.hash @@ -1097,15 +1094,14 @@ func (o *evmTxStore) UpdateTxForRebroadcast(ctx context.Context, etx Tx, etxAtte var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - return qq.Transaction(func(tx pg.Queryer) error { - if err := deleteEthReceipts(tx, etx.ID); err != nil { + return o.Transaction(ctx, false, func(orm *evmTxStore) error { + if err := deleteEthReceipts(ctx, orm, etx.ID); err != nil { return pkgerrors.Wrapf(err, "deleteEthReceipts failed for etx %v", etx.ID) } - if err := updateEthTxUnconfirm(tx, etx); err != nil { + if err := updateEthTxUnconfirm(ctx, orm, etx); err != nil { return pkgerrors.Wrapf(err, "updateEthTxUnconfirm failed for etx %v", etx.ID) } - return updateEthTxAttemptUnbroadcast(tx, etxAttempt) + return updateEthTxAttemptUnbroadcast(ctx, orm, etxAttempt) }) } @@ -1113,10 +1109,9 @@ func (o *evmTxStore) FindTransactionsConfirmedInBlockRange(ctx context.Context, var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - err = qq.Transaction(func(tx pg.Queryer) error { + err = o.Transaction(ctx, true, func(orm *evmTxStore) error { var dbEtxs []DbEthTx - err = tx.Select(&dbEtxs, ` + err = orm.q.SelectContext(ctx, &dbEtxs, ` SELECT DISTINCT evm.txes.* FROM evm.txes INNER JOIN evm.tx_attempts ON evm.txes.id = evm.tx_attempts.eth_tx_id AND evm.tx_attempts.state = 'broadcast' INNER JOIN evm.receipts ON evm.receipts.tx_hash = evm.tx_attempts.hash @@ -1128,12 +1123,12 @@ ORDER BY nonce ASC } etxs = make([]*Tx, len(dbEtxs)) dbEthTxsToEvmEthTxPtrs(dbEtxs, etxs) - if err = o.LoadTxesAttempts(etxs, pg.WithParentCtx(ctx), pg.WithQueryer(tx)); err != nil { + if err = orm.LoadTxesAttempts(ctx, etxs); err != nil { return pkgerrors.Wrap(err, "FindTransactionsConfirmedInBlockRange failed to load evm.tx_attempts") } - err = loadEthTxesAttemptsReceipts(tx, etxs) + err = orm.loadEthTxesAttemptsReceipts(ctx, etxs) return pkgerrors.Wrap(err, "FindTransactionsConfirmedInBlockRange failed to load evm.receipts") - }, pg.OptReadOnlyTx()) + }) return etxs, pkgerrors.Wrap(err, "FindTransactionsConfirmedInBlockRange failed") } @@ -1141,13 +1136,12 @@ func (o *evmTxStore) FindEarliestUnconfirmedBroadcastTime(ctx context.Context, c var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - err = qq.Transaction(func(tx pg.Queryer) error { - if err = qq.QueryRowContext(ctx, `SELECT min(initial_broadcast_at) FROM evm.txes WHERE state = 'unconfirmed' AND evm_chain_id = $1`, chainID.String()).Scan(&broadcastAt); err != nil { + err = o.Transaction(ctx, true, func(orm *evmTxStore) error { + if err = orm.q.QueryRowxContext(ctx, `SELECT min(initial_broadcast_at) FROM evm.txes WHERE state = 'unconfirmed' AND evm_chain_id = $1`, chainID.String()).Scan(&broadcastAt); err != nil { return fmt.Errorf("failed to query for unconfirmed eth_tx count: %w", err) } return nil - }, pg.OptReadOnlyTx()) + }) return broadcastAt, err } @@ -1155,9 +1149,8 @@ func (o *evmTxStore) FindEarliestUnconfirmedTxAttemptBlock(ctx context.Context, var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - err = qq.Transaction(func(tx pg.Queryer) error { - err = qq.QueryRowContext(ctx, ` + err = o.Transaction(ctx, true, func(orm *evmTxStore) error { + err = orm.q.QueryRowxContext(ctx, ` SELECT MIN(broadcast_before_block_num) FROM evm.tx_attempts JOIN evm.txes ON evm.txes.id = evm.tx_attempts.eth_tx_id WHERE evm.txes.state = 'unconfirmed' @@ -1166,7 +1159,7 @@ AND evm_chain_id = $1`, chainID.String()).Scan(&earliestUnconfirmedTxBlock) return fmt.Errorf("failed to query for earliest unconfirmed tx block: %w", err) } return nil - }, pg.OptReadOnlyTx()) + }) return earliestUnconfirmedTxBlock, err } @@ -1176,8 +1169,7 @@ func (o *evmTxStore) IsTxFinalized(ctx context.Context, blockHeight int64, txID defer cancel() var count int32 - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - err = qq.GetContext(ctx, &count, ` + err = o.q.GetContext(ctx, &count, ` SELECT COUNT(evm.receipts.receipt) FROM evm.txes INNER JOIN evm.tx_attempts ON evm.txes.id = evm.tx_attempts.eth_tx_id INNER JOIN evm.receipts ON evm.tx_attempts.hash = evm.receipts.tx_hash @@ -1189,17 +1181,17 @@ func (o *evmTxStore) IsTxFinalized(ctx context.Context, blockHeight int64, txID return count > 0, nil } -func saveAttemptWithNewState(ctx context.Context, q pg.Queryer, logger logger.Logger, attempt TxAttempt, broadcastAt time.Time) error { +func (o *evmTxStore) saveAttemptWithNewState(ctx context.Context, attempt TxAttempt, broadcastAt time.Time) error { var dbAttempt DbEthTxAttempt dbAttempt.FromTxAttempt(&attempt) - return pg.SqlxTransaction(ctx, q, logger, func(tx pg.Queryer) error { + return o.Transaction(ctx, false, func(orm *evmTxStore) error { // In case of null broadcast_at (shouldn't happen) we don't want to // update anyway because it indicates a state where broadcast_at makes // no sense e.g. fatal_error - if _, err := tx.Exec(`UPDATE evm.txes SET broadcast_at = $1 WHERE id = $2 AND broadcast_at < $1`, broadcastAt, dbAttempt.EthTxID); err != nil { + if _, err := orm.q.ExecContext(ctx, `UPDATE evm.txes SET broadcast_at = $1 WHERE id = $2 AND broadcast_at < $1`, broadcastAt, dbAttempt.EthTxID); err != nil { return pkgerrors.Wrap(err, "saveAttemptWithNewState failed to update evm.txes") } - _, err := tx.Exec(`UPDATE evm.tx_attempts SET state=$1 WHERE id=$2`, dbAttempt.State, dbAttempt.ID) + _, err := orm.q.ExecContext(ctx, `UPDATE evm.tx_attempts SET state=$1 WHERE id=$2`, dbAttempt.State, dbAttempt.ID) return pkgerrors.Wrap(err, "saveAttemptWithNewState failed to update evm.tx_attempts") }) } @@ -1208,44 +1200,41 @@ func (o *evmTxStore) SaveInsufficientFundsAttempt(ctx context.Context, timeout t var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) if !(attempt.State == txmgrtypes.TxAttemptInProgress || attempt.State == txmgrtypes.TxAttemptInsufficientFunds) { return errors.New("expected state to be either in_progress or insufficient_eth") } attempt.State = txmgrtypes.TxAttemptInsufficientFunds ctx, cancel = context.WithTimeout(ctx, timeout) defer cancel() - return pkgerrors.Wrap(saveAttemptWithNewState(ctx, qq, o.logger, *attempt, broadcastAt), "saveInsufficientEthAttempt failed") + return pkgerrors.Wrap(o.saveAttemptWithNewState(ctx, *attempt, broadcastAt), "saveInsufficientEthAttempt failed") } -func saveSentAttempt(ctx context.Context, q pg.Queryer, timeout time.Duration, logger logger.Logger, attempt *TxAttempt, broadcastAt time.Time) error { +func (o *evmTxStore) saveSentAttempt(ctx context.Context, timeout time.Duration, attempt *TxAttempt, broadcastAt time.Time) error { if attempt.State != txmgrtypes.TxAttemptInProgress { return errors.New("expected state to be in_progress") } attempt.State = txmgrtypes.TxAttemptBroadcast ctx, cancel := context.WithTimeout(ctx, timeout) defer cancel() - return pkgerrors.Wrap(saveAttemptWithNewState(ctx, q, logger, *attempt, broadcastAt), "saveSentAttempt failed") + return pkgerrors.Wrap(o.saveAttemptWithNewState(ctx, *attempt, broadcastAt), "saveSentAttempt failed") } func (o *evmTxStore) SaveSentAttempt(ctx context.Context, timeout time.Duration, attempt *TxAttempt, broadcastAt time.Time) error { var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - return saveSentAttempt(ctx, qq, timeout, o.logger, attempt, broadcastAt) + return o.saveSentAttempt(ctx, timeout, attempt, broadcastAt) } func (o *evmTxStore) SaveConfirmedMissingReceiptAttempt(ctx context.Context, timeout time.Duration, attempt *TxAttempt, broadcastAt time.Time) error { var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - err := qq.Transaction(func(tx pg.Queryer) error { - if err := saveSentAttempt(ctx, tx, timeout, o.logger, attempt, broadcastAt); err != nil { + err := o.Transaction(ctx, false, func(orm *evmTxStore) error { + if err := orm.saveSentAttempt(ctx, timeout, attempt, broadcastAt); err != nil { return err } - if _, err := tx.Exec(`UPDATE evm.txes SET state = 'confirmed_missing_receipt' WHERE id = $1`, attempt.TxID); err != nil { + if _, err := orm.q.ExecContext(ctx, `UPDATE evm.txes SET state = 'confirmed_missing_receipt' WHERE id = $1`, attempt.TxID); err != nil { return pkgerrors.Wrap(err, "failed to update evm.txes") } @@ -1258,14 +1247,13 @@ func (o *evmTxStore) DeleteInProgressAttempt(ctx context.Context, attempt TxAtte var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) if attempt.State != txmgrtypes.TxAttemptInProgress { return errors.New("DeleteInProgressAttempt: expected attempt state to be in_progress") } if attempt.ID == 0 { return errors.New("DeleteInProgressAttempt: expected attempt to have an id") } - _, err := qq.Exec(`DELETE FROM evm.tx_attempts WHERE id = $1`, attempt.ID) + _, err := o.q.ExecContext(ctx, `DELETE FROM evm.tx_attempts WHERE id = $1`, attempt.ID) return pkgerrors.Wrap(err, "DeleteInProgressAttempt failed") } @@ -1274,7 +1262,6 @@ func (o *evmTxStore) SaveInProgressAttempt(ctx context.Context, attempt *TxAttem var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) if attempt.State != txmgrtypes.TxAttemptInProgress { return errors.New("SaveInProgressAttempt failed: attempt state must be in_progress") } @@ -1282,16 +1269,16 @@ func (o *evmTxStore) SaveInProgressAttempt(ctx context.Context, attempt *TxAttem dbAttempt.FromTxAttempt(attempt) // Insert is the usual mode because the attempt is new if attempt.ID == 0 { - query, args, e := qq.BindNamed(insertIntoEthTxAttemptsQuery, &dbAttempt) + query, args, e := o.q.BindNamed(insertIntoEthTxAttemptsQuery, &dbAttempt) if e != nil { return pkgerrors.Wrap(e, "SaveInProgressAttempt failed to BindNamed") } - e = qq.Get(&dbAttempt, query, args...) + e = o.q.GetContext(ctx, &dbAttempt, query, args...) dbAttempt.ToTxAttempt(attempt) return pkgerrors.Wrap(e, "SaveInProgressAttempt failed to insert into evm.tx_attempts") } // Update only applies to case of insufficient eth and simply changes the state to in_progress - res, err := qq.Exec(`UPDATE evm.tx_attempts SET state=$1, broadcast_before_block_num=$2 WHERE id=$3`, dbAttempt.State, dbAttempt.BroadcastBeforeBlockNum, dbAttempt.ID) + res, err := o.q.ExecContext(ctx, `UPDATE evm.tx_attempts SET state=$1, broadcast_before_block_num=$2 WHERE id=$3`, dbAttempt.State, dbAttempt.BroadcastBeforeBlockNum, dbAttempt.ID) if err != nil { return pkgerrors.Wrap(err, "SaveInProgressAttempt failed to update evm.tx_attempts") } @@ -1309,21 +1296,20 @@ func (o *evmTxStore) GetNonFatalTransactions(ctx context.Context, chainID *big.I var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - err = qq.Transaction(func(tx pg.Queryer) error { + err = o.Transaction(ctx, true, func(orm *evmTxStore) error { stmt := `SELECT * FROM evm.txes WHERE state <> 'fatal_error' AND evm_chain_id = $1` var dbEtxs []DbEthTx - if err = tx.Select(&dbEtxs, stmt, chainID.String()); err != nil { + if err = orm.q.SelectContext(ctx, &dbEtxs, stmt, chainID.String()); err != nil { return fmt.Errorf("failed to load evm.txes: %w", err) } txes = make([]*Tx, len(dbEtxs)) dbEthTxsToEvmEthTxPtrs(dbEtxs, txes) - err = o.LoadTxesAttempts(txes, pg.WithParentCtx(ctx), pg.WithQueryer(tx)) + err = o.LoadTxesAttempts(ctx, txes) if err != nil { return fmt.Errorf("failed to load evm.txes: %w", err) } return nil - }, pg.OptReadOnlyTx()) + }) return txes, nil } @@ -1332,12 +1318,11 @@ func (o *evmTxStore) GetTxByID(ctx context.Context, id int64) (txe *Tx, err erro var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - err = qq.Transaction(func(tx pg.Queryer) error { + err = o.Transaction(ctx, true, func(orm *evmTxStore) error { stmt := `SELECT * FROM evm.txes WHERE id = $1` var dbEtxs []DbEthTx - if err = tx.Select(&dbEtxs, stmt, id); err != nil { + if err = orm.q.SelectContext(ctx, &dbEtxs, stmt, id); err != nil { return fmt.Errorf("failed to load evm.txes: %w", err) } txes := make([]*Tx, len(dbEtxs)) @@ -1346,12 +1331,12 @@ func (o *evmTxStore) GetTxByID(ctx context.Context, id int64) (txe *Tx, err erro return fmt.Errorf("failed to get tx with id %v", id) } txe = txes[0] - err = o.LoadTxesAttempts(txes, pg.WithParentCtx(ctx), pg.WithQueryer(tx)) + err = o.LoadTxesAttempts(ctx, txes) if err != nil { return fmt.Errorf("failed to load evm.tx_attempts: %w", err) } return nil - }, pg.OptReadOnlyTx()) + }) return txe, nil } @@ -1368,8 +1353,7 @@ func (o *evmTxStore) FindTxsRequiringGasBump(ctx context.Context, address common var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - err = qq.Transaction(func(tx pg.Queryer) error { + err = o.Transaction(ctx, true, func(orm *evmTxStore) error { stmt := ` SELECT evm.txes.* FROM evm.txes LEFT JOIN evm.tx_attempts ON evm.txes.id = evm.tx_attempts.eth_tx_id AND (broadcast_before_block_num > $4 OR broadcast_before_block_num IS NULL OR evm.tx_attempts.state != 'broadcast') @@ -1378,14 +1362,14 @@ WHERE evm.txes.state = 'unconfirmed' AND evm.tx_attempts.id IS NULL AND evm.txes ORDER BY nonce ASC ` var dbEtxs []DbEthTx - if err = tx.Select(&dbEtxs, stmt, address, chainID.String(), depth, blockNum-gasBumpThreshold); err != nil { + if err = orm.q.SelectContext(ctx, &dbEtxs, stmt, address, chainID.String(), depth, blockNum-gasBumpThreshold); err != nil { return pkgerrors.Wrap(err, "FindEthTxsRequiringGasBump failed to load evm.txes") } etxs = make([]*Tx, len(dbEtxs)) dbEthTxsToEvmEthTxPtrs(dbEtxs, etxs) - err = o.LoadTxesAttempts(etxs, pg.WithParentCtx(ctx), pg.WithQueryer(tx)) + err = orm.LoadTxesAttempts(ctx, etxs) return pkgerrors.Wrap(err, "FindEthTxsRequiringGasBump failed to load evm.tx_attempts") - }, pg.OptReadOnlyTx()) + }) return } @@ -1396,10 +1380,9 @@ func (o *evmTxStore) FindTxsRequiringResubmissionDueToInsufficientFunds(ctx cont var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - err = qq.Transaction(func(tx pg.Queryer) error { + err = o.Transaction(ctx, true, func(orm *evmTxStore) error { var dbEtxs []DbEthTx - err = tx.Select(&dbEtxs, ` + err = orm.q.SelectContext(ctx, &dbEtxs, ` SELECT DISTINCT evm.txes.* FROM evm.txes INNER JOIN evm.tx_attempts ON evm.txes.id = evm.tx_attempts.eth_tx_id AND evm.tx_attempts.state = 'insufficient_eth' WHERE evm.txes.from_address = $1 AND evm.txes.state = 'unconfirmed' AND evm.txes.evm_chain_id = $2 @@ -1410,9 +1393,9 @@ ORDER BY nonce ASC } etxs = make([]*Tx, len(dbEtxs)) dbEthTxsToEvmEthTxPtrs(dbEtxs, etxs) - err = o.LoadTxesAttempts(etxs, pg.WithParentCtx(ctx), pg.WithQueryer(tx)) + err = orm.LoadTxesAttempts(ctx, etxs) return pkgerrors.Wrap(err, "FindEthTxsRequiringResubmissionDueToInsufficientEth failed to load evm.tx_attempts") - }, pg.OptReadOnlyTx()) + }) return } @@ -1427,7 +1410,6 @@ func (o *evmTxStore) MarkOldTxesMissingReceiptAsErrored(ctx context.Context, blo var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) // cutoffBlockNum is a block height // Any 'confirmed_missing_receipt' eth_tx with all attempts older than this block height will be marked as errored // We will not try to query for receipts for this transaction any more @@ -1439,13 +1421,13 @@ func (o *evmTxStore) MarkOldTxesMissingReceiptAsErrored(ctx context.Context, blo return nil } // note: if QOpt passes in a sql.Tx this will reuse it - return qq.Transaction(func(q pg.Queryer) error { + return o.Transaction(ctx, false, func(orm *evmTxStore) error { type etx struct { ID int64 Nonce int64 } var data []etx - err := q.Select(&data, ` + err := orm.q.SelectContext(ctx, &data, ` UPDATE evm.txes SET state='fatal_error', nonce=NULL, error=$1, broadcast_at=NULL, initial_broadcast_at=NULL FROM ( @@ -1485,7 +1467,7 @@ RETURNING e0.id, e0.nonce`, ErrCouldNotGetReceipt, cutoff, chainID.String()) } var results []result - err = q.Select(&results, ` + err = orm.q.SelectContext(ctx, &results, ` SELECT e.id, e.from_address, max(a.broadcast_before_block_num) AS max_broadcast_before_block_num, array_agg(a.hash) AS tx_hashes FROM evm.txes e INNER JOIN evm.tx_attempts a ON e.id = a.eth_tx_id @@ -1504,7 +1486,7 @@ GROUP BY e.id txHashesHex[i] = common.BytesToAddress(r.TxHashes[i]) } - o.logger.Criticalw(fmt.Sprintf("eth_tx with ID %v expired without ever getting a receipt for any of our attempts. "+ + orm.logger.Criticalw(fmt.Sprintf("eth_tx with ID %v expired without ever getting a receipt for any of our attempts. "+ "Current block height is %v, transaction was broadcast before block height %v. This transaction may not have not been sent and will be marked as fatally errored. "+ "This can happen if there is another instance of chainlink running that is using the same private key, or if "+ "an external wallet has been used to send a transaction from account %s with nonce %v."+ @@ -1521,24 +1503,23 @@ func (o *evmTxStore) SaveReplacementInProgressAttempt(ctx context.Context, oldAt var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) if oldAttempt.State != txmgrtypes.TxAttemptInProgress || replacementAttempt.State != txmgrtypes.TxAttemptInProgress { return errors.New("expected attempts to be in_progress") } if oldAttempt.ID == 0 { return errors.New("expected oldAttempt to have an ID") } - return qq.Transaction(func(tx pg.Queryer) error { - if _, err := tx.Exec(`DELETE FROM evm.tx_attempts WHERE id=$1`, oldAttempt.ID); err != nil { + return o.Transaction(ctx, false, func(orm *evmTxStore) error { + if _, err := orm.q.ExecContext(ctx, `DELETE FROM evm.tx_attempts WHERE id=$1`, oldAttempt.ID); err != nil { return pkgerrors.Wrap(err, "saveReplacementInProgressAttempt failed to delete from evm.tx_attempts") } var dbAttempt DbEthTxAttempt dbAttempt.FromTxAttempt(replacementAttempt) - query, args, e := tx.BindNamed(insertIntoEthTxAttemptsQuery, &dbAttempt) + query, args, e := orm.q.BindNamed(insertIntoEthTxAttemptsQuery, &dbAttempt) if e != nil { return pkgerrors.Wrap(e, "saveReplacementInProgressAttempt failed to BindNamed") } - e = tx.Get(&dbAttempt, query, args...) + e = orm.q.GetContext(ctx, &dbAttempt, query, args...) dbAttempt.ToTxAttempt(replacementAttempt) return pkgerrors.Wrap(e, "saveReplacementInProgressAttempt failed to insert replacement attempt") }) @@ -1549,10 +1530,9 @@ func (o *evmTxStore) FindNextUnstartedTransactionFromAddress(ctx context.Context var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) var dbEtx DbEthTx + err := o.q.GetContext(ctx, &dbEtx, `SELECT * FROM evm.txes WHERE from_address = $1 AND state = 'unstarted' AND evm_chain_id = $2 ORDER BY value ASC, created_at ASC, id ASC`, fromAddress, chainID.String()) etx := new(Tx) - err := qq.Get(&dbEtx, `SELECT * FROM evm.txes WHERE from_address = $1 AND state = 'unstarted' AND evm_chain_id = $2 ORDER BY value ASC, created_at ASC, id ASC`, fromAddress, chainID.String()) dbEtx.ToTx(etx) if err != nil { return nil, pkgerrors.Wrap(err, "failed to FindNextUnstartedTransactionFromAddress") @@ -1565,7 +1545,6 @@ func (o *evmTxStore) UpdateTxFatalError(ctx context.Context, etx *Tx) error { var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) if etx.State != txmgr.TxInProgress && etx.State != txmgr.TxUnstarted { return pkgerrors.Errorf("can only transition to fatal_error from in_progress or unstarted, transaction is currently %s", etx.State) } @@ -1576,13 +1555,13 @@ func (o *evmTxStore) UpdateTxFatalError(ctx context.Context, etx *Tx) error { etx.Sequence = nil etx.State = txmgr.TxFatalError - return qq.Transaction(func(tx pg.Queryer) error { - if _, err := tx.Exec(`DELETE FROM evm.tx_attempts WHERE eth_tx_id = $1`, etx.ID); err != nil { + return o.Transaction(ctx, false, func(orm *evmTxStore) error { + if _, err := orm.q.ExecContext(ctx, `DELETE FROM evm.tx_attempts WHERE eth_tx_id = $1`, etx.ID); err != nil { return pkgerrors.Wrapf(err, "saveFatallyErroredTransaction failed to delete eth_tx_attempt with eth_tx.ID %v", etx.ID) } var dbEtx DbEthTx dbEtx.FromTx(etx) - err := pkgerrors.Wrap(tx.Get(&dbEtx, `UPDATE evm.txes SET state=$1, error=$2, broadcast_at=NULL, initial_broadcast_at=NULL, nonce=NULL WHERE id=$3 RETURNING *`, etx.State, etx.Error, etx.ID), "saveFatallyErroredTransaction failed to save eth_tx") + err := pkgerrors.Wrap(orm.q.GetContext(ctx, &dbEtx, `UPDATE evm.txes SET state=$1, error=$2, broadcast_at=NULL, initial_broadcast_at=NULL, nonce=NULL WHERE id=$3 RETURNING *`, etx.State, etx.Error, etx.ID), "saveFatallyErroredTransaction failed to save eth_tx") dbEtx.ToTx(etx) return err }) @@ -1593,7 +1572,6 @@ func (o *evmTxStore) UpdateTxAttemptInProgressToBroadcast(ctx context.Context, e var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) if etx.BroadcastAt == nil { return errors.New("unconfirmed transaction must have broadcast_at time") } @@ -1611,16 +1589,16 @@ func (o *evmTxStore) UpdateTxAttemptInProgressToBroadcast(ctx context.Context, e } etx.State = txmgr.TxUnconfirmed attempt.State = NewAttemptState - return qq.Transaction(func(tx pg.Queryer) error { + return o.Transaction(ctx, false, func(orm *evmTxStore) error { var dbEtx DbEthTx dbEtx.FromTx(etx) - if err := tx.Get(&dbEtx, `UPDATE evm.txes SET state=$1, error=$2, broadcast_at=$3, initial_broadcast_at=$4 WHERE id = $5 RETURNING *`, dbEtx.State, dbEtx.Error, dbEtx.BroadcastAt, dbEtx.InitialBroadcastAt, dbEtx.ID); err != nil { + if err := orm.q.GetContext(ctx, &dbEtx, `UPDATE evm.txes SET state=$1, error=$2, broadcast_at=$3, initial_broadcast_at=$4 WHERE id = $5 RETURNING *`, dbEtx.State, dbEtx.Error, dbEtx.BroadcastAt, dbEtx.InitialBroadcastAt, dbEtx.ID); err != nil { return pkgerrors.Wrap(err, "SaveEthTxAttempt failed to save eth_tx") } dbEtx.ToTx(etx) var dbAttempt DbEthTxAttempt dbAttempt.FromTxAttempt(&attempt) - if err := tx.Get(&dbAttempt, `UPDATE evm.tx_attempts SET state = $1 WHERE id = $2 RETURNING *`, dbAttempt.State, dbAttempt.ID); err != nil { + if err := orm.q.GetContext(ctx, &dbAttempt, `UPDATE evm.tx_attempts SET state = $1 WHERE id = $2 RETURNING *`, dbAttempt.State, dbAttempt.ID); err != nil { return pkgerrors.Wrap(err, "SaveEthTxAttempt failed to save eth_tx_attempt") } return nil @@ -1632,7 +1610,6 @@ func (o *evmTxStore) UpdateTxUnstartedToInProgress(ctx context.Context, etx *Tx, var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) if etx.Sequence == nil { return errors.New("in_progress transaction must have nonce") } @@ -1643,7 +1620,7 @@ func (o *evmTxStore) UpdateTxUnstartedToInProgress(ctx context.Context, etx *Tx, return errors.New("attempt state must be in_progress") } etx.State = txmgr.TxInProgress - return qq.Transaction(func(tx pg.Queryer) error { + return o.Transaction(ctx, false, func(orm *evmTxStore) error { // If a replay was triggered while unconfirmed transactions were pending, they will be marked as fatal_error => abandoned. // In this case, we must remove the abandoned attempt from evm.tx_attempts before replacing it with a new one. In any other // case, we uphold the constraint, leaving the original tx attempt as-is and returning the constraint violation error. @@ -1651,7 +1628,7 @@ func (o *evmTxStore) UpdateTxUnstartedToInProgress(ctx context.Context, etx *Tx, // Note: the record of the original abandoned transaction will remain in evm.txes, only the attempt is replaced. (Any receipt // associated with the abandoned attempt would also be lost, although this shouldn't happen since only unconfirmed transactions // can be abandoned.) - res, err2 := tx.Exec(`DELETE FROM evm.tx_attempts a USING evm.txes t + res, err2 := orm.q.ExecContext(ctx, `DELETE FROM evm.tx_attempts a USING evm.txes t WHERE t.id = a.eth_tx_id AND a.hash = $1 AND t.state = $2 AND t.error = 'abandoned'`, attempt.Hash, txmgr.TxFatalError, ) @@ -1672,11 +1649,11 @@ func (o *evmTxStore) UpdateTxUnstartedToInProgress(ctx context.Context, etx *Tx, var dbAttempt DbEthTxAttempt dbAttempt.FromTxAttempt(attempt) - query, args, e := tx.BindNamed(insertIntoEthTxAttemptsQuery, &dbAttempt) - if e != nil { - return pkgerrors.Wrap(e, "failed to BindNamed") + query, args, err := orm.q.BindNamed(insertIntoEthTxAttemptsQuery, &dbAttempt) + if err != nil { + return pkgerrors.Wrap(err, "UpdateTxUnstartedToInProgress failed to BindNamed") } - err := tx.Get(&dbAttempt, query, args...) + err = orm.q.GetContext(ctx, &dbAttempt, query, args...) if err != nil { var pqErr *pgconn.PgError if isPqErr := errors.As(err, &pqErr); isPqErr && @@ -1691,7 +1668,7 @@ func (o *evmTxStore) UpdateTxUnstartedToInProgress(ctx context.Context, etx *Tx, dbAttempt.ToTxAttempt(attempt) var dbEtx DbEthTx dbEtx.FromTx(etx) - err = tx.Get(&dbEtx, `UPDATE evm.txes SET nonce=$1, state=$2, broadcast_at=$3, initial_broadcast_at=$4 WHERE id=$5 RETURNING *`, etx.Sequence, etx.State, etx.BroadcastAt, etx.InitialBroadcastAt, etx.ID) + err = orm.q.GetContext(ctx, &dbEtx, `UPDATE evm.txes SET nonce=$1, state=$2, broadcast_at=$3, initial_broadcast_at=$4 WHERE id=$5 RETURNING *`, etx.Sequence, etx.State, etx.BroadcastAt, etx.InitialBroadcastAt, etx.ID) dbEtx.ToTx(etx) return pkgerrors.Wrap(err, "UpdateTxUnstartedToInProgress failed to update eth_tx") }) @@ -1705,14 +1682,13 @@ func (o *evmTxStore) GetTxInProgress(ctx context.Context, fromAddress common.Add var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) etx = new(Tx) if err != nil { return etx, pkgerrors.Wrap(err, "getInProgressEthTx failed") } - err = qq.Transaction(func(tx pg.Queryer) error { + err = o.Transaction(ctx, true, func(orm *evmTxStore) error { var dbEtx DbEthTx - err = tx.Get(&dbEtx, `SELECT * FROM evm.txes WHERE from_address = $1 and state = 'in_progress'`, fromAddress) + err = orm.q.GetContext(ctx, &dbEtx, `SELECT * FROM evm.txes WHERE from_address = $1 and state = 'in_progress'`, fromAddress) if errors.Is(err, sql.ErrNoRows) { etx = nil return nil @@ -1720,7 +1696,7 @@ func (o *evmTxStore) GetTxInProgress(ctx context.Context, fromAddress common.Add return pkgerrors.Wrap(err, "GetTxInProgress failed while loading eth tx") } dbEtx.ToTx(etx) - if err = o.loadTxAttemptsAtomic(etx, pg.WithParentCtx(ctx), pg.WithQueryer(tx)); err != nil { + if err = o.loadTxAttemptsAtomic(ctx, etx); err != nil { return pkgerrors.Wrap(err, "GetTxInProgress failed while loading EthTxAttempts") } if len(etx.TxAttempts) != 1 || etx.TxAttempts[0].State != txmgrtypes.TxAttemptInProgress { @@ -1737,37 +1713,15 @@ func (o *evmTxStore) HasInProgressTransaction(ctx context.Context, account commo var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - err = qq.Get(&exists, `SELECT EXISTS(SELECT 1 FROM evm.txes WHERE state = 'in_progress' AND from_address = $1 AND evm_chain_id = $2)`, account, chainID.String()) + err = o.q.GetContext(ctx, &exists, `SELECT EXISTS(SELECT 1 FROM evm.txes WHERE state = 'in_progress' AND from_address = $1 AND evm_chain_id = $2)`, account, chainID.String()) return exists, pkgerrors.Wrap(err, "hasInProgressTransaction failed") } -func (o *evmTxStore) UpdateKeyNextSequence(newNextNonce, currentNextNonce evmtypes.Nonce, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { - qq := o.q.WithOpts(qopts...) - return qq.Transaction(func(tx pg.Queryer) error { - // We filter by next_nonce here as an optimistic lock to make sure it - // didn't get changed out from under us. Shouldn't happen but can't hurt. - res, err := tx.Exec(`UPDATE evm.key_states SET next_nonce = $1, updated_at = $2 WHERE address = $3 AND next_nonce = $4 AND evm_chain_id = $5`, newNextNonce.Int64(), time.Now(), address, currentNextNonce.Int64(), chainID.String()) - if err != nil { - return pkgerrors.Wrap(err, "NonceSyncer#fastForwardNonceIfNecessary failed to update keys.next_nonce") - } - rowsAffected, err := res.RowsAffected() - if err != nil { - return pkgerrors.Wrap(err, "NonceSyncer#fastForwardNonceIfNecessary failed to get RowsAffected") - } - if rowsAffected == 0 { - return ErrKeyNotUpdated - } - return nil - }) -} - func (o *evmTxStore) countTransactionsWithState(ctx context.Context, fromAddress common.Address, state txmgrtypes.TxState, chainID *big.Int) (count uint32, err error) { var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - err = qq.Get(&count, `SELECT count(*) FROM evm.txes WHERE from_address = $1 AND state = $2 AND evm_chain_id = $3`, + err = o.q.GetContext(ctx, &count, `SELECT count(*) FROM evm.txes WHERE from_address = $1 AND state = $2 AND evm_chain_id = $3`, fromAddress, state, chainID.String()) return count, pkgerrors.Wrap(err, "failed to countTransactionsWithState") } @@ -1782,8 +1736,7 @@ func (o *evmTxStore) CountTransactionsByState(ctx context.Context, state txmgrty var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - err = qq.Get(&count, `SELECT count(*) FROM evm.txes WHERE state = $1 AND evm_chain_id = $2`, + err = o.q.GetContext(ctx, &count, `SELECT count(*) FROM evm.txes WHERE state = $1 AND evm_chain_id = $2`, state, chainID.String()) if err != nil { return 0, fmt.Errorf("failed to CountTransactionsByState: %w", err) @@ -1800,12 +1753,11 @@ func (o *evmTxStore) CheckTxQueueCapacity(ctx context.Context, fromAddress commo var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) if maxQueuedTransactions == 0 { return nil } var count uint64 - err = qq.Get(&count, `SELECT count(*) FROM evm.txes WHERE from_address = $1 AND state = 'unstarted' AND evm_chain_id = $2`, fromAddress, chainID.String()) + err = o.q.GetContext(ctx, &count, `SELECT count(*) FROM evm.txes WHERE from_address = $1 AND state = 'unstarted' AND evm_chain_id = $2`, fromAddress, chainID.String()) if err != nil { err = pkgerrors.Wrap(err, "CheckTxQueueCapacity query failed") return @@ -1821,12 +1773,11 @@ func (o *evmTxStore) CreateTransaction(ctx context.Context, txRequest TxRequest, var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) var dbEtx DbEthTx - err = qq.Transaction(func(tx pg.Queryer) error { + err = o.Transaction(ctx, false, func(orm *evmTxStore) error { if txRequest.PipelineTaskRunID != nil { - err = tx.Get(&dbEtx, `SELECT * FROM evm.txes WHERE pipeline_task_run_id = $1 AND evm_chain_id = $2`, txRequest.PipelineTaskRunID, chainID.String()) + err = orm.q.GetContext(ctx, &dbEtx, `SELECT * FROM evm.txes WHERE pipeline_task_run_id = $1 AND evm_chain_id = $2`, txRequest.PipelineTaskRunID, chainID.String()) // If no eth_tx matches (the common case) then continue if !errors.Is(err, sql.ErrNoRows) { if err != nil { @@ -1836,7 +1787,7 @@ func (o *evmTxStore) CreateTransaction(ctx context.Context, txRequest TxRequest, return nil } } - err = tx.Get(&dbEtx, ` + err = orm.q.GetContext(ctx, &dbEtx, ` INSERT INTO evm.txes (from_address, to_address, encoded_payload, value, gas_limit, state, created_at, meta, subject, evm_chain_id, min_confirmations, pipeline_task_run_id, transmit_checker, idempotency_key, signal_callback) VALUES ( $1,$2,$3,$4,$5,'unstarted',NOW(),$6,$7,$8,$9,$10,$11,$12,$13 @@ -1857,9 +1808,8 @@ func (o *evmTxStore) PruneUnstartedTxQueue(ctx context.Context, queueSize uint32 var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - err = qq.Transaction(func(tx pg.Queryer) error { - err := qq.Select(&ids, ` + err = o.Transaction(ctx, false, func(orm *evmTxStore) error { + err := orm.q.SelectContext(ctx, &ids, ` DELETE FROM evm.txes WHERE state = 'unstarted' AND subject = $1 AND id < ( @@ -1886,12 +1836,13 @@ func (o *evmTxStore) ReapTxHistory(ctx context.Context, minBlockNumberToKeep int var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + // Delete old confirmed evm.txes // NOTE that this relies on foreign key triggers automatically removing // the evm.tx_attempts and evm.receipts linked to every eth_tx - err := pg.Batch(func(_, limit uint) (count uint, err error) { - res, err := qq.Exec(` + const batchSize = 1000 + err := sqlutil.Batch(func(_, limit uint) (count uint, err error) { + res, err := o.q.ExecContext(ctx, ` WITH old_enough_receipts AS ( SELECT tx_hash FROM evm.receipts WHERE block_number < $1 @@ -1913,13 +1864,13 @@ AND evm_chain_id = $4`, minBlockNumberToKeep, limit, timeThreshold, chainID.Stri return count, pkgerrors.Wrap(err, "ReapTxes failed to get rows affected") } return uint(rowsAffected), err - }) + }, batchSize) if err != nil { return pkgerrors.Wrap(err, "TxmReaper#reapEthTxes batch delete of confirmed evm.txes failed") } // Delete old 'fatal_error' evm.txes - err = pg.Batch(func(_, limit uint) (count uint, err error) { - res, err := qq.Exec(` + err = sqlutil.Batch(func(_, limit uint) (count uint, err error) { + res, err := o.q.ExecContext(ctx, ` DELETE FROM evm.txes WHERE created_at < $1 AND state = 'fatal_error' @@ -1932,7 +1883,7 @@ AND evm_chain_id = $2`, timeThreshold, chainID.String()) return count, pkgerrors.Wrap(err, "ReapTxes failed to get rows affected") } return uint(rowsAffected), err - }) + }, batchSize) if err != nil { return pkgerrors.Wrap(err, "TxmReaper#reapEthTxes batch delete of fatally errored evm.txes failed") } @@ -1944,8 +1895,7 @@ func (o *evmTxStore) Abandon(ctx context.Context, chainID *big.Int, addr common. var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - _, err := qq.Exec(`UPDATE evm.txes SET state='fatal_error', nonce = NULL, error = 'abandoned' WHERE state IN ('unconfirmed', 'in_progress', 'unstarted') AND evm_chain_id = $1 AND from_address = $2`, chainID.String(), addr) + _, err := o.q.ExecContext(ctx, `UPDATE evm.txes SET state='fatal_error', nonce = NULL, error = 'abandoned' WHERE state IN ('unconfirmed', 'in_progress', 'unstarted') AND evm_chain_id = $1 AND from_address = $2`, chainID.String(), addr) return err } @@ -1954,10 +1904,9 @@ func (o *evmTxStore) FindTxesByMetaFieldAndStates(ctx context.Context, metaField var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) var dbEtxs []DbEthTx sql := fmt.Sprintf("SELECT * FROM evm.txes WHERE evm_chain_id = $1 AND meta->>'%s' = $2 AND state = ANY($3)", metaField) - err := qq.Select(&dbEtxs, sql, chainID.String(), metaValue, pq.Array(states)) + err := o.q.SelectContext(ctx, &dbEtxs, sql, chainID.String(), metaValue, pq.Array(states)) txes := make([]*Tx, len(dbEtxs)) dbEthTxsToEvmEthTxPtrs(dbEtxs, txes) return txes, pkgerrors.Wrap(err, "failed to FindTxesByMetaFieldAndStates") @@ -1968,10 +1917,9 @@ func (o *evmTxStore) FindTxesWithMetaFieldByStates(ctx context.Context, metaFiel var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) var dbEtxs []DbEthTx sql := fmt.Sprintf("SELECT * FROM evm.txes WHERE meta->'%s' IS NOT NULL AND state = ANY($1) AND evm_chain_id = $2", metaField) - err = qq.Select(&dbEtxs, sql, pq.Array(states), chainID.String()) + err = o.q.SelectContext(ctx, &dbEtxs, sql, pq.Array(states), chainID.String()) txes = make([]*Tx, len(dbEtxs)) dbEthTxsToEvmEthTxPtrs(dbEtxs, txes) return txes, pkgerrors.Wrap(err, "failed to FindTxesWithMetaFieldByStates") @@ -1982,10 +1930,9 @@ func (o *evmTxStore) FindTxesWithMetaFieldByReceiptBlockNum(ctx context.Context, var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) var dbEtxs []DbEthTx sql := fmt.Sprintf("SELECT et.* FROM evm.txes et JOIN evm.tx_attempts eta on et.id = eta.eth_tx_id JOIN evm.receipts er on eta.hash = er.tx_hash WHERE et.meta->'%s' IS NOT NULL AND er.block_number >= $1 AND et.evm_chain_id = $2", metaField) - err = qq.Select(&dbEtxs, sql, blockNum, chainID.String()) + err = o.q.SelectContext(ctx, &dbEtxs, sql, blockNum, chainID.String()) txes = make([]*Tx, len(dbEtxs)) dbEthTxsToEvmEthTxPtrs(dbEtxs, txes) return txes, pkgerrors.Wrap(err, "failed to FindTxesWithMetaFieldByReceiptBlockNum") @@ -1996,18 +1943,17 @@ func (o *evmTxStore) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Co var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - err = qq.Transaction(func(tx pg.Queryer) error { + err = o.Transaction(ctx, true, func(orm *evmTxStore) error { var dbEtxs []DbEthTx - if err = tx.Select(&dbEtxs, `SELECT * FROM evm.txes WHERE id = ANY($1) AND state = ANY($2) AND evm_chain_id = $3`, pq.Array(ids), pq.Array(states), chainID.String()); err != nil { + if err = orm.q.SelectContext(ctx, &dbEtxs, `SELECT * FROM evm.txes WHERE id = ANY($1) AND state = ANY($2) AND evm_chain_id = $3`, pq.Array(ids), pq.Array(states), chainID.String()); err != nil { return pkgerrors.Wrapf(err, "failed to find evm.txes") } txes = make([]*Tx, len(dbEtxs)) dbEthTxsToEvmEthTxPtrs(dbEtxs, txes) - if err = o.LoadTxesAttempts(txes, pg.WithQueryer(tx)); err != nil { + if err = orm.LoadTxesAttempts(ctx, txes); err != nil { return pkgerrors.Wrapf(err, "failed to load evm.tx_attempts for evm.tx") } - if err = loadEthTxesAttemptsReceipts(tx, txes); err != nil { + if err = orm.loadEthTxesAttemptsReceipts(ctx, txes); err != nil { return pkgerrors.Wrapf(err, "failed to load evm.receipts for evm.tx") } return nil @@ -2020,10 +1966,9 @@ func (o *evmTxStore) GetAllTxes(ctx context.Context) (txes []*Tx, err error) { var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) var dbEtxs []DbEthTx sql := "SELECT * FROM evm.txes" - err = qq.Select(&dbEtxs, sql) + err = o.q.SelectContext(ctx, &dbEtxs, sql) txes = make([]*Tx, len(dbEtxs)) dbEthTxsToEvmEthTxPtrs(dbEtxs, txes) return txes, err @@ -2034,10 +1979,9 @@ func (o *evmTxStore) GetAllTxAttempts(ctx context.Context) (attempts []TxAttempt var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) var dbAttempts []DbEthTxAttempt sql := "SELECT * FROM evm.tx_attempts" - err = qq.Select(&dbAttempts, sql) + err = o.q.SelectContext(ctx, &dbAttempts, sql) attempts = dbEthTxAttemptsToEthTxAttempts(dbAttempts) return attempts, err } @@ -2046,9 +1990,8 @@ func (o *evmTxStore) CountTxesByStateAndSubject(ctx context.Context, state txmgr var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) sql := "SELECT COUNT(*) FROM evm.txes WHERE state = $1 AND subject = $2" - err = qq.Get(&count, sql, state, subject) + err = o.q.GetContext(ctx, &count, sql, state, subject) return count, err } @@ -2056,10 +1999,9 @@ func (o *evmTxStore) FindTxesByFromAddressAndState(ctx context.Context, fromAddr var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) sql := "SELECT * FROM evm.txes WHERE from_address = $1 AND state = $2" var dbEtxs []DbEthTx - err = qq.Select(&dbEtxs, sql, fromAddress, state) + err = o.q.SelectContext(ctx, &dbEtxs, sql, fromAddress, state) txes = make([]*Tx, len(dbEtxs)) dbEthTxsToEvmEthTxPtrs(dbEtxs, txes) return txes, err @@ -2069,19 +2011,18 @@ func (o *evmTxStore) UpdateTxAttemptBroadcastBeforeBlockNum(ctx context.Context, var cancel context.CancelFunc ctx, cancel = o.mergeContexts(ctx) defer cancel() - qq := o.q.WithOpts(pg.WithParentCtx(ctx)) sql := "UPDATE evm.tx_attempts SET broadcast_before_block_num = $1 WHERE eth_tx_id = $2" - _, err := qq.Exec(sql, blockNum, id) + _, err := o.q.ExecContext(ctx, sql, blockNum, id) return err } // Returns a context that contains the values of the provided context, -// and which is canceled when either the provided contextg or TxStore parent context is canceled. +// and which is canceled when either the provided context or TxStore parent context is canceled. func (o *evmTxStore) mergeContexts(ctx context.Context) (context.Context, context.CancelFunc) { var cancel context.CancelCauseFunc ctx, cancel = context.WithCancelCause(ctx) - stop := context.AfterFunc(o.q.ParentCtx, func() { - cancel(context.Cause(o.q.ParentCtx)) + stop := context.AfterFunc(o.ctx, func() { + cancel(context.Cause(o.ctx)) }) return ctx, func() { stop() diff --git a/core/chains/evm/txmgr/evm_tx_store_test.go b/core/chains/evm/txmgr/evm_tx_store_test.go index 83d2381d007..4679ffd3339 100644 --- a/core/chains/evm/txmgr/evm_tx_store_test.go +++ b/core/chains/evm/txmgr/evm_tx_store_test.go @@ -9,6 +9,7 @@ import ( commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" @@ -22,7 +23,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/google/uuid" @@ -34,8 +34,9 @@ import ( func TestORM_TransactionsWithAttempts(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ctx := testutils.Context(t) _, from := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -48,7 +49,7 @@ func TestORM_TransactionsWithAttempts(t *testing.T) { attempt.State = txmgrtypes.TxAttemptBroadcast attempt.TxFee = gas.EvmFee{Legacy: assets.NewWeiI(3)} attempt.BroadcastBeforeBlockNum = &blockNum - require.NoError(t, txStore.InsertTxAttempt(&attempt)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt)) // tx 3 has no attempts mustCreateUnstartedGeneratedTx(t, txStore, from, &cltest.FixtureChainID) @@ -58,7 +59,7 @@ func TestORM_TransactionsWithAttempts(t *testing.T) { require.NoError(t, err) require.Equal(t, 3, count) - txs, count, err := txStore.TransactionsWithAttempts(0, 100) // should omit tx3 + txs, count, err := txStore.TransactionsWithAttempts(ctx, 0, 100) // should omit tx3 require.NoError(t, err) assert.Equal(t, 2, count, "only eth txs with attempts are counted") assert.Len(t, txs, 2) @@ -69,7 +70,7 @@ func TestORM_TransactionsWithAttempts(t *testing.T) { assert.Equal(t, int64(3), *txs[0].TxAttempts[0].BroadcastBeforeBlockNum, "attempts should be sorted by created_at") assert.Equal(t, int64(2), *txs[0].TxAttempts[1].BroadcastBeforeBlockNum, "attempts should be sorted by created_at") - txs, count, err = txStore.TransactionsWithAttempts(0, 1) + txs, count, err = txStore.TransactionsWithAttempts(ctx, 0, 1) require.NoError(t, err) assert.Equal(t, 2, count, "only eth txs with attempts are counted") assert.Len(t, txs, 1, "limit should apply to length of results") @@ -79,8 +80,9 @@ func TestORM_TransactionsWithAttempts(t *testing.T) { func TestORM_Transactions(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ctx := testutils.Context(t) _, from := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -93,7 +95,7 @@ func TestORM_Transactions(t *testing.T) { attempt.State = txmgrtypes.TxAttemptBroadcast attempt.TxFee = gas.EvmFee{Legacy: assets.NewWeiI(3)} attempt.BroadcastBeforeBlockNum = &blockNum - require.NoError(t, txStore.InsertTxAttempt(&attempt)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt)) // tx 3 has no attempts mustCreateUnstartedGeneratedTx(t, txStore, from, &cltest.FixtureChainID) @@ -103,7 +105,7 @@ func TestORM_Transactions(t *testing.T) { require.NoError(t, err) require.Equal(t, 3, count) - txs, count, err := txStore.Transactions(0, 100) + txs, count, err := txStore.Transactions(ctx, 0, 100) require.NoError(t, err) assert.Equal(t, 2, count, "only eth txs with attempts are counted") assert.Len(t, txs, 2) @@ -119,13 +121,14 @@ func TestORM(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) - orm := cltest.NewTestTxStore(t, db, cfg.Database()) + orm := cltest.NewTestTxStore(t, db) _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth()) + ctx := testutils.Context(t) var etx txmgr.Tx t.Run("InsertTx", func(t *testing.T) { etx = cltest.NewEthTx(fromAddress) - require.NoError(t, orm.InsertTx(&etx)) + require.NoError(t, orm.InsertTx(ctx, &etx)) assert.Greater(t, int(etx.ID), 0) cltest.AssertCount(t, db, "evm.txes", 1) }) @@ -133,21 +136,21 @@ func TestORM(t *testing.T) { var attemptD txmgr.TxAttempt t.Run("InsertTxAttempt", func(t *testing.T) { attemptD = cltest.NewDynamicFeeEthTxAttempt(t, etx.ID) - require.NoError(t, orm.InsertTxAttempt(&attemptD)) + require.NoError(t, orm.InsertTxAttempt(ctx, &attemptD)) assert.Greater(t, int(attemptD.ID), 0) cltest.AssertCount(t, db, "evm.tx_attempts", 1) attemptL = cltest.NewLegacyEthTxAttempt(t, etx.ID) attemptL.State = txmgrtypes.TxAttemptBroadcast attemptL.TxFee = gas.EvmFee{Legacy: assets.NewWeiI(42)} - require.NoError(t, orm.InsertTxAttempt(&attemptL)) + require.NoError(t, orm.InsertTxAttempt(ctx, &attemptL)) assert.Greater(t, int(attemptL.ID), 0) cltest.AssertCount(t, db, "evm.tx_attempts", 2) }) var r txmgr.Receipt t.Run("InsertReceipt", func(t *testing.T) { r = newEthReceipt(42, utils.NewHash(), attemptD.Hash, 0x1) - id, err := orm.InsertReceipt(&r.Receipt) + id, err := orm.InsertReceipt(ctx, &r.Receipt) r.ID = id require.NoError(t, err) assert.Greater(t, int(r.ID), 0) @@ -155,7 +158,7 @@ func TestORM(t *testing.T) { }) t.Run("FindTxWithAttempts", func(t *testing.T) { var err error - etx, err = orm.FindTxWithAttempts(etx.ID) + etx, err = orm.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) require.Len(t, etx.TxAttempts, 2) assert.Equal(t, etx.TxAttempts[0].ID, attemptD.ID) @@ -165,13 +168,13 @@ func TestORM(t *testing.T) { assert.Equal(t, r.BlockHash, etx.TxAttempts[0].Receipts[0].GetBlockHash()) }) t.Run("FindTxByHash", func(t *testing.T) { - foundEtx, err := orm.FindTxByHash(attemptD.Hash) + foundEtx, err := orm.FindTxByHash(ctx, attemptD.Hash) require.NoError(t, err) assert.Equal(t, etx.ID, foundEtx.ID) assert.Equal(t, etx.ChainID, foundEtx.ChainID) }) t.Run("FindTxAttemptsByTxIDs", func(t *testing.T) { - attempts, err := orm.FindTxAttemptsByTxIDs([]int64{etx.ID}) + attempts, err := orm.FindTxAttemptsByTxIDs(ctx, []int64{etx.ID}) require.NoError(t, err) require.Len(t, attempts, 2) assert.Equal(t, etx.TxAttempts[0].ID, attemptD.ID) @@ -185,8 +188,9 @@ func TestORM(t *testing.T) { func TestORM_FindTxAttemptConfirmedByTxIDs(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - orm := cltest.NewTestTxStore(t, db, cfg.Database()) + orm := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ctx := testutils.Context(t) _, from := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -199,13 +203,12 @@ func TestORM_FindTxAttemptConfirmedByTxIDs(t *testing.T) { attempt.State = txmgrtypes.TxAttemptBroadcast attempt.TxFee = gas.EvmFee{Legacy: assets.NewWeiI(3)} attempt.BroadcastBeforeBlockNum = &blockNum - require.NoError(t, orm.InsertTxAttempt(&attempt)) + require.NoError(t, orm.InsertTxAttempt(ctx, &attempt)) // add receipt for the second attempt r := newEthReceipt(4, utils.NewHash(), attempt.Hash, 0x1) - _, err := orm.InsertReceipt(&r.Receipt) + _, err := orm.InsertReceipt(ctx, &r.Receipt) require.NoError(t, err) - // tx 3 has no attempts mustCreateUnstartedGeneratedTx(t, orm, from, &cltest.FixtureChainID) @@ -221,7 +224,7 @@ func TestORM_FindTxAttemptConfirmedByTxIDs(t *testing.T) { require.NoError(t, err) require.Equal(t, 4, count) - confirmedAttempts, err := orm.FindTxAttemptConfirmedByTxIDs([]int64{tx1.ID, tx2.ID}) // should omit tx3 + confirmedAttempts, err := orm.FindTxAttemptConfirmedByTxIDs(ctx, []int64{tx1.ID, tx2.ID}) // should omit tx3 require.NoError(t, err) assert.Equal(t, 4, count, "only eth txs with attempts are counted") require.Len(t, confirmedAttempts, 1) @@ -236,7 +239,8 @@ func TestORM_FindTxAttemptsRequiringResend(t *testing.T) { db := pgtest.NewSqlxDB(t) logCfg := pgtest.NewQConfig(true) - txStore := cltest.NewTestTxStore(t, db, logCfg) + txStore := cltest.NewTestTxStore(t, db) + ctx := testutils.Context(t) ethKeyStore := cltest.NewKeyStore(t, db, logCfg).Eth() @@ -263,27 +267,27 @@ func TestORM_FindTxAttemptsRequiringResend(t *testing.T) { } attempt1_2 := newBroadcastLegacyEthTxAttempt(t, etxs[0].ID) attempt1_2.TxFee = gas.EvmFee{Legacy: assets.NewWeiI(10)} - require.NoError(t, txStore.InsertTxAttempt(&attempt1_2)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt1_2)) attempt3_2 := newInProgressLegacyEthTxAttempt(t, etxs[2].ID) attempt3_2.TxFee = gas.EvmFee{Legacy: assets.NewWeiI(10)} - require.NoError(t, txStore.InsertTxAttempt(&attempt3_2)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt3_2)) attempt4_2 := cltest.NewDynamicFeeEthTxAttempt(t, etxs[3].ID) attempt4_2.TxFee.DynamicTipCap = assets.NewWeiI(10) attempt4_2.TxFee.DynamicFeeCap = assets.NewWeiI(20) attempt4_2.State = txmgrtypes.TxAttemptBroadcast - require.NoError(t, txStore.InsertTxAttempt(&attempt4_2)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt4_2)) attempt4_4 := cltest.NewDynamicFeeEthTxAttempt(t, etxs[3].ID) attempt4_4.TxFee.DynamicTipCap = assets.NewWeiI(30) attempt4_4.TxFee.DynamicFeeCap = assets.NewWeiI(40) attempt4_4.State = txmgrtypes.TxAttemptBroadcast - require.NoError(t, txStore.InsertTxAttempt(&attempt4_4)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt4_4)) attempt4_3 := cltest.NewDynamicFeeEthTxAttempt(t, etxs[3].ID) attempt4_3.TxFee.DynamicTipCap = assets.NewWeiI(20) attempt4_3.TxFee.DynamicFeeCap = assets.NewWeiI(30) attempt4_3.State = txmgrtypes.TxAttemptBroadcast - require.NoError(t, txStore.InsertTxAttempt(&attempt4_3)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt4_3)) t.Run("returns nothing if there are transactions from a different key", func(t *testing.T) { olderThan := time.Now() @@ -324,12 +328,12 @@ func TestORM_UpdateBroadcastAts(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) - orm := cltest.NewTestTxStore(t, db, cfg.Database()) + orm := cltest.NewTestTxStore(t, db) _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth()) t.Run("does not update when broadcast_at is NULL", func(t *testing.T) { t.Parallel() - + ctx := testutils.Context(t) etx := mustCreateUnstartedGeneratedTx(t, orm, fromAddress, &cltest.FixtureChainID) var nullTime *time.Time @@ -338,7 +342,7 @@ func TestORM_UpdateBroadcastAts(t *testing.T) { currTime := time.Now() err := orm.UpdateBroadcastAts(testutils.Context(t), currTime, []int64{etx.ID}) require.NoError(t, err) - etx, err = orm.FindTxWithAttempts(etx.ID) + etx, err = orm.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.Equal(t, nullTime, etx.BroadcastAt) @@ -347,19 +351,20 @@ func TestORM_UpdateBroadcastAts(t *testing.T) { t.Run("updates when broadcast_at is non-NULL", func(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) time1 := time.Now() etx := cltest.NewEthTx(fromAddress) etx.Sequence = new(evmtypes.Nonce) etx.State = txmgrcommon.TxUnconfirmed etx.BroadcastAt = &time1 etx.InitialBroadcastAt = &time1 - err := orm.InsertTx(&etx) + err := orm.InsertTx(ctx, &etx) require.NoError(t, err) time2 := time.Date(2077, 8, 14, 10, 0, 0, 0, time.UTC) - err = orm.UpdateBroadcastAts(testutils.Context(t), time2, []int64{etx.ID}) + err = orm.UpdateBroadcastAts(ctx, time2, []int64{etx.ID}) require.NoError(t, err) - etx, err = orm.FindTxWithAttempts(etx.ID) + etx, err = orm.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) // assert year due to time rounding after database save assert.Equal(t, etx.BroadcastAt.Year(), time2.Year()) @@ -371,12 +376,13 @@ func TestORM_SetBroadcastBeforeBlockNum(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, fromAddress) chainID := ethClient.ConfiguredChainID() + ctx := testutils.Context(t) headNum := int64(9000) var err error @@ -385,7 +391,7 @@ func TestORM_SetBroadcastBeforeBlockNum(t *testing.T) { // Do the thing require.NoError(t, txStore.SetBroadcastBeforeBlockNum(testutils.Context(t), headNum, chainID)) - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) require.Len(t, etx.TxAttempts, 1) attempt := etx.TxAttempts[0] @@ -397,12 +403,12 @@ func TestORM_SetBroadcastBeforeBlockNum(t *testing.T) { n := int64(42) attempt := newBroadcastLegacyEthTxAttempt(t, etx.ID, 2) attempt.BroadcastBeforeBlockNum = &n - require.NoError(t, txStore.InsertTxAttempt(&attempt)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt)) // Do the thing require.NoError(t, txStore.SetBroadcastBeforeBlockNum(testutils.Context(t), headNum, chainID)) - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) require.Len(t, etx.TxAttempts, 2) attempt = etx.TxAttempts[0] @@ -418,14 +424,14 @@ func TestORM_SetBroadcastBeforeBlockNum(t *testing.T) { require.NoError(t, txStore.SetBroadcastBeforeBlockNum(testutils.Context(t), headNum, chainID)) - etxThisChain, err = txStore.FindTxWithAttempts(etxThisChain.ID) + etxThisChain, err = txStore.FindTxWithAttempts(ctx, etxThisChain.ID) require.NoError(t, err) require.Len(t, etxThisChain.TxAttempts, 1) attempt := etxThisChain.TxAttempts[0] assert.Equal(t, int64(9000), *attempt.BroadcastBeforeBlockNum) - etxOtherChain, err = txStore.FindTxWithAttempts(etxOtherChain.ID) + etxOtherChain, err = txStore.FindTxWithAttempts(ctx, etxOtherChain.ID) require.NoError(t, err) require.Len(t, etxOtherChain.TxAttempts, 1) attempt = etxOtherChain.TxAttempts[0] @@ -439,7 +445,7 @@ func TestORM_FindTxAttemptsConfirmedMissingReceipt(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -460,9 +466,10 @@ func TestORM_FindTxAttemptsConfirmedMissingReceipt(t *testing.T) { func TestORM_UpdateTxsUnconfirmed(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -472,7 +479,7 @@ func TestORM_UpdateTxsUnconfirmed(t *testing.T) { assert.Equal(t, etx0.State, txmgrcommon.TxConfirmedMissingReceipt) require.NoError(t, txStore.UpdateTxsUnconfirmed(testutils.Context(t), []int64{etx0.ID})) - etx0, err := txStore.FindTxWithAttempts(etx0.ID) + etx0, err := txStore.FindTxWithAttempts(ctx, etx0.ID) require.NoError(t, err) assert.Equal(t, etx0.State, txmgrcommon.TxUnconfirmed) } @@ -482,7 +489,7 @@ func TestORM_FindTxAttemptsRequiringReceiptFetch(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -503,10 +510,11 @@ func TestORM_SaveFetchedReceipts(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + ctx := testutils.Context(t) originalBroadcastAt := time.Unix(1616509100, 0) etx0 := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( @@ -524,7 +532,7 @@ func TestORM_SaveFetchedReceipts(t *testing.T) { err := txStore.SaveFetchedReceipts(testutils.Context(t), []*evmtypes.Receipt{&txmReceipt}, ethClient.ConfiguredChainID()) require.NoError(t, err) - etx0, err = txStore.FindTxWithAttempts(etx0.ID) + etx0, err = txStore.FindTxWithAttempts(ctx, etx0.ID) require.NoError(t, err) require.Len(t, etx0.TxAttempts, 1) require.Len(t, etx0.TxAttempts[0].Receipts, 1) @@ -537,17 +545,18 @@ func TestORM_MarkAllConfirmedMissingReceipt(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + ctx := testutils.Context(t) // create transaction 0 (nonce 0) that is unconfirmed (block 7) etx0_blocknum := int64(7) etx0 := cltest.MustInsertUnconfirmedEthTx(t, txStore, 0, fromAddress) etx0_attempt := newBroadcastLegacyEthTxAttempt(t, etx0.ID, int64(1)) etx0_attempt.BroadcastBeforeBlockNum = &etx0_blocknum - require.NoError(t, txStore.InsertTxAttempt(&etx0_attempt)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &etx0_attempt)) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx0.State) // create transaction 1 (nonce 1) that is confirmed (block 77) @@ -557,7 +566,7 @@ func TestORM_MarkAllConfirmedMissingReceipt(t *testing.T) { // mark transaction 0 confirmed_missing_receipt err := txStore.MarkAllConfirmedMissingReceipt(testutils.Context(t), ethClient.ConfiguredChainID()) require.NoError(t, err) - etx0, err = txStore.FindTxWithAttempts(etx0.ID) + etx0, err = txStore.FindTxWithAttempts(ctx, etx0.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxConfirmedMissingReceipt, etx0.State) } @@ -567,7 +576,7 @@ func TestORM_PreloadTxes(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -601,7 +610,7 @@ func TestORM_GetInProgressTxAttempts(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -622,7 +631,7 @@ func TestORM_FindTxesPendingCallback(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -695,7 +704,7 @@ func Test_FindTxWithIdempotencyKey(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -725,7 +734,7 @@ func TestORM_FindTxWithSequence(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -750,13 +759,14 @@ func TestORM_UpdateTxForRebroadcast(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + ctx := testutils.Context(t) t.Run("delete all receipts for eth transaction", func(t *testing.T) { etx := mustInsertConfirmedEthTxWithReceipt(t, txStore, fromAddress, 777, 1) - etx, err := txStore.FindTxWithAttempts(etx.ID) + etx, err := txStore.FindTxWithAttempts(ctx, etx.ID) assert.NoError(t, err) // assert attempt state attempt := etx.TxAttempts[0] @@ -770,7 +780,7 @@ func TestORM_UpdateTxForRebroadcast(t *testing.T) { err = txStore.UpdateTxForRebroadcast(testutils.Context(t), etx, attempt) require.NoError(t, err) - resultTx, err := txStore.FindTxWithAttempts(etx.ID) + resultTx, err := txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) require.Len(t, resultTx.TxAttempts, 1) resultTxAttempt := resultTx.TxAttempts[0] @@ -789,8 +799,7 @@ func TestORM_IsTxFinalized(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) t.Run("confirmed tx not past finality_depth", func(t *testing.T) { @@ -815,7 +824,7 @@ func TestORM_FindTransactionsConfirmedInBlockRange(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -851,7 +860,7 @@ func TestORM_FindEarliestUnconfirmedBroadcastTime(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -875,7 +884,7 @@ func TestORM_FindEarliestUnconfirmedTxAttemptBlock(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -904,9 +913,10 @@ func TestORM_FindEarliestUnconfirmedTxAttemptBlock(t *testing.T) { func TestORM_SaveInsufficientEthAttempt(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) defaultDuration, err := time.ParseDuration("5s") @@ -919,7 +929,7 @@ func TestORM_SaveInsufficientEthAttempt(t *testing.T) { err = txStore.SaveInsufficientFundsAttempt(testutils.Context(t), defaultDuration, &etx.TxAttempts[0], now) require.NoError(t, err) - attempt, err := txStore.FindTxAttempt(etx.TxAttempts[0].Hash) + attempt, err := txStore.FindTxAttempt(ctx, etx.TxAttempts[0].Hash) require.NoError(t, err) assert.Equal(t, txmgrtypes.TxAttemptInsufficientFunds, attempt.State) }) @@ -928,9 +938,10 @@ func TestORM_SaveInsufficientEthAttempt(t *testing.T) { func TestORM_SaveSentAttempt(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) defaultDuration, err := time.ParseDuration("5s") @@ -944,7 +955,7 @@ func TestORM_SaveSentAttempt(t *testing.T) { err = txStore.SaveSentAttempt(testutils.Context(t), defaultDuration, &etx.TxAttempts[0], now) require.NoError(t, err) - attempt, err := txStore.FindTxAttempt(etx.TxAttempts[0].Hash) + attempt, err := txStore.FindTxAttempt(ctx, etx.TxAttempts[0].Hash) require.NoError(t, err) assert.Equal(t, txmgrtypes.TxAttemptBroadcast, attempt.State) }) @@ -953,9 +964,10 @@ func TestORM_SaveSentAttempt(t *testing.T) { func TestORM_SaveConfirmedMissingReceiptAttempt(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) defaultDuration, err := time.ParseDuration("5s") @@ -968,7 +980,7 @@ func TestORM_SaveConfirmedMissingReceiptAttempt(t *testing.T) { err = txStore.SaveConfirmedMissingReceiptAttempt(testutils.Context(t), defaultDuration, &etx.TxAttempts[0], now) require.NoError(t, err) - etx, err := txStore.FindTxWithAttempts(etx.ID) + etx, err := txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxConfirmedMissingReceipt, etx.State) assert.Equal(t, txmgrtypes.TxAttemptBroadcast, etx.TxAttempts[0].State) @@ -978,9 +990,10 @@ func TestORM_SaveConfirmedMissingReceiptAttempt(t *testing.T) { func TestORM_DeleteInProgressAttempt(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -991,7 +1004,7 @@ func TestORM_DeleteInProgressAttempt(t *testing.T) { err := txStore.DeleteInProgressAttempt(testutils.Context(t), etx.TxAttempts[0]) require.NoError(t, err) - nilResult, err := txStore.FindTxAttempt(attempt.Hash) + nilResult, err := txStore.FindTxAttempt(ctx, attempt.Hash) assert.Nil(t, nilResult) require.Error(t, err) }) @@ -1000,9 +1013,10 @@ func TestORM_DeleteInProgressAttempt(t *testing.T) { func TestORM_SaveInProgressAttempt(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1015,7 +1029,7 @@ func TestORM_SaveInProgressAttempt(t *testing.T) { err := txStore.SaveInProgressAttempt(testutils.Context(t), &attempt) require.NoError(t, err) - attemptResult, err := txStore.FindTxAttempt(attempt.Hash) + attemptResult, err := txStore.FindTxAttempt(ctx, attempt.Hash) require.NoError(t, err) assert.Equal(t, txmgrtypes.TxAttemptInProgress, attemptResult.State) }) @@ -1031,7 +1045,7 @@ func TestORM_SaveInProgressAttempt(t *testing.T) { err := txStore.SaveInProgressAttempt(testutils.Context(t), &attempt) require.NoError(t, err) - attemptResult, err := txStore.FindTxAttempt(attempt.Hash) + attemptResult, err := txStore.FindTxAttempt(ctx, attempt.Hash) require.NoError(t, err) assert.Equal(t, txmgrtypes.TxAttemptInProgress, attemptResult.State) @@ -1041,9 +1055,10 @@ func TestORM_SaveInProgressAttempt(t *testing.T) { func TestORM_FindTxsRequiringGasBump(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1056,7 +1071,7 @@ func TestORM_FindTxsRequiringGasBump(t *testing.T) { require.NoError(t, err) // this tx will require gas bump - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) attempts := etx.TxAttempts require.NoError(t, err) assert.Len(t, attempts, 1) @@ -1083,7 +1098,8 @@ func TestEthConfirmer_FindTxsRequiringResubmissionDueToInsufficientEth(t *testin db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) + ctx := testutils.Context(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() @@ -1096,7 +1112,7 @@ func TestEthConfirmer_FindTxsRequiringResubmissionDueToInsufficientEth(t *testin attempt3_2 := cltest.NewLegacyEthTxAttempt(t, etx3.ID) attempt3_2.State = txmgrtypes.TxAttemptInsufficientFunds attempt3_2.TxFee.Legacy = assets.NewWeiI(100) - require.NoError(t, txStore.InsertTxAttempt(&attempt3_2)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt3_2)) etx1 := mustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 0, fromAddress) // These should never be returned @@ -1144,7 +1160,8 @@ func TestORM_MarkOldTxesMissingReceiptAsErrored(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) + ctx := testutils.Context(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1157,7 +1174,7 @@ func TestORM_MarkOldTxesMissingReceiptAsErrored(t *testing.T) { err := txStore.MarkOldTxesMissingReceiptAsErrored(testutils.Context(t), 10, 2, ethClient.ConfiguredChainID()) require.NoError(t, err) - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxFatalError, etx.State) }) @@ -1168,7 +1185,7 @@ func TestORM_MarkOldTxesMissingReceiptAsErrored(t *testing.T) { require.NoError(t, err) // must run other query outside of postgres transaction so changes are committed - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxFatalError, etx.State) }) @@ -1177,9 +1194,10 @@ func TestORM_MarkOldTxesMissingReceiptAsErrored(t *testing.T) { func TestORM_LoadEthTxesAttempts(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1187,37 +1205,41 @@ func TestORM_LoadEthTxesAttempts(t *testing.T) { etx := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt(t, txStore, 1, 7, time.Now(), fromAddress) etx.TxAttempts = []txmgr.TxAttempt{} - err := txStore.LoadTxesAttempts([]*txmgr.Tx{&etx}) + err := txStore.LoadTxesAttempts(ctx, []*txmgr.Tx{&etx}) require.NoError(t, err) assert.Len(t, etx.TxAttempts, 1) }) t.Run("load new attempt inserted in current postgres transaction", func(t *testing.T) { etx := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt(t, txStore, 3, 9, time.Now(), fromAddress) - etx.TxAttempts = []txmgr.TxAttempt{} - - q := pg.NewQ(db, logger.Test(t), cfg.Database()) - newAttempt := cltest.NewDynamicFeeEthTxAttempt(t, etx.ID) var dbAttempt txmgr.DbEthTxAttempt dbAttempt.FromTxAttempt(&newAttempt) - err := q.Transaction(func(tx pg.Queryer) error { + + func() { + tx, err := db.BeginTx(ctx, nil) + require.NoError(t, err) + const insertEthTxAttemptSQL = `INSERT INTO evm.tx_attempts (eth_tx_id, gas_price, signed_raw_tx, hash, broadcast_before_block_num, state, created_at, chain_specific_gas_limit, tx_type, gas_tip_cap, gas_fee_cap) VALUES ( - :eth_tx_id, :gas_price, :signed_raw_tx, :hash, :broadcast_before_block_num, :state, NOW(), :chain_specific_gas_limit, :tx_type, :gas_tip_cap, :gas_fee_cap - ) RETURNING *` - _, err := tx.NamedExec(insertEthTxAttemptSQL, dbAttempt) + :eth_tx_id, :gas_price, :signed_raw_tx, :hash, :broadcast_before_block_num, :state, NOW(), :chain_specific_gas_limit, :tx_type, :gas_tip_cap, :gas_fee_cap + ) RETURNING *` + query, args, err := sqlutil.DataSource(db).BindNamed(insertEthTxAttemptSQL, dbAttempt) + require.NoError(t, err) + _, err = tx.ExecContext(ctx, query, args...) require.NoError(t, err) - err = txStore.LoadTxesAttempts([]*txmgr.Tx{&etx}, pg.WithQueryer(tx)) + etx.TxAttempts = []txmgr.TxAttempt{} + err = txStore.LoadTxesAttempts(ctx, []*txmgr.Tx{&etx}) require.NoError(t, err) assert.Len(t, etx.TxAttempts, 2) - return nil - }) - require.NoError(t, err) + err = tx.Commit() + require.NoError(t, err) + }() + // also check after postgres transaction is committed etx.TxAttempts = []txmgr.TxAttempt{} - err = txStore.LoadTxesAttempts([]*txmgr.Tx{&etx}) + err := txStore.LoadTxesAttempts(ctx, []*txmgr.Tx{&etx}) require.NoError(t, err) assert.Len(t, etx.TxAttempts, 2) }) @@ -1226,9 +1248,10 @@ func TestORM_LoadEthTxesAttempts(t *testing.T) { func TestORM_SaveReplacementInProgressAttempt(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1240,7 +1263,7 @@ func TestORM_SaveReplacementInProgressAttempt(t *testing.T) { err := txStore.SaveReplacementInProgressAttempt(testutils.Context(t), oldAttempt, &newAttempt) require.NoError(t, err) - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.Len(t, etx.TxAttempts, 1) require.Equal(t, etx.TxAttempts[0].Hash, newAttempt.Hash) @@ -1252,7 +1275,7 @@ func TestORM_FindNextUnstartedTransactionFromAddress(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) @@ -1277,9 +1300,10 @@ func TestORM_FindNextUnstartedTransactionFromAddress(t *testing.T) { func TestORM_UpdateTxFatalError(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1291,7 +1315,7 @@ func TestORM_UpdateTxFatalError(t *testing.T) { err := txStore.UpdateTxFatalError(testutils.Context(t), &etx) require.NoError(t, err) - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.Len(t, etx.TxAttempts, 0) assert.Equal(t, txmgrcommon.TxFatalError, etx.State) @@ -1301,9 +1325,10 @@ func TestORM_UpdateTxFatalError(t *testing.T) { func TestORM_UpdateTxAttemptInProgressToBroadcast(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1321,7 +1346,7 @@ func TestORM_UpdateTxAttemptInProgressToBroadcast(t *testing.T) { // Increment sequence i++ - attemptResult, err := txStore.FindTxAttempt(attempt.Hash) + attemptResult, err := txStore.FindTxAttempt(ctx, attempt.Hash) require.NoError(t, err) require.Equal(t, attempt.Hash, attemptResult.Hash) assert.Equal(t, txmgrtypes.TxAttemptBroadcast, attemptResult.State) @@ -1332,12 +1357,12 @@ func TestORM_UpdateTxAttemptInProgressToBroadcast(t *testing.T) { func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) - q := pg.NewQ(db, logger.Test(t), cfg.Database()) nonce := evmtypes.Nonce(123) t.Run("update successful", func(t *testing.T) { @@ -1348,7 +1373,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { err := txStore.UpdateTxUnstartedToInProgress(testutils.Context(t), &etx, &attempt) require.NoError(t, err) - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxInProgress, etx.State) assert.Len(t, etx.TxAttempts, 1) @@ -1360,7 +1385,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { attempt := cltest.NewLegacyEthTxAttempt(t, etx.ID) - err := q.ExecQ("DELETE FROM evm.txes WHERE id = $1", etx.ID) + _, err := db.ExecContext(ctx, "DELETE FROM evm.txes WHERE id = $1", etx.ID) require.NoError(t, err) err = txStore.UpdateTxUnstartedToInProgress(testutils.Context(t), &etx, &attempt) @@ -1369,10 +1394,9 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { db = pgtest.NewSqlxDB(t) cfg = newTestChainScopedConfig(t) - txStore = cltest.NewTestTxStore(t, db, cfg.Database()) + txStore = cltest.NewTestTxStore(t, db) ethKeyStore = cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress = cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) - q = pg.NewQ(db, logger.Test(t), cfg.Database()) t.Run("update replaces abandoned tx with same hash", func(t *testing.T) { etx := mustInsertInProgressEthTxWithAttempt(t, txStore, nonce, fromAddress) @@ -1389,7 +1413,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { evmTxmCfg := txmgr.NewEvmTxmConfig(ccfg.EVM()) ec := evmtest.NewEthClientMockWithDefaultChain(t) txMgr := txmgr.NewEvmTxm(ec.ConfiguredChainID(), evmTxmCfg, ccfg.EVM().Transactions(), nil, logger.Test(t), nil, nil, - nil, txStore, nil, nil, nil, nil, nil) + nil, txStore, nil, nil, nil, nil) err := txMgr.XXXTestAbandon(fromAddress) // mark transaction as abandoned require.NoError(t, err) @@ -1416,7 +1440,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { // Should fail due to idx_eth_tx_attempt_hash constraint err := txStore.UpdateTxUnstartedToInProgress(testutils.Context(t), &etx, &etx.TxAttempts[0]) assert.ErrorContains(t, err, "idx_eth_tx_attempts_hash") - txStore = cltest.NewTestTxStore(t, db, cfg.Database()) // current txStore is poisened now, next test will need fresh one + txStore = cltest.NewTestTxStore(t, db) // current txStore is poisened now, next test will need fresh one }) } @@ -1425,7 +1449,7 @@ func TestORM_GetTxInProgress(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1449,7 +1473,7 @@ func TestORM_GetNonFatalTransactions(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1478,7 +1502,7 @@ func TestORM_GetTxByID(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1501,7 +1525,7 @@ func TestORM_GetFatalTransactions(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1524,7 +1548,7 @@ func TestORM_HasInProgressTransaction(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1549,7 +1573,7 @@ func TestORM_CountUnconfirmedTransactions(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -1570,7 +1594,7 @@ func TestORM_CountTransactionsByState(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress1 := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -1591,7 +1615,7 @@ func TestORM_CountUnstartedTransactions(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -1612,7 +1636,7 @@ func TestORM_CheckTxQueueCapacity(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -1708,7 +1732,7 @@ func TestORM_CreateTransaction(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - txStore := newTxStore(t, db, cfg.Database()) + txStore := newTxStore(t, db) kst := cltest.NewKeyStore(t, db, cfg.Database()) _, fromAddress := cltest.MustInsertRandomKey(t, kst.Eth()) @@ -1808,7 +1832,7 @@ func TestORM_PruneUnstartedTxQueue(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := txmgr.NewTxStore(db, logger.Test(t), cfg.Database()) + txStore := txmgr.NewTxStore(db, logger.Test(t)) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) diff --git a/core/chains/evm/txmgr/mocks/evm_tx_store.go b/core/chains/evm/txmgr/mocks/evm_tx_store.go index 9f1af016fea..61c948c1ff4 100644 --- a/core/chains/evm/txmgr/mocks/evm_tx_store.go +++ b/core/chains/evm/txmgr/mocks/evm_tx_store.go @@ -343,9 +343,9 @@ func (_m *EvmTxStore) FindTransactionsConfirmedInBlockRange(ctx context.Context, return r0, r1 } -// FindTxAttempt provides a mock function with given fields: hash -func (_m *EvmTxStore) FindTxAttempt(hash common.Hash) (*types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { - ret := _m.Called(hash) +// FindTxAttempt provides a mock function with given fields: ctx, hash +func (_m *EvmTxStore) FindTxAttempt(ctx context.Context, hash common.Hash) (*types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { + ret := _m.Called(ctx, hash) if len(ret) == 0 { panic("no return value specified for FindTxAttempt") @@ -353,19 +353,19 @@ func (_m *EvmTxStore) FindTxAttempt(hash common.Hash) (*types.TxAttempt[*big.Int var r0 *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error - if rf, ok := ret.Get(0).(func(common.Hash) (*types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { - return rf(hash) + if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { + return rf(ctx, hash) } - if rf, ok := ret.Get(0).(func(common.Hash) *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { - r0 = rf(hash) + if rf, ok := ret.Get(0).(func(context.Context, common.Hash) *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, hash) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) } } - if rf, ok := ret.Get(1).(func(common.Hash) error); ok { - r1 = rf(hash) + if rf, ok := ret.Get(1).(func(context.Context, common.Hash) error); ok { + r1 = rf(ctx, hash) } else { r1 = ret.Error(1) } @@ -373,9 +373,9 @@ func (_m *EvmTxStore) FindTxAttempt(hash common.Hash) (*types.TxAttempt[*big.Int return r0, r1 } -// FindTxAttemptConfirmedByTxIDs provides a mock function with given fields: ids -func (_m *EvmTxStore) FindTxAttemptConfirmedByTxIDs(ids []int64) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { - ret := _m.Called(ids) +// FindTxAttemptConfirmedByTxIDs provides a mock function with given fields: ctx, ids +func (_m *EvmTxStore) FindTxAttemptConfirmedByTxIDs(ctx context.Context, ids []int64) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { + ret := _m.Called(ctx, ids) if len(ret) == 0 { panic("no return value specified for FindTxAttemptConfirmedByTxIDs") @@ -383,19 +383,19 @@ func (_m *EvmTxStore) FindTxAttemptConfirmedByTxIDs(ids []int64) ([]types.TxAtte var r0 []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error - if rf, ok := ret.Get(0).(func([]int64) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { - return rf(ids) + if rf, ok := ret.Get(0).(func(context.Context, []int64) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { + return rf(ctx, ids) } - if rf, ok := ret.Get(0).(func([]int64) []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { - r0 = rf(ids) + if rf, ok := ret.Get(0).(func(context.Context, []int64) []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, ids) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) } } - if rf, ok := ret.Get(1).(func([]int64) error); ok { - r1 = rf(ids) + if rf, ok := ret.Get(1).(func(context.Context, []int64) error); ok { + r1 = rf(ctx, ids) } else { r1 = ret.Error(1) } @@ -493,9 +493,9 @@ func (_m *EvmTxStore) FindTxAttemptsRequiringResend(ctx context.Context, olderTh return r0, r1 } -// FindTxByHash provides a mock function with given fields: hash -func (_m *EvmTxStore) FindTxByHash(hash common.Hash) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { - ret := _m.Called(hash) +// FindTxByHash provides a mock function with given fields: ctx, hash +func (_m *EvmTxStore) FindTxByHash(ctx context.Context, hash common.Hash) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { + ret := _m.Called(ctx, hash) if len(ret) == 0 { panic("no return value specified for FindTxByHash") @@ -503,19 +503,19 @@ func (_m *EvmTxStore) FindTxByHash(hash common.Hash) (*types.Tx[*big.Int, common var r0 *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error - if rf, ok := ret.Get(0).(func(common.Hash) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { - return rf(hash) + if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { + return rf(ctx, hash) } - if rf, ok := ret.Get(0).(func(common.Hash) *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { - r0 = rf(hash) + if rf, ok := ret.Get(0).(func(context.Context, common.Hash) *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, hash) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) } } - if rf, ok := ret.Get(1).(func(common.Hash) error); ok { - r1 = rf(hash) + if rf, ok := ret.Get(1).(func(context.Context, common.Hash) error); ok { + r1 = rf(ctx, hash) } else { r1 = ret.Error(1) } @@ -523,9 +523,9 @@ func (_m *EvmTxStore) FindTxByHash(hash common.Hash) (*types.Tx[*big.Int, common return r0, r1 } -// FindTxWithAttempts provides a mock function with given fields: etxID -func (_m *EvmTxStore) FindTxWithAttempts(etxID int64) (types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { - ret := _m.Called(etxID) +// FindTxWithAttempts provides a mock function with given fields: ctx, etxID +func (_m *EvmTxStore) FindTxWithAttempts(ctx context.Context, etxID int64) (types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { + ret := _m.Called(ctx, etxID) if len(ret) == 0 { panic("no return value specified for FindTxWithAttempts") @@ -533,17 +533,17 @@ func (_m *EvmTxStore) FindTxWithAttempts(etxID int64) (types.Tx[*big.Int, common var r0 types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error - if rf, ok := ret.Get(0).(func(int64) (types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { - return rf(etxID) + if rf, ok := ret.Get(0).(func(context.Context, int64) (types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { + return rf(ctx, etxID) } - if rf, ok := ret.Get(0).(func(int64) types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { - r0 = rf(etxID) + if rf, ok := ret.Get(0).(func(context.Context, int64) types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, etxID) } else { r0 = ret.Get(0).(types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) } - if rf, ok := ret.Get(1).(func(int64) error); ok { - r1 = rf(etxID) + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, etxID) } else { r1 = ret.Error(1) } @@ -1243,9 +1243,9 @@ func (_m *EvmTxStore) SetBroadcastBeforeBlockNum(ctx context.Context, blockNum i return r0 } -// Transactions provides a mock function with given fields: offset, limit -func (_m *EvmTxStore) Transactions(offset int, limit int) ([]types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], int, error) { - ret := _m.Called(offset, limit) +// Transactions provides a mock function with given fields: ctx, offset, limit +func (_m *EvmTxStore) Transactions(ctx context.Context, offset int, limit int) ([]types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], int, error) { + ret := _m.Called(ctx, offset, limit) if len(ret) == 0 { panic("no return value specified for Transactions") @@ -1254,25 +1254,25 @@ func (_m *EvmTxStore) Transactions(offset int, limit int) ([]types.Tx[*big.Int, var r0 []types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 int var r2 error - if rf, ok := ret.Get(0).(func(int, int) ([]types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], int, error)); ok { - return rf(offset, limit) + if rf, ok := ret.Get(0).(func(context.Context, int, int) ([]types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], int, error)); ok { + return rf(ctx, offset, limit) } - if rf, ok := ret.Get(0).(func(int, int) []types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { - r0 = rf(offset, limit) + if rf, ok := ret.Get(0).(func(context.Context, int, int) []types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, offset, limit) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) } } - if rf, ok := ret.Get(1).(func(int, int) int); ok { - r1 = rf(offset, limit) + if rf, ok := ret.Get(1).(func(context.Context, int, int) int); ok { + r1 = rf(ctx, offset, limit) } else { r1 = ret.Get(1).(int) } - if rf, ok := ret.Get(2).(func(int, int) error); ok { - r2 = rf(offset, limit) + if rf, ok := ret.Get(2).(func(context.Context, int, int) error); ok { + r2 = rf(ctx, offset, limit) } else { r2 = ret.Error(2) } @@ -1280,9 +1280,9 @@ func (_m *EvmTxStore) Transactions(offset int, limit int) ([]types.Tx[*big.Int, return r0, r1, r2 } -// TransactionsWithAttempts provides a mock function with given fields: offset, limit -func (_m *EvmTxStore) TransactionsWithAttempts(offset int, limit int) ([]types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], int, error) { - ret := _m.Called(offset, limit) +// TransactionsWithAttempts provides a mock function with given fields: ctx, offset, limit +func (_m *EvmTxStore) TransactionsWithAttempts(ctx context.Context, offset int, limit int) ([]types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], int, error) { + ret := _m.Called(ctx, offset, limit) if len(ret) == 0 { panic("no return value specified for TransactionsWithAttempts") @@ -1291,25 +1291,25 @@ func (_m *EvmTxStore) TransactionsWithAttempts(offset int, limit int) ([]types.T var r0 []types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 int var r2 error - if rf, ok := ret.Get(0).(func(int, int) ([]types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], int, error)); ok { - return rf(offset, limit) + if rf, ok := ret.Get(0).(func(context.Context, int, int) ([]types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], int, error)); ok { + return rf(ctx, offset, limit) } - if rf, ok := ret.Get(0).(func(int, int) []types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { - r0 = rf(offset, limit) + if rf, ok := ret.Get(0).(func(context.Context, int, int) []types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, offset, limit) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) } } - if rf, ok := ret.Get(1).(func(int, int) int); ok { - r1 = rf(offset, limit) + if rf, ok := ret.Get(1).(func(context.Context, int, int) int); ok { + r1 = rf(ctx, offset, limit) } else { r1 = ret.Get(1).(int) } - if rf, ok := ret.Get(2).(func(int, int) error); ok { - r2 = rf(offset, limit) + if rf, ok := ret.Get(2).(func(context.Context, int, int) error); ok { + r2 = rf(ctx, offset, limit) } else { r2 = ret.Error(2) } @@ -1317,9 +1317,9 @@ func (_m *EvmTxStore) TransactionsWithAttempts(offset int, limit int) ([]types.T return r0, r1, r2 } -// TxAttempts provides a mock function with given fields: offset, limit -func (_m *EvmTxStore) TxAttempts(offset int, limit int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], int, error) { - ret := _m.Called(offset, limit) +// TxAttempts provides a mock function with given fields: ctx, offset, limit +func (_m *EvmTxStore) TxAttempts(ctx context.Context, offset int, limit int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], int, error) { + ret := _m.Called(ctx, offset, limit) if len(ret) == 0 { panic("no return value specified for TxAttempts") @@ -1328,25 +1328,25 @@ func (_m *EvmTxStore) TxAttempts(offset int, limit int) ([]types.TxAttempt[*big. var r0 []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 int var r2 error - if rf, ok := ret.Get(0).(func(int, int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], int, error)); ok { - return rf(offset, limit) + if rf, ok := ret.Get(0).(func(context.Context, int, int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], int, error)); ok { + return rf(ctx, offset, limit) } - if rf, ok := ret.Get(0).(func(int, int) []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { - r0 = rf(offset, limit) + if rf, ok := ret.Get(0).(func(context.Context, int, int) []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, offset, limit) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) } } - if rf, ok := ret.Get(1).(func(int, int) int); ok { - r1 = rf(offset, limit) + if rf, ok := ret.Get(1).(func(context.Context, int, int) int); ok { + r1 = rf(ctx, offset, limit) } else { r1 = ret.Get(1).(int) } - if rf, ok := ret.Get(2).(func(int, int) error); ok { - r2 = rf(offset, limit) + if rf, ok := ret.Get(2).(func(context.Context, int, int) error); ok { + r2 = rf(ctx, offset, limit) } else { r2 = ret.Error(2) } diff --git a/core/chains/evm/txmgr/models.go b/core/chains/evm/txmgr/models.go index 4c622ec945a..be06f5dd5e9 100644 --- a/core/chains/evm/txmgr/models.go +++ b/core/chains/evm/txmgr/models.go @@ -11,8 +11,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/keystore" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ) // Type aliases for EVM @@ -26,7 +26,7 @@ type ( TransactionStore = txmgrtypes.TransactionStore[common.Address, *big.Int, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] KeyStore = txmgrtypes.KeyStore[common.Address, *big.Int, evmtypes.Nonce] TxAttemptBuilder = txmgrtypes.TxAttemptBuilder[*big.Int, *evmtypes.Head, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] - NonceSyncer = txmgr.SequenceSyncer[common.Address, common.Hash, common.Hash, evmtypes.Nonce] + NonceTracker = txmgrtypes.SequenceTracker[common.Address, evmtypes.Nonce] TransmitCheckerFactory = txmgr.TransmitCheckerFactory[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] Txm = txmgr.Txm[*big.Int, *evmtypes.Head, common.Address, common.Hash, common.Hash, *evmtypes.Receipt, evmtypes.Nonce, gas.EvmFee] TxManager = txmgr.TxManager[*big.Int, *evmtypes.Head, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] diff --git a/core/chains/evm/txmgr/nonce_syncer.go b/core/chains/evm/txmgr/nonce_syncer.go deleted file mode 100644 index 0cb52a1321e..00000000000 --- a/core/chains/evm/txmgr/nonce_syncer.go +++ /dev/null @@ -1,106 +0,0 @@ -package txmgr - -import ( - "context" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/common" - pkgerrors "github.com/pkg/errors" - - "github.com/smartcontractkit/chainlink-common/pkg/logger" - "github.com/smartcontractkit/chainlink/v2/common/txmgr" - evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" -) - -// NonceSyncer manages the delicate task of syncing the local nonce with the -// chain nonce in case of divergence. -// -// On startup, we check each key for the nonce value on chain and compare -// it to our local value. -// -// Usually the on-chain nonce will be the same as (or lower than) the -// highest sequence in the DB, in which case we do nothing. -// -// If we are restoring from a backup however, or another wallet has used the -// account, the chain nonce might be higher than our local one. In this -// scenario, we must fastforward the local nonce to match the chain nonce. -// -// The problem with doing this is that now Chainlink does not have any -// ownership or control over potentially pending transactions with nonces -// between our local highest nonce and the chain nonce. If one of those -// transactions is pushed out of the mempool or re-org'd out of the chain, -// we run the risk of being stuck with a gap in the nonce sequence that -// will never be filled. -// -// The solution is to query the chain for our own transactions and take -// ownership of them by writing them to the database and letting the -// EthConfirmer handle them as it would any other transaction. -// -// This is not quite as straightforward as one might expect. We cannot -// query transactions from our account to infinite depth (geth does not -// support this). The best we can do is to query for all transactions sent -// within the past EVM.FinalityDepth blocks and find the ones sent by our -// address(es). -// -// This gives us re-org protection up to EVM.FinalityDepth deep in the -// worst case, which is in line with our other guarantees. -var _ txmgr.SequenceSyncer[common.Address, common.Hash, common.Hash, types.Nonce] = &nonceSyncerImpl{} - -type nonceSyncerImpl struct { - txStore EvmTxStore - client TxmClient - chainID *big.Int - logger logger.Logger -} - -// NewNonceSyncer returns a new syncer -func NewNonceSyncer( - txStore EvmTxStore, - lggr logger.Logger, - ethClient evmclient.Client, -) NonceSyncer { - lggr = logger.Named(lggr, "NonceSyncer") - return &nonceSyncerImpl{ - txStore: txStore, - client: NewEvmTxmClient(ethClient), - chainID: ethClient.ConfiguredChainID(), - logger: lggr, - } -} - -// SyncAll syncs nonces for all enabled keys in parallel -// -// This should only be called once, before the EthBroadcaster has started. -// Calling it later is not safe and could lead to races. -func (s nonceSyncerImpl) Sync(ctx context.Context, addr common.Address, localNonce types.Nonce) (nonce types.Nonce, err error) { - nonce, err = s.fastForwardNonceIfNecessary(ctx, addr, localNonce) - return nonce, pkgerrors.Wrap(err, "NonceSyncer#fastForwardNoncesIfNecessary failed") -} - -func (s nonceSyncerImpl) fastForwardNonceIfNecessary(ctx context.Context, address common.Address, localNonce types.Nonce) (types.Nonce, error) { - chainNonce, err := s.pendingNonceFromEthClient(ctx, address) - if err != nil { - return localNonce, pkgerrors.Wrap(err, "GetNextNonce failed to loadInitialNonceFromEthClient") - } - if chainNonce == 0 { - return localNonce, nil - } - if chainNonce <= localNonce { - return localNonce, nil - } - s.logger.Warnw(fmt.Sprintf("address %s has been used before, either by an external wallet or a different Chainlink node. "+ - "Local nonce is %v but the on-chain nonce for this account was %v. "+ - "It's possible that this node was restored from a backup. If so, transactions sent by the previous node will NOT be re-org protected and in rare cases may need to be manually bumped/resubmitted. "+ - "Please note that using the chainlink keys with an external wallet is NOT SUPPORTED and can lead to missed or stuck transactions. ", - address, localNonce, chainNonce), - "address", address.String(), "localNonce", localNonce, "chainNonce", chainNonce) - - return chainNonce, nil -} - -func (s nonceSyncerImpl) pendingNonceFromEthClient(ctx context.Context, account common.Address) (types.Nonce, error) { - nextNonce, err := s.client.PendingSequenceAt(ctx, account) - return nextNonce, pkgerrors.WithStack(err) -} diff --git a/core/chains/evm/txmgr/nonce_syncer_test.go b/core/chains/evm/txmgr/nonce_syncer_test.go deleted file mode 100644 index d9a741fb3c5..00000000000 --- a/core/chains/evm/txmgr/nonce_syncer_test.go +++ /dev/null @@ -1,114 +0,0 @@ -package txmgr_test - -import ( - "testing" - - "github.com/smartcontractkit/chainlink-common/pkg/logger" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - - pkgerrors "github.com/pkg/errors" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" -) - -func Test_NonceSyncer_Sync(t *testing.T) { - t.Parallel() - - t.Run("returns error if PendingNonceAt fails", func(t *testing.T) { - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - - _, from := cltest.MustInsertRandomKey(t, ethKeyStore) - - ns := txmgr.NewNonceSyncer(txStore, logger.Test(t), ethClient) - - ethClient.On("PendingNonceAt", mock.Anything, from).Return(uint64(0), pkgerrors.New("something exploded")) - _, err := ns.Sync(testutils.Context(t), from, types.Nonce(0)) - require.Error(t, err) - assert.Contains(t, err.Error(), "something exploded") - - cltest.AssertCount(t, db, "evm.txes", 0) - cltest.AssertCount(t, db, "evm.tx_attempts", 0) - }) - - t.Run("does nothing if chain nonce reflects local nonce", func(t *testing.T) { - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - - _, from := cltest.MustInsertRandomKey(t, ethKeyStore) - - ns := txmgr.NewNonceSyncer(txStore, logger.Test(t), ethClient) - - ethClient.On("PendingNonceAt", mock.Anything, from).Return(uint64(0), nil) - - nonce, err := ns.Sync(testutils.Context(t), from, 0) - require.Equal(t, nonce.Int64(), int64(0)) - require.NoError(t, err) - - cltest.AssertCount(t, db, "evm.txes", 0) - cltest.AssertCount(t, db, "evm.tx_attempts", 0) - }) - - t.Run("does nothing if chain nonce is behind local nonce", func(t *testing.T) { - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) - ks := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - - _, fromAddress := cltest.RandomKey{Nonce: 32}.MustInsert(t, ks) - - ns := txmgr.NewNonceSyncer(txStore, logger.Test(t), ethClient) - - // Used to mock the chain nonce - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(5), nil) - nonce, err := ns.Sync(testutils.Context(t), fromAddress, types.Nonce(32)) - require.Equal(t, nonce.Int64(), int64(32)) - require.NoError(t, err) - - cltest.AssertCount(t, db, "evm.txes", 0) - cltest.AssertCount(t, db, "evm.tx_attempts", 0) - }) - - t.Run("fast forwards if chain nonce is ahead of local nonce", func(t *testing.T) { - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - - _, key1 := cltest.MustInsertRandomKey(t, ethKeyStore) - _, key2 := cltest.RandomKey{Nonce: 32}.MustInsert(t, ethKeyStore) - - key1LocalNonce := types.Nonce(0) - key2LocalNonce := types.Nonce(32) - - ns := txmgr.NewNonceSyncer(txStore, logger.Test(t), ethClient) - - // Used to mock the chain nonce - ethClient.On("PendingNonceAt", mock.Anything, key1).Return(uint64(5), nil).Once() - ethClient.On("PendingNonceAt", mock.Anything, key2).Return(uint64(32), nil).Once() - - syncerNonce, err := ns.Sync(testutils.Context(t), key1, key1LocalNonce) - require.NoError(t, err) - require.Greater(t, syncerNonce, key1LocalNonce) - - syncerNonce, err = ns.Sync(testutils.Context(t), key2, key2LocalNonce) - require.NoError(t, err) - require.Equal(t, syncerNonce, key2LocalNonce) - }) -} diff --git a/core/chains/evm/txmgr/nonce_tracker.go b/core/chains/evm/txmgr/nonce_tracker.go new file mode 100644 index 00000000000..6fb708ed876 --- /dev/null +++ b/core/chains/evm/txmgr/nonce_tracker.go @@ -0,0 +1,186 @@ +package txmgr + +import ( + "context" + "fmt" + "math/big" + "slices" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/jpillora/backoff" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" +) + +type NonceTrackerTxStore interface { + FindLatestSequence(context.Context, common.Address, *big.Int) (evmtypes.Nonce, error) +} + +type NonceTrackerClient interface { + ConfiguredChainID() *big.Int + PendingSequenceAt(context.Context, common.Address) (evmtypes.Nonce, error) +} + +type nonceTracker struct { + lggr logger.SugaredLogger + nextSequenceMap map[common.Address]evmtypes.Nonce + txStore NonceTrackerTxStore + chainID *big.Int + client NonceTrackerClient + enabledAddresses []common.Address + + sequenceLock sync.RWMutex +} + +func NewNonceTracker(lggr logger.Logger, txStore NonceTrackerTxStore, client NonceTrackerClient) *nonceTracker { + lggr = logger.Named(lggr, "NonceTracker") + return &nonceTracker{ + lggr: logger.Sugared(lggr), + txStore: txStore, + chainID: client.ConfiguredChainID(), + client: client, + } +} + +func (s *nonceTracker) LoadNextSequences(ctx context.Context, addresses []common.Address) { + s.sequenceLock.Lock() + defer s.sequenceLock.Unlock() + + s.enabledAddresses = addresses + + s.nextSequenceMap = make(map[common.Address]evmtypes.Nonce) + for _, address := range addresses { + seq, err := s.getSequenceForAddr(ctx, address) + if err == nil { + s.nextSequenceMap[address] = seq + } + } +} + +func (s *nonceTracker) getSequenceForAddr(ctx context.Context, address common.Address) (seq evmtypes.Nonce, err error) { + // Get the highest sequence from the tx table + // Will need to be incremented since this sequence is already used + seq, err = s.txStore.FindLatestSequence(ctx, address, s.chainID) + if err == nil { + seq++ + return seq, nil + } + // Look for nonce on-chain if no tx found for address in TxStore or if error occurred + // Returns the nonce that should be used for the next transaction so no need to increment + nonce, err := s.client.PendingSequenceAt(ctx, address) + if err == nil { + return nonce, nil + } + s.lggr.Criticalw("failed to retrieve next sequence from on-chain for address: ", "address", address.String()) + return seq, err + +} + +// syncSequence tries to sync the key sequence, retrying indefinitely until success or stop signal is sent +func (s *nonceTracker) SyncSequence(ctx context.Context, addr common.Address, chStop services.StopChan) { + sequenceSyncRetryBackoff := backoff.Backoff{ + Min: 100 * time.Millisecond, + Max: 5 * time.Second, + Jitter: true, + } + + localSequence, err := s.GetNextSequence(ctx, addr) + // Address not found in map so skip sync + if err != nil { + s.lggr.Criticalw("Failed to retrieve local next sequence for address", "address", addr.String(), "err", err) + return + } + + // Enter loop with retries + var attempt int + for { + select { + case <-chStop: + return + case <-time.After(sequenceSyncRetryBackoff.Duration()): + attempt++ + err := s.SyncOnChain(ctx, addr, localSequence) + if err != nil { + if attempt > 5 { + s.lggr.Criticalw("Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) + } else { + s.lggr.Warnw("Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) + } + continue + } + return + } + } +} + +func (s *nonceTracker) SyncOnChain(ctx context.Context, addr common.Address, localSequence evmtypes.Nonce) error { + nonce, err := s.client.PendingSequenceAt(ctx, addr) + if err != nil { + return err + } + if nonce > localSequence { + s.lggr.Warnw(fmt.Sprintf("address %s has been used before, either by an external wallet or a different Chainlink node. "+ + "Local nonce is %v but the on-chain nonce for this account was %v. "+ + "It's possible that this node was restored from a backup. If so, transactions sent by the previous node will NOT be re-org protected and in rare cases may need to be manually bumped/resubmitted. "+ + "Please note that using the chainlink keys with an external wallet is NOT SUPPORTED and can lead to missed or stuck transactions. ", + addr, localSequence, nonce), + "address", addr.String(), "localNonce", localSequence, "chainNonce", nonce) + + s.lggr.Infow("Fast-forward sequence", "address", addr, "newNextSequence", nonce, "oldNextSequence", localSequence) + } + + s.sequenceLock.Lock() + defer s.sequenceLock.Unlock() + s.nextSequenceMap[addr] = max(localSequence, nonce) + return nil +} + +func (s *nonceTracker) GetNextSequence(ctx context.Context, address common.Address) (seq evmtypes.Nonce, err error) { + s.sequenceLock.Lock() + defer s.sequenceLock.Unlock() + // Get next sequence from map + seq, exists := s.nextSequenceMap[address] + if exists { + return seq, nil + } + + s.lggr.Infow("address not found in local next sequence map. Attempting to search and populate sequence.", "address", address.String()) + // Check if address is in the enabled address list + if !slices.Contains(s.enabledAddresses, address) { + return seq, fmt.Errorf("address disabled: %s", address) + } + + // Try to retrieve next sequence from tx table or on-chain to load the map + // A scenario could exist where loading the map during startup failed (e.g. All configured RPC's are unreachable at start) + // The expectation is that the node does not fail startup so sequences need to be loaded during runtime + foundSeq, err := s.getSequenceForAddr(ctx, address) + if err != nil { + return seq, fmt.Errorf("failed to find next sequence for address: %s", address) + } + + // Set sequence in map + s.nextSequenceMap[address] = foundSeq + return foundSeq, nil +} + +func (s *nonceTracker) GenerateNextSequence(address common.Address, nonceUsed evmtypes.Nonce) { + s.sequenceLock.Lock() + defer s.sequenceLock.Unlock() + currentNonce := s.nextSequenceMap[address] + + // In most cases, currentNonce would equal nonceUsed + // There is a chance currentNonce is 1 ahead of nonceUsed if the DB contains an in-progress tx during startup + // Incrementing currentNonce, which is already set to the next usable nonce, could lead to a nonce gap. Set the map to the incremented nonceUsed instead. + if currentNonce == nonceUsed || currentNonce == nonceUsed+1 { + s.nextSequenceMap[address] = nonceUsed + 1 + return + } + + // If currentNonce is ahead of even the incremented nonceUsed, maintain the unchanged currentNonce in the map + // This scenario should never occur but logging this discrepancy for visibility + s.lggr.Warnf("Local nonce map value %d for address %s is ahead of the nonce transmitted %d. Maintaining the existing value in the map without incrementing.", currentNonce, address.String(), nonceUsed) +} diff --git a/core/chains/evm/txmgr/nonce_tracker_test.go b/core/chains/evm/txmgr/nonce_tracker_test.go new file mode 100644 index 00000000000..38059b82335 --- /dev/null +++ b/core/chains/evm/txmgr/nonce_tracker_test.go @@ -0,0 +1,291 @@ +package txmgr_test + +import ( + "errors" + "fmt" + "math/big" + "testing" + + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + "github.com/ethereum/go-ethereum/common" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services" + + clientmock "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + txstoremock "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" +) + +func TestNonceTracker_LoadSequenceMap(t *testing.T) { + t.Parallel() + + ctx := testutils.Context(t) + chainID := big.NewInt(0) + txStore := txstoremock.NewEvmTxStore(t) + + client := clientmock.NewClient(t) + client.On("ConfiguredChainID").Return(chainID) + + nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(client)) + + addr1 := common.HexToAddress("0xd5e099c71b797516c10ed0f0d895f429c2781142") + addr2 := common.HexToAddress("0xd5e099c71b797516c10ed0f0d895f429c2781140") + enabledAddresses := []common.Address{addr1, addr2} + + t.Run("set next nonce using entries from tx table", func(t *testing.T) { + randNonce1 := testutils.NewRandomPositiveInt64() + randNonce2 := testutils.NewRandomPositiveInt64() + txStore.On("FindLatestSequence", mock.Anything, addr1, chainID).Return(types.Nonce(randNonce1), nil).Once() + txStore.On("FindLatestSequence", mock.Anything, addr2, chainID).Return(types.Nonce(randNonce2), nil).Once() + + nonceTracker.LoadNextSequences(ctx, enabledAddresses) + seq, err := nonceTracker.GetNextSequence(ctx, addr1) + require.NoError(t, err) + require.Equal(t, types.Nonce(randNonce1+1), seq) + seq, err = nonceTracker.GetNextSequence(ctx, addr2) + require.NoError(t, err) + require.Equal(t, types.Nonce(randNonce2+1), seq) + }) + + t.Run("set next nonce using client when not found in tx table", func(t *testing.T) { + var emptyNonce types.Nonce + txStore.On("FindLatestSequence", mock.Anything, addr1, chainID).Return(emptyNonce, errors.New("no rows")).Once() + txStore.On("FindLatestSequence", mock.Anything, addr2, chainID).Return(emptyNonce, errors.New("no rows")).Once() + + randNonce1 := testutils.NewRandomPositiveInt64() + randNonce2 := testutils.NewRandomPositiveInt64() + client.On("PendingNonceAt", mock.Anything, addr1).Return(uint64(randNonce1), nil).Once() + client.On("PendingNonceAt", mock.Anything, addr2).Return(uint64(randNonce2), nil).Once() + + nonceTracker.LoadNextSequences(ctx, enabledAddresses) + seq, err := nonceTracker.GetNextSequence(ctx, addr1) + require.NoError(t, err) + require.Equal(t, types.Nonce(randNonce1), seq) + seq, err = nonceTracker.GetNextSequence(ctx, addr2) + require.NoError(t, err) + require.Equal(t, types.Nonce(randNonce2), seq) + }) + +} + +func TestNonceTracker_syncOnChain(t *testing.T) { + t.Parallel() + + ctx := testutils.Context(t) + chainID := big.NewInt(0) + txStore := txstoremock.NewEvmTxStore(t) + + client := clientmock.NewClient(t) + client.On("ConfiguredChainID").Return(chainID) + + nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(client)) + + addr := common.HexToAddress("0xd5e099c71b797516c10ed0f0d895f429c2781142") + + t.Run("throws error if RPC call fails", func(t *testing.T) { + client.On("PendingNonceAt", mock.Anything, addr).Return(uint64(0), errors.New("RPC unavailable")).Once() + + err := nonceTracker.SyncOnChain(ctx, addr, types.Nonce(2)) + require.Error(t, err) + }) + + t.Run("uses local nonce instead of on-chain nonce if on-chain nonce is lower", func(t *testing.T) { + nonce := 2 + newNonce := 5 + client.On("PendingNonceAt", mock.Anything, addr).Return(uint64(nonce), nil).Once() + + enabledAddresses := []common.Address{} + nonceTracker.LoadNextSequences(ctx, enabledAddresses) + + // syncOnChain will set the next sequence even if the address is not present in the map + err := nonceTracker.SyncOnChain(ctx, addr, types.Nonce(newNonce)) + require.NoError(t, err) + + seq, err := nonceTracker.GetNextSequence(ctx, addr) + require.NoError(t, err) + require.Equal(t, types.Nonce(newNonce), seq) + }) + + t.Run("fast forwards nonce if on-chain nonce is higher than local nonce", func(t *testing.T) { + nonce := 10 + onChainNonce := 5 + client.On("PendingNonceAt", mock.Anything, addr).Return(uint64(nonce), nil).Once() + + enabledAddresses := []common.Address{} + nonceTracker.LoadNextSequences(ctx, enabledAddresses) + + // syncOnChain will set the next sequence even if the address is not present in the map + err := nonceTracker.SyncOnChain(ctx, addr, types.Nonce(onChainNonce)) + require.NoError(t, err) + + seq, err := nonceTracker.GetNextSequence(ctx, addr) + require.NoError(t, err) + require.Equal(t, types.Nonce(nonce), seq) + }) + +} + +func TestNonceTracker_SyncSequence(t *testing.T) { + t.Parallel() + + ctx := testutils.Context(t) + chainID := big.NewInt(0) + txStore := txstoremock.NewEvmTxStore(t) + + client := clientmock.NewClient(t) + client.On("ConfiguredChainID").Return(chainID) + + nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(client)) + + addr := common.HexToAddress("0xd5e099c71b797516c10ed0f0d895f429c2781142") + enabledAddresses := []common.Address{addr} + + t.Run("syncs sequence successfully", func(t *testing.T) { + txStoreNonce := 2 + onChainNonce := 3 + txStore.On("FindLatestSequence", mock.Anything, addr, chainID).Return(types.Nonce(txStoreNonce), nil).Once() + nonceTracker.LoadNextSequences(ctx, enabledAddresses) + + var chStop services.StopChan + client.On("PendingNonceAt", mock.Anything, addr).Return(uint64(onChainNonce), nil).Once() + nonceTracker.SyncSequence(ctx, addr, chStop) + + seq, err := nonceTracker.GetNextSequence(ctx, addr) + require.NoError(t, err) + require.Equal(t, types.Nonce(onChainNonce), seq) + }) + + t.Run("retries if on-chain syncing fails", func(t *testing.T) { + txStoreNonce := 2 + onChainNonce := 3 + txStore.On("FindLatestSequence", mock.Anything, addr, chainID).Return(types.Nonce(txStoreNonce), nil).Once() + nonceTracker.LoadNextSequences(ctx, enabledAddresses) + + var chStop services.StopChan + client.On("PendingNonceAt", mock.Anything, addr).Return(uint64(0), errors.New("RPC unavailable")).Once() + client.On("PendingNonceAt", mock.Anything, addr).Return(uint64(onChainNonce), nil).Once() + nonceTracker.SyncSequence(ctx, addr, chStop) + + seq, err := nonceTracker.GetNextSequence(ctx, addr) + require.NoError(t, err) + require.Equal(t, types.Nonce(onChainNonce), seq) + }) +} + +func TestNonceTracker_GetNextSequence(t *testing.T) { + t.Parallel() + + ctx := testutils.Context(t) + chainID := big.NewInt(0) + txStore := txstoremock.NewEvmTxStore(t) + + client := clientmock.NewClient(t) + client.On("ConfiguredChainID").Return(chainID) + + nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(client)) + + addr := common.HexToAddress("0xd5e099c71b797516c10ed0f0d895f429c2781142") + + t.Run("fails to get sequence if address doesn't exist in map", func(t *testing.T) { + _, err := nonceTracker.GetNextSequence(ctx, addr) + require.Error(t, err) + + }) + + t.Run("fails to get sequence if address doesn't exist in map and is disabled", func(t *testing.T) { + _, err := nonceTracker.GetNextSequence(ctx, addr) + require.Error(t, err) + require.Contains(t, err.Error(), fmt.Sprintf("address disabled: %s", addr.Hex())) + }) + + t.Run("fails to get sequence if address is enabled, doesn't exist in map, and getSequenceForAddr fails", func(t *testing.T) { + enabledAddresses := []common.Address{addr} + txStore.On("FindLatestSequence", mock.Anything, addr, chainID).Return(types.Nonce(0), errors.New("no rows")).Twice() + client.On("PendingNonceAt", mock.Anything, addr).Return(uint64(0), errors.New("RPC unavailable")).Twice() + nonceTracker.LoadNextSequences(ctx, enabledAddresses) + + _, err := nonceTracker.GetNextSequence(ctx, addr) + require.Error(t, err) + require.Contains(t, err.Error(), fmt.Sprintf("failed to find next sequence for address: %s", addr.Hex())) + }) + + t.Run("gets next sequence successfully if there is no entry in map but address is enabled and getSequenceForAddr is successful", func(t *testing.T) { + txStoreNonce := 4 + enabledAddresses := []common.Address{addr} + txStore.On("FindLatestSequence", mock.Anything, addr, chainID).Return(types.Nonce(0), errors.New("no rows")).Once() + client.On("PendingNonceAt", mock.Anything, addr).Return(uint64(0), errors.New("RPC unavailable")).Once() + nonceTracker.LoadNextSequences(ctx, enabledAddresses) + + txStore.On("FindLatestSequence", mock.Anything, addr, chainID).Return(types.Nonce(txStoreNonce), nil).Once() + seq, err := nonceTracker.GetNextSequence(ctx, addr) + require.NoError(t, err) + require.Equal(t, types.Nonce(txStoreNonce+1), seq) + + }) +} + +func TestNonceTracker_GenerateNextSequence(t *testing.T) { + t.Parallel() + + ctx := testutils.Context(t) + chainID := big.NewInt(0) + txStore := txstoremock.NewEvmTxStore(t) + + client := clientmock.NewClient(t) + client.On("ConfiguredChainID").Return(chainID) + + nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(client)) + + addr := common.HexToAddress("0xd5e099c71b797516c10ed0f0d895f429c2781142") + enabledAddresses := []common.Address{addr} + + randNonce := testutils.NewRandomPositiveInt64() + txStore.On("FindLatestSequence", mock.Anything, addr, chainID).Return(types.Nonce(randNonce), nil).Once() + nonceTracker.LoadNextSequences(ctx, enabledAddresses) + seq, err := nonceTracker.GetNextSequence(ctx, addr) + require.NoError(t, err) + require.Equal(t, types.Nonce(randNonce+1), seq) // Local nonce should be highest nonce in DB + 1 + + nonceTracker.GenerateNextSequence(addr, types.Nonce(randNonce+1)) + + seq, err = nonceTracker.GetNextSequence(ctx, addr) + require.NoError(t, err) + require.Equal(t, types.Nonce(randNonce+2), seq) // GenerateNextSequence increases local nonce by 1 +} + +func Test_SetNonceAfterInit(t *testing.T) { + t.Parallel() + + ctx := testutils.Context(t) + chainID := big.NewInt(0) + db := pgtest.NewSqlxDB(t) + txStore := cltest.NewTestTxStore(t, db) + + client := clientmock.NewClient(t) + client.On("ConfiguredChainID").Return(chainID) + + nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(client)) + + addr := common.HexToAddress("0xd5e099c71b797516c10ed0f0d895f429c2781142") + enabledAddresses := []common.Address{addr} + randNonce := testutils.NewRandomPositiveInt64() + client.On("PendingNonceAt", mock.Anything, addr).Return(uint64(0), errors.New("failed to retrieve nonce at startup")).Once() + client.On("PendingNonceAt", mock.Anything, addr).Return(uint64(randNonce), nil).Once() + nonceTracker.LoadNextSequences(ctx, enabledAddresses) + + nonce, err := nonceTracker.GetNextSequence(ctx, addr) + require.NoError(t, err) + require.Equal(t, randNonce, int64(nonce)) + + // Test that the new nonce is set in the map and does not need a client call to retrieve on subsequent calls + nonce, err = nonceTracker.GetNextSequence(ctx, addr) + require.NoError(t, err) + require.Equal(t, randNonce, int64(nonce)) +} diff --git a/core/chains/evm/txmgr/reaper_test.go b/core/chains/evm/txmgr/reaper_test.go index a539f0ac8cb..7918ed0e2ca 100644 --- a/core/chains/evm/txmgr/reaper_test.go +++ b/core/chains/evm/txmgr/reaper_test.go @@ -45,7 +45,7 @@ func TestReaper_ReapTxes(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, from := cltest.MustInsertRandomKey(t, ethKeyStore) diff --git a/core/chains/evm/txmgr/resender_test.go b/core/chains/evm/txmgr/resender_test.go index 7cf575e8c8d..57605c61785 100644 --- a/core/chains/evm/txmgr/resender_test.go +++ b/core/chains/evm/txmgr/resender_test.go @@ -41,7 +41,7 @@ func Test_EthResender_resendUnconfirmed(t *testing.T) { _, fromAddress2 := cltest.MustInsertRandomKey(t, ethKeyStore) _, fromAddress3 := cltest.MustInsertRandomKey(t, ethKeyStore) - txStore := cltest.NewTestTxStore(t, db, logCfg) + txStore := cltest.NewTestTxStore(t, db) originalBroadcastAt := time.Unix(1616509100, 0) @@ -118,7 +118,7 @@ func Test_EthResender_alertUnconfirmed(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - txStore := cltest.NewTestTxStore(t, db, logCfg) + txStore := cltest.NewTestTxStore(t, db) originalBroadcastAt := time.Unix(1616509100, 0) er := txmgr.NewEvmResender(lggr, txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTracker(txStore, ethKeyStore, big.NewInt(0), lggr), ethKeyStore, 100*time.Millisecond, ccfg.EVM(), ccfg.EVM().Transactions()) @@ -148,7 +148,7 @@ func Test_EthResender_Start(t *testing.T) { // Set batch size low to test batching c.EVM[0].RPCDefaultBatchSize = ptr[uint32](1) }) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ccfg := evmtest.NewChainScopedConfig(t, cfg) _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) diff --git a/core/chains/evm/txmgr/test_helpers.go b/core/chains/evm/txmgr/test_helpers.go index 8cb771943b0..64d23373282 100644 --- a/core/chains/evm/txmgr/test_helpers.go +++ b/core/chains/evm/txmgr/test_helpers.go @@ -8,10 +8,9 @@ import ( commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" - "github.com/smartcontractkit/chainlink/v2/core/config" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" - evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" + "github.com/smartcontractkit/chainlink/v2/core/config" ) func ptr[T any](t T) *T { return &t } @@ -79,7 +78,7 @@ func (g *TestGasEstimatorConfig) TipCapMin() *assets.Wei { return assets.New func (g *TestGasEstimatorConfig) LimitMax() uint64 { return 0 } func (g *TestGasEstimatorConfig) LimitMultiplier() float32 { return 0 } func (g *TestGasEstimatorConfig) BumpTxDepth() uint32 { return 42 } -func (g *TestGasEstimatorConfig) LimitTransfer() uint32 { return 42 } +func (g *TestGasEstimatorConfig) LimitTransfer() uint64 { return 42 } func (g *TestGasEstimatorConfig) PriceMax() *assets.Wei { return assets.NewWeiI(42) } func (g *TestGasEstimatorConfig) PriceMin() *assets.Wei { return assets.NewWeiI(42) } func (g *TestGasEstimatorConfig) Mode() string { return "FixedPrice" } @@ -145,7 +144,7 @@ func (c *MockConfig) FinalityTagEnabled() bool { return c.finalityTagEn func (c *MockConfig) RPCDefaultBatchSize() uint32 { return c.RpcDefaultBatchSize } func MakeTestConfigs(t *testing.T) (*MockConfig, *TestDatabaseConfig, *TestEvmConfig) { - db := &TestDatabaseConfig{defaultQueryTimeout: pg.DefaultQueryTimeout} + db := &TestDatabaseConfig{defaultQueryTimeout: utils.DefaultQueryTimeout} ec := &TestEvmConfig{BumpThreshold: 42, MaxInFlight: uint32(42), MaxQueued: uint64(0), ReaperInterval: time.Duration(0), ReaperThreshold: time.Duration(0)} config := &MockConfig{EvmConfig: ec} return config, db, ec diff --git a/core/chains/evm/txmgr/tracker_test.go b/core/chains/evm/txmgr/tracker_test.go index d3083372789..e95c005dc77 100644 --- a/core/chains/evm/txmgr/tracker_test.go +++ b/core/chains/evm/txmgr/tracker_test.go @@ -6,13 +6,13 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/keystore" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" @@ -23,20 +23,15 @@ const waitTime = 5 * time.Millisecond func newTestEvmTrackerSetup(t *testing.T) (*txmgr.Tracker, txmgr.TestEvmTxStore, keystore.Eth, []common.Address) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() chainID := big.NewInt(0) - enabledAddresses := generateEnabledAddresses(t, ethKeyStore, chainID) - lggr := logger.TestLogger(t) - return txmgr.NewEvmTracker(txStore, ethKeyStore, chainID, lggr), txStore, ethKeyStore, enabledAddresses -} - -func generateEnabledAddresses(t *testing.T, keyStore keystore.Eth, chainID *big.Int) []common.Address { var enabledAddresses []common.Address - _, addr1 := cltest.MustInsertRandomKey(t, keyStore, *ubig.NewI(chainID.Int64())) - _, addr2 := cltest.MustInsertRandomKey(t, keyStore, *ubig.NewI(chainID.Int64())) + _, addr1 := cltest.MustInsertRandomKey(t, ethKeyStore, *ubig.NewI(chainID.Int64())) + _, addr2 := cltest.MustInsertRandomKey(t, ethKeyStore, *ubig.NewI(chainID.Int64())) enabledAddresses = append(enabledAddresses, addr1, addr2) - return enabledAddresses + lggr := logger.TestLogger(t) + return txmgr.NewEvmTracker(txStore, ethKeyStore, chainID, lggr), txStore, ethKeyStore, enabledAddresses } func containsID(txes []*txmgr.Tx, id int64) bool { diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go index 332031bc776..1774a2ad86e 100644 --- a/core/chains/evm/txmgr/txmgr_test.go +++ b/core/chains/evm/txmgr/txmgr_test.go @@ -32,6 +32,8 @@ import ( evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/keystore" + ksmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/keystore/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -42,9 +44,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) func makeTestEvmTxm( @@ -109,7 +108,7 @@ func TestTxm_CreateTransaction(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) kst := cltest.NewKeyStore(t, db, cfg.Database()) _, fromAddress := cltest.MustInsertRandomKey(t, kst.Eth()) @@ -389,7 +388,7 @@ func newMockTxStrategy(t *testing.T) *commontxmmocks.TxStrategy { func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) etKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() thisKey, _ := cltest.RandomKey{Nonce: 1}.MustInsert(t, etKeyStore) @@ -533,7 +532,7 @@ func TestTxm_Reset(t *testing.T) { _, addr := cltest.RandomKey{}.MustInsert(t, kst.Eth()) _, addr2 := cltest.RandomKey{}.MustInsert(t, kst.Eth()) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) // 4 confirmed tx from addr1 for i := int64(0); i < 4; i++ { cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, i, i*42+1, addr) @@ -588,8 +587,8 @@ func TestTxm_Reset(t *testing.T) { }) } -func newTxStore(t *testing.T, db *sqlx.DB, cfg pg.QConfig) txmgr.EvmTxStore { - return txmgr.NewTxStore(db, logger.Test(t), cfg) +func newTxStore(t *testing.T, db *sqlx.DB) txmgr.EvmTxStore { + return txmgr.NewTxStore(db, logger.Test(t)) } func newEthReceipt(blockNumber int64, blockHash common.Hash, txHash common.Hash, status uint64) txmgr.Receipt { @@ -615,7 +614,7 @@ func newEthReceipt(blockNumber int64, blockHash common.Hash, txHash common.Hash, func mustInsertEthReceipt(t *testing.T, txStore txmgr.TestEvmTxStore, blockNumber int64, blockHash common.Hash, txHash common.Hash) txmgr.Receipt { r := newEthReceipt(blockNumber, blockHash, txHash, 0x1) - id, err := txStore.InsertReceipt(&r.Receipt) + id, err := txStore.InsertReceipt(testutils.Context(t), &r.Receipt) require.NoError(t, err) r.ID = id return r @@ -623,7 +622,7 @@ func mustInsertEthReceipt(t *testing.T, txStore txmgr.TestEvmTxStore, blockNumbe func mustInsertRevertedEthReceipt(t *testing.T, txStore txmgr.TestEvmTxStore, blockNumber int64, blockHash common.Hash, txHash common.Hash) txmgr.Receipt { r := newEthReceipt(blockNumber, blockHash, txHash, 0x0) - id, err := txStore.InsertReceipt(&r.Receipt) + id, err := txStore.InsertReceipt(testutils.Context(t), &r.Receipt) require.NoError(t, err) r.ID = id return r @@ -654,13 +653,14 @@ func mustInsertFatalErrorEthTx(t *testing.T, txStore txmgr.TestEvmTxStore, fromA etx.Error = null.StringFrom("something exploded") etx.State = txmgrcommon.TxFatalError - require.NoError(t, txStore.InsertTx(&etx)) + require.NoError(t, txStore.InsertTx(testutils.Context(t), &etx)) return etx } func mustInsertUnconfirmedEthTxWithAttemptState(t *testing.T, txStore txmgr.TestEvmTxStore, nonce int64, fromAddress common.Address, txAttemptState txmgrtypes.TxAttemptState, opts ...interface{}) txmgr.Tx { etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, nonce, fromAddress, opts...) attempt := cltest.NewLegacyEthTxAttempt(t, etx.ID) + ctx := testutils.Context(t) tx := cltest.NewLegacyTransaction(uint64(nonce), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) rlp := new(bytes.Buffer) @@ -668,9 +668,9 @@ func mustInsertUnconfirmedEthTxWithAttemptState(t *testing.T, txStore txmgr.Test attempt.SignedRawTx = rlp.Bytes() attempt.State = txAttemptState - require.NoError(t, txStore.InsertTxAttempt(&attempt)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt)) var err error - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) return etx } @@ -678,6 +678,7 @@ func mustInsertUnconfirmedEthTxWithAttemptState(t *testing.T, txStore txmgr.Test func mustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t *testing.T, txStore txmgr.TestEvmTxStore, nonce int64, fromAddress common.Address, opts ...interface{}) txmgr.Tx { etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, nonce, fromAddress, opts...) attempt := cltest.NewDynamicFeeEthTxAttempt(t, etx.ID) + ctx := testutils.Context(t) addr := testutils.NewAddress() dtx := types.DynamicFeeTx{ @@ -696,9 +697,9 @@ func mustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t *testing.T, txSt attempt.SignedRawTx = rlp.Bytes() attempt.State = txmgrtypes.TxAttemptBroadcast - require.NoError(t, txStore.InsertTxAttempt(&attempt)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt)) var err error - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) return etx } @@ -706,13 +707,14 @@ func mustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t *testing.T, txSt func mustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t *testing.T, txStore txmgr.TestEvmTxStore, nonce int64, fromAddress common.Address) txmgr.Tx { timeNow := time.Now() etx := cltest.NewEthTx(fromAddress) + ctx := testutils.Context(t) etx.BroadcastAt = &timeNow etx.InitialBroadcastAt = &timeNow n := evmtypes.Nonce(nonce) etx.Sequence = &n etx.State = txmgrcommon.TxUnconfirmed - require.NoError(t, txStore.InsertTx(&etx)) + require.NoError(t, txStore.InsertTx(ctx, &etx)) attempt := cltest.NewLegacyEthTxAttempt(t, etx.ID) tx := cltest.NewLegacyTransaction(uint64(nonce), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) @@ -721,9 +723,9 @@ func mustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t *testing.T, txStore attempt.SignedRawTx = rlp.Bytes() attempt.State = txmgrtypes.TxAttemptInsufficientFunds - require.NoError(t, txStore.InsertTxAttempt(&attempt)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt)) var err error - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) return etx } @@ -732,36 +734,38 @@ func mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t *testing.T, txStore txmgr.TestEvmTxStore, nonce int64, broadcastBeforeBlockNum int64, broadcastAt time.Time, fromAddress common.Address) txmgr.Tx { etx := cltest.NewEthTx(fromAddress) + ctx := testutils.Context(t) etx.BroadcastAt = &broadcastAt etx.InitialBroadcastAt = &broadcastAt n := evmtypes.Nonce(nonce) etx.Sequence = &n etx.State = txmgrcommon.TxConfirmedMissingReceipt - require.NoError(t, txStore.InsertTx(&etx)) + require.NoError(t, txStore.InsertTx(ctx, &etx)) attempt := cltest.NewLegacyEthTxAttempt(t, etx.ID) attempt.BroadcastBeforeBlockNum = &broadcastBeforeBlockNum attempt.State = txmgrtypes.TxAttemptBroadcast - require.NoError(t, txStore.InsertTxAttempt(&attempt)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt)) etx.TxAttempts = append(etx.TxAttempts, attempt) return etx } func mustInsertInProgressEthTxWithAttempt(t *testing.T, txStore txmgr.TestEvmTxStore, nonce evmtypes.Nonce, fromAddress common.Address) txmgr.Tx { etx := cltest.NewEthTx(fromAddress) + ctx := testutils.Context(t) etx.Sequence = &nonce etx.State = txmgrcommon.TxInProgress - require.NoError(t, txStore.InsertTx(&etx)) + require.NoError(t, txStore.InsertTx(ctx, &etx)) attempt := cltest.NewLegacyEthTxAttempt(t, etx.ID) tx := cltest.NewLegacyTransaction(uint64(nonce), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) rlp := new(bytes.Buffer) require.NoError(t, tx.EncodeRLP(rlp)) attempt.SignedRawTx = rlp.Bytes() attempt.State = txmgrtypes.TxAttemptInProgress - require.NoError(t, txStore.InsertTxAttempt(&attempt)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt)) var err error - etx, err = txStore.FindTxWithAttempts(etx.ID) + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) return etx } diff --git a/core/services/keystore/keys/ethkey/address.go b/core/chains/evm/types/address.go similarity index 99% rename from core/services/keystore/keys/ethkey/address.go rename to core/chains/evm/types/address.go index 0d93a4cdb29..4a77ce5f8db 100644 --- a/core/services/keystore/keys/ethkey/address.go +++ b/core/chains/evm/types/address.go @@ -1,4 +1,4 @@ -package ethkey +package types import ( "database/sql/driver" diff --git a/core/services/keystore/keys/ethkey/address_test.go b/core/chains/evm/types/address_test.go similarity index 76% rename from core/services/keystore/keys/ethkey/address_test.go rename to core/chains/evm/types/address_test.go index 15b502d1785..e6e6a4f37c9 100644 --- a/core/services/keystore/keys/ethkey/address_test.go +++ b/core/chains/evm/types/address_test.go @@ -1,4 +1,4 @@ -package ethkey_test +package types_test import ( "encoding/json" @@ -8,13 +8,13 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ) func TestEIP55Address(t *testing.T) { t.Parallel() - address := ethkey.EIP55Address("0xa0788FC17B1dEe36f057c42B6F373A34B014687e") + address := types.EIP55Address("0xa0788FC17B1dEe36f057c42B6F373A34B014687e") assert.Equal(t, []byte{ 0xa0, 0x78, 0x8f, 0xc1, 0x7b, 0x1d, 0xee, 0x36, @@ -35,12 +35,12 @@ func TestEIP55Address(t *testing.T) { assert.Equal(t, "0xa0788FC17B1dEe36f057c42B6F373A34B014687e", address.String()) - zeroAddress := ethkey.EIP55Address("") + zeroAddress := types.EIP55Address("") err := json.Unmarshal([]byte(`"0xa0788FC17B1dEe36f057c42B6F373A34B014687e"`), &zeroAddress) assert.NoError(t, err) assert.Equal(t, "0xa0788FC17B1dEe36f057c42B6F373A34B014687e", zeroAddress.String()) - zeroAddress = ethkey.EIP55Address("") + zeroAddress = types.EIP55Address("") err = zeroAddress.UnmarshalText([]byte("0xa0788FC17B1dEe36f057c42B6F373A34B014687e")) assert.NoError(t, err) assert.Equal(t, "0xa0788FC17B1dEe36f057c42B6F373A34B014687e", zeroAddress.String()) @@ -64,7 +64,7 @@ func TestValidateEIP55Address(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - _, err := ethkey.NewEIP55Address(test.input) + _, err := types.NewEIP55Address(test.input) valid := err == nil assert.Equal(t, test.valid, valid) }) @@ -75,20 +75,20 @@ func TestEIP55AddressFromAddress(t *testing.T) { t.Parallel() addr := common.HexToAddress("0xa0788FC17B1dEe36f057c42B6F373A34B014687e") - eip55 := ethkey.EIP55AddressFromAddress(addr) + eip55 := types.EIP55AddressFromAddress(addr) assert.Equal(t, addr, eip55.Address()) } func TestEIP55Address_Scan_Value(t *testing.T) { t.Parallel() - eip55, err := ethkey.NewEIP55Address("0xa0788FC17B1dEe36f057c42B6F373A34B014687e") + eip55, err := types.NewEIP55Address("0xa0788FC17B1dEe36f057c42B6F373A34B014687e") assert.NoError(t, err) val, err := eip55.Value() assert.NoError(t, err) - var eip55New ethkey.EIP55Address + var eip55New types.EIP55Address err = eip55New.Scan(val) assert.NoError(t, err) @@ -98,15 +98,15 @@ func TestEIP55Address_Scan_Value(t *testing.T) { func TestEIP55AddressCollection_Scan_Value(t *testing.T) { t.Parallel() - collection := ethkey.EIP55AddressCollection{ - ethkey.EIP55Address("0xa0788FC17B1dEe36f057c42B6F373A34B0146111"), - ethkey.EIP55Address("0xa0788FC17B1dEe36f057c42B6F373A34B0146222"), + collection := types.EIP55AddressCollection{ + types.EIP55Address("0xa0788FC17B1dEe36f057c42B6F373A34B0146111"), + types.EIP55Address("0xa0788FC17B1dEe36f057c42B6F373A34B0146222"), } val, err := collection.Value() assert.NoError(t, err) - var collectionNew ethkey.EIP55AddressCollection + var collectionNew types.EIP55AddressCollection err = collectionNew.Scan(val) assert.NoError(t, err) @@ -116,9 +116,9 @@ func TestEIP55AddressCollection_Scan_Value(t *testing.T) { func TestEIP55Address_IsZero(t *testing.T) { t.Parallel() - eip55 := ethkey.EIP55AddressFromAddress(common.HexToAddress("0x0")) + eip55 := types.EIP55AddressFromAddress(common.HexToAddress("0x0")) assert.True(t, eip55.IsZero()) - eip55 = ethkey.EIP55AddressFromAddress(common.HexToAddress("0x1")) + eip55 = types.EIP55AddressFromAddress(common.HexToAddress("0x1")) assert.False(t, eip55.IsZero()) } diff --git a/core/chains/evm/types/models.go b/core/chains/evm/types/models.go index 7f312401f7d..1bf47f84726 100644 --- a/core/chains/evm/types/models.go +++ b/core/chains/evm/types/models.go @@ -2,6 +2,7 @@ package types import ( "bytes" + "database/sql" "database/sql/driver" "encoding/json" "fmt" @@ -24,7 +25,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types/internal/blocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" - "github.com/smartcontractkit/chainlink/v2/core/null" ) // Head represents a BlockNumber, BlockHash. @@ -32,7 +32,7 @@ type Head struct { ID uint64 Hash common.Hash Number int64 - L1BlockNumber null.Int64 + L1BlockNumber sql.NullInt64 ParentHash common.Hash Parent *Head EVMChainID *ubig.Big @@ -285,7 +285,7 @@ func (h *Head) UnmarshalJSON(bs []byte) error { h.Timestamp = time.Unix(int64(jsonHead.Timestamp), 0).UTC() h.BaseFeePerGas = assets.NewWei((*big.Int)(jsonHead.BaseFeePerGas)) if jsonHead.L1BlockNumber != nil { - h.L1BlockNumber = null.Int64From((*big.Int)(jsonHead.L1BlockNumber).Int64()) + h.L1BlockNumber = sql.NullInt64{Int64: (*big.Int)(jsonHead.L1BlockNumber).Int64(), Valid: true} } h.ReceiptsRoot = jsonHead.ReceiptsRoot h.TransactionsRoot = jsonHead.TransactionsRoot @@ -461,7 +461,7 @@ var WeiPerEth = new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil) // ChainlinkFulfilledTopic is the signature for the event emitted after calling // ChainlinkClient.validateChainlinkCallback(requestId). See -// ../../contracts/src/v0.6/ChainlinkClient.sol +// ../../contracts/src/v0.8/ChainlinkClient.sol var ChainlinkFulfilledTopic = utils.MustHash("ChainlinkFulfilled(bytes32)") // ReceiptIndicatesRunLogFulfillment returns true if this tx receipt is the result of a diff --git a/core/chains/evm/types/models_test.go b/core/chains/evm/types/models_test.go index 4fc986ae9d3..38dbfa76a0a 100644 --- a/core/chains/evm/types/models_test.go +++ b/core/chains/evm/types/models_test.go @@ -2,6 +2,7 @@ package types_test import ( "bytes" + "database/sql" "encoding/json" "fmt" "math" @@ -17,6 +18,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -25,7 +27,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/null" ) func TestHead_NewHead(t *testing.T) { @@ -329,7 +330,20 @@ func TestHead_UnmarshalJSON(t *testing.T) { Number: 0x15156, ParentHash: common.HexToHash("0x923ad1e27c1d43cb2d2fb09e26d2502ca4b4914a2e0599161d279c6c06117d34"), Timestamp: time.Unix(0x60d0952d, 0).UTC(), - L1BlockNumber: null.Int64From(0x8652f9), + L1BlockNumber: sql.NullInt64{Int64: 0x8652f9, Valid: true}, + ReceiptsRoot: common.HexToHash("0x2c292672b8fc9d223647a2569e19721f0757c96a1421753a93e141f8e56cf504"), + TransactionsRoot: common.HexToHash("0x71448077f5ce420a8e24db62d4d58e8d8e6ad2c7e76318868e089d41f7e0faf3"), + StateRoot: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), + }, + }, + {"arbitrum_empty_l1BlockNumber", + `{"number":"0x15156","hash":"0x752dab43f7a2482db39227d46cd307623b26167841e2207e93e7566ab7ab7871","parentHash":"0x923ad1e27c1d43cb2d2fb09e26d2502ca4b4914a2e0599161d279c6c06117d34","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x71448077f5ce420a8e24db62d4d58e8d8e6ad2c7e76318868e089d41f7e0faf3","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x2c292672b8fc9d223647a2569e19721f0757c96a1421753a93e141f8e56cf504","miner":"0x0000000000000000000000000000000000000000","difficulty":"0x0","totalDifficulty":"0x0","extraData":"0x","size":"0x0","gasLimit":"0x11278208","gasUsed":"0x3d1fe9","timestamp":"0x60d0952d","transactions":["0xa1ea93556b93ed3b45cb24f21c8deb584e6a9049c35209242651bf3533c23b98","0xfc6593c45ba92351d17173aa1381e84734d252ab0169887783039212c4a41024","0x85ee9d04fd0ebb5f62191eeb53cb45d9c0945d43eba444c3548de2ac8421682f","0x50d120936473e5b75f6e04829ad4eeca7a1df7d3c5026ebb5d34af936a39b29c"],"uncles":[]}`, + evmtypes.Head{ + Hash: common.HexToHash("0x752dab43f7a2482db39227d46cd307623b26167841e2207e93e7566ab7ab7871"), + Number: 0x15156, + ParentHash: common.HexToHash("0x923ad1e27c1d43cb2d2fb09e26d2502ca4b4914a2e0599161d279c6c06117d34"), + Timestamp: time.Unix(0x60d0952d, 0).UTC(), + L1BlockNumber: sql.NullInt64{Int64: 0, Valid: false}, ReceiptsRoot: common.HexToHash("0x2c292672b8fc9d223647a2569e19721f0757c96a1421753a93e141f8e56cf504"), TransactionsRoot: common.HexToHash("0x71448077f5ce420a8e24db62d4d58e8d8e6ad2c7e76318868e089d41f7e0faf3"), StateRoot: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), diff --git a/core/chains/evm/types/nonce.go b/core/chains/evm/types/nonce.go index be295bdd2a9..0c3256dc545 100644 --- a/core/chains/evm/types/nonce.go +++ b/core/chains/evm/types/nonce.go @@ -17,7 +17,3 @@ func (n Nonce) Int64() int64 { func (n Nonce) String() string { return strconv.FormatInt(n.Int64(), 10) } - -func GenerateNextNonce(prev Nonce) Nonce { - return prev + 1 -} diff --git a/core/chains/evm/utils/utils.go b/core/chains/evm/utils/utils.go index 6784d33cdb7..85ae358e597 100644 --- a/core/chains/evm/utils/utils.go +++ b/core/chains/evm/utils/utils.go @@ -19,6 +19,9 @@ import ( // EVMWordByteLen the length of an EVM Word Byte const EVMWordByteLen = 32 +// DefaultQueryTimeout is the default timeout for database queries +const DefaultQueryTimeout = 10 * time.Second + // ZeroAddress is an address of all zeroes, otherwise in Ethereum as // 0x0000000000000000000000000000000000000000 var ZeroAddress = common.Address{} diff --git a/core/chains/legacyevm/chain.go b/core/chains/legacyevm/chain.go index f00f4b64b36..1066eeecbea 100644 --- a/core/chains/legacyevm/chain.go +++ b/core/chains/legacyevm/chain.go @@ -24,6 +24,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/keystore" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/monitor" @@ -32,7 +33,6 @@ import ( ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ) //go:generate mockery --quiet --name Chain --output ./mocks/ --case=underscore @@ -212,13 +212,13 @@ func NewTOMLChain(ctx context.Context, chain *toml.EVMConfig, opts ChainRelayExt } func newChain(ctx context.Context, cfg *evmconfig.ChainScoped, nodes []*toml.Node, opts ChainRelayExtenderConfig) (*chain, error) { - chainID, chainType := cfg.EVM().ChainID(), cfg.EVM().ChainType() + chainID := cfg.EVM().ChainID() l := opts.Logger var client evmclient.Client if !cfg.EVMRPCEnabled() { client = evmclient.NewNullClient(chainID, l) } else if opts.GenEthClient == nil { - client = evmclient.NewEvmClient(cfg.EVM().NodePool(), cfg.EVM().NodeNoNewHeadsThreshold(), l, chainID, chainType, nodes) + client = evmclient.NewEvmClient(cfg.EVM().NodePool(), cfg.EVM(), l, chainID, nodes) } else { client = opts.GenEthClient(chainID) } @@ -279,7 +279,7 @@ func newChain(ctx context.Context, cfg *evmconfig.ChainScoped, nodes []*toml.Nod if !cfg.EVMRPCEnabled() { logBroadcaster = &log.NullBroadcaster{ErrMsg: fmt.Sprintf("Ethereum is disabled for chain %d", chainID)} } else if opts.GenLogBroadcaster == nil { - logORM := log.NewORM(opts.SqlxDB, l, cfg.Database(), *chainID) + logORM := log.NewORM(opts.SqlxDB, *chainID) logBroadcaster = log.NewBroadcaster(logORM, client, cfg.EVM(), l, highestSeenHead, opts.MailMon) } else { logBroadcaster = opts.GenLogBroadcaster(chainID) diff --git a/core/cmd/admin_commands_test.go b/core/cmd/admin_commands_test.go index fc4c1b7e959..f27574f956e 100644 --- a/core/cmd/admin_commands_test.go +++ b/core/cmd/admin_commands_test.go @@ -5,6 +5,7 @@ import ( "flag" "fmt" "math/rand" + "strconv" "testing" "time" @@ -141,17 +142,23 @@ func TestShell_ListUsers(t *testing.T) { flagSetApplyFromAction(client.ListUsers, set, "") c := cli.NewContext(nil, set, nil) - buffer := bytes.NewBufferString("") - client.Renderer = cmd.RendererTable{Writer: buffer} - + testRenderer := &testRenderer{} + client.Renderer = testRenderer assert.NoError(t, client.ListUsers(c), user.Email) - output := buffer.String() - assert.Contains(t, output, user.Email) - assert.Contains(t, output, user.Role) - assert.Contains(t, output, user.TokenKey.String) - assert.Contains(t, output, user.CreatedAt.String()) - assert.Contains(t, output, user.UpdatedAt.String()) + userPresenterFound := false + for _, presenter := range testRenderer.presenters { + if presenter.Email == user.Email { + userPresenterFound = true + assert.Equal(t, presenter.Role, user.Role) + userHasActiveApiToken, err := strconv.ParseBool(presenter.HasActiveApiToken) + assert.NoError(t, err) + assert.Equal(t, userHasActiveApiToken, user.TokenKey.String != "") + assert.True(t, presenter.CreatedAt.Equal(user.CreatedAt)) + assert.True(t, presenter.CreatedAt.Equal(user.UpdatedAt)) + } + } + assert.Truef(t, userPresenterFound, "expected to find user %s in presenter list", user.Email) } func TestAdminUsersPresenter_RenderTable(t *testing.T) { @@ -187,3 +194,13 @@ func TestAdminUsersPresenter_RenderTable(t *testing.T) { assert.Contains(t, output, user.CreatedAt.String()) assert.Contains(t, output, user.UpdatedAt.String()) } + +type testRenderer struct { + presenters []cmd.AdminUsersPresenter +} + +func (t *testRenderer) Render(i interface{}, s ...string) error { + adminPresenters := i.(*cmd.AdminUsersPresenters) + t.presenters = *adminPresenters + return nil +} diff --git a/core/cmd/evm_transaction_commands_test.go b/core/cmd/evm_transaction_commands_test.go index 588e65027f2..df5d066927a 100644 --- a/core/cmd/evm_transaction_commands_test.go +++ b/core/cmd/evm_transaction_commands_test.go @@ -20,7 +20,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" ) @@ -33,7 +32,7 @@ func TestShell_IndexTransactions(t *testing.T) { _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) - txStore := cltest.NewTestTxStore(t, app.GetSqlxDB(), app.GetConfig().Database()) + txStore := cltest.NewTestTxStore(t, app.GetSqlxDB()) tx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 0, 1, from) attempt := tx.TxAttempts[0] @@ -74,7 +73,7 @@ func TestShell_ShowTransaction(t *testing.T) { db := app.GetSqlxDB() _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) - txStore := cltest.NewTestTxStore(t, db, app.GetConfig().Database()) + txStore := cltest.NewTestTxStore(t, db) tx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 0, 1, from) attempt := tx.TxAttempts[0] @@ -98,7 +97,7 @@ func TestShell_IndexTxAttempts(t *testing.T) { _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) - txStore := cltest.NewTestTxStore(t, app.GetSqlxDB(), app.GetConfig().Database()) + txStore := cltest.NewTestTxStore(t, app.GetSqlxDB()) tx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 0, 1, from) // page 1 @@ -158,8 +157,7 @@ func TestShell_SendEther_From_Txm(t *testing.T) { ) client, r := app.NewShellAndRenderer() db := app.GetSqlxDB() - cfg := pgtest.NewQConfig(false) - txStore := txmgr.NewTxStore(db, logger.TestLogger(t), cfg) + txStore := txmgr.NewTxStore(db, logger.TestLogger(t)) set := flag.NewFlagSet("sendether", 0) flagSetApplyFromAction(client.SendEther, set, "") @@ -224,8 +222,7 @@ func TestShell_SendEther_From_Txm_WEI(t *testing.T) { ) client, r := app.NewShellAndRenderer() db := app.GetSqlxDB() - cfg := pgtest.NewQConfig(false) - txStore := txmgr.NewTxStore(db, logger.TestLogger(t), cfg) + txStore := txmgr.NewTxStore(db, logger.TestLogger(t)) set := flag.NewFlagSet("sendether", 0) flagSetApplyFromAction(client.SendEther, set, "") diff --git a/core/cmd/shell.go b/core/cmd/shell.go index 7662ef5d781..65fa85fc018 100644 --- a/core/cmd/shell.go +++ b/core/cmd/shell.go @@ -35,8 +35,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/build" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/config" @@ -156,7 +154,7 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G return nil, err } - db := sqlutil.WrapDataSource(sqlxDB, appLggr, sqlutil.TimeoutHook(pg.DefaultQueryTimeout), sqlutil.MonitorHook(cfg.Database().LogSQL)) + db := sqlutil.WrapDataSource(sqlxDB, appLggr, sqlutil.TimeoutHook(cfg.Database().DefaultQueryTimeout), sqlutil.MonitorHook(cfg.Database().LogSQL)) err = handleNodeVersioning(ctx, sqlxDB, appLggr, cfg.RootDir(), cfg.Database(), cfg.WebServer().HTTPPort()) if err != nil { diff --git a/core/cmd/shell_local.go b/core/cmd/shell_local.go index 8391e3bc70b..afdf6c6fdb0 100644 --- a/core/cmd/shell_local.go +++ b/core/cmd/shell_local.go @@ -631,7 +631,7 @@ func (s *Shell) RebroadcastTransactions(c *cli.Context) (err error) { s.Logger.Infof("Rebroadcasting transactions from %v to %v", beginningNonce, endingNonce) - orm := txmgr.NewTxStore(app.GetSqlxDB(), lggr, s.Config.Database()) + orm := txmgr.NewTxStore(app.GetSqlxDB(), lggr) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), chain.Config().EVM().GasEstimator(), keyStore.Eth(), nil) cfg := txmgr.NewEvmTxmConfig(chain.Config().EVM()) feeCfg := txmgr.NewEvmTxmFeeConfig(chain.Config().EVM().GasEstimator()) diff --git a/core/cmd/shell_local_test.go b/core/cmd/shell_local_test.go index 0dcf77d0f8e..596b699ff7a 100644 --- a/core/cmd/shell_local_test.go +++ b/core/cmd/shell_local_test.go @@ -293,7 +293,7 @@ func TestShell_RebroadcastTransactions_Txm(t *testing.T) { keyStore := cltest.NewKeyStore(t, sqlxDB, config.Database()) _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth()) - txStore := cltest.NewTestTxStore(t, sqlxDB, config.Database()) + txStore := cltest.NewTestTxStore(t, sqlxDB) cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 7, 42, fromAddress) lggr := logger.TestLogger(t) @@ -374,7 +374,7 @@ func TestShell_RebroadcastTransactions_OutsideRange_Txm(t *testing.T) { _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth()) - txStore := cltest.NewTestTxStore(t, sqlxDB, config.Database()) + txStore := cltest.NewTestTxStore(t, sqlxDB) cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, int64(test.nonce), 42, fromAddress) lggr := logger.TestLogger(t) diff --git a/core/cmd/shell_test.go b/core/cmd/shell_test.go index f265d5f4787..d57cfe1f645 100644 --- a/core/cmd/shell_test.go +++ b/core/cmd/shell_test.go @@ -17,6 +17,7 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" + commoncfg "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-solana/pkg/solana" solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" @@ -474,22 +475,25 @@ func TestSetupStarkNetRelayer(t *testing.T) { tConfig := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Starknet = stkcfg.TOMLConfigs{ &stkcfg.TOMLConfig{ - ChainID: ptr[string]("starknet-id-1"), - Enabled: ptr(true), - Chain: stkcfg.Chain{}, - Nodes: []*config.Node{}, + ChainID: ptr[string]("starknet-id-1"), + Enabled: ptr(true), + Chain: stkcfg.Chain{}, + Nodes: []*config.Node{}, + FeederURL: commoncfg.MustParseURL("https://feeder.url"), }, &stkcfg.TOMLConfig{ - ChainID: ptr[string]("starknet-id-2"), - Enabled: ptr(true), - Chain: stkcfg.Chain{}, - Nodes: []*config.Node{}, + ChainID: ptr[string]("starknet-id-2"), + Enabled: ptr(true), + Chain: stkcfg.Chain{}, + Nodes: []*config.Node{}, + FeederURL: commoncfg.MustParseURL("https://feeder.url"), }, &stkcfg.TOMLConfig{ - ChainID: ptr[string]("disabled-starknet-id-1"), - Enabled: ptr(false), - Chain: stkcfg.Chain{}, - Nodes: []*config.Node{}, + ChainID: ptr[string]("disabled-starknet-id-1"), + Enabled: ptr(false), + Chain: stkcfg.Chain{}, + Nodes: []*config.Node{}, + FeederURL: commoncfg.MustParseURL("https://feeder.url"), }, } }) @@ -497,10 +501,11 @@ func TestSetupStarkNetRelayer(t *testing.T) { t2Config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Starknet = stkcfg.TOMLConfigs{ &stkcfg.TOMLConfig{ - ChainID: ptr[string]("starknet-id-3"), - Enabled: ptr(true), - Chain: stkcfg.Chain{}, - Nodes: []*config.Node{}, + ChainID: ptr[string]("starknet-id-3"), + Enabled: ptr(true), + Chain: stkcfg.Chain{}, + Nodes: []*config.Node{}, + FeederURL: commoncfg.MustParseURL("https://feeder.url"), }, } }) @@ -534,16 +539,18 @@ func TestSetupStarkNetRelayer(t *testing.T) { duplicateConfig := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Starknet = stkcfg.TOMLConfigs{ &stkcfg.TOMLConfig{ - ChainID: ptr[string]("dupe"), - Enabled: ptr(true), - Chain: stkcfg.Chain{}, - Nodes: []*config.Node{}, + ChainID: ptr[string]("dupe"), + Enabled: ptr(true), + Chain: stkcfg.Chain{}, + Nodes: []*config.Node{}, + FeederURL: commoncfg.MustParseURL("https://feeder.url"), }, &stkcfg.TOMLConfig{ - ChainID: ptr[string]("dupe"), - Enabled: ptr(true), - Chain: stkcfg.Chain{}, - Nodes: []*config.Node{}, + ChainID: ptr[string]("dupe"), + Enabled: ptr(true), + Chain: stkcfg.Chain{}, + Nodes: []*config.Node{}, + FeederURL: commoncfg.MustParseURL("https://feeder.url"), }, } }) diff --git a/core/config/docs/chains-evm.toml b/core/config/docs/chains-evm.toml index dcf2f6e688e..dd63edaf694 100644 --- a/core/config/docs/chains-evm.toml +++ b/core/config/docs/chains-evm.toml @@ -344,7 +344,14 @@ LeaseDuration = '0s' # Default # # Set true to enable this check NodeIsSyncingEnabled = false # Default - +# FinalizedBlockPollInterval controls how often to poll RPC for new finalized blocks. +# The finalized block is only used to report to the `pool_rpc_node_highest_finalized_block` metric. We plan to use it +# in RPCs health assessment in the future. +# If `FinalityTagEnabled = false`, poll is not performed and `pool_rpc_node_highest_finalized_block` is +# reported based on latest block and finality depth. +# +# Set to 0 to disable. +FinalizedBlockPollInterval = '5s' # Default [EVM.OCR] # ContractConfirmations sets `OCR.ContractConfirmations` for this EVM chain. ContractConfirmations = 4 # Default diff --git a/core/config/docs/chains-starknet.toml b/core/config/docs/chains-starknet.toml index 8694290a7d6..4ea2647a72d 100644 --- a/core/config/docs/chains-starknet.toml +++ b/core/config/docs/chains-starknet.toml @@ -1,6 +1,8 @@ [[Starknet]] # ChainID is the Starknet chain ID. ChainID = 'foobar' # Example +# FeederURL is required to get tx metadata (that the RPC can't) +FeederURL = 'http://feeder.url' # Example # Enabled enables this chain. Enabled = true # Default # OCR2CachePollPeriod is the rate to poll for the OCR2 state cache. @@ -19,3 +21,5 @@ ConfirmationPoll = '5s' # Default Name = 'primary' # Example # URL is the base HTTP(S) endpoint for this node. URL = 'http://stark.node' # Example +# APIKey Header is optional and only required for Nethermind RPCs +APIKey = 'key' # Example diff --git a/core/config/docs/core.toml b/core/config/docs/core.toml index 984080ea3f1..605f6ced0bc 100644 --- a/core/config/docs/core.toml +++ b/core/config/docs/core.toml @@ -30,7 +30,7 @@ MaxIdleConns = 10 # Default # MaxOpenConns configures the maximum number of database connections that a Chainlink node will have open at any one time. Think of this as the maximum burst upper bound limit of database connections per Chainlink node instance. Increasing this number can help to improve performance under database-heavy workloads. # # Postgres has connection limits, so you must use caution when increasing this value. If you are running several instances of a Chainlink node or another application on a single database server, you might run out of Postgres connection slots if you raise this value too high. -MaxOpenConns = 20 # Default +MaxOpenConns = 100 # Default # MigrateOnStartup controls whether a Chainlink node will attempt to automatically migrate the database on boot. If you want more control over your database migration process, set this variable to `false` and manually migrate the database using the CLI `migrate` command instead. MigrateOnStartup = true # Default @@ -280,6 +280,12 @@ ReaperThreshold = '24h' # Default # **ADVANCED** # ResultWriteQueueDepth controls how many writes will be buffered before subsequent writes are dropped, for jobs that write results asynchronously for performance reasons, such as OCR. ResultWriteQueueDepth = 100 # Default +# VerboseLogging enables detailed logging of pipeline execution steps. +# This can be useful for debugging failed runs without relying on the UI +# or database. +# +# You may disable if this results in excessive log volume. +VerboseLogging = true # Default [JobPipeline.HTTPRequest] # DefaultTimeout defines the default timeout for HTTP requests made by `http` and `bridge` adapters. diff --git a/core/config/docs/docs_test.go b/core/config/docs/docs_test.go index 919113e1d93..35a78762e64 100644 --- a/core/config/docs/docs_test.go +++ b/core/config/docs/docs_test.go @@ -17,10 +17,10 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/config/docs" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink/cfgtest" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" ) func TestDoc(t *testing.T) { @@ -51,7 +51,7 @@ func TestDoc(t *testing.T) { // clean up KeySpecific as a special case require.Equal(t, 1, len(docDefaults.KeySpecific)) - ks := evmcfg.KeySpecific{Key: new(ethkey.EIP55Address), + ks := evmcfg.KeySpecific{Key: new(types.EIP55Address), GasEstimator: evmcfg.KeySpecificGasEstimator{PriceMax: new(assets.Wei)}} require.Equal(t, ks, docDefaults.KeySpecific[0]) docDefaults.KeySpecific = nil diff --git a/core/config/job_pipeline_config.go b/core/config/job_pipeline_config.go index d4a01dbed03..9b1fdc6d090 100644 --- a/core/config/job_pipeline_config.go +++ b/core/config/job_pipeline_config.go @@ -15,4 +15,5 @@ type JobPipeline interface { ReaperThreshold() time.Duration ResultWriteQueueDepth() uint64 ExternalInitiatorsEnabled() bool + VerboseLogging() bool } diff --git a/core/config/ocr_config.go b/core/config/ocr_config.go index 9f891511dd3..bde2142c846 100644 --- a/core/config/ocr_config.go +++ b/core/config/ocr_config.go @@ -3,7 +3,7 @@ package config import ( "time" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ) // OCR is a subset of global config relevant to OCR v1. @@ -16,7 +16,7 @@ type OCR interface { KeyBundleID() (string, error) ObservationTimeout() time.Duration SimulateTransactions() bool - TransmitterAddress() (ethkey.EIP55Address, error) // OCR2 can support non-evm changes + TransmitterAddress() (types.EIP55Address, error) // OCR2 can support non-evm changes // OCR1 config, cannot override in jobs TraceLogging() bool DefaultTransactionQueueDepth() uint32 diff --git a/core/config/toml/types.go b/core/config/toml/types.go index 68445f5b860..ed52c21e34e 100644 --- a/core/config/toml/types.go +++ b/core/config/toml/types.go @@ -15,10 +15,11 @@ import ( ocrcommontypes "github.com/smartcontractkit/libocr/commontypes" commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink/v2/core/build" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/parse" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/sessions" "github.com/smartcontractkit/chainlink/v2/core/store/dialects" @@ -853,6 +854,7 @@ type JobPipeline struct { ReaperInterval *commonconfig.Duration ReaperThreshold *commonconfig.Duration ResultWriteQueueDepth *uint32 + VerboseLogging *bool HTTPRequest JobPipelineHTTPRequest `toml:",omitempty"` } @@ -876,6 +878,9 @@ func (j *JobPipeline) setFrom(f *JobPipeline) { if v := f.ResultWriteQueueDepth; v != nil { j.ResultWriteQueueDepth = v } + if v := f.VerboseLogging; v != nil { + j.VerboseLogging = v + } j.HTTPRequest.setFrom(&f.HTTPRequest) } @@ -976,7 +981,7 @@ type OCR struct { // Optional KeyBundleID *models.Sha256Hash SimulateTransactions *bool - TransmitterAddress *ethkey.EIP55Address + TransmitterAddress *types.EIP55Address CaptureEATelemetry *bool TraceLogging *bool } diff --git a/core/gethwrappers/README.md b/core/gethwrappers/README.md index 07830f44201..04a029cb532 100644 --- a/core/gethwrappers/README.md +++ b/core/gethwrappers/README.md @@ -18,14 +18,14 @@ To reduce explicit dependencies, and in case the system does not have the correct version of abigen installed , the above commands spin up docker containers. In my hands, total running time including compilation is about 13s. If you're modifying solidity code and testing against go code a lot, it -might be worthwhile to generate the the wrappers using a static container +might be worthwhile to generate the wrappers using a static container with abigen and solc, which will complete much faster. E.g. ``` - abigen -sol ../../contracts/src/v0.6/VRFAll.sol -pkg vrf -out solidity_interfaces.go + abigen -sol ../../contracts/src/v0.8/vrf/VRF.sol -pkg vrf -out solidity_interfaces.go ``` -where VRFAll.sol simply contains `import "contract_path";` instructions for +where VRF.sol simply contains `import "contract_path";` instructions for all the contracts you wish to target. This runs in about 0.25 seconds in my hands. diff --git a/core/gethwrappers/functions/generated/functions_allow_list/functions_allow_list.go b/core/gethwrappers/functions/generated/functions_allow_list/functions_allow_list.go index 023956b7314..2f98ae1623d 100644 --- a/core/gethwrappers/functions/generated/functions_allow_list/functions_allow_list.go +++ b/core/gethwrappers/functions/generated/functions_allow_list/functions_allow_list.go @@ -37,7 +37,7 @@ type TermsOfServiceAllowListConfig struct { var TermsOfServiceAllowListMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"internalType\":\"structTermsOfServiceAllowListConfig\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"initialAllowedSenders\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"initialBlockedSenders\",\"type\":\"address[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSignature\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidUsage\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIsBlocked\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"AddedAccess\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"BlockedAccess\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structTermsOfServiceAllowListConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"UnblockedAccess\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"acceptor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"}],\"name\":\"acceptTermsOfService\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"blockSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllAllowedSenders\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowedSendersCount\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"allowedSenderIdxStart\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"allowedSenderIdxEnd\",\"type\":\"uint64\"}],\"name\":\"getAllowedSendersInRange\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"allowedSenders\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBlockedSendersCount\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"blockedSenderIdxStart\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"blockedSenderIdxEnd\",\"type\":\"uint64\"}],\"name\":\"getBlockedSendersInRange\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"blockedSenders\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"internalType\":\"structTermsOfServiceAllowListConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"acceptor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"getMessage\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"hasAccess\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"isBlockedSender\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"unblockSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"internalType\":\"structTermsOfServiceAllowListConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60806040523480156200001157600080fd5b5060405162001a3038038062001a308339810160408190526200003491620004d9565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620001d4565b505050620000d2836200027f60201b60201c565b60005b8251811015620001255762000111838281518110620000f857620000f8620005a8565b602002602001015160026200030660201b90919060201c565b506200011d81620005be565b9050620000d5565b5060005b8151811015620001ca57620001658282815181106200014c576200014c620005a8565b602002602001015160026200032660201b90919060201c565b156200018457604051638129bbcd60e01b815260040160405180910390fd5b620001b68282815181106200019d576200019d620005a8565b602002602001015160046200030660201b90919060201c565b50620001c281620005be565b905062000129565b50505050620005e6565b336001600160a01b038216036200022e5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6200028962000349565b805160068054602080850180516001600160a81b0319909316941515610100600160a81b03198116959095176101006001600160a01b039485160217909355604080519485529251909116908301527f0d22b8a99f411b3dd338c961284f608489ca0dab9cdad17366a343c361bcf80a910160405180910390a150565b60006200031d836001600160a01b038416620003a7565b90505b92915050565b6001600160a01b038116600090815260018301602052604081205415156200031d565b6000546001600160a01b03163314620003a55760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000082565b565b6000818152600183016020526040812054620003f05750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000320565b50600062000320565b634e487b7160e01b600052604160045260246000fd5b80516001600160a01b03811681146200042757600080fd5b919050565b600082601f8301126200043e57600080fd5b815160206001600160401b03808311156200045d576200045d620003f9565b8260051b604051601f19603f83011681018181108482111715620004855762000485620003f9565b604052938452858101830193838101925087851115620004a457600080fd5b83870191505b84821015620004ce57620004be826200040f565b83529183019190830190620004aa565b979650505050505050565b60008060008385036080811215620004f057600080fd5b6040811215620004ff57600080fd5b50604080519081016001600160401b038082118383101715620005265762000526620003f9565b816040528651915081151582146200053d57600080fd5b8183526200054e602088016200040f565b60208401526040870151929550808311156200056957600080fd5b62000577888489016200042c565b945060608701519250808311156200058e57600080fd5b50506200059e868287016200042c565b9150509250925092565b634e487b7160e01b600052603260045260246000fd5b600060018201620005df57634e487b7160e01b600052601160045260246000fd5b5060010190565b61143a80620005f66000396000f3fe608060405234801561001057600080fd5b506004361061011b5760003560e01c8063817ef62e116100b2578063a39b06e311610081578063c3f909d411610066578063c3f909d4146102c3578063cc7ebf4914610322578063f2fde38b1461032a57600080fd5b8063a39b06e314610237578063a5e1d61d146102b057600080fd5b8063817ef62e146101e157806382184c7b146101e957806389f9a2c4146101fc5780638da5cb5b1461020f57600080fd5b80633908c4d4116100ee5780633908c4d41461018e57806347663acb146101a35780636b14daf8146101b657806379ba5097146101d957600080fd5b806301a05958146101205780630a8c9c2414610146578063181f5a771461016657806320229a861461017b575b600080fd5b61012861033d565b60405167ffffffffffffffff90911681526020015b60405180910390f35b610159610154366004610fd6565b61034e565b60405161013d9190611009565b61016e6104bc565b60405161013d9190611063565b610159610189366004610fd6565b6104d8565b6101a161019c3660046110f3565b61063e565b005b6101a16101b1366004611154565b6108e9565b6101c96101c436600461116f565b61094a565b604051901515815260200161013d565b6101a1610974565b610159610a76565b6101a16101f7366004611154565b610a82565b6101a161020a366004611221565b610ae8565b60005460405173ffffffffffffffffffffffffffffffffffffffff909116815260200161013d565b6102a26102453660046112aa565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084811b8216602084015283901b16603482015260009060480160405160208183030381529060405280519060200120905092915050565b60405190815260200161013d565b6101c96102be366004611154565b610ba3565b60408051808201825260008082526020918201528151808301835260065460ff8116151580835273ffffffffffffffffffffffffffffffffffffffff61010090920482169284019283528451908152915116918101919091520161013d565b610128610bc3565b6101a1610338366004611154565b610bcf565b60006103496004610be3565b905090565b60608167ffffffffffffffff168367ffffffffffffffff16118061038557506103776002610be3565b8267ffffffffffffffff1610155b8061039757506103956002610be3565b155b156103ce576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6103d88383611303565b6103e3906001611324565b67ffffffffffffffff1667ffffffffffffffff811115610405576104056111f2565b60405190808252806020026020018201604052801561042e578160200160208202803683370190505b50905060005b61043e8484611303565b67ffffffffffffffff1681116104b45761046d6104658267ffffffffffffffff8716611345565b600290610bed565b82828151811061047f5761047f611358565b73ffffffffffffffffffffffffffffffffffffffff909216602092830291909101909101526104ad81611387565b9050610434565b505b92915050565b6040518060600160405280602c8152602001611402602c913981565b60608167ffffffffffffffff168367ffffffffffffffff16118061050f57506105016004610be3565b8267ffffffffffffffff1610155b80610521575061051f6004610be3565b155b15610558576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105628383611303565b61056d906001611324565b67ffffffffffffffff1667ffffffffffffffff81111561058f5761058f6111f2565b6040519080825280602002602001820160405280156105b8578160200160208202803683370190505b50905060005b6105c88484611303565b67ffffffffffffffff1681116104b4576105f76105ef8267ffffffffffffffff8716611345565b600490610bed565b82828151811061060957610609611358565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015261063781611387565b90506105be565b610649600485610bf9565b15610680576040517f62b7a34d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051606087811b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009081166020808501919091529188901b16603483015282516028818403018152604890920190925280519101206000906040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c810191909152605c01604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815282825280516020918201206006546000855291840180845281905260ff8616928401929092526060830187905260808301869052909250610100900473ffffffffffffffffffffffffffffffffffffffff169060019060a0016020604051602081039080840390855afa1580156107b4573d6000803e3d6000fd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff161461080b576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff861614158061085057503373ffffffffffffffffffffffffffffffffffffffff8716148015906108505750333b155b15610887576040517f381cfcbd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610892600286610c28565b156108e15760405173ffffffffffffffffffffffffffffffffffffffff861681527f87286ad1f399c8e82bf0c4ef4fcdc570ea2e1e92176e5c848b6413545b885db49060200160405180910390a15b505050505050565b6108f1610c4a565b6108fc600482610ccd565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527f28bbd0761309a99e8fb5e5d02ada0b7b2db2e5357531ff5dbfc205c3f5b6592b906020015b60405180910390a150565b60065460009060ff1661095f5750600161096d565b61096a600285610bf9565b90505b9392505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146109fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60606103496002610cef565b610a8a610c4a565b610a95600282610ccd565b50610aa1600482610c28565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527f337cd0f3f594112b6d830afb510072d3b08556b446514f73b8109162fd1151e19060200161093f565b610af0610c4a565b805160068054602080850180517fffffffffffffffffffffff0000000000000000000000000000000000000000009093169415157fffffffffffffffffffffff0000000000000000000000000000000000000000ff81169590951761010073ffffffffffffffffffffffffffffffffffffffff9485160217909355604080519485529251909116908301527f0d22b8a99f411b3dd338c961284f608489ca0dab9cdad17366a343c361bcf80a910161093f565b60065460009060ff16610bb857506000919050565b6104b6600483610bf9565b60006103496002610be3565b610bd7610c4a565b610be081610cfc565b50565b60006104b6825490565b600061096d8383610df1565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600183016020526040812054151561096d565b600061096d8373ffffffffffffffffffffffffffffffffffffffff8416610e1b565b60005473ffffffffffffffffffffffffffffffffffffffff163314610ccb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016109f1565b565b600061096d8373ffffffffffffffffffffffffffffffffffffffff8416610e6a565b6060600061096d83610f5d565b3373ffffffffffffffffffffffffffffffffffffffff821603610d7b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016109f1565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000826000018281548110610e0857610e08611358565b9060005260206000200154905092915050565b6000818152600183016020526040812054610e62575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556104b6565b5060006104b6565b60008181526001830160205260408120548015610f53576000610e8e6001836113bf565b8554909150600090610ea2906001906113bf565b9050818114610f07576000866000018281548110610ec257610ec2611358565b9060005260206000200154905080876000018481548110610ee557610ee5611358565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610f1857610f186113d2565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506104b6565b60009150506104b6565b606081600001805480602002602001604051908101604052809291908181526020018280548015610fad57602002820191906000526020600020905b815481526020019060010190808311610f99575b50505050509050919050565b803567ffffffffffffffff81168114610fd157600080fd5b919050565b60008060408385031215610fe957600080fd5b610ff283610fb9565b915061100060208401610fb9565b90509250929050565b6020808252825182820181905260009190848201906040850190845b8181101561105757835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101611025565b50909695505050505050565b600060208083528351808285015260005b8181101561109057858101830151858201604001528201611074565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610fd157600080fd5b600080600080600060a0868803121561110b57600080fd5b611114866110cf565b9450611122602087016110cf565b93506040860135925060608601359150608086013560ff8116811461114657600080fd5b809150509295509295909350565b60006020828403121561116657600080fd5b61096d826110cf565b60008060006040848603121561118457600080fd5b61118d846110cf565b9250602084013567ffffffffffffffff808211156111aa57600080fd5b818601915086601f8301126111be57600080fd5b8135818111156111cd57600080fd5b8760208285010111156111df57600080fd5b6020830194508093505050509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006040828403121561123357600080fd5b6040516040810181811067ffffffffffffffff8211171561127d577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040528235801515811461129057600080fd5b815261129e602084016110cf565b60208201529392505050565b600080604083850312156112bd57600080fd5b6112c6836110cf565b9150611000602084016110cf565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b67ffffffffffffffff8281168282160390808211156104b4576104b46112d4565b67ffffffffffffffff8181168382160190808211156104b4576104b46112d4565b808201808211156104b6576104b66112d4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036113b8576113b86112d4565b5060010190565b818103818111156104b6576104b66112d4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe46756e6374696f6e73205465726d73206f66205365727669636520416c6c6f77204c6973742076312e312e30a164736f6c6343000813000a", + Bin: "0x60806040523480156200001157600080fd5b5060405162001a1e38038062001a1e8339810160408190526200003491620004d9565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620001d4565b505050620000d2836200027f60201b60201c565b60005b8251811015620001255762000111838281518110620000f857620000f8620005a8565b602002602001015160026200030660201b90919060201c565b506200011d81620005be565b9050620000d5565b5060005b8151811015620001ca57620001658282815181106200014c576200014c620005a8565b602002602001015160026200032660201b90919060201c565b156200018457604051638129bbcd60e01b815260040160405180910390fd5b620001b68282815181106200019d576200019d620005a8565b602002602001015160046200030660201b90919060201c565b50620001c281620005be565b905062000129565b50505050620005e6565b336001600160a01b038216036200022e5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6200028962000349565b805160068054602080850180516001600160a81b0319909316941515610100600160a81b03198116959095176101006001600160a01b039485160217909355604080519485529251909116908301527f0d22b8a99f411b3dd338c961284f608489ca0dab9cdad17366a343c361bcf80a910160405180910390a150565b60006200031d836001600160a01b038416620003a7565b90505b92915050565b6001600160a01b038116600090815260018301602052604081205415156200031d565b6000546001600160a01b03163314620003a55760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000082565b565b6000818152600183016020526040812054620003f05750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000320565b50600062000320565b634e487b7160e01b600052604160045260246000fd5b80516001600160a01b03811681146200042757600080fd5b919050565b600082601f8301126200043e57600080fd5b815160206001600160401b03808311156200045d576200045d620003f9565b8260051b604051601f19603f83011681018181108482111715620004855762000485620003f9565b604052938452858101830193838101925087851115620004a457600080fd5b83870191505b84821015620004ce57620004be826200040f565b83529183019190830190620004aa565b979650505050505050565b60008060008385036080811215620004f057600080fd5b6040811215620004ff57600080fd5b50604080519081016001600160401b038082118383101715620005265762000526620003f9565b816040528651915081151582146200053d57600080fd5b8183526200054e602088016200040f565b60208401526040870151929550808311156200056957600080fd5b62000577888489016200042c565b945060608701519250808311156200058e57600080fd5b50506200059e868287016200042c565b9150509250925092565b634e487b7160e01b600052603260045260246000fd5b600060018201620005df57634e487b7160e01b600052601160045260246000fd5b5060010190565b61142880620005f66000396000f3fe608060405234801561001057600080fd5b506004361061011b5760003560e01c8063817ef62e116100b2578063a39b06e311610081578063c3f909d411610066578063c3f909d4146102c3578063cc7ebf4914610322578063f2fde38b1461032a57600080fd5b8063a39b06e314610237578063a5e1d61d146102b057600080fd5b8063817ef62e146101e157806382184c7b146101e957806389f9a2c4146101fc5780638da5cb5b1461020f57600080fd5b80633908c4d4116100ee5780633908c4d41461018e57806347663acb146101a35780636b14daf8146101b657806379ba5097146101d957600080fd5b806301a05958146101205780630a8c9c2414610146578063181f5a771461016657806320229a861461017b575b600080fd5b61012861033d565b60405167ffffffffffffffff90911681526020015b60405180910390f35b610159610154366004610fc4565b61034e565b60405161013d9190610ff7565b61016e6104aa565b60405161013d9190611051565b610159610189366004610fc4565b6104c6565b6101a161019c3660046110e1565b61062c565b005b6101a16101b1366004611142565b6108d7565b6101c96101c436600461115d565b610938565b604051901515815260200161013d565b6101a1610962565b610159610a64565b6101a16101f7366004611142565b610a70565b6101a161020a36600461120f565b610ad6565b60005460405173ffffffffffffffffffffffffffffffffffffffff909116815260200161013d565b6102a2610245366004611298565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084811b8216602084015283901b16603482015260009060480160405160208183030381529060405280519060200120905092915050565b60405190815260200161013d565b6101c96102be366004611142565b610b91565b60408051808201825260008082526020918201528151808301835260065460ff8116151580835273ffffffffffffffffffffffffffffffffffffffff61010090920482169284019283528451908152915116918101919091520161013d565b610128610bb1565b6101a1610338366004611142565b610bbd565b60006103496004610bd1565b905090565b60608167ffffffffffffffff168367ffffffffffffffff16118061038557506103776002610bd1565b8267ffffffffffffffff1610155b156103bc576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6103c683836112f1565b6103d1906001611312565b67ffffffffffffffff1667ffffffffffffffff8111156103f3576103f36111e0565b60405190808252806020026020018201604052801561041c578160200160208202803683370190505b50905060005b61042c84846112f1565b67ffffffffffffffff1681116104a25761045b6104538267ffffffffffffffff8716611333565b600290610bdb565b82828151811061046d5761046d611346565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015261049b81611375565b9050610422565b505b92915050565b6040518060600160405280602c81526020016113f0602c913981565b60608167ffffffffffffffff168367ffffffffffffffff1611806104fd57506104ef6004610bd1565b8267ffffffffffffffff1610155b8061050f575061050d6004610bd1565b155b15610546576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61055083836112f1565b61055b906001611312565b67ffffffffffffffff1667ffffffffffffffff81111561057d5761057d6111e0565b6040519080825280602002602001820160405280156105a6578160200160208202803683370190505b50905060005b6105b684846112f1565b67ffffffffffffffff1681116104a2576105e56105dd8267ffffffffffffffff8716611333565b600490610bdb565b8282815181106105f7576105f7611346565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015261062581611375565b90506105ac565b610637600485610be7565b1561066e576040517f62b7a34d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051606087811b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009081166020808501919091529188901b16603483015282516028818403018152604890920190925280519101206000906040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c810191909152605c01604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815282825280516020918201206006546000855291840180845281905260ff8616928401929092526060830187905260808301869052909250610100900473ffffffffffffffffffffffffffffffffffffffff169060019060a0016020604051602081039080840390855afa1580156107a2573d6000803e3d6000fd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff16146107f9576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff861614158061083e57503373ffffffffffffffffffffffffffffffffffffffff87161480159061083e5750333b155b15610875576040517f381cfcbd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610880600286610c16565b156108cf5760405173ffffffffffffffffffffffffffffffffffffffff861681527f87286ad1f399c8e82bf0c4ef4fcdc570ea2e1e92176e5c848b6413545b885db49060200160405180910390a15b505050505050565b6108df610c38565b6108ea600482610cbb565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527f28bbd0761309a99e8fb5e5d02ada0b7b2db2e5357531ff5dbfc205c3f5b6592b906020015b60405180910390a150565b60065460009060ff1661094d5750600161095b565b610958600285610be7565b90505b9392505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146109e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60606103496002610cdd565b610a78610c38565b610a83600282610cbb565b50610a8f600482610c16565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527f337cd0f3f594112b6d830afb510072d3b08556b446514f73b8109162fd1151e19060200161092d565b610ade610c38565b805160068054602080850180517fffffffffffffffffffffff0000000000000000000000000000000000000000009093169415157fffffffffffffffffffffff0000000000000000000000000000000000000000ff81169590951761010073ffffffffffffffffffffffffffffffffffffffff9485160217909355604080519485529251909116908301527f0d22b8a99f411b3dd338c961284f608489ca0dab9cdad17366a343c361bcf80a910161092d565b60065460009060ff16610ba657506000919050565b6104a4600483610be7565b60006103496002610bd1565b610bc5610c38565b610bce81610cea565b50565b60006104a4825490565b600061095b8383610ddf565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600183016020526040812054151561095b565b600061095b8373ffffffffffffffffffffffffffffffffffffffff8416610e09565b60005473ffffffffffffffffffffffffffffffffffffffff163314610cb9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016109df565b565b600061095b8373ffffffffffffffffffffffffffffffffffffffff8416610e58565b6060600061095b83610f4b565b3373ffffffffffffffffffffffffffffffffffffffff821603610d69576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016109df565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000826000018281548110610df657610df6611346565b9060005260206000200154905092915050565b6000818152600183016020526040812054610e50575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556104a4565b5060006104a4565b60008181526001830160205260408120548015610f41576000610e7c6001836113ad565b8554909150600090610e90906001906113ad565b9050818114610ef5576000866000018281548110610eb057610eb0611346565b9060005260206000200154905080876000018481548110610ed357610ed3611346565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610f0657610f066113c0565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506104a4565b60009150506104a4565b606081600001805480602002602001604051908101604052809291908181526020018280548015610f9b57602002820191906000526020600020905b815481526020019060010190808311610f87575b50505050509050919050565b803567ffffffffffffffff81168114610fbf57600080fd5b919050565b60008060408385031215610fd757600080fd5b610fe083610fa7565b9150610fee60208401610fa7565b90509250929050565b6020808252825182820181905260009190848201906040850190845b8181101561104557835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101611013565b50909695505050505050565b600060208083528351808285015260005b8181101561107e57858101830151858201604001528201611062565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610fbf57600080fd5b600080600080600060a086880312156110f957600080fd5b611102866110bd565b9450611110602087016110bd565b93506040860135925060608601359150608086013560ff8116811461113457600080fd5b809150509295509295909350565b60006020828403121561115457600080fd5b61095b826110bd565b60008060006040848603121561117257600080fd5b61117b846110bd565b9250602084013567ffffffffffffffff8082111561119857600080fd5b818601915086601f8301126111ac57600080fd5b8135818111156111bb57600080fd5b8760208285010111156111cd57600080fd5b6020830194508093505050509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006040828403121561122157600080fd5b6040516040810181811067ffffffffffffffff8211171561126b577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040528235801515811461127e57600080fd5b815261128c602084016110bd565b60208201529392505050565b600080604083850312156112ab57600080fd5b6112b4836110bd565b9150610fee602084016110bd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b67ffffffffffffffff8281168282160390808211156104a2576104a26112c2565b67ffffffffffffffff8181168382160190808211156104a2576104a26112c2565b808201808211156104a4576104a46112c2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036113a6576113a66112c2565b5060010190565b818103818111156104a4576104a46112c2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe46756e6374696f6e73205465726d73206f66205365727669636520416c6c6f77204c6973742076312e312e30a164736f6c6343000813000a", } var TermsOfServiceAllowListABI = TermsOfServiceAllowListMetaData.ABI diff --git a/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go b/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go index 6099c541c69..286cb1befd6 100644 --- a/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go +++ b/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go @@ -75,7 +75,7 @@ type FunctionsResponseRequestMeta struct { var FunctionsCoordinatorMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint64\",\"name\":\"fallbackUsdPerUnitLink\",\"type\":\"uint64\"},{\"internalType\":\"uint8\",\"name\":\"fallbackUsdPerUnitLinkDecimals\",\"type\":\"uint8\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"donFeeCentsUsd\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"operationFeeCentsUsd\",\"type\":\"uint16\"}],\"internalType\":\"structFunctionsBillingConfig\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"linkToNativeFeed\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkToUsdFeed\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyPublicKey\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InconsistentReportData\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"usdLink\",\"type\":\"int256\"}],\"name\":\"InvalidUsdLinkPrice\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoTransmittersSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouterOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"ReportInvalid\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RouterMustBeSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedPublicKeyChange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSender\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsupportedRequestDataVersion\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"CommitmentDeleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint64\",\"name\":\"fallbackUsdPerUnitLink\",\"type\":\"uint64\"},{\"internalType\":\"uint8\",\"name\":\"fallbackUsdPerUnitLinkDecimals\",\"type\":\"uint8\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"donFeeCentsUsd\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"operationFeeCentsUsd\",\"type\":\"uint16\"}],\"indexed\":false,\"internalType\":\"structFunctionsBillingConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestInitiator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"callbackGasLimit\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"name\":\"OracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"OracleResponse\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"juelsPerGas\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1FeeShareWei\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"callbackCostJuels\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint72\",\"name\":\"donFeeJuels\",\"type\":\"uint72\"},{\"indexed\":false,\"internalType\":\"uint72\",\"name\":\"adminFeeJuels\",\"type\":\"uint72\"},{\"indexed\":false,\"internalType\":\"uint72\",\"name\":\"operationFeeJuels\",\"type\":\"uint72\"}],\"name\":\"RequestBilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"deleteCommitment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"gasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateCost\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdminFeeJuels\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint64\",\"name\":\"fallbackUsdPerUnitLink\",\"type\":\"uint64\"},{\"internalType\":\"uint8\",\"name\":\"fallbackUsdPerUnitLinkDecimals\",\"type\":\"uint8\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"donFeeCentsUsd\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"operationFeeCentsUsd\",\"type\":\"uint16\"}],\"internalType\":\"structFunctionsBillingConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"getDONFeeJuels\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDONPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getOperationFeeJuels\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getThresholdPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getUsdPerUnitLink\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oracleWithdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"_f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"_onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"_offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"_offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"donPublicKey\",\"type\":\"bytes\"}],\"name\":\"setDONPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"thresholdPublicKey\",\"type\":\"bytes\"}],\"name\":\"setThresholdPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"availableBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"initiatedRequests\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint64\",\"name\":\"completedRequests\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"}],\"internalType\":\"structFunctionsResponse.RequestMeta\",\"name\":\"request\",\"type\":\"tuple\"}],\"name\":\"startRequest\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"transmitters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint64\",\"name\":\"fallbackUsdPerUnitLink\",\"type\":\"uint64\"},{\"internalType\":\"uint8\",\"name\":\"fallbackUsdPerUnitLinkDecimals\",\"type\":\"uint8\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"donFeeCentsUsd\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"operationFeeCentsUsd\",\"type\":\"uint16\"}],\"internalType\":\"structFunctionsBillingConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b506040516200601f3803806200601f8339810160408190526200003491620004db565b83838383833380600081620000905760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c357620000c3816200014e565b5050506001600160a01b038116620000ee57604051632530e88560e11b815260040160405180910390fd5b6001600160a01b03908116608052600c80546001600160601b03166c0100000000000000000000000085841602179055600d80546001600160a01b0319169183169190911790556200014083620001f9565b505050505050505062000742565b336001600160a01b03821603620001a85760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000087565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620002036200039e565b80516008805460208401516040808601516060870151608088015160a089015160c08a015160e08b015160ff16600160f81b026001600160f81b036001600160401b03909216600160b81b02919091166001600160b81b0361ffff938416600160a81b0261ffff60a81b1964ffffffffff909616600160801b029590951666ffffffffffffff60801b1963ffffffff9788166c010000000000000000000000000263ffffffff60601b19998916680100000000000000000299909916600160401b600160801b03199b8916640100000000026001600160401b0319909d169e89169e909e179b909b17999099169b909b1795909517979097169590951717969096161792909217909255610100840151610120850151909316600160e01b026001600160e01b0390931692909217600955610140830151600a80546101608601518416620100000263ffffffff19919091169290931691909117919091179055517f2e2c8535dcc25459d519f2300c114d2d2128bf6399722d04eca078461a3bf33a906200039390839062000639565b60405180910390a150565b620003a8620003aa565b565b6000546001600160a01b03163314620003a85760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000087565b80516001600160a01b03811681146200041e57600080fd5b919050565b60405161018081016001600160401b03811182821017156200045557634e487b7160e01b600052604160045260246000fd5b60405290565b805163ffffffff811681146200041e57600080fd5b805164ffffffffff811681146200041e57600080fd5b805161ffff811681146200041e57600080fd5b80516001600160401b03811681146200041e57600080fd5b805160ff811681146200041e57600080fd5b80516001600160e01b03811681146200041e57600080fd5b6000806000808486036101e0811215620004f457600080fd5b620004ff8662000406565b945061018080601f19830112156200051657600080fd5b6200052062000423565b915062000530602088016200045b565b825262000540604088016200045b565b602083015262000553606088016200045b565b604083015262000566608088016200045b565b60608301526200057960a0880162000470565b60808301526200058c60c0880162000486565b60a08301526200059f60e0880162000499565b60c0830152610100620005b4818901620004b1565b60e0840152610120620005c9818a01620004c3565b828501526101409150620005df828a016200045b565b90840152610160620005f389820162000486565b8285015262000604838a0162000486565b90840152509093506200061d90506101a0860162000406565b91506200062e6101c0860162000406565b905092959194509250565b815163ffffffff1681526101808101602083015162000660602084018263ffffffff169052565b50604083015162000679604084018263ffffffff169052565b50606083015162000692606084018263ffffffff169052565b506080830151620006ac608084018264ffffffffff169052565b5060a0830151620006c360a084018261ffff169052565b5060c0830151620006df60c08401826001600160401b03169052565b5060e0830151620006f560e084018260ff169052565b50610100838101516001600160e01b0316908301526101208084015163ffffffff16908301526101408084015161ffff908116918401919091526101609384015116929091019190915290565b608051615897620007886000396000818161079c01528181610c7d01528181610f110152818161102701528181611b2d015281816129eb015261396901526158976000f3fe608060405234801561001057600080fd5b50600436106101a35760003560e01c80638da5cb5b116100ee578063d227d24511610097578063e4ddcea611610071578063e4ddcea6146105d5578063f2f22ef1146105eb578063f2fde38b146105f3578063f6ea41f61461060657600080fd5b8063d227d2451461058a578063d328a91e146105ba578063e3d0e712146105c257600080fd5b8063b1dc65a4116100c8578063b1dc65a414610396578063ba9c924d146103a9578063c3f909d4146103bc57600080fd5b80638da5cb5b1461032e578063a631571e14610356578063afcb95d71461037657600080fd5b80637d4807871161015057806381f1b9381161012a57806381f1b938146102a657806381ff7048146102ae57806385b214cf1461031b57600080fd5b80637d480787146102765780637f15e1661461027e578063814118341461029157600080fd5b806366316d8d1161018157806366316d8d1461023c5780637212762f1461024f57806379ba50971461026e57600080fd5b8063083a5466146101a8578063181f5a77146101bd578063626f458c1461020f575b600080fd5b6101bb6101b6366004614010565b61060e565b005b6101f96040518060400160405280601c81526020017f46756e6374696f6e7320436f6f7264696e61746f722076312e332e300000000081525081565b60405161020691906140c0565b60405180910390f35b61022261021d36600461422d565b610663565b60405168ffffffffffffffffff9091168152602001610206565b6101bb61024a3660046142b4565b6106a0565b610257610859565b6040805192835260ff909116602083015201610206565b6101bb610a6c565b6101bb610b69565b6101bb61028c366004614010565b610d69565b610299610db9565b604051610206919061433e565b6101f9610e28565b6102f860015460025463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610206565b6101bb610329366004614351565b610ef9565b60005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610206565b61036961036436600461436a565b610fb6565b60405161020691906144bf565b604080516001815260006020820181905291810191909152606001610206565b6101bb6103a4366004614513565b611247565b6101bb6103b736600461467e565b61185e565b61057d6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915250604080516101808101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c01000000000000000000000000810483166060830152700100000000000000000000000000000000810464ffffffffff1660808301527501000000000000000000000000000000000000000000810461ffff90811660a084015277010000000000000000000000000000000000000000000000820467ffffffffffffffff1660c08401527f010000000000000000000000000000000000000000000000000000000000000090910460ff1660e08301526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81166101008401527c01000000000000000000000000000000000000000000000000000000009004909216610120820152600a5480831661014083015262010000900490911661016082015290565b604051610206919061476a565b61059d610598366004614887565b611b29565b6040516bffffffffffffffffffffffff9091168152602001610206565b6101f9611c97565b6101bb6105d036600461498f565b611cee565b6105dd61286a565b604051908152602001610206565b6102226129ae565b6101bb610601366004614a5c565b6129d3565b6102226129e7565b610616612a78565b6000819003610651576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f61065e828483614b0c565b505050565b600a5460009061069a9060649061067d9061ffff16612afb565b6106879190614c85565b6bffffffffffffffffffffffff16612b48565b92915050565b6106a8612be7565b806bffffffffffffffffffffffff166000036106e25750336000908152600b60205260409020546bffffffffffffffffffffffff1661073c565b336000908152600b60205260409020546bffffffffffffffffffffffff8083169116101561073c576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600b6020526040812080548392906107699084906bffffffffffffffffffffffff16614cb0565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506107be7f000000000000000000000000000000000000000000000000000000000000000090565b6040517f66316d8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff8416602483015291909116906366316d8d90604401600060405180830381600087803b15801561083d57600080fd5b505af1158015610851573d6000803e3d6000fd5b505050505050565b600080600080600d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156108cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f09190614cf6565b5093505092505080426109039190614d46565b600854640100000000900463ffffffff161080156109305750600854640100000000900463ffffffff1615155b1561098d57505060085477010000000000000000000000000000000000000000000000810467ffffffffffffffff16937f010000000000000000000000000000000000000000000000000000000000000090910460ff1692509050565b600082136109cf576040517f56b22ab8000000000000000000000000000000000000000000000000000000008152600481018390526024015b60405180910390fd5b600d54604080517f313ce5670000000000000000000000000000000000000000000000000000000081529051849273ffffffffffffffffffffffffffffffffffffffff169163313ce5679160048083019260209291908290030181865afa158015610a3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a629190614d59565b9350935050509091565b60015473ffffffffffffffffffffffffffffffffffffffff163314610aed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016109c6565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610b71612d93565b610b79612be7565b6000610b83610db9565b905060005b8151811015610d65576000600b6000848481518110610ba957610ba9614d76565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252810191909152604001600020546bffffffffffffffffffffffff1690508015610d54576000600b6000858581518110610c0857610c08614d76565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610c9f7f000000000000000000000000000000000000000000000000000000000000000090565b73ffffffffffffffffffffffffffffffffffffffff166366316d8d848481518110610ccc57610ccc614d76565b6020026020010151836040518363ffffffff1660e01b8152600401610d2192919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610d3b57600080fd5b505af1158015610d4f573d6000803e3d6000fd5b505050505b50610d5e81614da5565b9050610b88565b5050565b610d71612a78565b6000819003610dac576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e61065e828483614b0c565b60606006805480602002602001604051908101604052809291908181526020018280548015610e1e57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610df3575b5050505050905090565b6060600f8054610e3790614a79565b9050600003610e72576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f8054610e7f90614a79565b80601f0160208091040260200160405190810160405280929190818152602001828054610eab90614a79565b8015610e1e5780601f10610ecd57610100808354040283529160200191610e1e565b820191906000526020600020905b815481529060010190602001808311610edb57509395945050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610f68576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602052604080822091909155517f8a4b97add3359bd6bcf5e82874363670eb5ad0f7615abddbd0ed0a3a98f0f41690610fab9083815260200190565b60405180910390a150565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091523373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461107e576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061109161108c84614dff565b612d9b565b90925090506110a66060840160408501614a5c565b825173ffffffffffffffffffffffffffffffffffffffff91909116907fbf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff326110f460c0880160a08901614eec565b61110661016089016101408a01614a5c565b6111108980614f09565b6111226101208c016101008d01614f6e565b60208c01356111386101008e0160e08f01614f89565b6040518061016001604052808e6000015181526020018e6020015173ffffffffffffffffffffffffffffffffffffffff1681526020018e604001516bffffffffffffffffffffffff1681526020018e6060015173ffffffffffffffffffffffffffffffffffffffff1681526020018e6080015167ffffffffffffffff1681526020018e60a0015163ffffffff1681526020018d68ffffffffffffffffff1681526020018e60e0015168ffffffffffffffffff1681526020018e610100015164ffffffffff1681526020018e610120015164ffffffffff1681526020018e610140015163ffffffff1681525060405161123899989796959493929190614fa6565b60405180910390a3505b919050565b600080611254898961314d565b915091508115611265575050611854565b604080518b3580825262ffffff6020808f0135600881901c9290921690840152909290917fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16112c28b8b8b8b8b8b6132d6565b6003546000906002906112e09060ff8082169161010090041661505c565b6112ea9190615075565b6112f590600161505c565b60ff169050888114611363576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e61747572657300000000000060448201526064016109c6565b8887146113f2576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f7265706f727420727320616e64207373206d757374206265206f66206571756160448201527f6c206c656e67746800000000000000000000000000000000000000000000000060648201526084016109c6565b3360009081526004602090815260408083208151808301909252805460ff8082168452929391929184019161010090910416600281111561143557611435615097565b600281111561144657611446615097565b905250905060028160200151600281111561146357611463615097565b141580156114ac57506006816000015160ff168154811061148657611486614d76565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff163314155b15611513576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f756e617574686f72697a6564207472616e736d6974746572000000000000000060448201526064016109c6565b5050505061151f613faf565b60008a8a6040516115319291906150c6565b604051908190038120611548918e906020016150d6565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838301909252600080845290830152915060005b898110156118445760006001848984602081106115b1576115b1614d76565b6115be91901a601b61505c565b8e8e868181106115d0576115d0614d76565b905060200201358d8d878181106115e9576115e9614d76565b9050602002013560405160008152602001604052604051611626949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611648573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526004602090815290849020838501909452835460ff808216855292965092945084019161010090041660028111156116c8576116c8615097565b60028111156116d9576116d9615097565b90525092506001836020015160028111156116f6576116f6615097565b1461175d576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f61646472657373206e6f7420617574686f72697a656420746f207369676e000060448201526064016109c6565b8251600090869060ff16601f811061177757611777614d76565b602002015173ffffffffffffffffffffffffffffffffffffffff16146117f9576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6e6f6e2d756e69717565207369676e617475726500000000000000000000000060448201526064016109c6565b8085846000015160ff16601f811061181357611813614d76565b73ffffffffffffffffffffffffffffffffffffffff90921660209290920201525061183d81614da5565b9050611592565b5050506118508261338d565b5050505b5050505050505050565b611866612d93565b80516008805460208401516040808601516060870151608088015160a089015160c08a015160e08b015160ff167f0100000000000000000000000000000000000000000000000000000000000000027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff67ffffffffffffffff90921677010000000000000000000000000000000000000000000000029190911676ffffffffffffffffffffffffffffffffffffffffffffff61ffff9384167501000000000000000000000000000000000000000000027fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff64ffffffffff90961670010000000000000000000000000000000002959095167fffffffffffffffffff00000000000000ffffffffffffffffffffffffffffffff63ffffffff9788166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff9989166801000000000000000002999099167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff9b8916640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909d169e89169e909e179b909b17999099169b909b17959095179790971695909517179690961617929092179092556101008401516101208501519093167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90931692909217600955610140830151600a8054610160860151841662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000919091169290931691909117919091179055517f2e2c8535dcc25459d519f2300c114d2d2128bf6399722d04eca078461a3bf33a90610fab90839061476a565b60007f00000000000000000000000000000000000000000000000000000000000000006040517f10fc49c100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015263ffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff91909116906310fc49c19060440160006040518083038186803b158015611bc957600080fd5b505afa158015611bdd573d6000803e3d6000fd5b5050505066038d7ea4c68000821115611c22576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611c2c6129e7565b90506000611c6f87878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061066392505050565b90506000611c7b6129ae565b9050611c8a86868486856134dc565b9998505050505050505050565b6060600e8054611ca690614a79565b9050600003611ce1576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e8054610e7f90614a79565b855185518560ff16601f831115611d61576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e6572730000000000000000000000000000000060448201526064016109c6565b80600003611dcb576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f736974697665000000000000000000000000000060448201526064016109c6565b818314611e59576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e0000000000000000000000000000000000000000000000000000000060648201526084016109c6565b611e648160036150ea565b8311611ecc576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f2068696768000000000000000060448201526064016109c6565b611ed4612a78565b6040805160c0810182528a8152602081018a905260ff89169181018290526060810188905267ffffffffffffffff8716608082015260a0810186905290611f1b9088613658565b600554156120d057600554600090611f3590600190614d46565b9050600060058281548110611f4c57611f4c614d76565b60009182526020822001546006805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110611f8657611f86614d76565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526004909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009081169091559290911680845292208054909116905560058054919250908061200657612006615101565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055600680548061206f5761206f615101565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611f1b915050565b60005b815151811015612687578151805160009190839081106120f5576120f5614d76565b602002602001015173ffffffffffffffffffffffffffffffffffffffff160361217a576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f7369676e6572206d757374206e6f7420626520656d707479000000000000000060448201526064016109c6565b600073ffffffffffffffffffffffffffffffffffffffff16826020015182815181106121a8576121a8614d76565b602002602001015173ffffffffffffffffffffffffffffffffffffffff160361222d576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f7472616e736d6974746572206d757374206e6f7420626520656d70747900000060448201526064016109c6565b6000600460008460000151848151811061224957612249614d76565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff16600281111561229357612293615097565b146122fa576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e6572206164647265737300000000000000000060448201526064016109c6565b6040805180820190915260ff8216815260016020820152825180516004916000918590811061232b5761232b614d76565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016176101008360028111156123cc576123cc615097565b0217905550600091506123dc9050565b60046000846020015184815181106123f6576123f6614d76565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff16600281111561244057612440615097565b146124a7576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d697474657220616464726573730000000060448201526064016109c6565b6040805180820190915260ff8216815260208101600281525060046000846020015184815181106124da576124da614d76565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000161761010083600281111561257b5761257b615097565b02179055505082518051600592508390811061259957612599614d76565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909316929092179091558201518051600691908390811061261557612615614d76565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790558061267f81614da5565b9150506120d3565b506040810151600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff8116780100000000000000000000000000000000000000000000000063ffffffff438116820292909217808555920481169291829160149161273f91849174010000000000000000000000000000000000000000900416615130565b92506101000a81548163ffffffff021916908363ffffffff16021790555061279e4630600160149054906101000a900463ffffffff1663ffffffff16856000015186602001518760400151886060015189608001518a60a00151613671565b600281905582518051600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff9093169290920291909117905560015460208501516040808701516060880151608089015160a08a015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0598612855988b9891977401000000000000000000000000000000000000000090920463ffffffff1696909591949193919261514d565b60405180910390a15050505050505050505050565b6000806000600c8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156128da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128fe9190614cf6565b5093505092505080426129119190614d46565b600854640100000000900463ffffffff1610801561293e5750600854640100000000900463ffffffff1615155b1561296b5750506009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b600082136129a8576040517f43d4cf66000000000000000000000000000000000000000000000000000000008152600481018390526024016109c6565b50919050565b600a546000906129ce9060649061067d9062010000900461ffff16612afb565b905090565b6129db612a78565b6129e48161371c565b50565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632a905ccc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a54573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ce91906151ee565b60005473ffffffffffffffffffffffffffffffffffffffff163314612af9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016109c6565b565b6000806000612b08610859565b9092509050612b4082612b1c83601261505c565b612b2790600a61532b565b612b3190876150ea565b612b3b919061533a565b613811565b949350505050565b600068ffffffffffffffffff821115612be3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203760448201527f322062697473000000000000000000000000000000000000000000000000000060648201526084016109c6565b5090565b600c546bffffffffffffffffffffffff16600003612c0157565b6000612c0b610db9565b80519091506000819003612c4b576040517f30274b3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c54600090612c6a9083906bffffffffffffffffffffffff16614c85565b905060005b82811015612d355781600b6000868481518110612c8e57612c8e614d76565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282829054906101000a90046bffffffffffffffffffffffff16612cf6919061534e565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080612d2e90614da5565b9050612c6f565b50612d408282615373565b600c8054600090612d609084906bffffffffffffffffffffffff16614cb0565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550505050565b612af9612a78565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915260085461010083015160009161ffff7501000000000000000000000000000000000000000000909104811691161115612e59576040517fdada758700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612e688460000151610663565b9050612e726129ae565b91506000612e8b8560e001513a848860800151876134dc565b9050806bffffffffffffffffffffffff1685606001516bffffffffffffffffffffffff161015612ee7576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600954600090612f1d907c0100000000000000000000000000000000000000000000000000000000900463ffffffff164261539b565b905060003087604001518860a001518960c001516001612f3d91906153ae565b8a5180516020918201206101008d015160e08e0151604051612ff198979695948c918c9132910173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a015267ffffffffffffffff97881660408a0152959096166060880152608087019390935261ffff9190911660a086015263ffffffff90811660c08601526bffffffffffffffffffffffff9190911660e0850152919091166101008301529091166101208201526101400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201206101608401835280845230848301526bffffffffffffffffffffffff8716848401528a83015173ffffffffffffffffffffffffffffffffffffffff16606085015260a0808c015167ffffffffffffffff1660808087019190915260e0808e015163ffffffff90811693880193909352908d015168ffffffffffffffffff90811660c08801528a169086015260085468010000000000000000810482166101008701526c0100000000000000000000000090048116610120860152861661014085015291519298509092506130fd918891016144bf565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181528151602092830120600093845260079092529091205550929491935090915050565b60006131816040518060a0016040528060608152602001606081526020016060815260200160608152602001606081525090565b600080808080613193888a018a6154aa565b84519499509297509095509350915060ff168015806131b3575084518114155b806131bf575083518114155b806131cb575082518114155b806131d7575081518114155b1561323e576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4669656c6473206d75737420626520657175616c206c656e677468000000000060448201526064016109c6565b60005b818110156132a45761327a87828151811061325e5761325e614d76565b6020026020010151600090815260076020526040902054151590565b6132a457613289600183614d46565b810361329457600198505b61329d81614da5565b9050613241565b50506040805160a0810182529586526020860194909452928401919091526060830152608082015290505b9250929050565b60006132e38260206150ea565b6132ee8560206150ea565b6132fa8861014461539b565b613304919061539b565b61330e919061539b565b61331990600061539b565b9050368114613384576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d61746368000000000000000060448201526064016109c6565b50505050505050565b80515160ff1660005b8181101561065e57600061343f846000015183815181106133b9576133b9614d76565b6020026020010151856020015184815181106133d7576133d7614d76565b6020026020010151866040015185815181106133f5576133f5614d76565b60200260200101518760600151868151811061341357613413614d76565b60200260200101518860800151878151811061343157613431614d76565b6020026020010151886138af565b9050600081600681111561345557613455615097565b14806134725750600181600681111561347057613470615097565b145b156134cb57835180518390811061348b5761348b614d76565b60209081029190910181015160405133815290917fc708e0440951fd63499c0f7a73819b469ee5dd3ecc356c0ab4eb7f18389009d9910160405180910390a25b506134d581614da5565b9050613396565b600854600090700100000000000000000000000000000000900464ffffffffff1685101561352557600854700100000000000000000000000000000000900464ffffffffff1694505b6008546000906127109061353f9063ffffffff16886150ea565b613549919061533a565b613553908761539b565b600854909150600090889061358c9063ffffffff6c01000000000000000000000000820481169168010000000000000000900416615130565b6135969190615130565b63ffffffff16905060006135e06000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613d7392505050565b90506000613601826135f285876150ea565b6135fc919061539b565b613eb5565b905060008668ffffffffffffffffff168868ffffffffffffffffff168a68ffffffffffffffffff16613633919061534e565b61363d919061534e565b9050613649818361534e565b9b9a5050505050505050505050565b6000613662610db9565b511115610d6557610d65612be7565b6000808a8a8a8a8a8a8a8a8a6040516020016136959998979695949392919061557c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff82160361379b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016109c6565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60006bffffffffffffffffffffffff821115612be3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f362062697473000000000000000000000000000000000000000000000000000060648201526084016109c6565b600080848060200190518101906138c69190615648565b905060003a8261012001518361010001516138e19190615710565b64ffffffffff166138f291906150ea565b905060008460ff1661393a6000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613d7392505050565b613944919061533a565b905060006139556135fc838561539b565b905060006139623a613eb5565b90506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663330605298e8e868b60c0015168ffffffffffffffffff168c60e0015168ffffffffffffffffff168a6139d1919061534e565b6139db919061534e565b336040518061016001604052808f6000015181526020018f6020015173ffffffffffffffffffffffffffffffffffffffff1681526020018f604001516bffffffffffffffffffffffff1681526020018f6060015173ffffffffffffffffffffffffffffffffffffffff1681526020018f6080015167ffffffffffffffff1681526020018f60a0015163ffffffff168152602001600068ffffffffffffffffff1681526020018f60e0015168ffffffffffffffffff1681526020018f610100015164ffffffffff1681526020018f610120015164ffffffffff1681526020018f610140015163ffffffff168152506040518763ffffffff1660e01b8152600401613ae99695949392919061572e565b60408051808303816000875af1158015613b07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b2b91906157aa565b90925090506000826006811115613b4457613b44615097565b1480613b6157506001826006811115613b5f57613b5f615097565b145b15613d625760008e815260076020526040812055613b7f818561534e565b336000908152600b602052604081208054909190613bac9084906bffffffffffffffffffffffff1661534e565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508660e0015168ffffffffffffffffff16600c60008282829054906101000a90046bffffffffffffffffffffffff16613c12919061534e565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508660c0015168ffffffffffffffffff16600b6000613c5c613ed4565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160009081208054909190613ca29084906bffffffffffffffffffffffff1661534e565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508d7f08a4a0761e3c98d288cb4af9342660f49550d83139fb3b762b70d34bed6273688487848b60e0015160008d60c00151604051613d59969594939291906bffffffffffffffffffffffff9687168152602081019590955292909416604084015268ffffffffffffffffff9081166060840152928316608083015290911660a082015260c00190565b60405180910390a25b509c9b505050505050505050505050565b600046613d7f81613f45565b15613dfb57606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613dd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613df491906157dd565b9392505050565b613e0481613f68565b15613eac5773420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e8460405180608001604052806048815260200161584360489139604051602001613e649291906157f6565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401613e8f91906140c0565b602060405180830381865afa158015613dd0573d6000803e3d6000fd5b50600092915050565b600061069a613ec261286a565b612b3184670de0b6b3a76400006150ea565b60003073ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613f21573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ce9190615825565b600061a4b1821480613f59575062066eed82145b8061069a57505062066eee1490565b6000600a821480613f7a57506101a482145b80613f87575062aa37dc82145b80613f93575061210582145b80613fa0575062014a3382145b8061069a57505062014a341490565b604051806103e00160405280601f906020820280368337509192915050565b60008083601f840112613fe057600080fd5b50813567ffffffffffffffff811115613ff857600080fd5b6020830191508360208285010111156132cf57600080fd5b6000806020838503121561402357600080fd5b823567ffffffffffffffff81111561403a57600080fd5b61404685828601613fce565b90969095509350505050565b60005b8381101561406d578181015183820152602001614055565b50506000910152565b6000815180845261408e816020860160208601614052565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000613df46020830184614076565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610180810167ffffffffffffffff81118282101715614126576141266140d3565b60405290565b604051610160810167ffffffffffffffff81118282101715614126576141266140d3565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614197576141976140d3565b604052919050565b600082601f8301126141b057600080fd5b813567ffffffffffffffff8111156141ca576141ca6140d3565b6141fb60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614150565b81815284602083860101111561421057600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561423f57600080fd5b813567ffffffffffffffff81111561425657600080fd5b612b408482850161419f565b73ffffffffffffffffffffffffffffffffffffffff811681146129e457600080fd5b803561124281614262565b6bffffffffffffffffffffffff811681146129e457600080fd5b80356112428161428f565b600080604083850312156142c757600080fd5b82356142d281614262565b915060208301356142e28161428f565b809150509250929050565b600081518084526020808501945080840160005b8381101561433357815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614301565b509495945050505050565b602081526000613df460208301846142ed565b60006020828403121561436357600080fd5b5035919050565b60006020828403121561437c57600080fd5b813567ffffffffffffffff81111561439357600080fd5b82016101608185031215613df457600080fd5b8051825260208101516143d1602084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060408101516143f160408401826bffffffffffffffffffffffff169052565b506060810151614419606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151614435608084018267ffffffffffffffff169052565b5060a081015161444d60a084018263ffffffff169052565b5060c081015161446a60c084018268ffffffffffffffffff169052565b5060e081015161448760e084018268ffffffffffffffffff169052565b506101008181015164ffffffffff9081169184019190915261012080830151909116908301526101409081015163ffffffff16910152565b610160810161069a82846143a6565b60008083601f8401126144e057600080fd5b50813567ffffffffffffffff8111156144f857600080fd5b6020830191508360208260051b85010111156132cf57600080fd5b60008060008060008060008060e0898b03121561452f57600080fd5b606089018a81111561454057600080fd5b8998503567ffffffffffffffff8082111561455a57600080fd5b6145668c838d01613fce565b909950975060808b013591508082111561457f57600080fd5b61458b8c838d016144ce565b909750955060a08b01359150808211156145a457600080fd5b506145b18b828c016144ce565b999c989b50969995989497949560c00135949350505050565b63ffffffff811681146129e457600080fd5b8035611242816145ca565b64ffffffffff811681146129e457600080fd5b8035611242816145e7565b803561ffff8116811461124257600080fd5b67ffffffffffffffff811681146129e457600080fd5b803561124281614617565b60ff811681146129e457600080fd5b803561124281614638565b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461124257600080fd5b6000610180828403121561469157600080fd5b614699614102565b6146a2836145dc565b81526146b0602084016145dc565b60208201526146c1604084016145dc565b60408201526146d2606084016145dc565b60608201526146e3608084016145fa565b60808201526146f460a08401614605565b60a082015261470560c0840161462d565b60c082015261471660e08401614647565b60e0820152610100614729818501614652565b9082015261012061473b8482016145dc565b9082015261014061474d848201614605565b9082015261016061475f848201614605565b908201529392505050565b815163ffffffff16815261018081016020830151614790602084018263ffffffff169052565b5060408301516147a8604084018263ffffffff169052565b5060608301516147c0606084018263ffffffff169052565b5060808301516147d9608084018264ffffffffff169052565b5060a08301516147ef60a084018261ffff169052565b5060c083015161480b60c084018267ffffffffffffffff169052565b5060e083015161482060e084018260ff169052565b50610100838101517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16908301526101208084015163ffffffff16908301526101408084015161ffff908116918401919091526101608085015191821681850152905b505092915050565b60008060008060006080868803121561489f57600080fd5b85356148aa81614617565b9450602086013567ffffffffffffffff8111156148c657600080fd5b6148d288828901613fce565b90955093505060408601356148e6816145ca565b949793965091946060013592915050565b600067ffffffffffffffff821115614911576149116140d3565b5060051b60200190565b600082601f83011261492c57600080fd5b8135602061494161493c836148f7565b614150565b82815260059290921b8401810191818101908684111561496057600080fd5b8286015b8481101561498457803561497781614262565b8352918301918301614964565b509695505050505050565b60008060008060008060c087890312156149a857600080fd5b863567ffffffffffffffff808211156149c057600080fd5b6149cc8a838b0161491b565b975060208901359150808211156149e257600080fd5b6149ee8a838b0161491b565b96506149fc60408a01614647565b95506060890135915080821115614a1257600080fd5b614a1e8a838b0161419f565b9450614a2c60808a0161462d565b935060a0890135915080821115614a4257600080fd5b50614a4f89828a0161419f565b9150509295509295509295565b600060208284031215614a6e57600080fd5b8135613df481614262565b600181811c90821680614a8d57607f821691505b6020821081036129a8577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b601f82111561065e57600081815260208120601f850160051c81016020861015614aed5750805b601f850160051c820191505b8181101561085157828155600101614af9565b67ffffffffffffffff831115614b2457614b246140d3565b614b3883614b328354614a79565b83614ac6565b6000601f841160018114614b8a5760008515614b545750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614c20565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b82811015614bd95786850135825560209485019460019092019101614bb9565b5086821015614c14577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006bffffffffffffffffffffffff80841680614ca457614ca4614c27565b92169190910492915050565b6bffffffffffffffffffffffff828116828216039080821115614cd557614cd5614c56565b5092915050565b805169ffffffffffffffffffff8116811461124257600080fd5b600080600080600060a08688031215614d0e57600080fd5b614d1786614cdc565b9450602086015193506040860151925060608601519150614d3a60808701614cdc565b90509295509295909350565b8181038181111561069a5761069a614c56565b600060208284031215614d6b57600080fd5b8151613df481614638565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614dd657614dd6614c56565b5060010190565b68ffffffffffffffffff811681146129e457600080fd5b803561124281614ddd565b60006101608236031215614e1257600080fd5b614e1a61412c565b823567ffffffffffffffff811115614e3157600080fd5b614e3d3682860161419f565b82525060208301356020820152614e5660408401614284565b6040820152614e67606084016142a9565b6060820152614e7860808401614df4565b6080820152614e8960a0840161462d565b60a0820152614e9a60c0840161462d565b60c0820152614eab60e084016145dc565b60e0820152610100614ebe818501614605565b90820152610120614ed084820161462d565b90820152610140614ee2848201614284565b9082015292915050565b600060208284031215614efe57600080fd5b8135613df481614617565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614f3e57600080fd5b83018035915067ffffffffffffffff821115614f5957600080fd5b6020019150368190038213156132cf57600080fd5b600060208284031215614f8057600080fd5b613df482614605565b600060208284031215614f9b57600080fd5b8135613df4816145ca565b73ffffffffffffffffffffffffffffffffffffffff8a8116825267ffffffffffffffff8a166020830152881660408201526102406060820181905281018690526000610260878982850137600083890182015261ffff8716608084015260a0830186905263ffffffff851660c0840152601f88017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016830101905061504e60e08301846143a6565b9a9950505050505050505050565b60ff818116838216019081111561069a5761069a614c56565b600060ff83168061508857615088614c27565b8060ff84160491505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8183823760009101908152919050565b828152606082602083013760800192915050565b808202811582820484141761069a5761069a614c56565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b63ffffffff818116838216019080821115614cd557614cd5614c56565b600061012063ffffffff808d1684528b6020850152808b1660408501525080606084015261517d8184018a6142ed565b9050828103608084015261519181896142ed565b905060ff871660a084015282810360c08401526151ae8187614076565b905067ffffffffffffffff851660e08401528281036101008401526151d38185614076565b9c9b505050505050505050505050565b805161124281614ddd565b60006020828403121561520057600080fd5b8151613df481614ddd565b600181815b8085111561526457817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561524a5761524a614c56565b8085161561525757918102915b93841c9390800290615210565b509250929050565b60008261527b5750600161069a565b816152885750600061069a565b816001811461529e57600281146152a8576152c4565b600191505061069a565b60ff8411156152b9576152b9614c56565b50506001821b61069a565b5060208310610133831016604e8410600b84101617156152e7575081810a61069a565b6152f1838361520b565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561532357615323614c56565b029392505050565b6000613df460ff84168361526c565b60008261534957615349614c27565b500490565b6bffffffffffffffffffffffff818116838216019080821115614cd557614cd5614c56565b6bffffffffffffffffffffffff81811683821602808216919082811461487f5761487f614c56565b8082018082111561069a5761069a614c56565b67ffffffffffffffff818116838216019080821115614cd557614cd5614c56565b600082601f8301126153e057600080fd5b813560206153f061493c836148f7565b82815260059290921b8401810191818101908684111561540f57600080fd5b8286015b848110156149845780358352918301918301615413565b600082601f83011261543b57600080fd5b8135602061544b61493c836148f7565b82815260059290921b8401810191818101908684111561546a57600080fd5b8286015b8481101561498457803567ffffffffffffffff81111561548e5760008081fd5b61549c8986838b010161419f565b84525091830191830161546e565b600080600080600060a086880312156154c257600080fd5b853567ffffffffffffffff808211156154da57600080fd5b6154e689838a016153cf565b965060208801359150808211156154fc57600080fd5b61550889838a0161542a565b9550604088013591508082111561551e57600080fd5b61552a89838a0161542a565b9450606088013591508082111561554057600080fd5b61554c89838a0161542a565b9350608088013591508082111561556257600080fd5b5061556f8882890161542a565b9150509295509295909350565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b1660408501528160608501526155c38285018b6142ed565b915083820360808501526155d7828a6142ed565b915060ff881660a085015283820360c08501526155f48288614076565b90861660e085015283810361010085015290506151d38185614076565b805161124281614262565b80516112428161428f565b805161124281614617565b8051611242816145ca565b8051611242816145e7565b6000610160828403121561565b57600080fd5b61566361412c565b8251815261567360208401615611565b60208201526156846040840161561c565b604082015261569560608401615611565b60608201526156a660808401615627565b60808201526156b760a08401615632565b60a08201526156c860c084016151e3565b60c08201526156d960e084016151e3565b60e08201526101006156ec81850161563d565b908201526101206156fe84820161563d565b9082015261014061475f848201615632565b64ffffffffff818116838216019080821115614cd557614cd5614c56565b60006102008083526157428184018a614076565b905082810360208401526157568189614076565b6bffffffffffffffffffffffff88811660408601528716606085015273ffffffffffffffffffffffffffffffffffffffff86166080850152915061579f905060a08301846143a6565b979650505050505050565b600080604083850312156157bd57600080fd5b8251600781106157cc57600080fd5b60208401519092506142e28161428f565b6000602082840312156157ef57600080fd5b5051919050565b60008351615808818460208801614052565b83519083019061581c818360208801614052565b01949350505050565b60006020828403121561583757600080fd5b8151613df48161426256fe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000813000a", + Bin: "0x60a06040523480156200001157600080fd5b506040516200603a3803806200603a8339810160408190526200003491620004db565b83838383833380600081620000905760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c357620000c3816200014e565b5050506001600160a01b038116620000ee57604051632530e88560e11b815260040160405180910390fd5b6001600160a01b03908116608052600c80546001600160601b03166c0100000000000000000000000085841602179055600d80546001600160a01b0319169183169190911790556200014083620001f9565b505050505050505062000742565b336001600160a01b03821603620001a85760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000087565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620002036200039e565b80516008805460208401516040808601516060870151608088015160a089015160c08a015160e08b015160ff16600160f81b026001600160f81b036001600160401b03909216600160b81b02919091166001600160b81b0361ffff938416600160a81b0261ffff60a81b1964ffffffffff909616600160801b029590951666ffffffffffffff60801b1963ffffffff9788166c010000000000000000000000000263ffffffff60601b19998916680100000000000000000299909916600160401b600160801b03199b8916640100000000026001600160401b0319909d169e89169e909e179b909b17999099169b909b1795909517979097169590951717969096161792909217909255610100840151610120850151909316600160e01b026001600160e01b0390931692909217600955610140830151600a80546101608601518416620100000263ffffffff19919091169290931691909117919091179055517f2e2c8535dcc25459d519f2300c114d2d2128bf6399722d04eca078461a3bf33a906200039390839062000639565b60405180910390a150565b620003a8620003aa565b565b6000546001600160a01b03163314620003a85760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000087565b80516001600160a01b03811681146200041e57600080fd5b919050565b60405161018081016001600160401b03811182821017156200045557634e487b7160e01b600052604160045260246000fd5b60405290565b805163ffffffff811681146200041e57600080fd5b805164ffffffffff811681146200041e57600080fd5b805161ffff811681146200041e57600080fd5b80516001600160401b03811681146200041e57600080fd5b805160ff811681146200041e57600080fd5b80516001600160e01b03811681146200041e57600080fd5b6000806000808486036101e0811215620004f457600080fd5b620004ff8662000406565b945061018080601f19830112156200051657600080fd5b6200052062000423565b915062000530602088016200045b565b825262000540604088016200045b565b602083015262000553606088016200045b565b604083015262000566608088016200045b565b60608301526200057960a0880162000470565b60808301526200058c60c0880162000486565b60a08301526200059f60e0880162000499565b60c0830152610100620005b4818901620004b1565b60e0840152610120620005c9818a01620004c3565b828501526101409150620005df828a016200045b565b90840152610160620005f389820162000486565b8285015262000604838a0162000486565b90840152509093506200061d90506101a0860162000406565b91506200062e6101c0860162000406565b905092959194509250565b815163ffffffff1681526101808101602083015162000660602084018263ffffffff169052565b50604083015162000679604084018263ffffffff169052565b50606083015162000692606084018263ffffffff169052565b506080830151620006ac608084018264ffffffffff169052565b5060a0830151620006c360a084018261ffff169052565b5060c0830151620006df60c08401826001600160401b03169052565b5060e0830151620006f560e084018260ff169052565b50610100838101516001600160e01b0316908301526101208084015163ffffffff16908301526101408084015161ffff908116918401919091526101609384015116929091019190915290565b6080516158b2620007886000396000818161079c01528181610c7d01528181610f110152818161102701528181611b2d015281816129eb015261398401526158b26000f3fe608060405234801561001057600080fd5b50600436106101a35760003560e01c80638da5cb5b116100ee578063d227d24511610097578063e4ddcea611610071578063e4ddcea6146105d5578063f2f22ef1146105eb578063f2fde38b146105f3578063f6ea41f61461060657600080fd5b8063d227d2451461058a578063d328a91e146105ba578063e3d0e712146105c257600080fd5b8063b1dc65a4116100c8578063b1dc65a414610396578063ba9c924d146103a9578063c3f909d4146103bc57600080fd5b80638da5cb5b1461032e578063a631571e14610356578063afcb95d71461037657600080fd5b80637d4807871161015057806381f1b9381161012a57806381f1b938146102a657806381ff7048146102ae57806385b214cf1461031b57600080fd5b80637d480787146102765780637f15e1661461027e578063814118341461029157600080fd5b806366316d8d1161018157806366316d8d1461023c5780637212762f1461024f57806379ba50971461026e57600080fd5b8063083a5466146101a8578063181f5a77146101bd578063626f458c1461020f575b600080fd5b6101bb6101b636600461402b565b61060e565b005b6101f96040518060400160405280601c81526020017f46756e6374696f6e7320436f6f7264696e61746f722076312e332e300000000081525081565b60405161020691906140db565b60405180910390f35b61022261021d366004614248565b610663565b60405168ffffffffffffffffff9091168152602001610206565b6101bb61024a3660046142cf565b6106a0565b610257610859565b6040805192835260ff909116602083015201610206565b6101bb610a6c565b6101bb610b69565b6101bb61028c36600461402b565b610d69565b610299610db9565b6040516102069190614359565b6101f9610e28565b6102f860015460025463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610206565b6101bb61032936600461436c565b610ef9565b60005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610206565b610369610364366004614385565b610fb6565b60405161020691906144da565b604080516001815260006020820181905291810191909152606001610206565b6101bb6103a436600461452e565b611247565b6101bb6103b7366004614699565b61185e565b61057d6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915250604080516101808101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c01000000000000000000000000810483166060830152700100000000000000000000000000000000810464ffffffffff1660808301527501000000000000000000000000000000000000000000810461ffff90811660a084015277010000000000000000000000000000000000000000000000820467ffffffffffffffff1660c08401527f010000000000000000000000000000000000000000000000000000000000000090910460ff1660e08301526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81166101008401527c01000000000000000000000000000000000000000000000000000000009004909216610120820152600a5480831661014083015262010000900490911661016082015290565b6040516102069190614785565b61059d6105983660046148a2565b611b29565b6040516bffffffffffffffffffffffff9091168152602001610206565b6101f9611c97565b6101bb6105d03660046149aa565b611cee565b6105dd61286a565b604051908152602001610206565b6102226129ae565b6101bb610601366004614a77565b6129d3565b6102226129e7565b610616612a78565b6000819003610651576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f61065e828483614b27565b505050565b600a5460009061069a9060649061067d9061ffff16612afb565b6106879190614ca0565b6bffffffffffffffffffffffff16612b48565b92915050565b6106a8612be7565b806bffffffffffffffffffffffff166000036106e25750336000908152600b60205260409020546bffffffffffffffffffffffff1661073c565b336000908152600b60205260409020546bffffffffffffffffffffffff8083169116101561073c576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600b6020526040812080548392906107699084906bffffffffffffffffffffffff16614ccb565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506107be7f000000000000000000000000000000000000000000000000000000000000000090565b6040517f66316d8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff8416602483015291909116906366316d8d90604401600060405180830381600087803b15801561083d57600080fd5b505af1158015610851573d6000803e3d6000fd5b505050505050565b600080600080600d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156108cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f09190614d11565b5093505092505080426109039190614d61565b600854640100000000900463ffffffff161080156109305750600854640100000000900463ffffffff1615155b1561098d57505060085477010000000000000000000000000000000000000000000000810467ffffffffffffffff16937f010000000000000000000000000000000000000000000000000000000000000090910460ff1692509050565b600082136109cf576040517f56b22ab8000000000000000000000000000000000000000000000000000000008152600481018390526024015b60405180910390fd5b600d54604080517f313ce5670000000000000000000000000000000000000000000000000000000081529051849273ffffffffffffffffffffffffffffffffffffffff169163313ce5679160048083019260209291908290030181865afa158015610a3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a629190614d74565b9350935050509091565b60015473ffffffffffffffffffffffffffffffffffffffff163314610aed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016109c6565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610b71612dae565b610b79612be7565b6000610b83610db9565b905060005b8151811015610d65576000600b6000848481518110610ba957610ba9614d91565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252810191909152604001600020546bffffffffffffffffffffffff1690508015610d54576000600b6000858581518110610c0857610c08614d91565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610c9f7f000000000000000000000000000000000000000000000000000000000000000090565b73ffffffffffffffffffffffffffffffffffffffff166366316d8d848481518110610ccc57610ccc614d91565b6020026020010151836040518363ffffffff1660e01b8152600401610d2192919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610d3b57600080fd5b505af1158015610d4f573d6000803e3d6000fd5b505050505b50610d5e81614dc0565b9050610b88565b5050565b610d71612a78565b6000819003610dac576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e61065e828483614b27565b60606006805480602002602001604051908101604052809291908181526020018280548015610e1e57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610df3575b5050505050905090565b6060600f8054610e3790614a94565b9050600003610e72576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f8054610e7f90614a94565b80601f0160208091040260200160405190810160405280929190818152602001828054610eab90614a94565b8015610e1e5780601f10610ecd57610100808354040283529160200191610e1e565b820191906000526020600020905b815481529060010190602001808311610edb57509395945050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610f68576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602052604080822091909155517f8a4b97add3359bd6bcf5e82874363670eb5ad0f7615abddbd0ed0a3a98f0f41690610fab9083815260200190565b60405180910390a150565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091523373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461107e576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061109161108c84614e1a565b612db6565b90925090506110a66060840160408501614a77565b825173ffffffffffffffffffffffffffffffffffffffff91909116907fbf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff326110f460c0880160a08901614f07565b61110661016089016101408a01614a77565b6111108980614f24565b6111226101208c016101008d01614f89565b60208c01356111386101008e0160e08f01614fa4565b6040518061016001604052808e6000015181526020018e6020015173ffffffffffffffffffffffffffffffffffffffff1681526020018e604001516bffffffffffffffffffffffff1681526020018e6060015173ffffffffffffffffffffffffffffffffffffffff1681526020018e6080015167ffffffffffffffff1681526020018e60a0015163ffffffff1681526020018d68ffffffffffffffffff1681526020018e60e0015168ffffffffffffffffff1681526020018e610100015164ffffffffff1681526020018e610120015164ffffffffff1681526020018e610140015163ffffffff1681525060405161123899989796959493929190614fc1565b60405180910390a3505b919050565b6000806112548989613168565b915091508115611265575050611854565b604080518b3580825262ffffff6020808f0135600881901c9290921690840152909290917fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16112c28b8b8b8b8b8b6132f1565b6003546000906002906112e09060ff80821691610100900416615077565b6112ea9190615090565b6112f5906001615077565b60ff169050888114611363576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e61747572657300000000000060448201526064016109c6565b8887146113f2576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f7265706f727420727320616e64207373206d757374206265206f66206571756160448201527f6c206c656e67746800000000000000000000000000000000000000000000000060648201526084016109c6565b3360009081526004602090815260408083208151808301909252805460ff80821684529293919291840191610100909104166002811115611435576114356150b2565b6002811115611446576114466150b2565b9052509050600281602001516002811115611463576114636150b2565b141580156114ac57506006816000015160ff168154811061148657611486614d91565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff163314155b15611513576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f756e617574686f72697a6564207472616e736d6974746572000000000000000060448201526064016109c6565b5050505061151f613fca565b60008a8a6040516115319291906150e1565b604051908190038120611548918e906020016150f1565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838301909252600080845290830152915060005b898110156118445760006001848984602081106115b1576115b1614d91565b6115be91901a601b615077565b8e8e868181106115d0576115d0614d91565b905060200201358d8d878181106115e9576115e9614d91565b9050602002013560405160008152602001604052604051611626949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611648573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526004602090815290849020838501909452835460ff808216855292965092945084019161010090041660028111156116c8576116c86150b2565b60028111156116d9576116d96150b2565b90525092506001836020015160028111156116f6576116f66150b2565b1461175d576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f61646472657373206e6f7420617574686f72697a656420746f207369676e000060448201526064016109c6565b8251600090869060ff16601f811061177757611777614d91565b602002015173ffffffffffffffffffffffffffffffffffffffff16146117f9576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6e6f6e2d756e69717565207369676e617475726500000000000000000000000060448201526064016109c6565b8085846000015160ff16601f811061181357611813614d91565b73ffffffffffffffffffffffffffffffffffffffff90921660209290920201525061183d81614dc0565b9050611592565b505050611850826133a8565b5050505b5050505050505050565b611866612dae565b80516008805460208401516040808601516060870151608088015160a089015160c08a015160e08b015160ff167f0100000000000000000000000000000000000000000000000000000000000000027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff67ffffffffffffffff90921677010000000000000000000000000000000000000000000000029190911676ffffffffffffffffffffffffffffffffffffffffffffff61ffff9384167501000000000000000000000000000000000000000000027fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff64ffffffffff90961670010000000000000000000000000000000002959095167fffffffffffffffffff00000000000000ffffffffffffffffffffffffffffffff63ffffffff9788166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff9989166801000000000000000002999099167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff9b8916640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909d169e89169e909e179b909b17999099169b909b17959095179790971695909517179690961617929092179092556101008401516101208501519093167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90931692909217600955610140830151600a8054610160860151841662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000919091169290931691909117919091179055517f2e2c8535dcc25459d519f2300c114d2d2128bf6399722d04eca078461a3bf33a90610fab908390614785565b60007f00000000000000000000000000000000000000000000000000000000000000006040517f10fc49c100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015263ffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff91909116906310fc49c19060440160006040518083038186803b158015611bc957600080fd5b505afa158015611bdd573d6000803e3d6000fd5b5050505066038d7ea4c68000821115611c22576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611c2c6129e7565b90506000611c6f87878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061066392505050565b90506000611c7b6129ae565b9050611c8a86868486856134f7565b9998505050505050505050565b6060600e8054611ca690614a94565b9050600003611ce1576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e8054610e7f90614a94565b855185518560ff16601f831115611d61576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e6572730000000000000000000000000000000060448201526064016109c6565b80600003611dcb576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f736974697665000000000000000000000000000060448201526064016109c6565b818314611e59576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e0000000000000000000000000000000000000000000000000000000060648201526084016109c6565b611e64816003615105565b8311611ecc576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f2068696768000000000000000060448201526064016109c6565b611ed4612a78565b6040805160c0810182528a8152602081018a905260ff89169181018290526060810188905267ffffffffffffffff8716608082015260a0810186905290611f1b9088613673565b600554156120d057600554600090611f3590600190614d61565b9050600060058281548110611f4c57611f4c614d91565b60009182526020822001546006805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110611f8657611f86614d91565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526004909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000908116909155929091168084529220805490911690556005805491925090806120065761200661511c565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055600680548061206f5761206f61511c565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611f1b915050565b60005b815151811015612687578151805160009190839081106120f5576120f5614d91565b602002602001015173ffffffffffffffffffffffffffffffffffffffff160361217a576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f7369676e6572206d757374206e6f7420626520656d707479000000000000000060448201526064016109c6565b600073ffffffffffffffffffffffffffffffffffffffff16826020015182815181106121a8576121a8614d91565b602002602001015173ffffffffffffffffffffffffffffffffffffffff160361222d576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f7472616e736d6974746572206d757374206e6f7420626520656d70747900000060448201526064016109c6565b6000600460008460000151848151811061224957612249614d91565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115612293576122936150b2565b146122fa576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e6572206164647265737300000000000000000060448201526064016109c6565b6040805180820190915260ff8216815260016020820152825180516004916000918590811061232b5761232b614d91565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016176101008360028111156123cc576123cc6150b2565b0217905550600091506123dc9050565b60046000846020015184815181106123f6576123f6614d91565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115612440576124406150b2565b146124a7576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d697474657220616464726573730000000060448201526064016109c6565b6040805180820190915260ff8216815260208101600281525060046000846020015184815181106124da576124da614d91565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000161761010083600281111561257b5761257b6150b2565b02179055505082518051600592508390811061259957612599614d91565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909316929092179091558201518051600691908390811061261557612615614d91565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790558061267f81614dc0565b9150506120d3565b506040810151600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff8116780100000000000000000000000000000000000000000000000063ffffffff438116820292909217808555920481169291829160149161273f9184917401000000000000000000000000000000000000000090041661514b565b92506101000a81548163ffffffff021916908363ffffffff16021790555061279e4630600160149054906101000a900463ffffffff1663ffffffff16856000015186602001518760400151886060015189608001518a60a0015161368c565b600281905582518051600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff9093169290920291909117905560015460208501516040808701516060880151608089015160a08a015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0598612855988b9891977401000000000000000000000000000000000000000090920463ffffffff16969095919491939192615168565b60405180910390a15050505050505050505050565b6000806000600c8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156128da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128fe9190614d11565b5093505092505080426129119190614d61565b600854640100000000900463ffffffff1610801561293e5750600854640100000000900463ffffffff1615155b1561296b5750506009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b600082136129a8576040517f43d4cf66000000000000000000000000000000000000000000000000000000008152600481018390526024016109c6565b50919050565b600a546000906129ce9060649061067d9062010000900461ffff16612afb565b905090565b6129db612a78565b6129e481613737565b50565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632a905ccc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a54573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ce9190615209565b60005473ffffffffffffffffffffffffffffffffffffffff163314612af9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016109c6565b565b6000806000612b08610859565b9092509050612b4082612b1c836012615077565b612b2790600a615346565b612b319087615105565b612b3b9190615355565b61382c565b949350505050565b600068ffffffffffffffffff821115612be3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203760448201527f322062697473000000000000000000000000000000000000000000000000000060648201526084016109c6565b5090565b600c546bffffffffffffffffffffffff16600003612c0157565b6000612c0b610db9565b80519091506000819003612c4b576040517f30274b3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c54600090612c6a9083906bffffffffffffffffffffffff16614ca0565b9050806bffffffffffffffffffffffff16600003612c8757505050565b60005b82811015612d505781600b6000868481518110612ca957612ca9614d91565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282829054906101000a90046bffffffffffffffffffffffff16612d119190615369565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080612d4990614dc0565b9050612c8a565b50612d5b828261538e565b600c8054600090612d7b9084906bffffffffffffffffffffffff16614ccb565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550505050565b612af9612a78565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915260085461010083015160009161ffff7501000000000000000000000000000000000000000000909104811691161115612e74576040517fdada758700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612e838460000151610663565b9050612e8d6129ae565b91506000612ea68560e001513a848860800151876134f7565b9050806bffffffffffffffffffffffff1685606001516bffffffffffffffffffffffff161015612f02576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600954600090612f38907c0100000000000000000000000000000000000000000000000000000000900463ffffffff16426153b6565b905060003087604001518860a001518960c001516001612f5891906153c9565b8a5180516020918201206101008d015160e08e015160405161300c98979695948c918c9132910173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a015267ffffffffffffffff97881660408a0152959096166060880152608087019390935261ffff9190911660a086015263ffffffff90811660c08601526bffffffffffffffffffffffff9190911660e0850152919091166101008301529091166101208201526101400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201206101608401835280845230848301526bffffffffffffffffffffffff8716848401528a83015173ffffffffffffffffffffffffffffffffffffffff16606085015260a0808c015167ffffffffffffffff1660808087019190915260e0808e015163ffffffff90811693880193909352908d015168ffffffffffffffffff90811660c08801528a169086015260085468010000000000000000810482166101008701526c010000000000000000000000009004811661012086015286166101408501529151929850909250613118918891016144da565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181528151602092830120600093845260079092529091205550929491935090915050565b600061319c6040518060a0016040528060608152602001606081526020016060815260200160608152602001606081525090565b6000808080806131ae888a018a6154c5565b84519499509297509095509350915060ff168015806131ce575084518114155b806131da575083518114155b806131e6575082518114155b806131f2575081518114155b15613259576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4669656c6473206d75737420626520657175616c206c656e677468000000000060448201526064016109c6565b60005b818110156132bf5761329587828151811061327957613279614d91565b6020026020010151600090815260076020526040902054151590565b6132bf576132a4600183614d61565b81036132af57600198505b6132b881614dc0565b905061325c565b50506040805160a0810182529586526020860194909452928401919091526060830152608082015290505b9250929050565b60006132fe826020615105565b613309856020615105565b613315886101446153b6565b61331f91906153b6565b61332991906153b6565b6133349060006153b6565b905036811461339f576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d61746368000000000000000060448201526064016109c6565b50505050505050565b80515160ff1660005b8181101561065e57600061345a846000015183815181106133d4576133d4614d91565b6020026020010151856020015184815181106133f2576133f2614d91565b60200260200101518660400151858151811061341057613410614d91565b60200260200101518760600151868151811061342e5761342e614d91565b60200260200101518860800151878151811061344c5761344c614d91565b6020026020010151886138ca565b90506000816006811115613470576134706150b2565b148061348d5750600181600681111561348b5761348b6150b2565b145b156134e65783518051839081106134a6576134a6614d91565b60209081029190910181015160405133815290917fc708e0440951fd63499c0f7a73819b469ee5dd3ecc356c0ab4eb7f18389009d9910160405180910390a25b506134f081614dc0565b90506133b1565b600854600090700100000000000000000000000000000000900464ffffffffff1685101561354057600854700100000000000000000000000000000000900464ffffffffff1694505b6008546000906127109061355a9063ffffffff1688615105565b6135649190615355565b61356e90876153b6565b60085490915060009088906135a79063ffffffff6c0100000000000000000000000082048116916801000000000000000090041661514b565b6135b1919061514b565b63ffffffff16905060006135fb6000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613d8e92505050565b9050600061361c8261360d8587615105565b61361791906153b6565b613ed0565b905060008668ffffffffffffffffff168868ffffffffffffffffff168a68ffffffffffffffffff1661364e9190615369565b6136589190615369565b90506136648183615369565b9b9a5050505050505050505050565b600061367d610db9565b511115610d6557610d65612be7565b6000808a8a8a8a8a8a8a8a8a6040516020016136b099989796959493929190615597565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036137b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016109c6565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60006bffffffffffffffffffffffff821115612be3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f362062697473000000000000000000000000000000000000000000000000000060648201526084016109c6565b600080848060200190518101906138e19190615663565b905060003a8261012001518361010001516138fc919061572b565b64ffffffffff1661390d9190615105565b905060008460ff166139556000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613d8e92505050565b61395f9190615355565b9050600061397061361783856153b6565b9050600061397d3a613ed0565b90506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663330605298e8e868b60c0015168ffffffffffffffffff168c60e0015168ffffffffffffffffff168a6139ec9190615369565b6139f69190615369565b336040518061016001604052808f6000015181526020018f6020015173ffffffffffffffffffffffffffffffffffffffff1681526020018f604001516bffffffffffffffffffffffff1681526020018f6060015173ffffffffffffffffffffffffffffffffffffffff1681526020018f6080015167ffffffffffffffff1681526020018f60a0015163ffffffff168152602001600068ffffffffffffffffff1681526020018f60e0015168ffffffffffffffffff1681526020018f610100015164ffffffffff1681526020018f610120015164ffffffffff1681526020018f610140015163ffffffff168152506040518763ffffffff1660e01b8152600401613b0496959493929190615749565b60408051808303816000875af1158015613b22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b4691906157c5565b90925090506000826006811115613b5f57613b5f6150b2565b1480613b7c57506001826006811115613b7a57613b7a6150b2565b145b15613d7d5760008e815260076020526040812055613b9a8185615369565b336000908152600b602052604081208054909190613bc79084906bffffffffffffffffffffffff16615369565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508660e0015168ffffffffffffffffff16600c60008282829054906101000a90046bffffffffffffffffffffffff16613c2d9190615369565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508660c0015168ffffffffffffffffff16600b6000613c77613eef565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160009081208054909190613cbd9084906bffffffffffffffffffffffff16615369565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508d7f08a4a0761e3c98d288cb4af9342660f49550d83139fb3b762b70d34bed6273688487848b60e0015160008d60c00151604051613d74969594939291906bffffffffffffffffffffffff9687168152602081019590955292909416604084015268ffffffffffffffffff9081166060840152928316608083015290911660a082015260c00190565b60405180910390a25b509c9b505050505050505050505050565b600046613d9a81613f60565b15613e1657606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613deb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e0f91906157f8565b9392505050565b613e1f81613f83565b15613ec75773420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e8460405180608001604052806048815260200161585e60489139604051602001613e7f929190615811565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401613eaa91906140db565b602060405180830381865afa158015613deb573d6000803e3d6000fd5b50600092915050565b600061069a613edd61286a565b612b3184670de0b6b3a7640000615105565b60003073ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613f3c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ce9190615840565b600061a4b1821480613f74575062066eed82145b8061069a57505062066eee1490565b6000600a821480613f9557506101a482145b80613fa2575062aa37dc82145b80613fae575061210582145b80613fbb575062014a3382145b8061069a57505062014a341490565b604051806103e00160405280601f906020820280368337509192915050565b60008083601f840112613ffb57600080fd5b50813567ffffffffffffffff81111561401357600080fd5b6020830191508360208285010111156132ea57600080fd5b6000806020838503121561403e57600080fd5b823567ffffffffffffffff81111561405557600080fd5b61406185828601613fe9565b90969095509350505050565b60005b83811015614088578181015183820152602001614070565b50506000910152565b600081518084526140a981602086016020860161406d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000613e0f6020830184614091565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610180810167ffffffffffffffff81118282101715614141576141416140ee565b60405290565b604051610160810167ffffffffffffffff81118282101715614141576141416140ee565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156141b2576141b26140ee565b604052919050565b600082601f8301126141cb57600080fd5b813567ffffffffffffffff8111156141e5576141e56140ee565b61421660207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161416b565b81815284602083860101111561422b57600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561425a57600080fd5b813567ffffffffffffffff81111561427157600080fd5b612b40848285016141ba565b73ffffffffffffffffffffffffffffffffffffffff811681146129e457600080fd5b80356112428161427d565b6bffffffffffffffffffffffff811681146129e457600080fd5b8035611242816142aa565b600080604083850312156142e257600080fd5b82356142ed8161427d565b915060208301356142fd816142aa565b809150509250929050565b600081518084526020808501945080840160005b8381101561434e57815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161431c565b509495945050505050565b602081526000613e0f6020830184614308565b60006020828403121561437e57600080fd5b5035919050565b60006020828403121561439757600080fd5b813567ffffffffffffffff8111156143ae57600080fd5b82016101608185031215613e0f57600080fd5b8051825260208101516143ec602084018273ffffffffffffffffffffffffffffffffffffffff169052565b50604081015161440c60408401826bffffffffffffffffffffffff169052565b506060810151614434606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151614450608084018267ffffffffffffffff169052565b5060a081015161446860a084018263ffffffff169052565b5060c081015161448560c084018268ffffffffffffffffff169052565b5060e08101516144a260e084018268ffffffffffffffffff169052565b506101008181015164ffffffffff9081169184019190915261012080830151909116908301526101409081015163ffffffff16910152565b610160810161069a82846143c1565b60008083601f8401126144fb57600080fd5b50813567ffffffffffffffff81111561451357600080fd5b6020830191508360208260051b85010111156132ea57600080fd5b60008060008060008060008060e0898b03121561454a57600080fd5b606089018a81111561455b57600080fd5b8998503567ffffffffffffffff8082111561457557600080fd5b6145818c838d01613fe9565b909950975060808b013591508082111561459a57600080fd5b6145a68c838d016144e9565b909750955060a08b01359150808211156145bf57600080fd5b506145cc8b828c016144e9565b999c989b50969995989497949560c00135949350505050565b63ffffffff811681146129e457600080fd5b8035611242816145e5565b64ffffffffff811681146129e457600080fd5b803561124281614602565b803561ffff8116811461124257600080fd5b67ffffffffffffffff811681146129e457600080fd5b803561124281614632565b60ff811681146129e457600080fd5b803561124281614653565b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461124257600080fd5b600061018082840312156146ac57600080fd5b6146b461411d565b6146bd836145f7565b81526146cb602084016145f7565b60208201526146dc604084016145f7565b60408201526146ed606084016145f7565b60608201526146fe60808401614615565b608082015261470f60a08401614620565b60a082015261472060c08401614648565b60c082015261473160e08401614662565b60e082015261010061474481850161466d565b908201526101206147568482016145f7565b90820152610140614768848201614620565b9082015261016061477a848201614620565b908201529392505050565b815163ffffffff168152610180810160208301516147ab602084018263ffffffff169052565b5060408301516147c3604084018263ffffffff169052565b5060608301516147db606084018263ffffffff169052565b5060808301516147f4608084018264ffffffffff169052565b5060a083015161480a60a084018261ffff169052565b5060c083015161482660c084018267ffffffffffffffff169052565b5060e083015161483b60e084018260ff169052565b50610100838101517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16908301526101208084015163ffffffff16908301526101408084015161ffff908116918401919091526101608085015191821681850152905b505092915050565b6000806000806000608086880312156148ba57600080fd5b85356148c581614632565b9450602086013567ffffffffffffffff8111156148e157600080fd5b6148ed88828901613fe9565b9095509350506040860135614901816145e5565b949793965091946060013592915050565b600067ffffffffffffffff82111561492c5761492c6140ee565b5060051b60200190565b600082601f83011261494757600080fd5b8135602061495c61495783614912565b61416b565b82815260059290921b8401810191818101908684111561497b57600080fd5b8286015b8481101561499f5780356149928161427d565b835291830191830161497f565b509695505050505050565b60008060008060008060c087890312156149c357600080fd5b863567ffffffffffffffff808211156149db57600080fd5b6149e78a838b01614936565b975060208901359150808211156149fd57600080fd5b614a098a838b01614936565b9650614a1760408a01614662565b95506060890135915080821115614a2d57600080fd5b614a398a838b016141ba565b9450614a4760808a01614648565b935060a0890135915080821115614a5d57600080fd5b50614a6a89828a016141ba565b9150509295509295509295565b600060208284031215614a8957600080fd5b8135613e0f8161427d565b600181811c90821680614aa857607f821691505b6020821081036129a8577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b601f82111561065e57600081815260208120601f850160051c81016020861015614b085750805b601f850160051c820191505b8181101561085157828155600101614b14565b67ffffffffffffffff831115614b3f57614b3f6140ee565b614b5383614b4d8354614a94565b83614ae1565b6000601f841160018114614ba55760008515614b6f5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614c3b565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b82811015614bf45786850135825560209485019460019092019101614bd4565b5086821015614c2f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006bffffffffffffffffffffffff80841680614cbf57614cbf614c42565b92169190910492915050565b6bffffffffffffffffffffffff828116828216039080821115614cf057614cf0614c71565b5092915050565b805169ffffffffffffffffffff8116811461124257600080fd5b600080600080600060a08688031215614d2957600080fd5b614d3286614cf7565b9450602086015193506040860151925060608601519150614d5560808701614cf7565b90509295509295909350565b8181038181111561069a5761069a614c71565b600060208284031215614d8657600080fd5b8151613e0f81614653565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614df157614df1614c71565b5060010190565b68ffffffffffffffffff811681146129e457600080fd5b803561124281614df8565b60006101608236031215614e2d57600080fd5b614e35614147565b823567ffffffffffffffff811115614e4c57600080fd5b614e58368286016141ba565b82525060208301356020820152614e716040840161429f565b6040820152614e82606084016142c4565b6060820152614e9360808401614e0f565b6080820152614ea460a08401614648565b60a0820152614eb560c08401614648565b60c0820152614ec660e084016145f7565b60e0820152610100614ed9818501614620565b90820152610120614eeb848201614648565b90820152610140614efd84820161429f565b9082015292915050565b600060208284031215614f1957600080fd5b8135613e0f81614632565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614f5957600080fd5b83018035915067ffffffffffffffff821115614f7457600080fd5b6020019150368190038213156132ea57600080fd5b600060208284031215614f9b57600080fd5b613e0f82614620565b600060208284031215614fb657600080fd5b8135613e0f816145e5565b73ffffffffffffffffffffffffffffffffffffffff8a8116825267ffffffffffffffff8a166020830152881660408201526102406060820181905281018690526000610260878982850137600083890182015261ffff8716608084015260a0830186905263ffffffff851660c0840152601f88017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016830101905061506960e08301846143c1565b9a9950505050505050505050565b60ff818116838216019081111561069a5761069a614c71565b600060ff8316806150a3576150a3614c42565b8060ff84160491505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8183823760009101908152919050565b828152606082602083013760800192915050565b808202811582820484141761069a5761069a614c71565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b63ffffffff818116838216019080821115614cf057614cf0614c71565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526151988184018a614308565b905082810360808401526151ac8189614308565b905060ff871660a084015282810360c08401526151c98187614091565b905067ffffffffffffffff851660e08401528281036101008401526151ee8185614091565b9c9b505050505050505050505050565b805161124281614df8565b60006020828403121561521b57600080fd5b8151613e0f81614df8565b600181815b8085111561527f57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561526557615265614c71565b8085161561527257918102915b93841c939080029061522b565b509250929050565b6000826152965750600161069a565b816152a35750600061069a565b81600181146152b957600281146152c3576152df565b600191505061069a565b60ff8411156152d4576152d4614c71565b50506001821b61069a565b5060208310610133831016604e8410600b8410161715615302575081810a61069a565b61530c8383615226565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561533e5761533e614c71565b029392505050565b6000613e0f60ff841683615287565b60008261536457615364614c42565b500490565b6bffffffffffffffffffffffff818116838216019080821115614cf057614cf0614c71565b6bffffffffffffffffffffffff81811683821602808216919082811461489a5761489a614c71565b8082018082111561069a5761069a614c71565b67ffffffffffffffff818116838216019080821115614cf057614cf0614c71565b600082601f8301126153fb57600080fd5b8135602061540b61495783614912565b82815260059290921b8401810191818101908684111561542a57600080fd5b8286015b8481101561499f578035835291830191830161542e565b600082601f83011261545657600080fd5b8135602061546661495783614912565b82815260059290921b8401810191818101908684111561548557600080fd5b8286015b8481101561499f57803567ffffffffffffffff8111156154a95760008081fd5b6154b78986838b01016141ba565b845250918301918301615489565b600080600080600060a086880312156154dd57600080fd5b853567ffffffffffffffff808211156154f557600080fd5b61550189838a016153ea565b9650602088013591508082111561551757600080fd5b61552389838a01615445565b9550604088013591508082111561553957600080fd5b61554589838a01615445565b9450606088013591508082111561555b57600080fd5b61556789838a01615445565b9350608088013591508082111561557d57600080fd5b5061558a88828901615445565b9150509295509295909350565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b1660408501528160608501526155de8285018b614308565b915083820360808501526155f2828a614308565b915060ff881660a085015283820360c085015261560f8288614091565b90861660e085015283810361010085015290506151ee8185614091565b80516112428161427d565b8051611242816142aa565b805161124281614632565b8051611242816145e5565b805161124281614602565b6000610160828403121561567657600080fd5b61567e614147565b8251815261568e6020840161562c565b602082015261569f60408401615637565b60408201526156b06060840161562c565b60608201526156c160808401615642565b60808201526156d260a0840161564d565b60a08201526156e360c084016151fe565b60c08201526156f460e084016151fe565b60e0820152610100615707818501615658565b90820152610120615719848201615658565b9082015261014061477a84820161564d565b64ffffffffff818116838216019080821115614cf057614cf0614c71565b600061020080835261575d8184018a614091565b905082810360208401526157718189614091565b6bffffffffffffffffffffffff88811660408601528716606085015273ffffffffffffffffffffffffffffffffffffffff8616608085015291506157ba905060a08301846143c1565b979650505050505050565b600080604083850312156157d857600080fd5b8251600781106157e757600080fd5b60208401519092506142fd816142aa565b60006020828403121561580a57600080fd5b5051919050565b6000835161582381846020880161406d565b83519083019061583781836020880161406d565b01949350505050565b60006020828403121561585257600080fd5b8151613e0f8161427d56fe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000813000a", } var FunctionsCoordinatorABI = FunctionsCoordinatorMetaData.ABI diff --git a/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 7f441a59284..70ac49d79d3 100644 --- a/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -1,10 +1,10 @@ GETH_VERSION: 1.13.8 functions: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRequest.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRequest.bin 3c972870b0afeb6d73a29ebb182f24956a2cebb127b21c4f867d1ecf19a762db -functions_allow_list: ../../../contracts/solc/v0.8.19/functions/v1_X/TermsOfServiceAllowList.abi ../../../contracts/solc/v0.8.19/functions/v1_X/TermsOfServiceAllowList.bin 0c2156289e11f884ca6e92bf851192d3917c9094a0a301bcefa61266678d0e57 +functions_allow_list: ../../../contracts/solc/v0.8.19/functions/v1_X/TermsOfServiceAllowList.abi ../../../contracts/solc/v0.8.19/functions/v1_X/TermsOfServiceAllowList.bin 268de8b3c061b53a1a2a1ccc0149eff68545959e29cd41b5f2e9f5dab19075cf functions_billing_registry_events_mock: ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsBillingRegistryEventsMock.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsBillingRegistryEventsMock.bin 50deeb883bd9c3729702be335c0388f9d8553bab4be5e26ecacac496a89e2b77 functions_client: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClient.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClient.bin 2368f537a04489c720a46733f8596c4fc88a31062ecfa966d05f25dd98608aca functions_client_example: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClientExample.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClientExample.bin abf32e69f268f40e8530eb8d8e96bf310b798a4c0049a58022d9d2fb527b601b -functions_coordinator: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.bin 292d4742d039a154ed7875a0167c9725e2a90674ad9a05f152377819bb991082 +functions_coordinator: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.bin 97a625c7ce8c8c167faad5e532a5894a52af5dee722b2da7e7528f5eaa32a0fe functions_load_test_client: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsLoadTestClient.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsLoadTestClient.bin c8dbbd5ebb34435800d6674700068837c3a252db60046a14b0e61e829db517de functions_oracle_events_mock: ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsOracleEventsMock.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsOracleEventsMock.bin 3ca70f966f8fe751987f0ccb50bebb6aa5be77e4a9f835d1ae99e0e9bfb7d52c functions_router: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRouter.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRouter.bin 1f6d18f9e0846ad74b37a0a6acef5942ab73ace1e84307f201899f69e732e776 diff --git a/core/gethwrappers/generated/automation_registrar_wrapper2_3/automation_registrar_wrapper2_3.go b/core/gethwrappers/generated/automation_registrar_wrapper2_3/automation_registrar_wrapper2_3.go index 668a2235b45..cbcbe0fa40f 100644 --- a/core/gethwrappers/generated/automation_registrar_wrapper2_3/automation_registrar_wrapper2_3.go +++ b/core/gethwrappers/generated/automation_registrar_wrapper2_3/automation_registrar_wrapper2_3.go @@ -37,16 +37,17 @@ type AutomationRegistrar23InitialTriggerConfig struct { } type AutomationRegistrar23RegistrationParams struct { - Name string - EncryptedEmail []byte UpkeepContract common.Address - GasLimit uint32 + Amount *big.Int AdminAddress common.Address + GasLimit uint32 TriggerType uint8 + BillingToken common.Address + Name string + EncryptedEmail []byte CheckData []byte TriggerConfig []byte OffchainConfig []byte - Amount *big.Int } type AutomationRegistrar23TriggerRegistrationStorage struct { @@ -56,15 +57,15 @@ type AutomationRegistrar23TriggerRegistrationStorage struct { } var AutomationRegistrarMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"LINKAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"AutomationRegistry\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"minLINKJuels\",\"type\":\"uint96\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"enumAutomationRegistrar2_3.AutoApproveType\",\"name\":\"autoApproveType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"autoApproveMaxAllowed\",\"type\":\"uint32\"}],\"internalType\":\"structAutomationRegistrar2_3.InitialTriggerConfig[]\",\"name\":\"triggerConfigs\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AmountMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FunctionNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"HashMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientPayment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidAdminAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"LinkTransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyAdminOrOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyLink\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistrationRequestFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RequestNotFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderMismatch\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"}],\"name\":\"AutoApproveAllowedSenderSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"AutomationRegistry\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"minLINKJuels\",\"type\":\"uint96\"}],\"name\":\"ConfigChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"displayName\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"RegistrationApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"RegistrationRejected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"encryptedEmail\",\"type\":\"bytes\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"upkeepContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"RegistrationRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"enumAutomationRegistrar2_3.AutoApproveType\",\"name\":\"autoApproveType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"autoApproveMaxAllowed\",\"type\":\"uint32\"}],\"name\":\"TriggerConfigSet\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"upkeepContract\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"approve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"cancel\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"}],\"name\":\"getAutoApproveAllowedSender\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"AutomationRegistry\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minLINKJuels\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"getPendingRequest\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"}],\"name\":\"getTriggerRegistrationDetails\",\"outputs\":[{\"components\":[{\"internalType\":\"enumAutomationRegistrar2_3.AutoApproveType\",\"name\":\"autoApproveType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"autoApproveMaxAllowed\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"approvedCount\",\"type\":\"uint32\"}],\"internalType\":\"structAutomationRegistrar2_3.TriggerRegistrationStorage\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"encryptedEmail\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"upkeepContract\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"register\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"encryptedEmail\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"upkeepContract\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"internalType\":\"structAutomationRegistrar2_3.RegistrationParams\",\"name\":\"requestParams\",\"type\":\"tuple\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"}],\"name\":\"setAutoApproveAllowedSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"AutomationRegistry\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"minLINKJuels\",\"type\":\"uint96\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"enumAutomationRegistrar2_3.AutoApproveType\",\"name\":\"autoApproveType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"autoApproveMaxAllowed\",\"type\":\"uint32\"}],\"name\":\"setTriggerConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b5060405162002d8238038062002d8283398101604081905262000034916200043b565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be816200017a565b5050506001600160a01b038416608052620000da838362000225565b60005b81518110156200016f576200015a82828151811062000100576200010062000598565b60200260200101516000015183838151811062000121576200012162000598565b60200260200101516020015184848151811062000142576200014262000598565b6020026020010151604001516200029e60201b60201c565b806200016681620005ae565b915050620000dd565b50505050506200062f565b336001600160a01b03821603620001d45760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6200022f6200034c565b6040805180820182526001600160a01b0384168082526001600160601b0384166020928301819052600160a01b810282176004558351918252918101919091527f39ce5d867555f0b0183e358fce5b158e7ca4fecd7c01cb7e0e19f1e23285838a910160405180910390a15050565b620002a86200034c565b60ff83166000908152600360205260409020805483919060ff19166001836002811115620002da57620002da620005d6565b021790555060ff831660009081526003602052604090819020805464ffffffff00191661010063ffffffff851602179055517f830a6d06a4e2caac67eba04323de22bdb04f032dd8b3d6a0c52b503d9a7036a3906200033f90859085908590620005ec565b60405180910390a1505050565b6000546001600160a01b03163314620003a85760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000082565b565b80516001600160a01b0381168114620003c257600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b0381118282101715620004025762000402620003c7565b60405290565b604051601f8201601f191681016001600160401b0381118282101715620004335762000433620003c7565b604052919050565b600080600080608085870312156200045257600080fd5b6200045d85620003aa565b935060206200046e818701620003aa565b604087810151919550906001600160601b03811681146200048e57600080fd5b606088810151919550906001600160401b0380821115620004ae57600080fd5b818a0191508a601f830112620004c357600080fd5b815181811115620004d857620004d8620003c7565b620004e8868260051b0162000408565b818152868101925090840283018601908c8211156200050657600080fd5b928601925b81841015620005875784848e031215620005255760008081fd5b6200052f620003dd565b845160ff81168114620005425760008081fd5b81528488015160038110620005575760008081fd5b818901528487015163ffffffff81168114620005735760008081fd5b81880152835292840192918601916200050b565b999c989b5096995050505050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201620005cf57634e487b7160e01b600052601160045260246000fd5b5060010190565b634e487b7160e01b600052602160045260246000fd5b60ff8416815260608101600384106200061557634e487b7160e01b600052602160045260246000fd5b83602083015263ffffffff83166040830152949350505050565b6080516127146200066e60003960008181610177015281816105d601528181610887015281816109bd01528181610f0e015261171b01526127146000f3fe608060405234801561001057600080fd5b506004361061011b5760003560e01c8063856853e6116100b2578063b5ff5b4111610081578063c4d252f511610066578063c4d252f5146103e3578063e8d4070d146103f6578063f2fde38b1461040957600080fd5b8063b5ff5b4114610369578063c3f909d41461037c57600080fd5b8063856853e61461027857806388b12d551461028b5780638da5cb5b14610338578063a4c0ed361461035657600080fd5b80633f678e11116100ee5780633f678e11146101f35780636c4cdfc31461021457806379ba5097146102275780637e776f7f1461022f57600080fd5b8063181f5a77146101205780631b6b6d2314610172578063212d0884146101be578063367b9b4f146101de575b600080fd5b61015c6040518060400160405280601981526020017f4175746f6d6174696f6e52656769737472617220322e332e300000000000000081525081565b6040516101699190611a74565b60405180910390f35b6101997f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610169565b6101d16101cc366004611aa4565b61041c565b6040516101699190611b29565b6101f16101ec366004611b9d565b6104a9565b005b610206610201366004611bd6565b61053b565b604051908152602001610169565b6101f1610222366004611c2e565b6106d3565b6101f161076d565b61026861023d366004611c63565b73ffffffffffffffffffffffffffffffffffffffff1660009081526005602052604090205460ff1690565b6040519015158152602001610169565b6101f1610286366004611de1565b61086f565b6102ff610299366004611f40565b60009081526002602090815260409182902082518084019093525473ffffffffffffffffffffffffffffffffffffffff8116808452740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff169290910182905291565b6040805173ffffffffffffffffffffffffffffffffffffffff90931683526bffffffffffffffffffffffff909116602083015201610169565b60005473ffffffffffffffffffffffffffffffffffffffff16610199565b6101f1610364366004611f59565b6109a5565b6101f1610377366004611fb5565b610ce3565b60408051808201825260045473ffffffffffffffffffffffffffffffffffffffff8116808352740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff16602092830181905283519182529181019190915201610169565b6101f16103f1366004611f40565b610dc2565b6101f1610404366004611ffe565b61104c565b6101f1610417366004611c63565b6112d9565b60408051606080820183526000808352602080840182905283850182905260ff86811683526003909152908490208451928301909452835492939192839116600281111561046c5761046c611abf565b600281111561047d5761047d611abf565b8152905463ffffffff610100820481166020840152650100000000009091041660409091015292915050565b6104b16112ed565b73ffffffffffffffffffffffffffffffffffffffff821660008181526005602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182527f20c6237dac83526a849285a9f79d08a483291bdd3a056a0ef9ae94ecee1ad356910160405180910390a25050565b6004546000907401000000000000000000000000000000000000000090046bffffffffffffffffffffffff1661057961014084016101208501612109565b6bffffffffffffffffffffffff1610156105bf576040517fcd1c886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166323b872dd333061060f61014087016101208801612109565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff93841660048201529290911660248301526bffffffffffffffffffffffff1660448201526064016020604051808303816000875af1158015610696573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ba9190612124565b506106cd6106c783612141565b33611370565b92915050565b6106db6112ed565b60408051808201825273ffffffffffffffffffffffffffffffffffffffff84168082526bffffffffffffffffffffffff8416602092830181905274010000000000000000000000000000000000000000810282176004558351918252918101919091527f39ce5d867555f0b0183e358fce5b158e7ca4fecd7c01cb7e0e19f1e23285838a910160405180910390a15050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146107f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146108de576040517f018d10be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109966040518061014001604052808e81526020018d8d8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525073ffffffffffffffffffffffffffffffffffffffff808d16602083015263ffffffff8c1660408301528a16606082015260ff8916608082015260a0810188905260c0810187905260e081018690526bffffffffffffffffffffffff85166101009091015282611370565b50505050505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610a14576040517f018d10be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81818080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050505060208101517fffffffff0000000000000000000000000000000000000000000000000000000081167f856853e60000000000000000000000000000000000000000000000000000000014610aca576040517fe3d6792100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8484846000610adc8260048186612276565b810190610ae991906122a0565b509950505050505050505050806bffffffffffffffffffffffff168414610b3c576040517f55e97b0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8988886000610b4e8260048186612276565b810190610b5b91906122a0565b9a50505050505050505050508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614610bcc576040517ff8c5638e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004547401000000000000000000000000000000000000000090046bffffffffffffffffffffffff168d1015610c2e576040517fcd1c886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003073ffffffffffffffffffffffffffffffffffffffff168d8d604051610c579291906123dd565b600060405180830381855af49150503d8060008114610c92576040519150601f19603f3d011682016040523d82523d6000602084013e610c97565b606091505b5050905080610cd2576040517f649bf81000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050505050505050565b610ceb6112ed565b60ff8316600090815260036020526040902080548391907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001836002811115610d3857610d38611abf565b021790555060ff83166000908152600360205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff1661010063ffffffff851602179055517f830a6d06a4e2caac67eba04323de22bdb04f032dd8b3d6a0c52b503d9a7036a390610db5908590859085906123ed565b60405180910390a1505050565b60008181526002602090815260409182902082518084019093525473ffffffffffffffffffffffffffffffffffffffff8116808452740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff1691830191909152331480610e49575060005473ffffffffffffffffffffffffffffffffffffffff1633145b610e7f576040517f61685c2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805173ffffffffffffffffffffffffffffffffffffffff16610ecd576040517f4b13b31e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260026020908152604080832083905583519184015190517fa9059cbb0000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169263a9059cbb92610f859260040173ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b6020604051808303816000875af1158015610fa4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc89190612124565b90508061101c5781516040517fc2e4dce800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911660048201526024016107ea565b60405183907f3663fb28ebc87645eb972c9dad8521bf665c623f287e79f1c56f1eb374b82a2290600090a2505050565b6110546112ed565b60008181526002602090815260409182902082518084019093525473ffffffffffffffffffffffffffffffffffffffff8116808452740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff16918301919091526110ed576040517f4b13b31e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008b8b8b8b8b8b8b8b8b60405160200161111099989796959493929190612461565b604051602081830303815290604052805190602001209050808314611161576040517f3f4d605300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60026000848152602001908152602001600020600080820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556000820160146101000a8154906bffffffffffffffffffffffff021916905550506112c96040518061014001604052808f81526020016040518060200160405280600081525081526020018e73ffffffffffffffffffffffffffffffffffffffff1681526020018d63ffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b60ff1681526020018a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525060208082018a905260408051601f8a0183900483028101830182528981529201919089908990819084018382808284376000920191909152505050908252506020858101516bffffffffffffffffffffffff1691015282611647565b5050505050505050505050505050565b6112e16112ed565b6112ea81611876565b50565b60005473ffffffffffffffffffffffffffffffffffffffff16331461136e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016107ea565b565b608082015160009073ffffffffffffffffffffffffffffffffffffffff166113c4576040517f05bb467c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008360400151846060015185608001518660a001518760c001518860e0015189610100015160405160200161140097969594939291906124e7565b604051602081830303815290604052805190602001209050836040015173ffffffffffffffffffffffffffffffffffffffff16817f7684390ebb103102f7f48c71439c2408713f8d437782a6fab2756acc0e42c1b786600001518760200151886060015189608001518a60a001518b60e001518c61010001518d60c001518e610120015160405161149999989796959493929190612569565b60405180910390a360a084015160ff9081166000908152600360205260408082208151606081019092528054929361151c9383911660028111156114df576114df611abf565b60028111156114f0576114f0611abf565b8152905463ffffffff61010082048116602084015265010000000000909104166040909101528561196b565b156115845760a085015160ff166000908152600360205260409020805465010000000000900463ffffffff1690600561155483612653565b91906101000a81548163ffffffff021916908363ffffffff1602179055505061157d8583611647565b905061163f565b61012085015160008381526002602052604081205490916115ca917401000000000000000000000000000000000000000090046bffffffffffffffffffffffff16612676565b604080518082018252608089015173ffffffffffffffffffffffffffffffffffffffff90811682526bffffffffffffffffffffffff9384166020808401918252600089815260029091529390932091519251909316740100000000000000000000000000000000000000000291909216179055505b949350505050565b600480546040808501516060860151608087015160a088015160c089015160e08a01516101008b015196517f28f32f3800000000000000000000000000000000000000000000000000000000815260009973ffffffffffffffffffffffffffffffffffffffff909916988a988a986328f32f38986116d29891979096919590949193909291016124e7565b6020604051808303816000875af11580156116f1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061171591906126a2565b905060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16634000aea0848861012001518560405160200161176f91815260200190565b6040516020818303038152906040526040518463ffffffff1660e01b815260040161179c939291906126bb565b6020604051808303816000875af11580156117bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117df9190612124565b905080611830576040517fc2e4dce800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201526024016107ea565b81857fb9a292fb7e3edd920cd2d2829a3615a640c43fd7de0a0820aa0668feb4c37d4b88600001516040516118659190611a74565b60405180910390a350949350505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036118f5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016107ea565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000808351600281111561198157611981611abf565b0361198e575060006106cd565b6001835160028111156119a3576119a3611abf565b1480156119d6575073ffffffffffffffffffffffffffffffffffffffff821660009081526005602052604090205460ff16155b156119e3575060006106cd565b826020015163ffffffff16836040015163ffffffff161015611a07575060016106cd565b50600092915050565b6000815180845260005b81811015611a3657602081850181015186830182015201611a1a565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000611a876020830184611a10565b9392505050565b803560ff81168114611a9f57600080fd5b919050565b600060208284031215611ab657600080fd5b611a8782611a8e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60038110611b25577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b6000606082019050611b3c828451611aee565b602083015163ffffffff8082166020850152806040860151166040850152505092915050565b73ffffffffffffffffffffffffffffffffffffffff811681146112ea57600080fd5b8035611a9f81611b62565b80151581146112ea57600080fd5b60008060408385031215611bb057600080fd5b8235611bbb81611b62565b91506020830135611bcb81611b8f565b809150509250929050565b600060208284031215611be857600080fd5b813567ffffffffffffffff811115611bff57600080fd5b82016101408185031215611a8757600080fd5b80356bffffffffffffffffffffffff81168114611a9f57600080fd5b60008060408385031215611c4157600080fd5b8235611c4c81611b62565b9150611c5a60208401611c12565b90509250929050565b600060208284031215611c7557600080fd5b8135611a8781611b62565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610140810167ffffffffffffffff81118282101715611cd357611cd3611c80565b60405290565b600082601f830112611cea57600080fd5b813567ffffffffffffffff80821115611d0557611d05611c80565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715611d4b57611d4b611c80565b81604052838152866020858801011115611d6457600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008083601f840112611d9657600080fd5b50813567ffffffffffffffff811115611dae57600080fd5b602083019150836020828501011115611dc657600080fd5b9250929050565b803563ffffffff81168114611a9f57600080fd5b6000806000806000806000806000806000806101608d8f031215611e0457600080fd5b67ffffffffffffffff8d351115611e1a57600080fd5b611e278e8e358f01611cd9565b9b5067ffffffffffffffff60208e01351115611e4257600080fd5b611e528e60208f01358f01611d84565b909b509950611e6360408e01611b84565b9850611e7160608e01611dcd565b9750611e7f60808e01611b84565b9650611e8d60a08e01611a8e565b955067ffffffffffffffff60c08e01351115611ea857600080fd5b611eb88e60c08f01358f01611cd9565b945067ffffffffffffffff60e08e01351115611ed357600080fd5b611ee38e60e08f01358f01611cd9565b935067ffffffffffffffff6101008e01351115611eff57600080fd5b611f108e6101008f01358f01611cd9565b9250611f1f6101208e01611c12565b9150611f2e6101408e01611b84565b90509295989b509295989b509295989b565b600060208284031215611f5257600080fd5b5035919050565b60008060008060608587031215611f6f57600080fd5b8435611f7a81611b62565b935060208501359250604085013567ffffffffffffffff811115611f9d57600080fd5b611fa987828801611d84565b95989497509550505050565b600080600060608486031215611fca57600080fd5b611fd384611a8e565b9250602084013560038110611fe757600080fd5b9150611ff560408501611dcd565b90509250925092565b60008060008060008060008060008060006101208c8e03121561202057600080fd5b67ffffffffffffffff808d35111561203757600080fd5b6120448e8e358f01611cd9565b9b5061205260208e01611b84565b9a5061206060408e01611dcd565b995061206e60608e01611b84565b985061207c60808e01611a8e565b97508060a08e0135111561208f57600080fd5b61209f8e60a08f01358f01611d84565b909750955060c08d01358110156120b557600080fd5b6120c58e60c08f01358f01611cd9565b94508060e08e013511156120d857600080fd5b506120e98d60e08e01358e01611d84565b81945080935050506101008c013590509295989b509295989b9093969950565b60006020828403121561211b57600080fd5b611a8782611c12565b60006020828403121561213657600080fd5b8151611a8781611b8f565b6000610140823603121561215457600080fd5b61215c611caf565b823567ffffffffffffffff8082111561217457600080fd5b61218036838701611cd9565b8352602085013591508082111561219657600080fd5b6121a236838701611cd9565b60208401526121b360408601611b84565b60408401526121c460608601611dcd565b60608401526121d560808601611b84565b60808401526121e660a08601611a8e565b60a084015260c08501359150808211156121ff57600080fd5b61220b36838701611cd9565b60c084015260e085013591508082111561222457600080fd5b61223036838701611cd9565b60e08401526101009150818501358181111561224b57600080fd5b61225736828801611cd9565b8385015250505061012061226c818501611c12565b9082015292915050565b6000808585111561228657600080fd5b8386111561229357600080fd5b5050820193919092039150565b60008060008060008060008060008060006101608c8e0312156122c257600080fd5b67ffffffffffffffff808d3511156122d957600080fd5b6122e68e8e358f01611cd9565b9b508060208e013511156122f957600080fd5b6123098e60208f01358f01611cd9565b9a5061231760408e01611b84565b995061232560608e01611dcd565b985061233360808e01611b84565b975061234160a08e01611a8e565b96508060c08e0135111561235457600080fd5b6123648e60c08f01358f01611cd9565b95508060e08e0135111561237757600080fd5b6123878e60e08f01358f01611cd9565b9450806101008e0135111561239b57600080fd5b506123ad8d6101008e01358e01611cd9565b92506123bc6101208d01611c12565b91506123cb6101408d01611b84565b90509295989b509295989b9093969950565b8183823760009101908152919050565b60ff84168152606081016124046020830185611aee565b63ffffffff83166040830152949350505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600073ffffffffffffffffffffffffffffffffffffffff808c16835263ffffffff8b166020840152808a1660408401525060ff8816606083015260e060808301526124b060e083018789612418565b82810360a08401526124c28187611a10565b905082810360c08401526124d7818587612418565b9c9b505050505050505050505050565b600073ffffffffffffffffffffffffffffffffffffffff808a16835263ffffffff8916602084015280881660408401525060ff8616606083015260e0608083015261253560e0830186611a10565b82810360a08401526125478186611a10565b905082810360c084015261255b8185611a10565b9a9950505050505050505050565b600061012080835261257d8184018d611a10565b90508281036020840152612591818c611a10565b905063ffffffff8a16604084015273ffffffffffffffffffffffffffffffffffffffff8916606084015260ff8816608084015282810360a08401526125d68188611a10565b905082810360c08401526125ea8187611a10565b905082810360e08401526125fe8186611a10565b9150506bffffffffffffffffffffffff83166101008301529a9950505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff80831681810361266c5761266c612624565b6001019392505050565b6bffffffffffffffffffffffff81811683821601908082111561269b5761269b612624565b5092915050565b6000602082840312156126b457600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff841681526bffffffffffffffffffffffff831660208201526060604082015260006126fe6060830184611a10565b9594505050505056fea164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"LINKAddress\",\"type\":\"address\"},{\"internalType\":\"contractIAutomationRegistryMaster2_3\",\"name\":\"registry\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"enumAutomationRegistrar2_3.AutoApproveType\",\"name\":\"autoApproveType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"autoApproveMaxAllowed\",\"type\":\"uint32\"}],\"internalType\":\"structAutomationRegistrar2_3.InitialTriggerConfig[]\",\"name\":\"triggerConfigs\",\"type\":\"tuple[]\"},{\"internalType\":\"contractIERC20[]\",\"name\":\"billingTokens\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"minRegistrationFees\",\"type\":\"uint256[]\"},{\"internalType\":\"contractIWrappedNative\",\"name\":\"wrappedNativeToken\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"HashMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientPayment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidAdminAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidBillingToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyAdminOrOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyLink\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RequestNotFound\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"TransferFailed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"}],\"name\":\"AutoApproveAllowedSenderSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"ConfigChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"displayName\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"RegistrationApproved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"RegistrationRejected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"encryptedEmail\",\"type\":\"bytes\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"upkeepContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"RegistrationRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"enumAutomationRegistrar2_3.AutoApproveType\",\"name\":\"autoApproveType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"autoApproveMaxAllowed\",\"type\":\"uint32\"}],\"name\":\"TriggerConfigSet\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"upkeepContract\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"contractIERC20\",\"name\":\"billingToken\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"encryptedEmail\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"internalType\":\"structAutomationRegistrar2_3.RegistrationParams\",\"name\":\"requestParams\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"approve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"cancel\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"}],\"name\":\"getAutoApproveAllowedSender\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"billingToken\",\"type\":\"address\"}],\"name\":\"getMinimumRegistrationAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"}],\"name\":\"getPendingRequest\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRegistry\",\"outputs\":[{\"internalType\":\"contractIAutomationRegistryMaster2_3\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"}],\"name\":\"getTriggerRegistrationDetails\",\"outputs\":[{\"components\":[{\"internalType\":\"enumAutomationRegistrar2_3.AutoApproveType\",\"name\":\"autoApproveType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"autoApproveMaxAllowed\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"approvedCount\",\"type\":\"uint32\"}],\"internalType\":\"structAutomationRegistrar2_3.TriggerRegistrationStorage\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_WRAPPED_NATIVE_TOKEN\",\"outputs\":[{\"internalType\":\"contractIWrappedNative\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"upkeepContract\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"contractIERC20\",\"name\":\"billingToken\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"encryptedEmail\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"internalType\":\"structAutomationRegistrar2_3.RegistrationParams\",\"name\":\"requestParams\",\"type\":\"tuple\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"}],\"name\":\"setAutoApproveAllowedSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIAutomationRegistryMaster2_3\",\"name\":\"registry\",\"type\":\"address\"},{\"internalType\":\"contractIERC20[]\",\"name\":\"billingTokens\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"minBalances\",\"type\":\"uint256[]\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"enumAutomationRegistrar2_3.AutoApproveType\",\"name\":\"autoApproveType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"autoApproveMaxAllowed\",\"type\":\"uint32\"}],\"name\":\"setTriggerConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x60c06040523480156200001157600080fd5b5060405162003187380380620031878339810160408190526200003491620005db565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be8162000183565b5050506001600160a01b03808716608052811660a052620000e18584846200022e565b60005b84518110156200017657620001618582815181106200010757620001076200076d565b6020026020010151600001518683815181106200012857620001286200076d565b6020026020010151602001518784815181106200014957620001496200076d565b6020026020010151604001516200032a60201b60201c565b806200016d8162000783565b915050620000e4565b5050505050505062000804565b336001600160a01b03821603620001dd5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b62000238620003d8565b80518251146200025b57604051630dfe930960e41b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b03851617905560005b8251811015620002fb578181815181106200029857620002986200076d565b602002602001015160046000858481518110620002b957620002b96200076d565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020819055508080620002f29062000783565b91505062000279565b506040517fb9b6902016bd1219d5fa6161243b61e7e9f7f959526dd94ef8fa3e403bf881c390600090a1505050565b62000334620003d8565b60ff83166000908152600660205260409020805483919060ff19166001836002811115620003665762000366620007ab565b021790555060ff831660009081526006602052604090819020805464ffffffff00191661010063ffffffff851602179055517f830a6d06a4e2caac67eba04323de22bdb04f032dd8b3d6a0c52b503d9a7036a390620003cb90859085908590620007c1565b60405180910390a1505050565b6000546001600160a01b03163314620004345760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000082565b565b6001600160a01b03811681146200044c57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b03811182821017156200048a576200048a6200044f565b60405290565b604051601f8201601f191681016001600160401b0381118282101715620004bb57620004bb6200044f565b604052919050565b60006001600160401b03821115620004df57620004df6200044f565b5060051b60200190565b600082601f830112620004fb57600080fd5b81516020620005146200050e83620004c3565b62000490565b82815260059290921b840181019181810190868411156200053457600080fd5b8286015b848110156200055c5780516200054e8162000436565b835291830191830162000538565b509695505050505050565b600082601f8301126200057957600080fd5b815160206200058c6200050e83620004c3565b82815260059290921b84018101918181019086841115620005ac57600080fd5b8286015b848110156200055c5780518352918301918301620005b0565b8051620005d68162000436565b919050565b60008060008060008060c08789031215620005f557600080fd5b8651620006028162000436565b80965050602080880151620006178162000436565b60408901519096506001600160401b03808211156200063557600080fd5b818a0191508a601f8301126200064a57600080fd5b81516200065b6200050e82620004c3565b81815260609091028301840190848101908d8311156200067a57600080fd5b938501935b8285101562000701576060858f0312156200069a5760008081fd5b620006a462000465565b855160ff81168114620006b75760008081fd5b81528587015160038110620006cc5760008081fd5b81880152604086015163ffffffff81168114620006e95760008081fd5b6040820152825260609490940193908501906200067f565b60608d015190995094505050808311156200071b57600080fd5b620007298b848c01620004e9565b955060808a01519250808311156200074057600080fd5b50506200075089828a0162000567565b9250506200076160a08801620005c9565b90509295509295509295565b634e487b7160e01b600052603260045260246000fd5b600060018201620007a457634e487b7160e01b600052601160045260246000fd5b5060010190565b634e487b7160e01b600052602160045260246000fd5b60ff841681526060810160038410620007ea57634e487b7160e01b600052602160045260246000fd5b83602083015263ffffffff83166040830152949350505050565b60805160a05161292c6200085b6000396000818161027b0152818161059501526106280152600081816104a201528181610a9d01528181610b0601528181610f0b0152818161164901526116a0015261292c6000f3fe6080604052600436106101295760003560e01c806388b12d55116100a5578063accb832311610074578063befdae4611610059578063befdae4614610490578063c4d252f5146104c4578063f2fde38b146104e457600080fd5b8063accb832314610450578063b5ff5b411461047057600080fd5b806388b12d55146103085780638da5cb5b146103c2578063a2b1ff94146103ed578063a4c0ed361461043057600080fd5b80635ab1bd53116100fc5780636bf7d75f116100e15780636bf7d75f1461026957806379ba50971461029d5780637e776f7f146102b257600080fd5b80635ab1bd53146101fd57806366ab87f91461024957600080fd5b8063181f5a771461012e578063212d08841461018d5780632ce3a14a146101ba578063367b9b4f146101db575b600080fd5b34801561013a57600080fd5b506101776040518060400160405280601981526020017f4175746f6d6174696f6e52656769737472617220322e332e300000000000000081525081565b6040516101849190611b51565b60405180910390f35b34801561019957600080fd5b506101ad6101a8366004611b81565b610504565b6040516101849190611c06565b6101cd6101c8366004611f1d565b610591565b604051908152602001610184565b3480156101e757600080fd5b506101fb6101f6366004611f60565b6107af565b005b34801561020957600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610184565b34801561025557600080fd5b506101fb610264366004612028565b610841565b34801561027557600080fd5b506102247f000000000000000000000000000000000000000000000000000000000000000081565b3480156102a957600080fd5b506101fb610988565b3480156102be57600080fd5b506102f86102cd3660046120fe565b73ffffffffffffffffffffffffffffffffffffffff1660009081526003602052604090205460ff1690565b6040519015158152602001610184565b34801561031457600080fd5b5061038961032336600461211b565b60009081526005602090815260409182902082518084019093525473ffffffffffffffffffffffffffffffffffffffff8116808452740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff169290910182905291565b6040805173ffffffffffffffffffffffffffffffffffffffff90931683526bffffffffffffffffffffffff909116602083015201610184565b3480156103ce57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610224565b3480156103f957600080fd5b506101cd6104083660046120fe565b73ffffffffffffffffffffffffffffffffffffffff1660009081526004602052604090205490565b34801561043c57600080fd5b506101fb61044b366004612134565b610a85565b34801561045c57600080fd5b506101fb61046b3660046121bd565b610bb3565b34801561047c57600080fd5b506101fb61048b366004612208565b610ce0565b34801561049c57600080fd5b506102247f000000000000000000000000000000000000000000000000000000000000000081565b3480156104d057600080fd5b506101fb6104df36600461211b565b610dbf565b3480156104f057600080fd5b506101fb6104ff3660046120fe565b611049565b60408051606080820183526000808352602080840182905283850182905260ff86811683526006909152908490208451928301909452835492939192839116600281111561055457610554611b9c565b600281111561056557610565611b9c565b8152905463ffffffff610100820481166020840152650100000000009091041660409091015292915050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168260a0015173ffffffffffffffffffffffffffffffffffffffff161480156105f157503415155b156106ac576105ff3461105d565b82602001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff16815250507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561068e57600080fd5b505af11580156106a2573d6000803e3d6000fd5b505050505061079f565b60a082015160208301516040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526bffffffffffffffffffffffff909116604482015273ffffffffffffffffffffffffffffffffffffffff909116906323b872dd906064016020604051808303816000875af115801561073e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107629190612251565b61079f576040517f39f1c8d90000000000000000000000000000000000000000000000000000000081523060048201526024015b60405180910390fd5b6107a982336110ff565b92915050565b6107b76114ed565b73ffffffffffffffffffffffffffffffffffffffff821660008181526003602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182527f20c6237dac83526a849285a9f79d08a483291bdd3a056a0ef9ae94ecee1ad356910160405180910390a25050565b6108496114ed565b8051825114610884576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff851617905560005b8251811015610959578181815181106108e2576108e261226e565b6020026020010151600460008584815181106109005761090061226e565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508080610951906122cc565b9150506108c7565b506040517fb9b6902016bd1219d5fa6161243b61e7e9f7f959526dd94ef8fa3e403bf881c390600090a1505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610a09576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610796565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610af4576040517f018d10be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610b0282840184611f1d565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168160a0015173ffffffffffffffffffffffffffffffffffffffff1614610b8d576040517f018d10be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6bffffffffffffffffffffffff84166020820152610bab81866110ff565b505050505050565b610bbb6114ed565b60008181526005602090815260409182902082518084019093525473ffffffffffffffffffffffffffffffffffffffff8116808452740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff1691830191909152610c54576040517f4b13b31e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083604051602001610c6791906123b8565b604051602081830303815290604052805190602001209050808314610cb8576040517f3f4d605300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083815260056020526040812055610cd9610cd38561257f565b82611570565b5050505050565b610ce86114ed565b60ff8316600090815260066020526040902080548391907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001836002811115610d3557610d35611b9c565b021790555060ff83166000908152600660205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff1661010063ffffffff851602179055517f830a6d06a4e2caac67eba04323de22bdb04f032dd8b3d6a0c52b503d9a7036a390610db29085908590859061258b565b60405180910390a1505050565b60008181526005602090815260409182902082518084019093525473ffffffffffffffffffffffffffffffffffffffff8116808452740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff1691830191909152331480610e46575060005473ffffffffffffffffffffffffffffffffffffffff1633145b610e7c576040517f61685c2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805173ffffffffffffffffffffffffffffffffffffffff16610eca576040517f4b13b31e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020908152604080832083905583519184015190517fa9059cbb0000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169263a9059cbb92610f829260040173ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b6020604051808303816000875af1158015610fa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc59190612251565b9050806110195781516040517f39f1c8d900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610796565b60405183907f3663fb28ebc87645eb972c9dad8521bf665c623f287e79f1c56f1eb374b82a2290600090a2505050565b6110516114ed565b61105a81611953565b50565b60006bffffffffffffffffffffffff8211156110fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610796565b5090565b60a082015173ffffffffffffffffffffffffffffffffffffffff166000908152600460209081526040822054908401516bffffffffffffffffffffffff161015611175576040517fcd1c886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604083015173ffffffffffffffffffffffffffffffffffffffff166111c6576040517f05bb467c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025460a08401516040517fa538b2eb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff918216600482015291169063a538b2eb90602401602060405180830381865afa15801561123a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061125e9190612251565b611294576040517f1183afea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000836040516020016112a791906125b6565b604051602081830303815290604052805190602001209050836000015173ffffffffffffffffffffffffffffffffffffffff16817f7684390ebb103102f7f48c71439c2408713f8d437782a6fab2756acc0e42c1b78660c001518760e00151886060015189604001518a608001518b61012001518c61014001518d61010001518e6020015160405161134199989796959493929190612722565b60405180910390a3608084015160ff908116600090815260066020526040808220815160608101909252805492936113c493839116600281111561138757611387611b9c565b600281111561139857611398611b9c565b8152905463ffffffff610100820481166020840152650100000000009091041660409091015285611a48565b1561142c57608085015160ff166000908152600660205260409020805465010000000000900463ffffffff169060056113fc836127dd565b91906101000a81548163ffffffff021916908363ffffffff160217905550506114258583611570565b90506114e5565b60208581015160008481526005909252604082205461147191907401000000000000000000000000000000000000000090046bffffffffffffffffffffffff16612800565b6040805180820182528882015173ffffffffffffffffffffffffffffffffffffffff90811682526bffffffffffffffffffffffff9384166020808401918252600089815260059091529390932091519251909316740100000000000000000000000000000000000000000291909216179055505b949350505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461156e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610796565b565b60025482516060840151604080860151608087015160a08801516101008901516101208a01516101408b015195517fc62cf68400000000000000000000000000000000000000000000000000000000815260009973ffffffffffffffffffffffffffffffffffffffff16988a988a9863c62cf684986116009893979296909593949293909290919060040161282c565b6020604051808303816000875af115801561161f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061164391906128ba565b905060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168660a0015173ffffffffffffffffffffffffffffffffffffffff160361176a577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16634000aea0848860200151856040516020016116f391815260200190565b6040516020818303038152906040526040518463ffffffff1660e01b8152600401611720939291906128d3565b6020604051808303816000875af115801561173f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117639190612251565b90506118be565b60a086015160208701516040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301526bffffffffffffffffffffffff909216602482015291169063095ea7b3906044016020604051808303816000875af11580156117f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061181b9190612251565b905080156118be5760208601516040517f948108f7000000000000000000000000000000000000000000000000000000008152600481018490526bffffffffffffffffffffffff909116602482015273ffffffffffffffffffffffffffffffffffffffff84169063948108f790604401600060405180830381600087803b1580156118a557600080fd5b505af11580156118b9573d6000803e3d6000fd5b505050505b8061190d576040517f39f1c8d900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610796565b81857fb9a292fb7e3edd920cd2d2829a3615a640c43fd7de0a0820aa0668feb4c37d4b8860c001516040516119429190611b51565b60405180910390a350949350505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036119d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610796565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008083516002811115611a5e57611a5e611b9c565b03611a6b575060006107a9565b600183516002811115611a8057611a80611b9c565b148015611ab3575073ffffffffffffffffffffffffffffffffffffffff821660009081526003602052604090205460ff16155b15611ac0575060006107a9565b826020015163ffffffff16836040015163ffffffff161015611ae4575060016107a9565b50600092915050565b6000815180845260005b81811015611b1357602081850181015186830182015201611af7565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000611b646020830184611aed565b9392505050565b803560ff81168114611b7c57600080fd5b919050565b600060208284031215611b9357600080fd5b611b6482611b6b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60038110611c02577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b6000606082019050611c19828451611bcb565b602083015163ffffffff8082166020850152806040860151166040850152505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610160810167ffffffffffffffff81118282101715611c9257611c92611c3f565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611cdf57611cdf611c3f565b604052919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461105a57600080fd5b8035611b7c81611ce7565b80356bffffffffffffffffffffffff81168114611b7c57600080fd5b803563ffffffff81168114611b7c57600080fd5b600082601f830112611d5557600080fd5b813567ffffffffffffffff811115611d6f57611d6f611c3f565b611da060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601611c98565b818152846020838601011115611db557600080fd5b816020850160208301376000918101602001919091529392505050565b60006101608284031215611de557600080fd5b611ded611c6e565b9050611df882611d09565b8152611e0660208301611d14565b6020820152611e1760408301611d09565b6040820152611e2860608301611d30565b6060820152611e3960808301611b6b565b6080820152611e4a60a08301611d09565b60a082015260c082013567ffffffffffffffff80821115611e6a57600080fd5b611e7685838601611d44565b60c084015260e0840135915080821115611e8f57600080fd5b611e9b85838601611d44565b60e084015261010091508184013581811115611eb657600080fd5b611ec286828701611d44565b838501525061012091508184013581811115611edd57600080fd5b611ee986828701611d44565b838501525061014091508184013581811115611f0457600080fd5b611f1086828701611d44565b8385015250505092915050565b600060208284031215611f2f57600080fd5b813567ffffffffffffffff811115611f4657600080fd5b6114e584828501611dd2565b801515811461105a57600080fd5b60008060408385031215611f7357600080fd5b8235611f7e81611ce7565b91506020830135611f8e81611f52565b809150509250929050565b600067ffffffffffffffff821115611fb357611fb3611c3f565b5060051b60200190565b600082601f830112611fce57600080fd5b81356020611fe3611fde83611f99565b611c98565b82815260059290921b8401810191818101908684111561200257600080fd5b8286015b8481101561201d5780358352918301918301612006565b509695505050505050565b60008060006060848603121561203d57600080fd5b833561204881611ce7565b925060208481013567ffffffffffffffff8082111561206657600080fd5b818701915087601f83011261207a57600080fd5b8135612088611fde82611f99565b81815260059190911b8301840190848101908a8311156120a757600080fd5b938501935b828510156120ce5784356120bf81611ce7565b825293850193908501906120ac565b9650505060408701359250808311156120e657600080fd5b50506120f486828701611fbd565b9150509250925092565b60006020828403121561211057600080fd5b8135611b6481611ce7565b60006020828403121561212d57600080fd5b5035919050565b6000806000806060858703121561214a57600080fd5b843561215581611ce7565b935060208501359250604085013567ffffffffffffffff8082111561217957600080fd5b818701915087601f83011261218d57600080fd5b81358181111561219c57600080fd5b8860208285010111156121ae57600080fd5b95989497505060200194505050565b600080604083850312156121d057600080fd5b823567ffffffffffffffff8111156121e757600080fd5b830161016081860312156121fa57600080fd5b946020939093013593505050565b60008060006060848603121561221d57600080fd5b61222684611b6b565b925060208401356003811061223a57600080fd5b915061224860408501611d30565b90509250925092565b60006020828403121561226357600080fd5b8151611b6481611f52565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036122fd576122fd61229d565b5060010190565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261233957600080fd5b830160208101925035905067ffffffffffffffff81111561235957600080fd5b80360382131561236857600080fd5b9250929050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b602081526123e6602082016123cc84611d09565b73ffffffffffffffffffffffffffffffffffffffff169052565b60006123f460208401611d14565b6bffffffffffffffffffffffff811660408401525061241560408401611d09565b73ffffffffffffffffffffffffffffffffffffffff811660608401525061243e60608401611d30565b63ffffffff811660808401525061245760808401611b6b565b60ff811660a08401525061246d60a08401611d09565b73ffffffffffffffffffffffffffffffffffffffff811660c08401525061249760c0840184612304565b6101608060e08601526124af6101808601838561236f565b92506124be60e0870187612304565b92507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06101008188870301818901526124f886868561236f565b9550612506818a018a612304565b955092505061012081888703018189015261252286868561236f565b9550612530818a018a612304565b955092505061014081888703018189015261254c86868561236f565b955061255a818a018a612304565b95509250508087860301838801525061257484848361236f565b979650505050505050565b60006107a93683611dd2565b60ff84168152606081016125a26020830185611bcb565b63ffffffff83166040830152949350505050565b602081526125dd60208201835173ffffffffffffffffffffffffffffffffffffffff169052565b600060208301516125fe60408401826bffffffffffffffffffffffff169052565b50604083015173ffffffffffffffffffffffffffffffffffffffff8116606084015250606083015163ffffffff8116608084015250608083015160ff811660a08401525060a083015173ffffffffffffffffffffffffffffffffffffffff811660c08401525060c08301516101608060e0850152612680610180850183611aed565b915060e08501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06101008187860301818801526126be8584611aed565b9450808801519250506101208187860301818801526126dd8584611aed565b9450808801519250506101408187860301818801526126fc8584611aed565b9088015187820390920184880152935090506127188382611aed565b9695505050505050565b60006101208083526127368184018d611aed565b9050828103602084015261274a818c611aed565b905063ffffffff8a16604084015273ffffffffffffffffffffffffffffffffffffffff8916606084015260ff8816608084015282810360a084015261278f8188611aed565b905082810360c08401526127a38187611aed565b905082810360e08401526127b78186611aed565b9150506bffffffffffffffffffffffff83166101008301529a9950505050505050505050565b600063ffffffff8083168181036127f6576127f661229d565b6001019392505050565b6bffffffffffffffffffffffff8181168382160190808211156128255761282561229d565b5092915050565b600061010073ffffffffffffffffffffffffffffffffffffffff808c16845263ffffffff8b166020850152808a16604085015260ff891660608501528088166080850152508060a084015261288381840187611aed565b905082810360c08401526128978186611aed565b905082810360e08401526128ab8185611aed565b9b9a5050505050505050505050565b6000602082840312156128cc57600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff841681526bffffffffffffffffffffffff831660208201526060604082015260006129166060830184611aed565b9594505050505056fea164736f6c6343000813000a", } var AutomationRegistrarABI = AutomationRegistrarMetaData.ABI var AutomationRegistrarBin = AutomationRegistrarMetaData.Bin -func DeployAutomationRegistrar(auth *bind.TransactOpts, backend bind.ContractBackend, LINKAddress common.Address, AutomationRegistry common.Address, minLINKJuels *big.Int, triggerConfigs []AutomationRegistrar23InitialTriggerConfig) (common.Address, *types.Transaction, *AutomationRegistrar, error) { +func DeployAutomationRegistrar(auth *bind.TransactOpts, backend bind.ContractBackend, LINKAddress common.Address, registry common.Address, triggerConfigs []AutomationRegistrar23InitialTriggerConfig, billingTokens []common.Address, minRegistrationFees []*big.Int, wrappedNativeToken common.Address) (common.Address, *types.Transaction, *AutomationRegistrar, error) { parsed, err := AutomationRegistrarMetaData.GetAbi() if err != nil { return common.Address{}, nil, nil, err @@ -73,7 +74,7 @@ func DeployAutomationRegistrar(auth *bind.TransactOpts, backend bind.ContractBac return common.Address{}, nil, nil, errors.New("GetABI returned nil") } - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(AutomationRegistrarBin), backend, LINKAddress, AutomationRegistry, minLINKJuels, triggerConfigs) + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(AutomationRegistrarBin), backend, LINKAddress, registry, triggerConfigs, billingTokens, minRegistrationFees, wrappedNativeToken) if err != nil { return common.Address{}, nil, nil, err } @@ -196,28 +197,6 @@ func (_AutomationRegistrar *AutomationRegistrarTransactorRaw) Transact(opts *bin return _AutomationRegistrar.Contract.contract.Transact(opts, method, params...) } -func (_AutomationRegistrar *AutomationRegistrarCaller) LINK(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _AutomationRegistrar.contract.Call(opts, &out, "LINK") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -func (_AutomationRegistrar *AutomationRegistrarSession) LINK() (common.Address, error) { - return _AutomationRegistrar.Contract.LINK(&_AutomationRegistrar.CallOpts) -} - -func (_AutomationRegistrar *AutomationRegistrarCallerSession) LINK() (common.Address, error) { - return _AutomationRegistrar.Contract.LINK(&_AutomationRegistrar.CallOpts) -} - func (_AutomationRegistrar *AutomationRegistrarCaller) GetAutoApproveAllowedSender(opts *bind.CallOpts, senderAddress common.Address) (bool, error) { var out []interface{} err := _AutomationRegistrar.contract.Call(opts, &out, "getAutoApproveAllowedSender", senderAddress) @@ -240,34 +219,26 @@ func (_AutomationRegistrar *AutomationRegistrarCallerSession) GetAutoApproveAllo return _AutomationRegistrar.Contract.GetAutoApproveAllowedSender(&_AutomationRegistrar.CallOpts, senderAddress) } -func (_AutomationRegistrar *AutomationRegistrarCaller) GetConfig(opts *bind.CallOpts) (GetConfig, - - error) { +func (_AutomationRegistrar *AutomationRegistrarCaller) GetMinimumRegistrationAmount(opts *bind.CallOpts, billingToken common.Address) (*big.Int, error) { var out []interface{} - err := _AutomationRegistrar.contract.Call(opts, &out, "getConfig") + err := _AutomationRegistrar.contract.Call(opts, &out, "getMinimumRegistrationAmount", billingToken) - outstruct := new(GetConfig) if err != nil { - return *outstruct, err + return *new(*big.Int), err } - outstruct.AutomationRegistry = *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - outstruct.MinLINKJuels = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - return *outstruct, err + return out0, err } -func (_AutomationRegistrar *AutomationRegistrarSession) GetConfig() (GetConfig, - - error) { - return _AutomationRegistrar.Contract.GetConfig(&_AutomationRegistrar.CallOpts) +func (_AutomationRegistrar *AutomationRegistrarSession) GetMinimumRegistrationAmount(billingToken common.Address) (*big.Int, error) { + return _AutomationRegistrar.Contract.GetMinimumRegistrationAmount(&_AutomationRegistrar.CallOpts, billingToken) } -func (_AutomationRegistrar *AutomationRegistrarCallerSession) GetConfig() (GetConfig, - - error) { - return _AutomationRegistrar.Contract.GetConfig(&_AutomationRegistrar.CallOpts) +func (_AutomationRegistrar *AutomationRegistrarCallerSession) GetMinimumRegistrationAmount(billingToken common.Address) (*big.Int, error) { + return _AutomationRegistrar.Contract.GetMinimumRegistrationAmount(&_AutomationRegistrar.CallOpts, billingToken) } func (_AutomationRegistrar *AutomationRegistrarCaller) GetPendingRequest(opts *bind.CallOpts, hash [32]byte) (common.Address, *big.Int, error) { @@ -293,6 +264,28 @@ func (_AutomationRegistrar *AutomationRegistrarCallerSession) GetPendingRequest( return _AutomationRegistrar.Contract.GetPendingRequest(&_AutomationRegistrar.CallOpts, hash) } +func (_AutomationRegistrar *AutomationRegistrarCaller) GetRegistry(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistrar.contract.Call(opts, &out, "getRegistry") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_AutomationRegistrar *AutomationRegistrarSession) GetRegistry() (common.Address, error) { + return _AutomationRegistrar.Contract.GetRegistry(&_AutomationRegistrar.CallOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarCallerSession) GetRegistry() (common.Address, error) { + return _AutomationRegistrar.Contract.GetRegistry(&_AutomationRegistrar.CallOpts) +} + func (_AutomationRegistrar *AutomationRegistrarCaller) GetTriggerRegistrationDetails(opts *bind.CallOpts, triggerType uint8) (AutomationRegistrar23TriggerRegistrationStorage, error) { var out []interface{} err := _AutomationRegistrar.contract.Call(opts, &out, "getTriggerRegistrationDetails", triggerType) @@ -315,6 +308,50 @@ func (_AutomationRegistrar *AutomationRegistrarCallerSession) GetTriggerRegistra return _AutomationRegistrar.Contract.GetTriggerRegistrationDetails(&_AutomationRegistrar.CallOpts, triggerType) } +func (_AutomationRegistrar *AutomationRegistrarCaller) ILINK(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistrar.contract.Call(opts, &out, "i_LINK") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_AutomationRegistrar *AutomationRegistrarSession) ILINK() (common.Address, error) { + return _AutomationRegistrar.Contract.ILINK(&_AutomationRegistrar.CallOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarCallerSession) ILINK() (common.Address, error) { + return _AutomationRegistrar.Contract.ILINK(&_AutomationRegistrar.CallOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarCaller) IWRAPPEDNATIVETOKEN(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistrar.contract.Call(opts, &out, "i_WRAPPED_NATIVE_TOKEN") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_AutomationRegistrar *AutomationRegistrarSession) IWRAPPEDNATIVETOKEN() (common.Address, error) { + return _AutomationRegistrar.Contract.IWRAPPEDNATIVETOKEN(&_AutomationRegistrar.CallOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarCallerSession) IWRAPPEDNATIVETOKEN() (common.Address, error) { + return _AutomationRegistrar.Contract.IWRAPPEDNATIVETOKEN(&_AutomationRegistrar.CallOpts) +} + func (_AutomationRegistrar *AutomationRegistrarCaller) Owner(opts *bind.CallOpts) (common.Address, error) { var out []interface{} err := _AutomationRegistrar.contract.Call(opts, &out, "owner") @@ -371,16 +408,16 @@ func (_AutomationRegistrar *AutomationRegistrarTransactorSession) AcceptOwnershi return _AutomationRegistrar.Contract.AcceptOwnership(&_AutomationRegistrar.TransactOpts) } -func (_AutomationRegistrar *AutomationRegistrarTransactor) Approve(opts *bind.TransactOpts, name string, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, hash [32]byte) (*types.Transaction, error) { - return _AutomationRegistrar.contract.Transact(opts, "approve", name, upkeepContract, gasLimit, adminAddress, triggerType, checkData, triggerConfig, offchainConfig, hash) +func (_AutomationRegistrar *AutomationRegistrarTransactor) Approve(opts *bind.TransactOpts, requestParams AutomationRegistrar23RegistrationParams, hash [32]byte) (*types.Transaction, error) { + return _AutomationRegistrar.contract.Transact(opts, "approve", requestParams, hash) } -func (_AutomationRegistrar *AutomationRegistrarSession) Approve(name string, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, hash [32]byte) (*types.Transaction, error) { - return _AutomationRegistrar.Contract.Approve(&_AutomationRegistrar.TransactOpts, name, upkeepContract, gasLimit, adminAddress, triggerType, checkData, triggerConfig, offchainConfig, hash) +func (_AutomationRegistrar *AutomationRegistrarSession) Approve(requestParams AutomationRegistrar23RegistrationParams, hash [32]byte) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.Approve(&_AutomationRegistrar.TransactOpts, requestParams, hash) } -func (_AutomationRegistrar *AutomationRegistrarTransactorSession) Approve(name string, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, hash [32]byte) (*types.Transaction, error) { - return _AutomationRegistrar.Contract.Approve(&_AutomationRegistrar.TransactOpts, name, upkeepContract, gasLimit, adminAddress, triggerType, checkData, triggerConfig, offchainConfig, hash) +func (_AutomationRegistrar *AutomationRegistrarTransactorSession) Approve(requestParams AutomationRegistrar23RegistrationParams, hash [32]byte) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.Approve(&_AutomationRegistrar.TransactOpts, requestParams, hash) } func (_AutomationRegistrar *AutomationRegistrarTransactor) Cancel(opts *bind.TransactOpts, hash [32]byte) (*types.Transaction, error) { @@ -407,18 +444,6 @@ func (_AutomationRegistrar *AutomationRegistrarTransactorSession) OnTokenTransfe return _AutomationRegistrar.Contract.OnTokenTransfer(&_AutomationRegistrar.TransactOpts, sender, amount, data) } -func (_AutomationRegistrar *AutomationRegistrarTransactor) Register(opts *bind.TransactOpts, name string, encryptedEmail []byte, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, amount *big.Int, sender common.Address) (*types.Transaction, error) { - return _AutomationRegistrar.contract.Transact(opts, "register", name, encryptedEmail, upkeepContract, gasLimit, adminAddress, triggerType, checkData, triggerConfig, offchainConfig, amount, sender) -} - -func (_AutomationRegistrar *AutomationRegistrarSession) Register(name string, encryptedEmail []byte, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, amount *big.Int, sender common.Address) (*types.Transaction, error) { - return _AutomationRegistrar.Contract.Register(&_AutomationRegistrar.TransactOpts, name, encryptedEmail, upkeepContract, gasLimit, adminAddress, triggerType, checkData, triggerConfig, offchainConfig, amount, sender) -} - -func (_AutomationRegistrar *AutomationRegistrarTransactorSession) Register(name string, encryptedEmail []byte, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, amount *big.Int, sender common.Address) (*types.Transaction, error) { - return _AutomationRegistrar.Contract.Register(&_AutomationRegistrar.TransactOpts, name, encryptedEmail, upkeepContract, gasLimit, adminAddress, triggerType, checkData, triggerConfig, offchainConfig, amount, sender) -} - func (_AutomationRegistrar *AutomationRegistrarTransactor) RegisterUpkeep(opts *bind.TransactOpts, requestParams AutomationRegistrar23RegistrationParams) (*types.Transaction, error) { return _AutomationRegistrar.contract.Transact(opts, "registerUpkeep", requestParams) } @@ -443,16 +468,16 @@ func (_AutomationRegistrar *AutomationRegistrarTransactorSession) SetAutoApprove return _AutomationRegistrar.Contract.SetAutoApproveAllowedSender(&_AutomationRegistrar.TransactOpts, senderAddress, allowed) } -func (_AutomationRegistrar *AutomationRegistrarTransactor) SetConfig(opts *bind.TransactOpts, AutomationRegistry common.Address, minLINKJuels *big.Int) (*types.Transaction, error) { - return _AutomationRegistrar.contract.Transact(opts, "setConfig", AutomationRegistry, minLINKJuels) +func (_AutomationRegistrar *AutomationRegistrarTransactor) SetConfig(opts *bind.TransactOpts, registry common.Address, billingTokens []common.Address, minBalances []*big.Int) (*types.Transaction, error) { + return _AutomationRegistrar.contract.Transact(opts, "setConfig", registry, billingTokens, minBalances) } -func (_AutomationRegistrar *AutomationRegistrarSession) SetConfig(AutomationRegistry common.Address, minLINKJuels *big.Int) (*types.Transaction, error) { - return _AutomationRegistrar.Contract.SetConfig(&_AutomationRegistrar.TransactOpts, AutomationRegistry, minLINKJuels) +func (_AutomationRegistrar *AutomationRegistrarSession) SetConfig(registry common.Address, billingTokens []common.Address, minBalances []*big.Int) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.SetConfig(&_AutomationRegistrar.TransactOpts, registry, billingTokens, minBalances) } -func (_AutomationRegistrar *AutomationRegistrarTransactorSession) SetConfig(AutomationRegistry common.Address, minLINKJuels *big.Int) (*types.Transaction, error) { - return _AutomationRegistrar.Contract.SetConfig(&_AutomationRegistrar.TransactOpts, AutomationRegistry, minLINKJuels) +func (_AutomationRegistrar *AutomationRegistrarTransactorSession) SetConfig(registry common.Address, billingTokens []common.Address, minBalances []*big.Int) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.SetConfig(&_AutomationRegistrar.TransactOpts, registry, billingTokens, minBalances) } func (_AutomationRegistrar *AutomationRegistrarTransactor) SetTriggerConfig(opts *bind.TransactOpts, triggerType uint8, autoApproveType uint8, autoApproveMaxAllowed uint32) (*types.Transaction, error) { @@ -668,9 +693,7 @@ func (it *AutomationRegistrarConfigChangedIterator) Close() error { } type AutomationRegistrarConfigChanged struct { - AutomationRegistry common.Address - MinLINKJuels *big.Int - Raw types.Log + Raw types.Log } func (_AutomationRegistrar *AutomationRegistrarFilterer) FilterConfigChanged(opts *bind.FilterOpts) (*AutomationRegistrarConfigChangedIterator, error) { @@ -1529,11 +1552,6 @@ func (_AutomationRegistrar *AutomationRegistrarFilterer) ParseTriggerConfigSet(l return event, nil } -type GetConfig struct { - AutomationRegistry common.Address - MinLINKJuels *big.Int -} - func (_AutomationRegistrar *AutomationRegistrar) ParseLog(log types.Log) (generated.AbigenLog, error) { switch log.Topics[0] { case _AutomationRegistrar.abi.Events["AutoApproveAllowedSenderSet"].ID: @@ -1563,7 +1581,7 @@ func (AutomationRegistrarAutoApproveAllowedSenderSet) Topic() common.Hash { } func (AutomationRegistrarConfigChanged) Topic() common.Hash { - return common.HexToHash("0x39ce5d867555f0b0183e358fce5b158e7ca4fecd7c01cb7e0e19f1e23285838a") + return common.HexToHash("0xb9b6902016bd1219d5fa6161243b61e7e9f7f959526dd94ef8fa3e403bf881c3") } func (AutomationRegistrarOwnershipTransferRequested) Topic() common.Hash { @@ -1595,37 +1613,37 @@ func (_AutomationRegistrar *AutomationRegistrar) Address() common.Address { } type AutomationRegistrarInterface interface { - LINK(opts *bind.CallOpts) (common.Address, error) - GetAutoApproveAllowedSender(opts *bind.CallOpts, senderAddress common.Address) (bool, error) - GetConfig(opts *bind.CallOpts) (GetConfig, - - error) + GetMinimumRegistrationAmount(opts *bind.CallOpts, billingToken common.Address) (*big.Int, error) GetPendingRequest(opts *bind.CallOpts, hash [32]byte) (common.Address, *big.Int, error) + GetRegistry(opts *bind.CallOpts) (common.Address, error) + GetTriggerRegistrationDetails(opts *bind.CallOpts, triggerType uint8) (AutomationRegistrar23TriggerRegistrationStorage, error) + ILINK(opts *bind.CallOpts) (common.Address, error) + + IWRAPPEDNATIVETOKEN(opts *bind.CallOpts) (common.Address, error) + Owner(opts *bind.CallOpts) (common.Address, error) TypeAndVersion(opts *bind.CallOpts) (string, error) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) - Approve(opts *bind.TransactOpts, name string, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, hash [32]byte) (*types.Transaction, error) + Approve(opts *bind.TransactOpts, requestParams AutomationRegistrar23RegistrationParams, hash [32]byte) (*types.Transaction, error) Cancel(opts *bind.TransactOpts, hash [32]byte) (*types.Transaction, error) OnTokenTransfer(opts *bind.TransactOpts, sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) - Register(opts *bind.TransactOpts, name string, encryptedEmail []byte, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, amount *big.Int, sender common.Address) (*types.Transaction, error) - RegisterUpkeep(opts *bind.TransactOpts, requestParams AutomationRegistrar23RegistrationParams) (*types.Transaction, error) SetAutoApproveAllowedSender(opts *bind.TransactOpts, senderAddress common.Address, allowed bool) (*types.Transaction, error) - SetConfig(opts *bind.TransactOpts, AutomationRegistry common.Address, minLINKJuels *big.Int) (*types.Transaction, error) + SetConfig(opts *bind.TransactOpts, registry common.Address, billingTokens []common.Address, minBalances []*big.Int) (*types.Transaction, error) SetTriggerConfig(opts *bind.TransactOpts, triggerType uint8, autoApproveType uint8, autoApproveMaxAllowed uint32) (*types.Transaction, error) diff --git a/core/gethwrappers/generated/automation_registry_logic_a_wrapper_2_2/automation_registry_logic_a_wrapper_2_2.go b/core/gethwrappers/generated/automation_registry_logic_a_wrapper_2_2/automation_registry_logic_a_wrapper_2_2.go index 4496ee2ab23..60b720b6ea6 100644 --- a/core/gethwrappers/generated/automation_registry_logic_a_wrapper_2_2/automation_registry_logic_a_wrapper_2_2.go +++ b/core/gethwrappers/generated/automation_registry_logic_a_wrapper_2_2/automation_registry_logic_a_wrapper_2_2.go @@ -31,8 +31,8 @@ var ( ) var AutomationRegistryLogicAMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistryLogicB2_2\",\"name\":\"logicB\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxCheckDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxPerformDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentGreaterThanAllLINK\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newModule\",\"type\":\"address\"}],\"name\":\"ChainSpecificModuleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"OwnerFundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"cancelUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_2.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_2.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkNative\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_2.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkNative\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"executeCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_2.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"migrateUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedUpkeeps\",\"type\":\"bytes\"}],\"name\":\"receiveUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"enumAutomationRegistryBase2_2.Trigger\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"setUpkeepTriggerConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x6101406040523480156200001257600080fd5b5060405162005f1538038062005f158339810160408190526200003591620003b1565b80816001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b9190620003b1565b826001600160a01b031663b10b673c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001009190620003b1565b836001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001659190620003b1565b846001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca9190620003b1565b856001600160a01b031663a08714c06040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f9190620003b1565b3380600081620002865760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620002b957620002b981620002ed565b5050506001600160a01b0394851660805292841660a05290831660c052821660e052811661010052166101205250620003d8565b336001600160a01b03821603620003475760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200027d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b0381168114620003ae57600080fd5b50565b600060208284031215620003c457600080fd5b8151620003d18162000398565b9392505050565b60805160a05160c05160e0516101005161012051615ad86200043d6000396000818161010e01526101a9015260006131540152600081816103e10152611ffe0152600061333d01526000613421015260008181611e40015261240c0152615ad86000f3fe60806040523480156200001157600080fd5b50600436106200010c5760003560e01c806385c1b0ba11620000a5578063c8048022116200006f578063c804802214620002b7578063ce7dc5b414620002ce578063f2fde38b14620002e5578063f7d334ba14620002fc576200010c565b806385c1b0ba14620002535780638da5cb5b146200026a5780638e86139b1462000289578063948108f714620002a0576200010c565b80634ee88d3511620000e75780634ee88d3514620001ef5780636ded9eae146200020657806371791aa0146200021d57806379ba50971462000249576200010c565b806328f32f38146200015457806329c5efad146200017e578063349e8cca14620001a7575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e8080156200014d573d6000f35b3d6000fd5b005b6200016b6200016536600462004073565b62000313565b6040519081526020015b60405180910390f35b620001956200018f36600462004159565b6200068d565b60405162000175949392919062004281565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200162000175565b6200015262000200366004620042be565b62000931565b6200016b620002173660046200430e565b62000999565b620002346200022e36600462004159565b620009ff565b604051620001759796959493929190620043c1565b620001526200114d565b620001526200026436600462004413565b62001250565b60005473ffffffffffffffffffffffffffffffffffffffff16620001c9565b620001526200029a366004620044a0565b62001ec1565b62000152620002b136600462004503565b62002249565b62000152620002c836600462004532565b620024dc565b62000195620002df36600462004608565b62002955565b62000152620002f63660046200467f565b62002a1b565b620002346200030d36600462004532565b62002a33565b6000805473ffffffffffffffffffffffffffffffffffffffff1633148015906200034757506200034560093362002a71565b155b156200037f576040517fd48b678b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff89163b620003ce576040517f09ee12d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b620003d98662002aa5565b9050600089307f00000000000000000000000000000000000000000000000000000000000000006040516200040e9062003dff565b73ffffffffffffffffffffffffffffffffffffffff938416815291831660208301529091166040820152606001604051809103906000f08015801562000458573d6000803e3d6000fd5b5090506200051f826040518060e001604052806000151581526020018c63ffffffff16815260200163ffffffff801681526020018473ffffffffffffffffffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff168152602001600063ffffffff168152508a89898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508b92508a915062002d519050565b6015805474010000000000000000000000000000000000000000900463ffffffff169060146200054f83620046ce565b91906101000a81548163ffffffff021916908363ffffffff16021790555050817fbae366358c023f887e791d7a62f2e4316f1026bd77f6fb49501a917b3bc5d0128a8a604051620005c892919063ffffffff92909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a2817fcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d8787604051620006049291906200473d565b60405180910390a2817f2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d5664856040516200063e919062004753565b60405180910390a2817f3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf48508460405162000678919062004753565b60405180910390a25098975050505050505050565b600060606000806200069e6200313c565b600086815260046020908152604091829020825160e081018452815460ff811615158252610100810463ffffffff90811694830194909452650100000000008104841694820194909452690100000000000000000090930473ffffffffffffffffffffffffffffffffffffffff166060840152600101546bffffffffffffffffffffffff80821660808501526c0100000000000000000000000082041660a0840152780100000000000000000000000000000000000000000000000090041660c08201525a9150600080826060015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620007b8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620007de919062004775565b73ffffffffffffffffffffffffffffffffffffffff166014600101600c9054906101000a900463ffffffff1663ffffffff168960405162000820919062004795565b60006040518083038160008787f1925050503d806000811462000860576040519150601f19603f3d011682016040523d82523d6000602084013e62000865565b606091505b50915091505a620008779085620047b3565b935081620008a257600060405180602001604052806000815250600796509650965050505062000928565b80806020019051810190620008b8919062004824565b909750955086620008e657600060405180602001604052806000815250600496509650965050505062000928565b601654865164010000000090910463ffffffff1610156200092457600060405180602001604052806000815250600596509650965050505062000928565b5050505b92959194509250565b6200093c83620031ae565b6000838152601b602052604090206200095782848362004919565b50827f2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d566483836040516200098c9291906200473d565b60405180910390a2505050565b6000620009f388888860008989604051806020016040528060008152508a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506200031392505050565b98975050505050505050565b60006060600080600080600062000a156200313c565b600062000a228a62003264565b905060006012604051806101600160405290816000820160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160008201600c9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160109054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160149054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160189054906101000a900462ffffff1662ffffff1662ffffff16815260200160008201601b9054906101000a900461ffff1661ffff1661ffff16815260200160008201601d9054906101000a900460ff1660ff1660ff16815260200160008201601e9054906101000a900460ff1615151515815260200160008201601f9054906101000a900460ff161515151581526020016001820160009054906101000a900460ff161515151581526020016001820160019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505090506000600460008d81526020019081526020016000206040518060e00160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160059054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160099054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160018201600c9054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff1681526020016001820160189054906101000a900463ffffffff1663ffffffff1663ffffffff168152505090508160e001511562000db7576000604051806020016040528060008152506009600084602001516000808263ffffffff169250995099509950995099509950995050505062001141565b604081015163ffffffff9081161462000e08576000604051806020016040528060008152506001600084602001516000808263ffffffff169250995099509950995099509950995050505062001141565b80511562000e4e576000604051806020016040528060008152506002600084602001516000808263ffffffff169250995099509950995099509950995050505062001141565b62000e59826200331a565b8095508196505050600062000e768385846020015189896200350c565b9050806bffffffffffffffffffffffff168260a001516bffffffffffffffffffffffff16101562000ee0576000604051806020016040528060008152506006600085602001516000808263ffffffff1692509a509a509a509a509a509a509a505050505062001141565b600062000eef8e868f620037c1565b90505a9850600080846060015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000f47573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000f6d919062004775565b73ffffffffffffffffffffffffffffffffffffffff166014600101600c9054906101000a900463ffffffff1663ffffffff168460405162000faf919062004795565b60006040518083038160008787f1925050503d806000811462000fef576040519150601f19603f3d011682016040523d82523d6000602084013e62000ff4565b606091505b50915091505a62001006908c620047b3565b9a5081620010865760165481516801000000000000000090910463ffffffff1610156200106357505060408051602080820190925260008082529490910151939c509a50600899505063ffffffff90911695506200114192505050565b602090940151939b5060039a505063ffffffff9092169650620011419350505050565b808060200190518101906200109c919062004824565b909e509c508d620010dd57505060408051602080820190925260008082529490910151939c509a50600499505063ffffffff90911695506200114192505050565b6016548d5164010000000090910463ffffffff1610156200112e57505060408051602080820190925260008082529490910151939c509a50600599505063ffffffff90911695506200114192505050565b505050506020015163ffffffff16945050505b92959891949750929550565b60015473ffffffffffffffffffffffffffffffffffffffff163314620011d4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600173ffffffffffffffffffffffffffffffffffffffff82166000908152601a602052604090205460ff1660038111156200128f576200128f62004216565b14158015620012db5750600373ffffffffffffffffffffffffffffffffffffffff82166000908152601a602052604090205460ff166003811115620012d857620012d862004216565b14155b1562001313576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6014546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1662001373576040517fd12d7d8d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000829003620013af576040517f2c2fc94100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081018290526000808567ffffffffffffffff81111562001406576200140662003efa565b60405190808252806020026020018201604052801562001430578160200160208202803683370190505b50905060008667ffffffffffffffff81111562001451576200145162003efa565b604051908082528060200260200182016040528015620014d857816020015b6040805160e08101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181620014705790505b50905060008767ffffffffffffffff811115620014f957620014f962003efa565b6040519080825280602002602001820160405280156200152e57816020015b6060815260200190600190039081620015185790505b50905060008867ffffffffffffffff8111156200154f576200154f62003efa565b6040519080825280602002602001820160405280156200158457816020015b60608152602001906001900390816200156e5790505b50905060008967ffffffffffffffff811115620015a557620015a562003efa565b604051908082528060200260200182016040528015620015da57816020015b6060815260200190600190039081620015c45790505b50905060005b8a81101562001bbe578b8b82818110620015fe57620015fe62004a41565b60209081029290920135600081815260048452604090819020815160e081018352815460ff811615158252610100810463ffffffff90811697830197909752650100000000008104871693820193909352690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff166060830152600101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490931660c08401529a50909850620016dd905089620031ae565b60608801516040517f1a5da6c800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8c8116600483015290911690631a5da6c890602401600060405180830381600087803b1580156200174d57600080fd5b505af115801562001762573d6000803e3d6000fd5b50505050878582815181106200177c576200177c62004a41565b6020026020010181905250600560008a815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16868281518110620017d057620017d062004a41565b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910182015260008a815260079091526040902080546200180f9062004871565b80601f01602080910402602001604051908101604052809291908181526020018280546200183d9062004871565b80156200188e5780601f1062001862576101008083540402835291602001916200188e565b820191906000526020600020905b8154815290600101906020018083116200187057829003601f168201915b5050505050848281518110620018a857620018a862004a41565b6020026020010181905250601b60008a81526020019081526020016000208054620018d39062004871565b80601f0160208091040260200160405190810160405280929190818152602001828054620019019062004871565b8015620019525780601f10620019265761010080835404028352916020019162001952565b820191906000526020600020905b8154815290600101906020018083116200193457829003601f168201915b50505050508382815181106200196c576200196c62004a41565b6020026020010181905250601c60008a81526020019081526020016000208054620019979062004871565b80601f0160208091040260200160405190810160405280929190818152602001828054620019c59062004871565b801562001a165780601f10620019ea5761010080835404028352916020019162001a16565b820191906000526020600020905b815481529060010190602001808311620019f857829003601f168201915b505050505082828151811062001a305762001a3062004a41565b60200260200101819052508760a001516bffffffffffffffffffffffff168762001a5b919062004a70565b60008a815260046020908152604080832080547fffffff000000000000000000000000000000000000000000000000000000000016815560010180547fffffffff000000000000000000000000000000000000000000000000000000001690556007909152812091985062001ad1919062003e0d565b6000898152601b6020526040812062001aea9162003e0d565b6000898152601c6020526040812062001b039162003e0d565b600089815260066020526040902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905562001b4460028a620039b1565b5060a0880151604080516bffffffffffffffffffffffff909216825273ffffffffffffffffffffffffffffffffffffffff8c1660208301528a917fb38647142fbb1ea4c000fc4569b37a4e9a9f6313317b84ee3e5326c1a6cd06ff910160405180910390a28062001bb58162004a86565b915050620015e0565b508560195462001bcf9190620047b3565b60195560008b8b868167ffffffffffffffff81111562001bf35762001bf362003efa565b60405190808252806020026020018201604052801562001c1d578160200160208202803683370190505b508988888860405160200162001c3b98979695949392919062004c4d565b60405160208183030381529060405290508973ffffffffffffffffffffffffffffffffffffffff16638e86139b6014600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c71249ab60038e73ffffffffffffffffffffffffffffffffffffffff1663aab9edd66040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001cf7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001d1d919062004d2c565b866040518463ffffffff1660e01b815260040162001d3e9392919062004d51565b600060405180830381865afa15801562001d5c573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405262001da4919081019062004d78565b6040518263ffffffff1660e01b815260040162001dc2919062004753565b600060405180830381600087803b15801562001ddd57600080fd5b505af115801562001df2573d6000803e3d6000fd5b50506040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8d81166004830152602482018b90527f000000000000000000000000000000000000000000000000000000000000000016925063a9059cbb91506044016020604051808303816000875af115801562001e8c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001eb2919062004db1565b50505050505050505050505050565b6002336000908152601a602052604090205460ff16600381111562001eea5762001eea62004216565b1415801562001f2057506003336000908152601a602052604090205460ff16600381111562001f1d5762001f1d62004216565b14155b1562001f58576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080808080808062001f6e888a018a62004f9c565b965096509650965096509650965060005b87518110156200223d57600073ffffffffffffffffffffffffffffffffffffffff1687828151811062001fb65762001fb662004a41565b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff1603620020ca5785818151811062001ff35762001ff362004a41565b6020026020010151307f00000000000000000000000000000000000000000000000000000000000000006040516200202b9062003dff565b73ffffffffffffffffffffffffffffffffffffffff938416815291831660208301529091166040820152606001604051809103906000f08015801562002075573d6000803e3d6000fd5b508782815181106200208b576200208b62004a41565b60200260200101516060019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250505b62002182888281518110620020e357620020e362004a41565b602002602001015188838151811062002100576200210062004a41565b60200260200101518784815181106200211d576200211d62004a41565b60200260200101518785815181106200213a576200213a62004a41565b602002602001015187868151811062002157576200215762004a41565b602002602001015187878151811062002174576200217462004a41565b602002602001015162002d51565b87818151811062002197576200219762004a41565b60200260200101517f74931a144e43a50694897f241d973aecb5024c0e910f9bb80a163ea3c1cf5a71888381518110620021d557620021d562004a41565b602002602001015160a0015133604051620022209291906bffffffffffffffffffffffff92909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a280620022348162004a86565b91505062001f7f565b50505050505050505050565b600082815260046020908152604091829020825160e081018452815460ff81161515825263ffffffff6101008204811694830194909452650100000000008104841694820185905273ffffffffffffffffffffffffffffffffffffffff69010000000000000000009091041660608201526001909101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a083015278010000000000000000000000000000000000000000000000009004821660c0820152911462002347576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818160a00151620023599190620050cd565b600084815260046020526040902060010180547fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff166c010000000000000000000000006bffffffffffffffffffffffff93841602179055601954620023c19184169062004a70565b6019556040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526bffffffffffffffffffffffff831660448201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906323b872dd906064016020604051808303816000875af11580156200246b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002491919062004db1565b506040516bffffffffffffffffffffffff83168152339084907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a3505050565b6000818152600460209081526040808320815160e081018352815460ff81161515825263ffffffff610100820481169583019590955265010000000000810485169382019390935273ffffffffffffffffffffffffffffffffffffffff6901000000000000000000909304929092166060830152600101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490911660c082015290620025c460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161490506000601260010160019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa15801562002667573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200268d9190620050f5565b9050826040015163ffffffff16600003620026d4576040517ffbc0357800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604083015163ffffffff9081161462002719576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b811580156200274c575060008481526005602052604090205473ffffffffffffffffffffffffffffffffffffffff163314155b1562002784576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816200279a576200279760328262004a70565b90505b6000848152600460205260409020805463ffffffff80841665010000000000027fffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffff90921691909117909155620027f6906002908690620039b116565b5060145460808401516bffffffffffffffffffffffff91821691600091168211156200285f5760808501516200282d90836200510f565b90508460a001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff1611156200285f575060a08401515b808560a001516200287191906200510f565b600087815260046020526040902060010180547fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff166c010000000000000000000000006bffffffffffffffffffffffff93841602179055601554620028d991839116620050cd565b601580547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff9290921691909117905560405167ffffffffffffffff84169087907f91cb3bb75cfbd718bbfccc56b7f53d92d7048ef4ca39a3b7b7c6d4af1f79118190600090a3505050505050565b600060606000806000634b56a42e60e01b8888886040516024016200297d9392919062005137565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152905062002a0889826200068d565b929c919b50995090975095505050505050565b62002a25620039bf565b62002a308162003a42565b50565b60006060600080600080600062002a5a8860405180602001604052806000815250620009ff565b959e949d50929b5090995097509550909350915050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260018301602052604081205415155b90505b92915050565b6000806000601260010160019054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060008173ffffffffffffffffffffffffffffffffffffffff166385df51fd60018473ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa15801562002b3e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002b649190620050f5565b62002b709190620047b3565b6040518263ffffffff1660e01b815260040162002b8f91815260200190565b602060405180830381865afa15801562002bad573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002bd39190620050f5565b601554604080516020810193909352309083015274010000000000000000000000000000000000000000900463ffffffff166060820152608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201209083015201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060045b600f81101562002cdf578382828151811062002c9b5762002c9b62004a41565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508062002cd68162004a86565b91505062002c7b565b5084600181111562002cf55762002cf562004216565b60f81b81600f8151811062002d0e5762002d0e62004a41565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535062002d48816200516b565b95945050505050565b6012547e01000000000000000000000000000000000000000000000000000000000000900460ff161562002db1576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601654835163ffffffff909116101562002df7576040517fae7235df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108fc856020015163ffffffff16108062002e355750601554602086015163ffffffff70010000000000000000000000000000000090920482169116115b1562002e6d576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000868152600460205260409020546901000000000000000000900473ffffffffffffffffffffffffffffffffffffffff161562002ed7576040517f6e3b930b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000868152600460209081526040808320885181548a8501518b85015160608d01517fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000009093169315157fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff169390931761010063ffffffff92831602177fffffff000000000000000000000000000000000000000000000000ffffffffff1665010000000000938216939093027fffffff0000000000000000000000000000000000000000ffffffffffffffffff1692909217690100000000000000000073ffffffffffffffffffffffffffffffffffffffff9283160217835560808b01516001909301805460a08d015160c08e01516bffffffffffffffffffffffff9687167fffffffffffffffff000000000000000000000000000000000000000000000000909316929092176c010000000000000000000000009690911695909502949094177fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff1678010000000000000000000000000000000000000000000000009490931693909302919091179091556005835281842080547fffffffffffffffffffffffff00000000000000000000000000000000000000001691891691909117905560079091529020620030ca8482620051ae565b508460a001516bffffffffffffffffffffffff16601954620030ed919062004a70565b6019556000868152601b602052604090206200310a8382620051ae565b506000868152601c60205260409020620031258282620051ae565b506200313360028762003b39565b50505050505050565b3273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614620031ac576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60008181526005602052604090205473ffffffffffffffffffffffffffffffffffffffff1633146200320c576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526004602052604090205465010000000000900463ffffffff9081161462002a30576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818160045b600f811015620032f9577fff000000000000000000000000000000000000000000000000000000000000008216838260208110620032ad57620032ad62004a41565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614620032e457506000949350505050565b80620032f08162004a86565b9150506200326b565b5081600f1a600181111562003312576200331262004216565b949350505050565b6000806000836080015162ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015620033a7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620033cd9190620052f0565b5094509092505050600081131580620033e557508142105b806200340a57508280156200340a5750620034018242620047b3565b8463ffffffff16105b156200341b5760175495506200341f565b8095505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156200348b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620034b19190620052f0565b5094509092505050600081131580620034c957508142105b80620034ee5750828015620034ee5750620034e58242620047b3565b8463ffffffff16105b15620034ff57601854945062003503565b8094505b50505050915091565b6000808086600181111562003525576200352562004216565b0362003535575061ea606200358f565b60018660018111156200354c576200354c62004216565b036200355d575062014c086200358f565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008760c001516001620035a4919062005345565b620035b49060ff16604062005361565b601654620035d4906103a490640100000000900463ffffffff1662004a70565b620035e0919062004a70565b601354604080517fde9ee35e00000000000000000000000000000000000000000000000000000000815281519394506000938493610100900473ffffffffffffffffffffffffffffffffffffffff169263de9ee35e92600480820193918290030181865afa15801562003657573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200367d91906200537b565b909250905081836200369183601862004a70565b6200369d919062005361565b60c08c0151620036af90600162005345565b620036c09060ff166115e062005361565b620036cc919062004a70565b620036d8919062004a70565b620036e4908562004a70565b935060008a610140015173ffffffffffffffffffffffffffffffffffffffff166312544140856040518263ffffffff1660e01b81526004016200372991815260200190565b602060405180830381865afa15801562003747573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200376d9190620050f5565b8b60a0015161ffff1662003782919062005361565b90506000806200379f8d8c63ffffffff1689868e8e600062003b47565b9092509050620037b08183620050cd565b9d9c50505050505050505050505050565b60606000836001811115620037da57620037da62004216565b03620038a7576000848152600760205260409081902090517f6e04ff0d0000000000000000000000000000000000000000000000000000000091620038229160240162005443565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050620039aa565b6001836001811115620038be57620038be62004216565b036200355d57600082806020019051810190620038dc9190620054ba565b6000868152600760205260409081902090519192507f40691db4000000000000000000000000000000000000000000000000000000009162003923918491602401620055ce565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529150620039aa9050565b9392505050565b600062002a9c838362003ca2565b60005473ffffffffffffffffffffffffffffffffffffffff163314620031ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401620011cb565b3373ffffffffffffffffffffffffffffffffffffffff82160362003ac3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620011cb565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600062002a9c838362003dad565b60008060008960a0015161ffff168662003b62919062005361565b905083801562003b715750803a105b1562003b7a57503a5b6000858862003b8a8b8d62004a70565b62003b96908562005361565b62003ba2919062004a70565b62003bb690670de0b6b3a764000062005361565b62003bc2919062005696565b905060008b6040015163ffffffff1664e8d4a5100062003be3919062005361565b60208d0151889063ffffffff168b62003bfd8f8862005361565b62003c09919062004a70565b62003c1990633b9aca0062005361565b62003c25919062005361565b62003c31919062005696565b62003c3d919062004a70565b90506b033b2e3c9fd0803ce800000062003c58828462004a70565b111562003c91576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b909b909a5098505050505050505050565b6000818152600183016020526040812054801562003d9b57600062003cc9600183620047b3565b855490915060009062003cdf90600190620047b3565b905081811462003d4b57600086600001828154811062003d035762003d0362004a41565b906000526020600020015490508087600001848154811062003d295762003d2962004a41565b6000918252602080832090910192909255918252600188019052604090208390555b855486908062003d5f5762003d5f620056d2565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505062002a9f565b600091505062002a9f565b5092915050565b600081815260018301602052604081205462003df65750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562002a9f565b50600062002a9f565b6103ca806200570283390190565b50805462003e1b9062004871565b6000825580601f1062003e2c575050565b601f01602090049060005260206000209081019062002a3091905b8082111562003e5d576000815560010162003e47565b5090565b73ffffffffffffffffffffffffffffffffffffffff8116811462002a3057600080fd5b803563ffffffff8116811462003e9957600080fd5b919050565b80356002811062003e9957600080fd5b60008083601f84011262003ec157600080fd5b50813567ffffffffffffffff81111562003eda57600080fd5b60208301915083602082850101111562003ef357600080fd5b9250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160e0810167ffffffffffffffff8111828210171562003f4f5762003f4f62003efa565b60405290565b604051610100810167ffffffffffffffff8111828210171562003f4f5762003f4f62003efa565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171562003fc65762003fc662003efa565b604052919050565b600067ffffffffffffffff82111562003feb5762003feb62003efa565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f8301126200402957600080fd5b8135620040406200403a8262003fce565b62003f7c565b8181528460208386010111156200405657600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060008060e0898b0312156200409057600080fd5b88356200409d8162003e61565b9750620040ad60208a0162003e84565b96506040890135620040bf8162003e61565b9550620040cf60608a0162003e9e565b9450608089013567ffffffffffffffff80821115620040ed57600080fd5b620040fb8c838d0162003eae565b909650945060a08b01359150808211156200411557600080fd5b620041238c838d0162004017565b935060c08b01359150808211156200413a57600080fd5b50620041498b828c0162004017565b9150509295985092959890939650565b600080604083850312156200416d57600080fd5b82359150602083013567ffffffffffffffff8111156200418c57600080fd5b6200419a8582860162004017565b9150509250929050565b60005b83811015620041c1578181015183820152602001620041a7565b50506000910152565b60008151808452620041e4816020860160208601620041a4565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600a81106200427d577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b84151581526080602082015260006200429e6080830186620041ca565b9050620042af604083018562004245565b82606083015295945050505050565b600080600060408486031215620042d457600080fd5b83359250602084013567ffffffffffffffff811115620042f357600080fd5b620043018682870162003eae565b9497909650939450505050565b600080600080600080600060a0888a0312156200432a57600080fd5b8735620043378162003e61565b9650620043476020890162003e84565b95506040880135620043598162003e61565b9450606088013567ffffffffffffffff808211156200437757600080fd5b620043858b838c0162003eae565b909650945060808a01359150808211156200439f57600080fd5b50620043ae8a828b0162003eae565b989b979a50959850939692959293505050565b871515815260e060208201526000620043de60e0830189620041ca565b9050620043ef604083018862004245565b8560608301528460808301528360a08301528260c083015298975050505050505050565b6000806000604084860312156200442957600080fd5b833567ffffffffffffffff808211156200444257600080fd5b818601915086601f8301126200445757600080fd5b8135818111156200446757600080fd5b8760208260051b85010111156200447d57600080fd5b60209283019550935050840135620044958162003e61565b809150509250925092565b60008060208385031215620044b457600080fd5b823567ffffffffffffffff811115620044cc57600080fd5b620044da8582860162003eae565b90969095509350505050565b80356bffffffffffffffffffffffff8116811462003e9957600080fd5b600080604083850312156200451757600080fd5b823591506200452960208401620044e6565b90509250929050565b6000602082840312156200454557600080fd5b5035919050565b600067ffffffffffffffff82111562004569576200456962003efa565b5060051b60200190565b600082601f8301126200458557600080fd5b81356020620045986200403a836200454c565b82815260059290921b84018101918181019086841115620045b857600080fd5b8286015b84811015620045fd57803567ffffffffffffffff811115620045de5760008081fd5b620045ee8986838b010162004017565b845250918301918301620045bc565b509695505050505050565b600080600080606085870312156200461f57600080fd5b84359350602085013567ffffffffffffffff808211156200463f57600080fd5b6200464d8883890162004573565b945060408701359150808211156200466457600080fd5b50620046738782880162003eae565b95989497509550505050565b6000602082840312156200469257600080fd5b8135620039aa8162003e61565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff808316818103620046ea57620046ea6200469f565b6001019392505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60208152600062003312602083018486620046f4565b60208152600062002a9c6020830184620041ca565b805162003e998162003e61565b6000602082840312156200478857600080fd5b8151620039aa8162003e61565b60008251620047a9818460208701620041a4565b9190910192915050565b8181038181111562002a9f5762002a9f6200469f565b801515811462002a3057600080fd5b600082601f830112620047ea57600080fd5b8151620047fb6200403a8262003fce565b8181528460208386010111156200481157600080fd5b62003312826020830160208701620041a4565b600080604083850312156200483857600080fd5b82516200484581620047c9565b602084015190925067ffffffffffffffff8111156200486357600080fd5b6200419a85828601620047d8565b600181811c908216806200488657607f821691505b602082108103620048c0577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156200491457600081815260208120601f850160051c81016020861015620048ef5750805b601f850160051c820191505b818110156200491057828155600101620048fb565b5050505b505050565b67ffffffffffffffff83111562004934576200493462003efa565b6200494c8362004945835462004871565b83620048c6565b6000601f841160018114620049a157600085156200496a5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b17835562004a3a565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b82811015620049f25786850135825560209485019460019092019101620049d0565b508682101562004a2e577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8082018082111562002a9f5762002a9f6200469f565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820362004aba5762004aba6200469f565b5060010190565b600081518084526020808501945080840160005b8381101562004b805781518051151588528381015163ffffffff908116858a01526040808301519091169089015260608082015173ffffffffffffffffffffffffffffffffffffffff16908901526080808201516bffffffffffffffffffffffff169089015260a08082015162004b5b828b01826bffffffffffffffffffffffff169052565b505060c09081015163ffffffff169088015260e0909601959082019060010162004ad5565b509495945050505050565b600081518084526020808501945080840160005b8381101562004b8057815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010162004b9f565b600082825180855260208086019550808260051b84010181860160005b8481101562004c40577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe086840301895262004c2d838351620041ca565b9884019892509083019060010162004bf0565b5090979650505050505050565b60e081528760e082015260006101007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a111562004c8a57600080fd5b8960051b808c8386013783018381038201602085015262004cae8282018b62004ac1565b915050828103604084015262004cc5818962004b8b565b9050828103606084015262004cdb818862004b8b565b9050828103608084015262004cf1818762004bd3565b905082810360a084015262004d07818662004bd3565b905082810360c084015262004d1d818562004bd3565b9b9a5050505050505050505050565b60006020828403121562004d3f57600080fd5b815160ff81168114620039aa57600080fd5b60ff8416815260ff8316602082015260606040820152600062002d486060830184620041ca565b60006020828403121562004d8b57600080fd5b815167ffffffffffffffff81111562004da357600080fd5b6200331284828501620047d8565b60006020828403121562004dc457600080fd5b8151620039aa81620047c9565b600082601f83011262004de357600080fd5b8135602062004df66200403a836200454c565b82815260059290921b8401810191818101908684111562004e1657600080fd5b8286015b84811015620045fd578035835291830191830162004e1a565b600082601f83011262004e4557600080fd5b8135602062004e586200403a836200454c565b82815260e0928302850182019282820191908785111562004e7857600080fd5b8387015b8581101562004c405781818a03121562004e965760008081fd5b62004ea062003f29565b813562004ead81620047c9565b815262004ebc82870162003e84565b86820152604062004ecf81840162003e84565b9082015260608281013562004ee48162003e61565b90820152608062004ef7838201620044e6565b9082015260a062004f0a838201620044e6565b9082015260c062004f1d83820162003e84565b90820152845292840192810162004e7c565b600082601f83011262004f4157600080fd5b8135602062004f546200403a836200454c565b82815260059290921b8401810191818101908684111562004f7457600080fd5b8286015b84811015620045fd57803562004f8e8162003e61565b835291830191830162004f78565b600080600080600080600060e0888a03121562004fb857600080fd5b873567ffffffffffffffff8082111562004fd157600080fd5b62004fdf8b838c0162004dd1565b985060208a013591508082111562004ff657600080fd5b620050048b838c0162004e33565b975060408a01359150808211156200501b57600080fd5b620050298b838c0162004f2f565b965060608a01359150808211156200504057600080fd5b6200504e8b838c0162004f2f565b955060808a01359150808211156200506557600080fd5b620050738b838c0162004573565b945060a08a01359150808211156200508a57600080fd5b620050988b838c0162004573565b935060c08a0135915080821115620050af57600080fd5b50620050be8a828b0162004573565b91505092959891949750929550565b6bffffffffffffffffffffffff81811683821601908082111562003da65762003da66200469f565b6000602082840312156200510857600080fd5b5051919050565b6bffffffffffffffffffffffff82811682821603908082111562003da65762003da66200469f565b6040815260006200514c604083018662004bd3565b828103602084015262005161818587620046f4565b9695505050505050565b80516020808301519190811015620048c0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b815167ffffffffffffffff811115620051cb57620051cb62003efa565b620051e381620051dc845462004871565b84620048c6565b602080601f831160018114620052395760008415620052025750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b17855562004910565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015620052885788860151825594840194600190910190840162005267565b5085821015620052c557878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b805169ffffffffffffffffffff8116811462003e9957600080fd5b600080600080600060a086880312156200530957600080fd5b6200531486620052d5565b94506020860151935060408601519250606086015191506200533960808701620052d5565b90509295509295909350565b60ff818116838216019081111562002a9f5762002a9f6200469f565b808202811582820484141762002a9f5762002a9f6200469f565b600080604083850312156200538f57600080fd5b505080516020909101519092909150565b60008154620053af8162004871565b808552602060018381168015620053cf5760018114620054085762005438565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b890101955062005438565b866000528260002060005b85811015620054305781548a820186015290830190840162005413565b890184019650505b505050505092915050565b60208152600062002a9c6020830184620053a0565b600082601f8301126200546a57600080fd5b815160206200547d6200403a836200454c565b82815260059290921b840181019181810190868411156200549d57600080fd5b8286015b84811015620045fd5780518352918301918301620054a1565b600060208284031215620054cd57600080fd5b815167ffffffffffffffff80821115620054e657600080fd5b908301906101008286031215620054fc57600080fd5b6200550662003f55565b82518152602083015160208201526040830151604082015260608301516060820152608083015160808201526200554060a0840162004768565b60a082015260c0830151828111156200555857600080fd5b620055668782860162005458565b60c08301525060e0830151828111156200557f57600080fd5b6200558d87828601620047d8565b60e08301525095945050505050565b600081518084526020808501945080840160005b8381101562004b8057815187529582019590820190600101620055b0565b60408152825160408201526020830151606082015260408301516080820152606083015160a0820152608083015160c082015273ffffffffffffffffffffffffffffffffffffffff60a08401511660e0820152600060c0840151610100808185015250620056416101408401826200559c565b905060e08501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0848303016101208501526200567f8282620041ca565b915050828103602084015262002d488185620053a0565b600082620056cd577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe60c060405234801561001057600080fd5b506040516103ca3803806103ca83398101604081905261002f91610076565b600080546001600160a01b0319166001600160a01b039384161790559181166080521660a0526100b9565b80516001600160a01b038116811461007157600080fd5b919050565b60008060006060848603121561008b57600080fd5b6100948461005a565b92506100a26020850161005a565b91506100b06040850161005a565b90509250925092565b60805160a0516102e76100e36000396000603801526000818160c4015261011701526102e76000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806379188d161461007b578063f00e6a2a146100aa575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e808015610076573d6000f35b3d6000fd5b61008e6100893660046101c1565b6100ee565b6040805192151583526020830191909152015b60405180910390f35b60405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001681526020016100a1565b60008054819073ffffffffffffffffffffffffffffffffffffffff16331461011557600080fd5b7f00000000000000000000000000000000000000000000000000000000000000005a91505a61138881101561014957600080fd5b61138881039050856040820482031161016157600080fd5b50803b61016d57600080fd5b6000808551602087016000858af192505a610188908361029a565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080604083850312156101d457600080fd5b82359150602083013567ffffffffffffffff808211156101f357600080fd5b818501915085601f83011261020757600080fd5b81358181111561021957610219610192565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561025f5761025f610192565b8160405282815288602084870101111561027857600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b818103818111156102d4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea164736f6c6343000813000aa164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistryLogicB2_2\",\"name\":\"logicB\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxCheckDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxPerformDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentGreaterThanAllLINK\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newModule\",\"type\":\"address\"}],\"name\":\"ChainSpecificModuleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"OwnerFundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"cancelUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_2.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_2.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkNative\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_2.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkNative\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"executeCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_2.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"migrateUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedUpkeeps\",\"type\":\"bytes\"}],\"name\":\"receiveUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"enumAutomationRegistryBase2_2.Trigger\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"setUpkeepTriggerConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x6101406040523480156200001257600080fd5b5060405162005fd938038062005fd98339810160408190526200003591620003b1565b80816001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b9190620003b1565b826001600160a01b031663b10b673c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001009190620003b1565b836001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001659190620003b1565b846001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca9190620003b1565b856001600160a01b031663a08714c06040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f9190620003b1565b3380600081620002865760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620002b957620002b981620002ed565b5050506001600160a01b0394851660805292841660a05290831660c052821660e052811661010052166101205250620003d8565b336001600160a01b03821603620003475760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200027d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b0381168114620003ae57600080fd5b50565b600060208284031215620003c457600080fd5b8151620003d18162000398565b9392505050565b60805160a05160c05160e0516101005161012051615b9c6200043d6000396000818161010001526101c5015260006132180152600081816104a501526120c201526000613401015260006134e5015260008181611f0401526124d00152615b9c6000f3fe608060405260043610620000fe5760003560e01c806385c1b0ba1162000097578063c80480221162000061578063c80480221462000343578063ce7dc5b41462000368578063f2fde38b146200038d578063f7d334ba14620003b257620000fe565b806385c1b0ba14620002a75780638da5cb5b14620002cc5780638e86139b14620002f9578063948108f7146200031e57620000fe565b80634ee88d3511620000d95780634ee88d35146200020b5780636ded9eae146200023057806371791aa0146200025557806379ba5097146200028f57620000fe565b806328f32f38146200014657806329c5efad146200017e578063349e8cca14620001b5575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e8080156200013f573d6000f35b3d6000fd5b005b3480156200015357600080fd5b506200016b6200016536600462004137565b620003d7565b6040519081526020015b60405180910390f35b3480156200018b57600080fd5b50620001a36200019d3660046200421d565b62000751565b60405162000175949392919062004345565b348015620001c257600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200162000175565b3480156200021857600080fd5b50620001446200022a36600462004382565b620009f5565b3480156200023d57600080fd5b506200016b6200024f366004620043d2565b62000a5d565b3480156200026257600080fd5b506200027a620002743660046200421d565b62000ac3565b60405162000175979695949392919062004485565b3480156200029c57600080fd5b506200014462001211565b348015620002b457600080fd5b5062000144620002c6366004620044d7565b62001314565b348015620002d957600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16620001e5565b3480156200030657600080fd5b50620001446200031836600462004564565b62001f85565b3480156200032b57600080fd5b50620001446200033d366004620045c7565b6200230d565b3480156200035057600080fd5b506200014462000362366004620045f6565b620025a0565b3480156200037557600080fd5b50620001a362000387366004620046cc565b62002a19565b3480156200039a57600080fd5b5062000144620003ac36600462004743565b62002adf565b348015620003bf57600080fd5b506200027a620003d1366004620045f6565b62002af7565b6000805473ffffffffffffffffffffffffffffffffffffffff1633148015906200040b57506200040960093362002b35565b155b1562000443576040517fd48b678b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff89163b62000492576040517f09ee12d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6200049d8662002b69565b9050600089307f0000000000000000000000000000000000000000000000000000000000000000604051620004d29062003ec3565b73ffffffffffffffffffffffffffffffffffffffff938416815291831660208301529091166040820152606001604051809103906000f0801580156200051c573d6000803e3d6000fd5b509050620005e3826040518060e001604052806000151581526020018c63ffffffff16815260200163ffffffff801681526020018473ffffffffffffffffffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff168152602001600063ffffffff168152508a89898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508b92508a915062002e159050565b6015805474010000000000000000000000000000000000000000900463ffffffff16906014620006138362004792565b91906101000a81548163ffffffff021916908363ffffffff16021790555050817fbae366358c023f887e791d7a62f2e4316f1026bd77f6fb49501a917b3bc5d0128a8a6040516200068c92919063ffffffff92909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a2817fcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d8787604051620006c892919062004801565b60405180910390a2817f2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d56648560405162000702919062004817565b60405180910390a2817f3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf4850846040516200073c919062004817565b60405180910390a25098975050505050505050565b600060606000806200076262003200565b600086815260046020908152604091829020825160e081018452815460ff811615158252610100810463ffffffff90811694830194909452650100000000008104841694820194909452690100000000000000000090930473ffffffffffffffffffffffffffffffffffffffff166060840152600101546bffffffffffffffffffffffff80821660808501526c0100000000000000000000000082041660a0840152780100000000000000000000000000000000000000000000000090041660c08201525a9150600080826060015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200087c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620008a2919062004839565b73ffffffffffffffffffffffffffffffffffffffff166014600101600c9054906101000a900463ffffffff1663ffffffff1689604051620008e4919062004859565b60006040518083038160008787f1925050503d806000811462000924576040519150601f19603f3d011682016040523d82523d6000602084013e62000929565b606091505b50915091505a6200093b908562004877565b93508162000966576000604051806020016040528060008152506007965096509650505050620009ec565b808060200190518101906200097c9190620048e8565b909750955086620009aa576000604051806020016040528060008152506004965096509650505050620009ec565b601654865164010000000090910463ffffffff161015620009e8576000604051806020016040528060008152506005965096509650505050620009ec565b5050505b92959194509250565b62000a008362003272565b6000838152601b6020526040902062000a1b828483620049dd565b50827f2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d5664838360405162000a5092919062004801565b60405180910390a2505050565b600062000ab788888860008989604051806020016040528060008152508a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250620003d792505050565b98975050505050505050565b60006060600080600080600062000ad962003200565b600062000ae68a62003328565b905060006012604051806101600160405290816000820160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160008201600c9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160109054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160149054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160189054906101000a900462ffffff1662ffffff1662ffffff16815260200160008201601b9054906101000a900461ffff1661ffff1661ffff16815260200160008201601d9054906101000a900460ff1660ff1660ff16815260200160008201601e9054906101000a900460ff1615151515815260200160008201601f9054906101000a900460ff161515151581526020016001820160009054906101000a900460ff161515151581526020016001820160019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505090506000600460008d81526020019081526020016000206040518060e00160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160059054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160099054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160018201600c9054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff1681526020016001820160189054906101000a900463ffffffff1663ffffffff1663ffffffff168152505090508160e001511562000e7b576000604051806020016040528060008152506009600084602001516000808263ffffffff169250995099509950995099509950995050505062001205565b604081015163ffffffff9081161462000ecc576000604051806020016040528060008152506001600084602001516000808263ffffffff169250995099509950995099509950995050505062001205565b80511562000f12576000604051806020016040528060008152506002600084602001516000808263ffffffff169250995099509950995099509950995050505062001205565b62000f1d82620033de565b8095508196505050600062000f3a838584602001518989620035d0565b9050806bffffffffffffffffffffffff168260a001516bffffffffffffffffffffffff16101562000fa4576000604051806020016040528060008152506006600085602001516000808263ffffffff1692509a509a509a509a509a509a509a505050505062001205565b600062000fb38e868f62003885565b90505a9850600080846060015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200100b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001031919062004839565b73ffffffffffffffffffffffffffffffffffffffff166014600101600c9054906101000a900463ffffffff1663ffffffff168460405162001073919062004859565b60006040518083038160008787f1925050503d8060008114620010b3576040519150601f19603f3d011682016040523d82523d6000602084013e620010b8565b606091505b50915091505a620010ca908c62004877565b9a50816200114a5760165481516801000000000000000090910463ffffffff1610156200112757505060408051602080820190925260008082529490910151939c509a50600899505063ffffffff90911695506200120592505050565b602090940151939b5060039a505063ffffffff9092169650620012059350505050565b80806020019051810190620011609190620048e8565b909e509c508d620011a157505060408051602080820190925260008082529490910151939c509a50600499505063ffffffff90911695506200120592505050565b6016548d5164010000000090910463ffffffff161015620011f257505060408051602080820190925260008082529490910151939c509a50600599505063ffffffff90911695506200120592505050565b505050506020015163ffffffff16945050505b92959891949750929550565b60015473ffffffffffffffffffffffffffffffffffffffff16331462001298576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600173ffffffffffffffffffffffffffffffffffffffff82166000908152601a602052604090205460ff166003811115620013535762001353620042da565b141580156200139f5750600373ffffffffffffffffffffffffffffffffffffffff82166000908152601a602052604090205460ff1660038111156200139c576200139c620042da565b14155b15620013d7576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6014546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1662001437576040517fd12d7d8d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082900362001473576040517f2c2fc94100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081018290526000808567ffffffffffffffff811115620014ca57620014ca62003fbe565b604051908082528060200260200182016040528015620014f4578160200160208202803683370190505b50905060008667ffffffffffffffff81111562001515576200151562003fbe565b6040519080825280602002602001820160405280156200159c57816020015b6040805160e08101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181620015345790505b50905060008767ffffffffffffffff811115620015bd57620015bd62003fbe565b604051908082528060200260200182016040528015620015f257816020015b6060815260200190600190039081620015dc5790505b50905060008867ffffffffffffffff81111562001613576200161362003fbe565b6040519080825280602002602001820160405280156200164857816020015b6060815260200190600190039081620016325790505b50905060008967ffffffffffffffff81111562001669576200166962003fbe565b6040519080825280602002602001820160405280156200169e57816020015b6060815260200190600190039081620016885790505b50905060005b8a81101562001c82578b8b82818110620016c257620016c262004b05565b60209081029290920135600081815260048452604090819020815160e081018352815460ff811615158252610100810463ffffffff90811697830197909752650100000000008104871693820193909352690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff166060830152600101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490931660c08401529a50909850620017a190508962003272565b60608801516040517f1a5da6c800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8c8116600483015290911690631a5da6c890602401600060405180830381600087803b1580156200181157600080fd5b505af115801562001826573d6000803e3d6000fd5b505050508785828151811062001840576200184062004b05565b6020026020010181905250600560008a815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1686828151811062001894576200189462004b05565b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910182015260008a81526007909152604090208054620018d39062004935565b80601f0160208091040260200160405190810160405280929190818152602001828054620019019062004935565b8015620019525780601f10620019265761010080835404028352916020019162001952565b820191906000526020600020905b8154815290600101906020018083116200193457829003601f168201915b50505050508482815181106200196c576200196c62004b05565b6020026020010181905250601b60008a81526020019081526020016000208054620019979062004935565b80601f0160208091040260200160405190810160405280929190818152602001828054620019c59062004935565b801562001a165780601f10620019ea5761010080835404028352916020019162001a16565b820191906000526020600020905b815481529060010190602001808311620019f857829003601f168201915b505050505083828151811062001a305762001a3062004b05565b6020026020010181905250601c60008a8152602001908152602001600020805462001a5b9062004935565b80601f016020809104026020016040519081016040528092919081815260200182805462001a899062004935565b801562001ada5780601f1062001aae5761010080835404028352916020019162001ada565b820191906000526020600020905b81548152906001019060200180831162001abc57829003601f168201915b505050505082828151811062001af45762001af462004b05565b60200260200101819052508760a001516bffffffffffffffffffffffff168762001b1f919062004b34565b60008a815260046020908152604080832080547fffffff000000000000000000000000000000000000000000000000000000000016815560010180547fffffffff000000000000000000000000000000000000000000000000000000001690556007909152812091985062001b95919062003ed1565b6000898152601b6020526040812062001bae9162003ed1565b6000898152601c6020526040812062001bc79162003ed1565b600089815260066020526040902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905562001c0860028a62003a75565b5060a0880151604080516bffffffffffffffffffffffff909216825273ffffffffffffffffffffffffffffffffffffffff8c1660208301528a917fb38647142fbb1ea4c000fc4569b37a4e9a9f6313317b84ee3e5326c1a6cd06ff910160405180910390a28062001c798162004b4a565b915050620016a4565b508560195462001c93919062004877565b60195560008b8b868167ffffffffffffffff81111562001cb75762001cb762003fbe565b60405190808252806020026020018201604052801562001ce1578160200160208202803683370190505b508988888860405160200162001cff98979695949392919062004d11565b60405160208183030381529060405290508973ffffffffffffffffffffffffffffffffffffffff16638e86139b6014600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c71249ab60038e73ffffffffffffffffffffffffffffffffffffffff1663aab9edd66040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001dbb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001de1919062004df0565b866040518463ffffffff1660e01b815260040162001e029392919062004e15565b600060405180830381865afa15801562001e20573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405262001e68919081019062004e3c565b6040518263ffffffff1660e01b815260040162001e86919062004817565b600060405180830381600087803b15801562001ea157600080fd5b505af115801562001eb6573d6000803e3d6000fd5b50506040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8d81166004830152602482018b90527f000000000000000000000000000000000000000000000000000000000000000016925063a9059cbb91506044016020604051808303816000875af115801562001f50573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001f76919062004e75565b50505050505050505050505050565b6002336000908152601a602052604090205460ff16600381111562001fae5762001fae620042da565b1415801562001fe457506003336000908152601a602052604090205460ff16600381111562001fe15762001fe1620042da565b14155b156200201c576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080808080808062002032888a018a62005060565b965096509650965096509650965060005b87518110156200230157600073ffffffffffffffffffffffffffffffffffffffff168782815181106200207a576200207a62004b05565b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff16036200218e57858181518110620020b757620020b762004b05565b6020026020010151307f0000000000000000000000000000000000000000000000000000000000000000604051620020ef9062003ec3565b73ffffffffffffffffffffffffffffffffffffffff938416815291831660208301529091166040820152606001604051809103906000f08015801562002139573d6000803e3d6000fd5b508782815181106200214f576200214f62004b05565b60200260200101516060019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250505b62002246888281518110620021a757620021a762004b05565b6020026020010151888381518110620021c457620021c462004b05565b6020026020010151878481518110620021e157620021e162004b05565b6020026020010151878581518110620021fe57620021fe62004b05565b60200260200101518786815181106200221b576200221b62004b05565b602002602001015187878151811062002238576200223862004b05565b602002602001015162002e15565b8781815181106200225b576200225b62004b05565b60200260200101517f74931a144e43a50694897f241d973aecb5024c0e910f9bb80a163ea3c1cf5a7188838151811062002299576200229962004b05565b602002602001015160a0015133604051620022e49291906bffffffffffffffffffffffff92909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a280620022f88162004b4a565b91505062002043565b50505050505050505050565b600082815260046020908152604091829020825160e081018452815460ff81161515825263ffffffff6101008204811694830194909452650100000000008104841694820185905273ffffffffffffffffffffffffffffffffffffffff69010000000000000000009091041660608201526001909101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a083015278010000000000000000000000000000000000000000000000009004821660c082015291146200240b576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818160a001516200241d919062005191565b600084815260046020526040902060010180547fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff166c010000000000000000000000006bffffffffffffffffffffffff93841602179055601954620024859184169062004b34565b6019556040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526bffffffffffffffffffffffff831660448201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906323b872dd906064016020604051808303816000875af11580156200252f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002555919062004e75565b506040516bffffffffffffffffffffffff83168152339084907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a3505050565b6000818152600460209081526040808320815160e081018352815460ff81161515825263ffffffff610100820481169583019590955265010000000000810485169382019390935273ffffffffffffffffffffffffffffffffffffffff6901000000000000000000909304929092166060830152600101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490911660c0820152906200268860005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161490506000601260010160019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200272b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620027519190620051b9565b9050826040015163ffffffff1660000362002798576040517ffbc0357800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604083015163ffffffff90811614620027dd576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8115801562002810575060008481526005602052604090205473ffffffffffffffffffffffffffffffffffffffff163314155b1562002848576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816200285e576200285b60328262004b34565b90505b6000848152600460205260409020805463ffffffff80841665010000000000027fffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffff90921691909117909155620028ba90600290869062003a7516565b5060145460808401516bffffffffffffffffffffffff918216916000911682111562002923576080850151620028f19083620051d3565b90508460a001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff16111562002923575060a08401515b808560a00151620029359190620051d3565b600087815260046020526040902060010180547fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff166c010000000000000000000000006bffffffffffffffffffffffff938416021790556015546200299d9183911662005191565b601580547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff9290921691909117905560405167ffffffffffffffff84169087907f91cb3bb75cfbd718bbfccc56b7f53d92d7048ef4ca39a3b7b7c6d4af1f79118190600090a3505050505050565b600060606000806000634b56a42e60e01b88888860405160240162002a4193929190620051fb565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152905062002acc898262000751565b929c919b50995090975095505050505050565b62002ae962003a83565b62002af48162003b06565b50565b60006060600080600080600062002b1e886040518060200160405280600081525062000ac3565b959e949d50929b5090995097509550909350915050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260018301602052604081205415155b90505b92915050565b6000806000601260010160019054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060008173ffffffffffffffffffffffffffffffffffffffff166385df51fd60018473ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa15801562002c02573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002c289190620051b9565b62002c34919062004877565b6040518263ffffffff1660e01b815260040162002c5391815260200190565b602060405180830381865afa15801562002c71573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002c979190620051b9565b601554604080516020810193909352309083015274010000000000000000000000000000000000000000900463ffffffff166060820152608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201209083015201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060045b600f81101562002da3578382828151811062002d5f5762002d5f62004b05565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508062002d9a8162004b4a565b91505062002d3f565b5084600181111562002db95762002db9620042da565b60f81b81600f8151811062002dd25762002dd262004b05565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535062002e0c816200522f565b95945050505050565b6012547e01000000000000000000000000000000000000000000000000000000000000900460ff161562002e75576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601654835163ffffffff909116101562002ebb576040517fae7235df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108fc856020015163ffffffff16108062002ef95750601554602086015163ffffffff70010000000000000000000000000000000090920482169116115b1562002f31576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000868152600460205260409020546901000000000000000000900473ffffffffffffffffffffffffffffffffffffffff161562002f9b576040517f6e3b930b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000868152600460209081526040808320885181548a8501518b85015160608d01517fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000009093169315157fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff169390931761010063ffffffff92831602177fffffff000000000000000000000000000000000000000000000000ffffffffff1665010000000000938216939093027fffffff0000000000000000000000000000000000000000ffffffffffffffffff1692909217690100000000000000000073ffffffffffffffffffffffffffffffffffffffff9283160217835560808b01516001909301805460a08d015160c08e01516bffffffffffffffffffffffff9687167fffffffffffffffff000000000000000000000000000000000000000000000000909316929092176c010000000000000000000000009690911695909502949094177fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff1678010000000000000000000000000000000000000000000000009490931693909302919091179091556005835281842080547fffffffffffffffffffffffff000000000000000000000000000000000000000016918916919091179055600790915290206200318e848262005272565b508460a001516bffffffffffffffffffffffff16601954620031b1919062004b34565b6019556000868152601b60205260409020620031ce838262005272565b506000868152601c60205260409020620031e9828262005272565b50620031f760028762003bfd565b50505050505050565b3273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161462003270576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60008181526005602052604090205473ffffffffffffffffffffffffffffffffffffffff163314620032d0576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526004602052604090205465010000000000900463ffffffff9081161462002af4576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818160045b600f811015620033bd577fff00000000000000000000000000000000000000000000000000000000000000821683826020811062003371576200337162004b05565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614620033a857506000949350505050565b80620033b48162004b4a565b9150506200332f565b5081600f1a6001811115620033d657620033d6620042da565b949350505050565b6000806000836080015162ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156200346b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620034919190620053b4565b5094509092505050600081131580620034a957508142105b80620034ce5750828015620034ce5750620034c5824262004877565b8463ffffffff16105b15620034df576017549550620034e3565b8095505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156200354f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620035759190620053b4565b50945090925050506000811315806200358d57508142105b80620035b25750828015620035b25750620035a9824262004877565b8463ffffffff16105b15620035c3576018549450620035c7565b8094505b50505050915091565b60008080866001811115620035e957620035e9620042da565b03620035f9575061ea6062003653565b6001866001811115620036105762003610620042da565b0362003621575062014c0862003653565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008760c00151600162003668919062005409565b620036789060ff16604062005425565b60165462003698906103a490640100000000900463ffffffff1662004b34565b620036a4919062004b34565b601354604080517fde9ee35e00000000000000000000000000000000000000000000000000000000815281519394506000938493610100900473ffffffffffffffffffffffffffffffffffffffff169263de9ee35e92600480820193918290030181865afa1580156200371b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200374191906200543f565b909250905081836200375583601862004b34565b62003761919062005425565b60c08c01516200377390600162005409565b620037849060ff166115e062005425565b62003790919062004b34565b6200379c919062004b34565b620037a8908562004b34565b935060008a610140015173ffffffffffffffffffffffffffffffffffffffff166312544140856040518263ffffffff1660e01b8152600401620037ed91815260200190565b602060405180830381865afa1580156200380b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620038319190620051b9565b8b60a0015161ffff1662003846919062005425565b9050600080620038638d8c63ffffffff1689868e8e600062003c0b565b909250905062003874818362005191565b9d9c50505050505050505050505050565b606060008360018111156200389e576200389e620042da565b036200396b576000848152600760205260409081902090517f6e04ff0d0000000000000000000000000000000000000000000000000000000091620038e69160240162005507565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152905062003a6e565b6001836001811115620039825762003982620042da565b036200362157600082806020019051810190620039a091906200557e565b6000868152600760205260409081902090519192507f40691db40000000000000000000000000000000000000000000000000000000091620039e791849160240162005692565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152915062003a6e9050565b9392505050565b600062002b60838362003d66565b60005473ffffffffffffffffffffffffffffffffffffffff16331462003270576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016200128f565b3373ffffffffffffffffffffffffffffffffffffffff82160362003b87576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200128f565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600062002b60838362003e71565b60008060008960a0015161ffff168662003c26919062005425565b905083801562003c355750803a105b1562003c3e57503a5b6000858862003c4e8b8d62004b34565b62003c5a908562005425565b62003c66919062004b34565b62003c7a90670de0b6b3a764000062005425565b62003c8691906200575a565b905060008b6040015163ffffffff1664e8d4a5100062003ca7919062005425565b60208d0151889063ffffffff168b62003cc18f8862005425565b62003ccd919062004b34565b62003cdd90633b9aca0062005425565b62003ce9919062005425565b62003cf591906200575a565b62003d01919062004b34565b90506b033b2e3c9fd0803ce800000062003d1c828462004b34565b111562003d55576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b909b909a5098505050505050505050565b6000818152600183016020526040812054801562003e5f57600062003d8d60018362004877565b855490915060009062003da39060019062004877565b905081811462003e0f57600086600001828154811062003dc75762003dc762004b05565b906000526020600020015490508087600001848154811062003ded5762003ded62004b05565b6000918252602080832090910192909255918252600188019052604090208390555b855486908062003e235762003e2362005796565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505062002b63565b600091505062002b63565b5092915050565b600081815260018301602052604081205462003eba5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562002b63565b50600062002b63565b6103ca80620057c683390190565b50805462003edf9062004935565b6000825580601f1062003ef0575050565b601f01602090049060005260206000209081019062002af491905b8082111562003f21576000815560010162003f0b565b5090565b73ffffffffffffffffffffffffffffffffffffffff8116811462002af457600080fd5b803563ffffffff8116811462003f5d57600080fd5b919050565b80356002811062003f5d57600080fd5b60008083601f84011262003f8557600080fd5b50813567ffffffffffffffff81111562003f9e57600080fd5b60208301915083602082850101111562003fb757600080fd5b9250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160e0810167ffffffffffffffff8111828210171562004013576200401362003fbe565b60405290565b604051610100810167ffffffffffffffff8111828210171562004013576200401362003fbe565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156200408a576200408a62003fbe565b604052919050565b600067ffffffffffffffff821115620040af57620040af62003fbe565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112620040ed57600080fd5b813562004104620040fe8262004092565b62004040565b8181528460208386010111156200411a57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060008060e0898b0312156200415457600080fd5b8835620041618162003f25565b97506200417160208a0162003f48565b96506040890135620041838162003f25565b95506200419360608a0162003f62565b9450608089013567ffffffffffffffff80821115620041b157600080fd5b620041bf8c838d0162003f72565b909650945060a08b0135915080821115620041d957600080fd5b620041e78c838d01620040db565b935060c08b0135915080821115620041fe57600080fd5b506200420d8b828c01620040db565b9150509295985092959890939650565b600080604083850312156200423157600080fd5b82359150602083013567ffffffffffffffff8111156200425057600080fd5b6200425e85828601620040db565b9150509250929050565b60005b83811015620042855781810151838201526020016200426b565b50506000910152565b60008151808452620042a881602086016020860162004268565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600a811062004341577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b84151581526080602082015260006200436260808301866200428e565b905062004373604083018562004309565b82606083015295945050505050565b6000806000604084860312156200439857600080fd5b83359250602084013567ffffffffffffffff811115620043b757600080fd5b620043c58682870162003f72565b9497909650939450505050565b600080600080600080600060a0888a031215620043ee57600080fd5b8735620043fb8162003f25565b96506200440b6020890162003f48565b955060408801356200441d8162003f25565b9450606088013567ffffffffffffffff808211156200443b57600080fd5b620044498b838c0162003f72565b909650945060808a01359150808211156200446357600080fd5b50620044728a828b0162003f72565b989b979a50959850939692959293505050565b871515815260e060208201526000620044a260e08301896200428e565b9050620044b3604083018862004309565b8560608301528460808301528360a08301528260c083015298975050505050505050565b600080600060408486031215620044ed57600080fd5b833567ffffffffffffffff808211156200450657600080fd5b818601915086601f8301126200451b57600080fd5b8135818111156200452b57600080fd5b8760208260051b85010111156200454157600080fd5b60209283019550935050840135620045598162003f25565b809150509250925092565b600080602083850312156200457857600080fd5b823567ffffffffffffffff8111156200459057600080fd5b6200459e8582860162003f72565b90969095509350505050565b80356bffffffffffffffffffffffff8116811462003f5d57600080fd5b60008060408385031215620045db57600080fd5b82359150620045ed60208401620045aa565b90509250929050565b6000602082840312156200460957600080fd5b5035919050565b600067ffffffffffffffff8211156200462d576200462d62003fbe565b5060051b60200190565b600082601f8301126200464957600080fd5b813560206200465c620040fe8362004610565b82815260059290921b840181019181810190868411156200467c57600080fd5b8286015b84811015620046c157803567ffffffffffffffff811115620046a25760008081fd5b620046b28986838b0101620040db565b84525091830191830162004680565b509695505050505050565b60008060008060608587031215620046e357600080fd5b84359350602085013567ffffffffffffffff808211156200470357600080fd5b620047118883890162004637565b945060408701359150808211156200472857600080fd5b50620047378782880162003f72565b95989497509550505050565b6000602082840312156200475657600080fd5b813562003a6e8162003f25565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff808316818103620047ae57620047ae62004763565b6001019392505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b602081526000620033d6602083018486620047b8565b60208152600062002b6060208301846200428e565b805162003f5d8162003f25565b6000602082840312156200484c57600080fd5b815162003a6e8162003f25565b600082516200486d81846020870162004268565b9190910192915050565b8181038181111562002b635762002b6362004763565b801515811462002af457600080fd5b600082601f830112620048ae57600080fd5b8151620048bf620040fe8262004092565b818152846020838601011115620048d557600080fd5b620033d682602083016020870162004268565b60008060408385031215620048fc57600080fd5b825162004909816200488d565b602084015190925067ffffffffffffffff8111156200492757600080fd5b6200425e858286016200489c565b600181811c908216806200494a57607f821691505b60208210810362004984577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f821115620049d857600081815260208120601f850160051c81016020861015620049b35750805b601f850160051c820191505b81811015620049d457828155600101620049bf565b5050505b505050565b67ffffffffffffffff831115620049f857620049f862003fbe565b62004a108362004a09835462004935565b836200498a565b6000601f84116001811462004a65576000851562004a2e5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b17835562004afe565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b8281101562004ab6578685013582556020948501946001909201910162004a94565b508682101562004af2577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8082018082111562002b635762002b6362004763565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820362004b7e5762004b7e62004763565b5060010190565b600081518084526020808501945080840160005b8381101562004c445781518051151588528381015163ffffffff908116858a01526040808301519091169089015260608082015173ffffffffffffffffffffffffffffffffffffffff16908901526080808201516bffffffffffffffffffffffff169089015260a08082015162004c1f828b01826bffffffffffffffffffffffff169052565b505060c09081015163ffffffff169088015260e0909601959082019060010162004b99565b509495945050505050565b600081518084526020808501945080840160005b8381101562004c4457815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010162004c63565b600082825180855260208086019550808260051b84010181860160005b8481101562004d04577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe086840301895262004cf18383516200428e565b9884019892509083019060010162004cb4565b5090979650505050505050565b60e081528760e082015260006101007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a111562004d4e57600080fd5b8960051b808c8386013783018381038201602085015262004d728282018b62004b85565b915050828103604084015262004d89818962004c4f565b9050828103606084015262004d9f818862004c4f565b9050828103608084015262004db5818762004c97565b905082810360a084015262004dcb818662004c97565b905082810360c084015262004de1818562004c97565b9b9a5050505050505050505050565b60006020828403121562004e0357600080fd5b815160ff8116811462003a6e57600080fd5b60ff8416815260ff8316602082015260606040820152600062002e0c60608301846200428e565b60006020828403121562004e4f57600080fd5b815167ffffffffffffffff81111562004e6757600080fd5b620033d6848285016200489c565b60006020828403121562004e8857600080fd5b815162003a6e816200488d565b600082601f83011262004ea757600080fd5b8135602062004eba620040fe8362004610565b82815260059290921b8401810191818101908684111562004eda57600080fd5b8286015b84811015620046c1578035835291830191830162004ede565b600082601f83011262004f0957600080fd5b8135602062004f1c620040fe8362004610565b82815260e0928302850182019282820191908785111562004f3c57600080fd5b8387015b8581101562004d045781818a03121562004f5a5760008081fd5b62004f6462003fed565b813562004f71816200488d565b815262004f8082870162003f48565b86820152604062004f9381840162003f48565b9082015260608281013562004fa88162003f25565b90820152608062004fbb838201620045aa565b9082015260a062004fce838201620045aa565b9082015260c062004fe183820162003f48565b90820152845292840192810162004f40565b600082601f8301126200500557600080fd5b8135602062005018620040fe8362004610565b82815260059290921b840181019181810190868411156200503857600080fd5b8286015b84811015620046c1578035620050528162003f25565b83529183019183016200503c565b600080600080600080600060e0888a0312156200507c57600080fd5b873567ffffffffffffffff808211156200509557600080fd5b620050a38b838c0162004e95565b985060208a0135915080821115620050ba57600080fd5b620050c88b838c0162004ef7565b975060408a0135915080821115620050df57600080fd5b620050ed8b838c0162004ff3565b965060608a01359150808211156200510457600080fd5b620051128b838c0162004ff3565b955060808a01359150808211156200512957600080fd5b620051378b838c0162004637565b945060a08a01359150808211156200514e57600080fd5b6200515c8b838c0162004637565b935060c08a01359150808211156200517357600080fd5b50620051828a828b0162004637565b91505092959891949750929550565b6bffffffffffffffffffffffff81811683821601908082111562003e6a5762003e6a62004763565b600060208284031215620051cc57600080fd5b5051919050565b6bffffffffffffffffffffffff82811682821603908082111562003e6a5762003e6a62004763565b60408152600062005210604083018662004c97565b828103602084015262005225818587620047b8565b9695505050505050565b8051602080830151919081101562004984577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b815167ffffffffffffffff8111156200528f576200528f62003fbe565b620052a781620052a0845462004935565b846200498a565b602080601f831160018114620052fd5760008415620052c65750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555620049d4565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156200534c578886015182559484019460019091019084016200532b565b50858210156200538957878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b805169ffffffffffffffffffff8116811462003f5d57600080fd5b600080600080600060a08688031215620053cd57600080fd5b620053d88662005399565b9450602086015193506040860151925060608601519150620053fd6080870162005399565b90509295509295909350565b60ff818116838216019081111562002b635762002b6362004763565b808202811582820484141762002b635762002b6362004763565b600080604083850312156200545357600080fd5b505080516020909101519092909150565b60008154620054738162004935565b808552602060018381168015620054935760018114620054cc57620054fc565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b8901019550620054fc565b866000528260002060005b85811015620054f45781548a8201860152908301908401620054d7565b890184019650505b505050505092915050565b60208152600062002b60602083018462005464565b600082601f8301126200552e57600080fd5b8151602062005541620040fe8362004610565b82815260059290921b840181019181810190868411156200556157600080fd5b8286015b84811015620046c1578051835291830191830162005565565b6000602082840312156200559157600080fd5b815167ffffffffffffffff80821115620055aa57600080fd5b908301906101008286031215620055c057600080fd5b620055ca62004019565b82518152602083015160208201526040830151604082015260608301516060820152608083015160808201526200560460a084016200482c565b60a082015260c0830151828111156200561c57600080fd5b6200562a878286016200551c565b60c08301525060e0830151828111156200564357600080fd5b62005651878286016200489c565b60e08301525095945050505050565b600081518084526020808501945080840160005b8381101562004c445781518752958201959082019060010162005674565b60408152825160408201526020830151606082015260408301516080820152606083015160a0820152608083015160c082015273ffffffffffffffffffffffffffffffffffffffff60a08401511660e0820152600060c08401516101008081850152506200570561014084018262005660565b905060e08501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0848303016101208501526200574382826200428e565b915050828103602084015262002e0c818562005464565b60008262005791577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe60c060405234801561001057600080fd5b506040516103ca3803806103ca83398101604081905261002f91610076565b600080546001600160a01b0319166001600160a01b039384161790559181166080521660a0526100b9565b80516001600160a01b038116811461007157600080fd5b919050565b60008060006060848603121561008b57600080fd5b6100948461005a565b92506100a26020850161005a565b91506100b06040850161005a565b90509250925092565b60805160a0516102e76100e36000396000603801526000818160c4015261011701526102e76000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806379188d161461007b578063f00e6a2a146100aa575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e808015610076573d6000f35b3d6000fd5b61008e6100893660046101c1565b6100ee565b6040805192151583526020830191909152015b60405180910390f35b60405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001681526020016100a1565b60008054819073ffffffffffffffffffffffffffffffffffffffff16331461011557600080fd5b7f00000000000000000000000000000000000000000000000000000000000000005a91505a61138881101561014957600080fd5b61138881039050856040820482031161016157600080fd5b50803b61016d57600080fd5b6000808551602087016000858af192505a610188908361029a565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080604083850312156101d457600080fd5b82359150602083013567ffffffffffffffff808211156101f357600080fd5b818501915085601f83011261020757600080fd5b81358181111561021957610219610192565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561025f5761025f610192565b8160405282815288602084870101111561027857600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b818103818111156102d4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea164736f6c6343000813000aa164736f6c6343000813000a", } var AutomationRegistryLogicAABI = AutomationRegistryLogicAMetaData.ABI diff --git a/core/gethwrappers/generated/automation_registry_logic_a_wrapper_2_3/automation_registry_logic_a_wrapper_2_3.go b/core/gethwrappers/generated/automation_registry_logic_a_wrapper_2_3/automation_registry_logic_a_wrapper_2_3.go index 9094317d93d..f982e6ce11a 100644 --- a/core/gethwrappers/generated/automation_registry_logic_a_wrapper_2_3/automation_registry_logic_a_wrapper_2_3.go +++ b/core/gethwrappers/generated/automation_registry_logic_a_wrapper_2_3/automation_registry_logic_a_wrapper_2_3.go @@ -31,14 +31,21 @@ var ( ) type AutomationRegistryBase23BillingConfig struct { - GasFeePPB uint32 - FlatFeeMicroLink *big.Int - PriceFeed common.Address + GasFeePPB uint32 + FlatFeeMilliCents *big.Int + PriceFeed common.Address + FallbackPrice *big.Int + MinSpend *big.Int +} + +type AutomationRegistryBase23BillingOverrides struct { + GasFeePPB uint32 + FlatFeeMilliCents *big.Int } var AutomationRegistryLogicAMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistryLogicB2_3\",\"name\":\"logicB\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidFeed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxCheckDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxPerformDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyFinanceAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentGreaterThanAllLINK\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint24\"},{\"internalType\":\"address\",\"name\":\"priceFeed\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"BillingConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newModule\",\"type\":\"address\"}],\"name\":\"ChainSpecificModuleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"cancelUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_3.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_3.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkUSD\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_3.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkUSD\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"executeCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_3.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"migrateUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedUpkeeps\",\"type\":\"bytes\"}],\"name\":\"receiveUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"enumAutomationRegistryBase2_3.Trigger\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"setUpkeepTriggerConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x6101606040523480156200001257600080fd5b50604051620064c2380380620064c2833981016040819052620000359162000520565b80816001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b919062000520565b826001600160a01b031663226cf83c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000100919062000520565b836001600160a01b031663614486af6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000165919062000520565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca919062000520565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f919062000520565b866001600160a01b031663a08714c06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200026e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000294919062000520565b3380600081620002eb5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156200031e576200031e816200045c565b5050506001600160a01b0380871660805285811660a05284811660c081905284821660e05283821661010052908216610120526040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa1580156200038d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003b3919062000547565b60ff1660a0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620003f7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200041d919062000547565b60ff16146200043f576040516301f86e1760e41b815260040160405180910390fd5b5050506001600160a01b0390931661014052506200056c92505050565b336001600160a01b03821603620004b65760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620002e2565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b03811681146200051d57600080fd5b50565b6000602082840312156200053357600080fd5b8151620005408162000507565b9392505050565b6000602082840312156200055a57600080fd5b815160ff811681146200054057600080fd5b60805160a05160c05160e051610100516101205161014051615eae620006146000396000818161010e01526101a9015260006133160152600081816103e101526120a0015260006135000152600081816136c80152613e06015260006135e4015260008181611bf101528181611c4401528181611ee201528181612457015281816124a6015281816129bf01528181612a230152818161322301526132830152615eae6000f3fe60806040523480156200001157600080fd5b50600436106200010c5760003560e01c806385c1b0ba11620000a5578063c8048022116200006f578063c804802214620002b7578063ce7dc5b414620002ce578063f2fde38b14620002e5578063f7d334ba14620002fc576200010c565b806385c1b0ba14620002535780638da5cb5b146200026a5780638e86139b1462000289578063948108f714620002a0576200010c565b80634ee88d3511620000e75780634ee88d3514620001ef5780636ded9eae146200020657806371791aa0146200021d57806379ba50971462000249576200010c565b806328f32f38146200015457806329c5efad146200017e578063349e8cca14620001a7575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e8080156200014d573d6000f35b3d6000fd5b005b6200016b6200016536600462004449565b62000313565b6040519081526020015b60405180910390f35b620001956200018f3660046200452f565b62000681565b60405162000175949392919062004657565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200162000175565b620001526200020036600462004694565b6200092d565b6200016b62000217366004620046e4565b62000995565b620002346200022e3660046200452f565b620009fb565b60405162000175979695949392919062004797565b6200015262001168565b6200015262000264366004620047e9565b6200126b565b60005473ffffffffffffffffffffffffffffffffffffffff16620001c9565b620001526200029a36600462004876565b62001f63565b62000152620002b1366004620048d9565b620022eb565b62000152620002c836600462004908565b620025ce565b62000195620002df366004620049de565b62002a92565b62000152620002f636600462004a55565b62002b58565b620002346200030d36600462004908565b62002b70565b6000805473ffffffffffffffffffffffffffffffffffffffff1633148015906200034757506200034560093362002bae565b155b156200037f576040517fd48b678b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff89163b620003ce576040517f09ee12d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b620003d98662002be2565b9050600089307f00000000000000000000000000000000000000000000000000000000000000006040516200040e90620041dc565b73ffffffffffffffffffffffffffffffffffffffff938416815291831660208301529091166040820152606001604051809103906000f08015801562000458573d6000803e3d6000fd5b5090506200051f826040518060e001604052806000151581526020018c63ffffffff16815260200163ffffffff801681526020018473ffffffffffffffffffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff168152602001600063ffffffff168152508a89898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508b92508a915062002e829050565b6015805468010000000000000000900463ffffffff16906008620005438362004aa4565b91906101000a81548163ffffffff021916908363ffffffff16021790555050817fbae366358c023f887e791d7a62f2e4316f1026bd77f6fb49501a917b3bc5d0128a8a604051620005bc92919063ffffffff92909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a2817fcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d8787604051620005f892919062004b13565b60405180910390a2817f2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d56648560405162000632919062004b29565b60405180910390a2817f3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf4850846040516200066c919062004b29565b60405180910390a25098975050505050505050565b6000606060008062000692620032fe565b600086815260046020908152604091829020825160e081018452815460ff811615158252610100810463ffffffff90811694830194909452650100000000008104841694820194909452690100000000000000000090930473ffffffffffffffffffffffffffffffffffffffff166060840152600101546bffffffffffffffffffffffff80821660808501526c0100000000000000000000000082041660a0840152780100000000000000000000000000000000000000000000000090041660c08201525a9150600080826060015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620007ac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620007d2919062004b4b565b60155460405173ffffffffffffffffffffffffffffffffffffffff929092169163ffffffff9091169062000808908b9062004b6b565b60006040518083038160008787f1925050503d806000811462000848576040519150601f19603f3d011682016040523d82523d6000602084013e6200084d565b606091505b50915091505a6200085f908562004b89565b9350816200088a57600060405180602001604052806000815250600796509650965050505062000924565b80806020019051810190620008a0919062004bfa565b909750955086620008ce57600060405180602001604052806000815250600496509650965050505062000924565b6015548651780100000000000000000000000000000000000000000000000090910463ffffffff1610156200092057600060405180602001604052806000815250600596509650965050505062000924565b5050505b92959194509250565b620009388362003370565b6000838152601d602052604090206200095382848362004cef565b50827f2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d566483836040516200098892919062004b13565b60405180910390a2505050565b6000620009ef88888860008989604051806020016040528060008152508a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506200031392505050565b98975050505050505050565b60006060600080600080600062000a11620032fe565b600062000a1e8a62003426565b905060006012604051806101600160405290816000820160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160008201600c9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160109054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160149054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160189054906101000a900462ffffff1662ffffff1662ffffff16815260200160008201601b9054906101000a900461ffff1661ffff1661ffff16815260200160008201601d9054906101000a900460ff1660ff1660ff16815260200160008201601e9054906101000a900460ff1615151515815260200160008201601f9054906101000a900460ff161515151581526020016001820160009054906101000a900460ff161515151581526020016001820160019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505090506000600460008d81526020019081526020016000206040518060e00160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160059054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160099054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160018201600c9054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff1681526020016001820160189054906101000a900463ffffffff1663ffffffff1663ffffffff168152505090506000808360e001511562000db8576000604051806020016040528060008152506009600086602001516000808263ffffffff1692509b509b509b509b509b509b509b5050505050506200115c565b604083015163ffffffff9081161462000e0b576000604051806020016040528060008152506001600086602001516000808263ffffffff1692509b509b509b509b509b509b509b5050505050506200115c565b82511562000e53576000604051806020016040528060008152506002600086602001516000808263ffffffff1692509b509b509b509b509b509b509b5050505050506200115c565b62000e5e84620034dc565b6020860151929950909750925062000e7d90859087908a8a8762003780565b9050806bffffffffffffffffffffffff168360a001516bffffffffffffffffffffffff16101562000ee8576000604051806020016040528060008152506006600086602001516000808263ffffffff1692509b509b509b509b509b509b509b5050505050506200115c565b5050600062000ef98d858e62003a79565b90505a9750600080836060015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000f51573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000f77919062004b4b565b60155460405173ffffffffffffffffffffffffffffffffffffffff929092169163ffffffff9091169062000fad90869062004b6b565b60006040518083038160008787f1925050503d806000811462000fed576040519150601f19603f3d011682016040523d82523d6000602084013e62000ff2565b606091505b50915091505a62001004908b62004b89565b995081620010945760155481517c010000000000000000000000000000000000000000000000000000000090910463ffffffff1610156200107257505060408051602080820190925260008082529390910151929b509950600898505063ffffffff1694506200115c915050565b602090930151929a50600399505063ffffffff90911695506200115c92505050565b80806020019051810190620010aa919062004bfa565b909d509b508c620010e857505060408051602080820190925260008082529390910151929b509950600498505063ffffffff1694506200115c915050565b6015548c51780100000000000000000000000000000000000000000000000090910463ffffffff1610156200114a57505060408051602080820190925260008082529390910151929b509950600598505063ffffffff1694506200115c915050565b5050506020015163ffffffff16945050505b92959891949750929550565b60015473ffffffffffffffffffffffffffffffffffffffff163314620011ef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600173ffffffffffffffffffffffffffffffffffffffff82166000908152601c602052604090205460ff166003811115620012aa57620012aa620045ec565b14158015620012f65750600373ffffffffffffffffffffffffffffffffffffffff82166000908152601c602052604090205460ff166003811115620012f357620012f3620045ec565b14155b156200132e576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6014546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff166200138e576040517fd12d7d8d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000829003620013ca576040517f2c2fc94100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081018290526000808567ffffffffffffffff811115620014215762001421620042d0565b6040519080825280602002602001820160405280156200144b578160200160208202803683370190505b50905060008667ffffffffffffffff8111156200146c576200146c620042d0565b604051908082528060200260200182016040528015620014f357816020015b6040805160e08101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816200148b5790505b50905060008767ffffffffffffffff811115620015145762001514620042d0565b6040519080825280602002602001820160405280156200154957816020015b6060815260200190600190039081620015335790505b50905060008867ffffffffffffffff8111156200156a576200156a620042d0565b6040519080825280602002602001820160405280156200159f57816020015b6060815260200190600190039081620015895790505b50905060008967ffffffffffffffff811115620015c057620015c0620042d0565b604051908082528060200260200182016040528015620015f557816020015b6060815260200190600190039081620015df5790505b50905060005b8a81101562001bd9578b8b8281811062001619576200161962004e17565b60209081029290920135600081815260048452604090819020815160e081018352815460ff811615158252610100810463ffffffff90811697830197909752650100000000008104871693820193909352690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff166060830152600101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490931660c08401529a50909850620016f890508962003370565b60608801516040517f1a5da6c800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8c8116600483015290911690631a5da6c890602401600060405180830381600087803b1580156200176857600080fd5b505af11580156200177d573d6000803e3d6000fd5b505050508785828151811062001797576200179762004e17565b6020026020010181905250600560008a815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16868281518110620017eb57620017eb62004e17565b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910182015260008a815260079091526040902080546200182a9062004c47565b80601f0160208091040260200160405190810160405280929190818152602001828054620018589062004c47565b8015620018a95780601f106200187d57610100808354040283529160200191620018a9565b820191906000526020600020905b8154815290600101906020018083116200188b57829003601f168201915b5050505050848281518110620018c357620018c362004e17565b6020026020010181905250601d60008a81526020019081526020016000208054620018ee9062004c47565b80601f01602080910402602001604051908101604052809291908181526020018280546200191c9062004c47565b80156200196d5780601f1062001941576101008083540402835291602001916200196d565b820191906000526020600020905b8154815290600101906020018083116200194f57829003601f168201915b505050505083828151811062001987576200198762004e17565b6020026020010181905250601e60008a81526020019081526020016000208054620019b29062004c47565b80601f0160208091040260200160405190810160405280929190818152602001828054620019e09062004c47565b801562001a315780601f1062001a055761010080835404028352916020019162001a31565b820191906000526020600020905b81548152906001019060200180831162001a1357829003601f168201915b505050505082828151811062001a4b5762001a4b62004e17565b60200260200101819052508760a001516bffffffffffffffffffffffff168762001a76919062004e46565b60008a815260046020908152604080832080547fffffff000000000000000000000000000000000000000000000000000000000016815560010180547fffffffff000000000000000000000000000000000000000000000000000000001690556007909152812091985062001aec9190620041ea565b6000898152601d6020526040812062001b0591620041ea565b6000898152601e6020526040812062001b1e91620041ea565b600089815260066020526040902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905562001b5f60028a62003c69565b5060a0880151604080516bffffffffffffffffffffffff909216825273ffffffffffffffffffffffffffffffffffffffff8c1660208301528a917fb38647142fbb1ea4c000fc4569b37a4e9a9f6313317b84ee3e5326c1a6cd06ff910160405180910390a28062001bd08162004e5c565b915050620015fb565b5073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166000908152601b602052604090205462001c2d90879062004b89565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166000908152601b60205260408120919091558b8b868167ffffffffffffffff81111562001c955762001c95620042d0565b60405190808252806020026020018201604052801562001cbf578160200160208202803683370190505b508988888860405160200162001cdd98979695949392919062005023565b60405160208183030381529060405290508973ffffffffffffffffffffffffffffffffffffffff16638e86139b6014600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c71249ab60038e73ffffffffffffffffffffffffffffffffffffffff1663aab9edd66040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001d99573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001dbf919062005102565b866040518463ffffffff1660e01b815260040162001de09392919062005127565b600060405180830381865afa15801562001dfe573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405262001e4691908101906200514e565b6040518263ffffffff1660e01b815260040162001e64919062004b29565b600060405180830381600087803b15801562001e7f57600080fd5b505af115801562001e94573d6000803e3d6000fd5b50506040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8d81166004830152602482018b90527f000000000000000000000000000000000000000000000000000000000000000016925063a9059cbb91506044016020604051808303816000875af115801562001f2e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001f54919062005187565b50505050505050505050505050565b6002336000908152601c602052604090205460ff16600381111562001f8c5762001f8c620045ec565b1415801562001fc257506003336000908152601c602052604090205460ff16600381111562001fbf5762001fbf620045ec565b14155b1562001ffa576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080808080808062002010888a018a62005372565b965096509650965096509650965060005b8751811015620022df57600073ffffffffffffffffffffffffffffffffffffffff1687828151811062002058576200205862004e17565b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff16036200216c5785818151811062002095576200209562004e17565b6020026020010151307f0000000000000000000000000000000000000000000000000000000000000000604051620020cd90620041dc565b73ffffffffffffffffffffffffffffffffffffffff938416815291831660208301529091166040820152606001604051809103906000f08015801562002117573d6000803e3d6000fd5b508782815181106200212d576200212d62004e17565b60200260200101516060019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250505b6200222488828151811062002185576200218562004e17565b6020026020010151888381518110620021a257620021a262004e17565b6020026020010151878481518110620021bf57620021bf62004e17565b6020026020010151878581518110620021dc57620021dc62004e17565b6020026020010151878681518110620021f957620021f962004e17565b602002602001015187878151811062002216576200221662004e17565b602002602001015162002e82565b87818151811062002239576200223962004e17565b60200260200101517f74931a144e43a50694897f241d973aecb5024c0e910f9bb80a163ea3c1cf5a7188838151811062002277576200227762004e17565b602002602001015160a0015133604051620022c29291906bffffffffffffffffffffffff92909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a280620022d68162004e5c565b91505062002021565b50505050505050505050565b600082815260046020908152604091829020825160e081018452815460ff81161515825263ffffffff6101008204811694830194909452650100000000008104841694820185905273ffffffffffffffffffffffffffffffffffffffff69010000000000000000009091041660608201526001909101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a083015278010000000000000000000000000000000000000000000000009004821660c08201529114620023e9576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818160a00151620023fb9190620054a3565b600084815260046020908152604080832060010180547fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff166c010000000000000000000000006bffffffffffffffffffffffff968716021790557f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168352601b909152902054620024a49184169062004e46565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166000818152601b6020526040908190209290925590517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526bffffffffffffffffffffffff841660448201526323b872dd906064016020604051808303816000875af11580156200255d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002583919062005187565b506040516bffffffffffffffffffffffff83168152339084907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a3505050565b6000818152600460209081526040808320815160e081018352815460ff81161515825263ffffffff610100820481169583019590955265010000000000810485169382019390935273ffffffffffffffffffffffffffffffffffffffff6901000000000000000000909304929092166060830152600101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490911660c082015290620026b660005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161490506000601260010160019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa15801562002759573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200277f9190620054cb565b9050826040015163ffffffff16600003620027c6576040517ffbc0357800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604083015163ffffffff908116146200280b576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b811580156200283e575060008481526005602052604090205473ffffffffffffffffffffffffffffffffffffffff163314155b1562002876576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816200288c576200288960328262004e46565b90505b6000848152600460205260409020805463ffffffff80841665010000000000027fffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffff90921691909117909155620028e890600290869062003c6916565b5060145460808401516bffffffffffffffffffffffff9182169160009116821115620029515760808501516200291f9083620054e5565b90508460a001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff16111562002951575060a08401515b808560a00151620029639190620054e5565b600087815260046020908152604080832060010180547fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff166c010000000000000000000000006bffffffffffffffffffffffff968716021790557f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168352601b90915290205462002a0c9183169062004b89565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166000908152601b602052604080822092909255905167ffffffffffffffff85169188917f91cb3bb75cfbd718bbfccc56b7f53d92d7048ef4ca39a3b7b7c6d4af1f7911819190a3505050505050565b600060606000806000634b56a42e60e01b88888860405160240162002aba939291906200550d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152905062002b45898262000681565b929c919b50995090975095505050505050565b62002b6262003c77565b62002b6d8162003cfa565b50565b60006060600080600080600062002b978860405180602001604052806000815250620009fb565b959e949d50929b5090995097509550909350915050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260018301602052604081205415155b90505b92915050565b6000806000601260010160019054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060008173ffffffffffffffffffffffffffffffffffffffff166385df51fd60018473ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa15801562002c7b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002ca19190620054cb565b62002cad919062004b89565b6040518263ffffffff1660e01b815260040162002ccc91815260200190565b602060405180830381865afa15801562002cea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002d109190620054cb565b601554604080516020810193909352309083015268010000000000000000900463ffffffff166060820152608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201209083015201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060045b600f81101562002e10578382828151811062002dcc5762002dcc62004e17565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508062002e078162004e5c565b91505062002dac565b5084600181111562002e265762002e26620045ec565b60f81b81600f8151811062002e3f5762002e3f62004e17565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535062002e798162005541565b95945050505050565b6012547e01000000000000000000000000000000000000000000000000000000000000900460ff161562002ee2576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60155483517401000000000000000000000000000000000000000090910463ffffffff16101562002f3f576040517fae7235df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108fc856020015163ffffffff16108062002f715750601554602086015163ffffffff64010000000090920482169116115b1562002fa9576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000868152600460205260409020546901000000000000000000900473ffffffffffffffffffffffffffffffffffffffff161562003013576040517f6e3b930b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000868152600460209081526040808320885181548a8501518b85015160608d01517fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000009093169315157fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff169390931761010063ffffffff92831602177fffffff000000000000000000000000000000000000000000000000ffffffffff1665010000000000938216939093027fffffff0000000000000000000000000000000000000000ffffffffffffffffff1692909217690100000000000000000073ffffffffffffffffffffffffffffffffffffffff9283160217835560808b01516001909301805460a08d015160c08e01516bffffffffffffffffffffffff9687167fffffffffffffffff000000000000000000000000000000000000000000000000909316929092176c010000000000000000000000009690911695909502949094177fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff1678010000000000000000000000000000000000000000000000009490931693909302919091179091556005835281842080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169189169190911790556007909152902062003206848262005584565b5060a085015173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166000908152601b60205260409020546200326c916bffffffffffffffffffffffff169062004e46565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166000908152601b6020908152604080832093909355888252601d905220620032cc838262005584565b506000868152601e60205260409020620032e7828262005584565b50620032f560028762003df1565b50505050505050565b3273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146200336e576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60008181526005602052604090205473ffffffffffffffffffffffffffffffffffffffff163314620033ce576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526004602052604090205465010000000000900463ffffffff9081161462002b6d576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818160045b600f811015620034bb577fff0000000000000000000000000000000000000000000000000000000000000082168382602081106200346f576200346f62004e17565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614620034a657506000949350505050565b80620034b28162004e5c565b9150506200342d565b5081600f1a6001811115620034d457620034d4620045ec565b949350505050565b600080600080846080015162ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156200356a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620035909190620056c6565b5094509092505050600081131580620035a857508142105b80620035cd5750828015620035cd5750620035c4824262004b89565b8463ffffffff16105b15620035de576018549650620035e2565b8096505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156200364e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620036749190620056c6565b50945090925050506000811315806200368c57508142105b80620036b15750828015620036b15750620036a8824262004b89565b8463ffffffff16105b15620036c2576019549550620036c6565b8095505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801562003732573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620037589190620056c6565b5094509092508891508790506200376f8a62003dff565b965096509650505050509193909250565b60008080876001811115620037995762003799620045ec565b03620037a9575061ea6062003803565b6001876001811115620037c057620037c0620045ec565b03620037d1575062014c0862003803565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008860c0015160016200381891906200571b565b620038289060ff16604062005737565b6015546200385c906103a4907801000000000000000000000000000000000000000000000000900463ffffffff1662004e46565b62003868919062004e46565b601354604080517fde9ee35e00000000000000000000000000000000000000000000000000000000815281519394506000938493610100900473ffffffffffffffffffffffffffffffffffffffff169263de9ee35e92600480820193918290030181865afa158015620038df573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003905919062005751565b909250905081836200391983601862004e46565b62003925919062005737565b60c08d0151620039379060016200571b565b620039489060ff166115e062005737565b62003954919062004e46565b62003960919062004e46565b6200396c908562004e46565b935060008b610140015173ffffffffffffffffffffffffffffffffffffffff166312544140856040518263ffffffff1660e01b8152600401620039b191815260200190565b602060405180830381865afa158015620039cf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620039f59190620054cb565b8c60a0015161ffff1662003a0a919062005737565b905060008062003a568e6040518060e001604052808f63ffffffff1681526020018a81526020018681526020018e81526020018d81526020018c81526020016000151581525062003ef9565b909250905062003a678183620054a3565b9e9d5050505050505050505050505050565b6060600083600181111562003a925762003a92620045ec565b0362003b5f576000848152600760205260409081902090517f6e04ff0d000000000000000000000000000000000000000000000000000000009162003ada9160240162005819565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152905062003c62565b600183600181111562003b765762003b76620045ec565b03620037d15760008280602001905181019062003b94919062005890565b6000868152600760205260409081902090519192507f40691db4000000000000000000000000000000000000000000000000000000009162003bdb918491602401620059a4565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152915062003c629050565b9392505050565b600062002bd9838362004086565b60005473ffffffffffffffffffffffffffffffffffffffff1633146200336e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401620011e6565b3373ffffffffffffffffffffffffffffffffffffffff82160362003d7b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620011e6565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600062002bd983836200418a565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801562003e70573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003e969190620056c6565b5093505092505060008213158062003ead57508042105b8062003ee157506000846080015162ffffff1611801562003ee1575062003ed5814262004b89565b846080015162ffffff16105b1562003ef2575050601a5492915050565b5092915050565b60008060008460a0015161ffff16846060015162003f18919062005737565b90508360c00151801562003f2b5750803a105b1562003f3457503a5b600084608001518560a0015186604001518760200151886000015162003f5b919062004e46565b62003f67908662005737565b62003f73919062004e46565b62003f7f919062005737565b62003f8b919062005a6c565b90506000866040015163ffffffff1664e8d4a5100062003fac919062005737565b608087015162003fc190633b9aca0062005737565b8760a00151896020015163ffffffff1689604001518a600001518862003fe8919062005737565b62003ff4919062004e46565b62004000919062005737565b6200400c919062005737565b62004018919062005a6c565b62004024919062004e46565b90506b033b2e3c9fd0803ce80000006200403f828462004e46565b111562004078576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9093509150505b9250929050565b600081815260018301602052604081205480156200417f576000620040ad60018362004b89565b8554909150600090620040c39060019062004b89565b90508181146200412f576000866000018281548110620040e757620040e762004e17565b90600052602060002001549050808760000184815481106200410d576200410d62004e17565b6000918252602080832090910192909255918252600188019052604090208390555b855486908062004143576200414362005aa8565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505062002bdc565b600091505062002bdc565b6000818152600183016020526040812054620041d35750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562002bdc565b50600062002bdc565b6103ca8062005ad883390190565b508054620041f89062004c47565b6000825580601f1062004209575050565b601f01602090049060005260206000209081019062002b6d91905b808211156200423a576000815560010162004224565b5090565b73ffffffffffffffffffffffffffffffffffffffff8116811462002b6d57600080fd5b803563ffffffff811681146200427657600080fd5b919050565b8035600281106200427657600080fd5b60008083601f8401126200429e57600080fd5b50813567ffffffffffffffff811115620042b757600080fd5b6020830191508360208285010111156200407f57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160e0810167ffffffffffffffff81118282101715620043255762004325620042d0565b60405290565b604051610100810167ffffffffffffffff81118282101715620043255762004325620042d0565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156200439c576200439c620042d0565b604052919050565b600067ffffffffffffffff821115620043c157620043c1620042d0565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112620043ff57600080fd5b8135620044166200441082620043a4565b62004352565b8181528460208386010111156200442c57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060008060e0898b0312156200446657600080fd5b883562004473816200423e565b97506200448360208a0162004261565b9650604089013562004495816200423e565b9550620044a560608a016200427b565b9450608089013567ffffffffffffffff80821115620044c357600080fd5b620044d18c838d016200428b565b909650945060a08b0135915080821115620044eb57600080fd5b620044f98c838d01620043ed565b935060c08b01359150808211156200451057600080fd5b506200451f8b828c01620043ed565b9150509295985092959890939650565b600080604083850312156200454357600080fd5b82359150602083013567ffffffffffffffff8111156200456257600080fd5b6200457085828601620043ed565b9150509250929050565b60005b83811015620045975781810151838201526020016200457d565b50506000910152565b60008151808452620045ba8160208601602086016200457a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600a811062004653577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b8415158152608060208201526000620046746080830186620045a0565b90506200468560408301856200461b565b82606083015295945050505050565b600080600060408486031215620046aa57600080fd5b83359250602084013567ffffffffffffffff811115620046c957600080fd5b620046d7868287016200428b565b9497909650939450505050565b600080600080600080600060a0888a0312156200470057600080fd5b87356200470d816200423e565b96506200471d6020890162004261565b955060408801356200472f816200423e565b9450606088013567ffffffffffffffff808211156200474d57600080fd5b6200475b8b838c016200428b565b909650945060808a01359150808211156200477557600080fd5b50620047848a828b016200428b565b989b979a50959850939692959293505050565b871515815260e060208201526000620047b460e0830189620045a0565b9050620047c560408301886200461b565b8560608301528460808301528360a08301528260c083015298975050505050505050565b600080600060408486031215620047ff57600080fd5b833567ffffffffffffffff808211156200481857600080fd5b818601915086601f8301126200482d57600080fd5b8135818111156200483d57600080fd5b8760208260051b85010111156200485357600080fd5b602092830195509350508401356200486b816200423e565b809150509250925092565b600080602083850312156200488a57600080fd5b823567ffffffffffffffff811115620048a257600080fd5b620048b0858286016200428b565b90969095509350505050565b80356bffffffffffffffffffffffff811681146200427657600080fd5b60008060408385031215620048ed57600080fd5b82359150620048ff60208401620048bc565b90509250929050565b6000602082840312156200491b57600080fd5b5035919050565b600067ffffffffffffffff8211156200493f576200493f620042d0565b5060051b60200190565b600082601f8301126200495b57600080fd5b813560206200496e620044108362004922565b82815260059290921b840181019181810190868411156200498e57600080fd5b8286015b84811015620049d357803567ffffffffffffffff811115620049b45760008081fd5b620049c48986838b0101620043ed565b84525091830191830162004992565b509695505050505050565b60008060008060608587031215620049f557600080fd5b84359350602085013567ffffffffffffffff8082111562004a1557600080fd5b62004a238883890162004949565b9450604087013591508082111562004a3a57600080fd5b5062004a49878288016200428b565b95989497509550505050565b60006020828403121562004a6857600080fd5b813562003c62816200423e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff80831681810362004ac05762004ac062004a75565b6001019392505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b602081526000620034d460208301848662004aca565b60208152600062002bd96020830184620045a0565b805162004276816200423e565b60006020828403121562004b5e57600080fd5b815162003c62816200423e565b6000825162004b7f8184602087016200457a565b9190910192915050565b8181038181111562002bdc5762002bdc62004a75565b801515811462002b6d57600080fd5b600082601f83011262004bc057600080fd5b815162004bd16200441082620043a4565b81815284602083860101111562004be757600080fd5b620034d48260208301602087016200457a565b6000806040838503121562004c0e57600080fd5b825162004c1b8162004b9f565b602084015190925067ffffffffffffffff81111562004c3957600080fd5b620045708582860162004bae565b600181811c9082168062004c5c57607f821691505b60208210810362004c96577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f82111562004cea57600081815260208120601f850160051c8101602086101562004cc55750805b601f850160051c820191505b8181101562004ce65782815560010162004cd1565b5050505b505050565b67ffffffffffffffff83111562004d0a5762004d0a620042d0565b62004d228362004d1b835462004c47565b8362004c9c565b6000601f84116001811462004d77576000851562004d405750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b17835562004e10565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b8281101562004dc8578685013582556020948501946001909201910162004da6565b508682101562004e04577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8082018082111562002bdc5762002bdc62004a75565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820362004e905762004e9062004a75565b5060010190565b600081518084526020808501945080840160005b8381101562004f565781518051151588528381015163ffffffff908116858a01526040808301519091169089015260608082015173ffffffffffffffffffffffffffffffffffffffff16908901526080808201516bffffffffffffffffffffffff169089015260a08082015162004f31828b01826bffffffffffffffffffffffff169052565b505060c09081015163ffffffff169088015260e0909601959082019060010162004eab565b509495945050505050565b600081518084526020808501945080840160005b8381101562004f5657815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010162004f75565b600082825180855260208086019550808260051b84010181860160005b8481101562005016577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe086840301895262005003838351620045a0565b9884019892509083019060010162004fc6565b5090979650505050505050565b60e081528760e082015260006101007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a11156200506057600080fd5b8960051b808c83860137830183810382016020850152620050848282018b62004e97565b91505082810360408401526200509b818962004f61565b90508281036060840152620050b1818862004f61565b90508281036080840152620050c7818762004fa9565b905082810360a0840152620050dd818662004fa9565b905082810360c0840152620050f3818562004fa9565b9b9a5050505050505050505050565b6000602082840312156200511557600080fd5b815160ff8116811462003c6257600080fd5b60ff8416815260ff8316602082015260606040820152600062002e796060830184620045a0565b6000602082840312156200516157600080fd5b815167ffffffffffffffff8111156200517957600080fd5b620034d48482850162004bae565b6000602082840312156200519a57600080fd5b815162003c628162004b9f565b600082601f830112620051b957600080fd5b81356020620051cc620044108362004922565b82815260059290921b84018101918181019086841115620051ec57600080fd5b8286015b84811015620049d35780358352918301918301620051f0565b600082601f8301126200521b57600080fd5b813560206200522e620044108362004922565b82815260e092830285018201928282019190878511156200524e57600080fd5b8387015b85811015620050165781818a0312156200526c5760008081fd5b62005276620042ff565b8135620052838162004b9f565b81526200529282870162004261565b868201526040620052a581840162004261565b90820152606082810135620052ba816200423e565b908201526080620052cd838201620048bc565b9082015260a0620052e0838201620048bc565b9082015260c0620052f383820162004261565b90820152845292840192810162005252565b600082601f8301126200531757600080fd5b813560206200532a620044108362004922565b82815260059290921b840181019181810190868411156200534a57600080fd5b8286015b84811015620049d357803562005364816200423e565b83529183019183016200534e565b600080600080600080600060e0888a0312156200538e57600080fd5b873567ffffffffffffffff80821115620053a757600080fd5b620053b58b838c01620051a7565b985060208a0135915080821115620053cc57600080fd5b620053da8b838c0162005209565b975060408a0135915080821115620053f157600080fd5b620053ff8b838c0162005305565b965060608a01359150808211156200541657600080fd5b620054248b838c0162005305565b955060808a01359150808211156200543b57600080fd5b620054498b838c0162004949565b945060a08a01359150808211156200546057600080fd5b6200546e8b838c0162004949565b935060c08a01359150808211156200548557600080fd5b50620054948a828b0162004949565b91505092959891949750929550565b6bffffffffffffffffffffffff81811683821601908082111562003ef25762003ef262004a75565b600060208284031215620054de57600080fd5b5051919050565b6bffffffffffffffffffffffff82811682821603908082111562003ef25762003ef262004a75565b60408152600062005522604083018662004fa9565b82810360208401526200553781858762004aca565b9695505050505050565b8051602080830151919081101562004c96577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b815167ffffffffffffffff811115620055a157620055a1620042d0565b620055b981620055b2845462004c47565b8462004c9c565b602080601f8311600181146200560f5760008415620055d85750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b17855562004ce6565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156200565e578886015182559484019460019091019084016200563d565b50858210156200569b57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b805169ffffffffffffffffffff811681146200427657600080fd5b600080600080600060a08688031215620056df57600080fd5b620056ea86620056ab565b94506020860151935060408601519250606086015191506200570f60808701620056ab565b90509295509295909350565b60ff818116838216019081111562002bdc5762002bdc62004a75565b808202811582820484141762002bdc5762002bdc62004a75565b600080604083850312156200576557600080fd5b505080516020909101519092909150565b60008154620057858162004c47565b808552602060018381168015620057a55760018114620057de576200580e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b89010195506200580e565b866000528260002060005b85811015620058065781548a8201860152908301908401620057e9565b890184019650505b505050505092915050565b60208152600062002bd9602083018462005776565b600082601f8301126200584057600080fd5b8151602062005853620044108362004922565b82815260059290921b840181019181810190868411156200587357600080fd5b8286015b84811015620049d3578051835291830191830162005877565b600060208284031215620058a357600080fd5b815167ffffffffffffffff80821115620058bc57600080fd5b908301906101008286031215620058d257600080fd5b620058dc6200432b565b82518152602083015160208201526040830151604082015260608301516060820152608083015160808201526200591660a0840162004b3e565b60a082015260c0830151828111156200592e57600080fd5b6200593c878286016200582e565b60c08301525060e0830151828111156200595557600080fd5b620059638782860162004bae565b60e08301525095945050505050565b600081518084526020808501945080840160005b8381101562004f565781518752958201959082019060010162005986565b60408152825160408201526020830151606082015260408301516080820152606083015160a0820152608083015160c082015273ffffffffffffffffffffffffffffffffffffffff60a08401511660e0820152600060c084015161010080818501525062005a1761014084018262005972565b905060e08501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08483030161012085015262005a558282620045a0565b915050828103602084015262002e79818562005776565b60008262005aa3577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe60c060405234801561001057600080fd5b506040516103ca3803806103ca83398101604081905261002f91610076565b600080546001600160a01b0319166001600160a01b039384161790559181166080521660a0526100b9565b80516001600160a01b038116811461007157600080fd5b919050565b60008060006060848603121561008b57600080fd5b6100948461005a565b92506100a26020850161005a565b91506100b06040850161005a565b90509250925092565b60805160a0516102e76100e36000396000603801526000818160c4015261011701526102e76000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806379188d161461007b578063f00e6a2a146100aa575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e808015610076573d6000f35b3d6000fd5b61008e6100893660046101c1565b6100ee565b6040805192151583526020830191909152015b60405180910390f35b60405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001681526020016100a1565b60008054819073ffffffffffffffffffffffffffffffffffffffff16331461011557600080fd5b7f00000000000000000000000000000000000000000000000000000000000000005a91505a61138881101561014957600080fd5b61138881039050856040820482031161016157600080fd5b50803b61016d57600080fd5b6000808551602087016000858af192505a610188908361029a565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080604083850312156101d457600080fd5b82359150602083013567ffffffffffffffff808211156101f357600080fd5b818501915085601f83011261020757600080fd5b81358181111561021957610219610192565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561025f5761025f610192565b8160405282815288602084870101111561027857600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b818103818111156102d4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea164736f6c6343000813000aa164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistryLogicB2_3\",\"name\":\"logicB\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientLinkLiquidity\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidFeed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOffchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOnchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyFinanceAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingOverrides\",\"name\":\"overrides\",\"type\":\"tuple\"}],\"name\":\"BillingConfigOverridden\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"BillingConfigOverrideRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"BillingConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newModule\",\"type\":\"address\"}],\"name\":\"ChainSpecificModuleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"payments\",\"type\":\"uint256[]\"}],\"name\":\"NOPsSettledOffchain\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"cancelUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"migrateUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedUpkeeps\",\"type\":\"bytes\"}],\"name\":\"receiveUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"enumAutomationRegistryBase2_3.Trigger\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"contractIERC20\",\"name\":\"billingToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x6101806040523480156200001257600080fd5b50604051620047863803806200478683398101604081905262000035916200062f565b80816001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b91906200062f565b826001600160a01b031663226cf83c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200010091906200062f565b836001600160a01b031663614486af6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200016591906200062f565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca91906200062f565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f91906200062f565b866001600160a01b031663a08714c06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200026e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200029491906200062f565b876001600160a01b031663c5b964e06040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002f9919062000656565b886001600160a01b031663ac4dc59a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000338573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200035e91906200062f565b3380600081620003b55760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620003e857620003e8816200056b565b5050506001600160a01b0380891660805287811660a05286811660c05285811660e052848116610100528316610120526025805483919060ff19166001838181111562000439576200043962000679565b0217905550806001600160a01b0316610140816001600160a01b03168152505060c0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200049a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004c091906200068f565b60ff1660a0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000504573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200052a91906200068f565b60ff16146200054c576040516301f86e1760e41b815260040160405180910390fd5b5050506001600160a01b039095166101605250620006b4945050505050565b336001600160a01b03821603620005c55760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620003ac565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b03811681146200062c57600080fd5b50565b6000602082840312156200064257600080fd5b81516200064f8162000616565b9392505050565b6000602082840312156200066957600080fd5b8151600281106200064f57600080fd5b634e487b7160e01b600052602160045260246000fd5b600060208284031215620006a257600080fd5b815160ff811681146200064f57600080fd5b60805160a05160c05160e0516101005161012051610140516101605161407262000714600039600081816088015260de01526000505060005050600081816111c701526114e00152600050506000505060005050600050506140726000f3fe608060405260043610620000865760003560e01c80638e86139b11620000555780638e86139b1462000192578063c62cf68414620001b7578063c804802214620001eb578063f2fde38b14620002105762000086565b8063349e8cca14620000ce57806379ba5097146200012857806385c1b0ba14620001405780638da5cb5b1462000165575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e808015620000c7573d6000f35b3d6000fd5b005b348015620000db57600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156200013557600080fd5b50620000cc62000235565b3480156200014d57600080fd5b50620000cc6200015f36600462002cb6565b62000338565b3480156200017257600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16620000fe565b3480156200019f57600080fd5b50620000cc620001b136600462002d8f565b6200108a565b348015620001c457600080fd5b50620001dc620001d636600462002f4d565b62001412565b6040519081526020016200011f565b348015620001f857600080fd5b50620000cc6200020a36600462003042565b620017bf565b3480156200021d57600080fd5b50620000cc6200022f3660046200305c565b62001c97565b60015473ffffffffffffffffffffffffffffffffffffffff163314620002bc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600173ffffffffffffffffffffffffffffffffffffffff82166000908152601c602052604090205460ff16600381111562000377576200037762003083565b14158015620003c35750600373ffffffffffffffffffffffffffffffffffffffff82166000908152601c602052604090205460ff166003811115620003c057620003c062003083565b14155b15620003fb576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60165473ffffffffffffffffffffffffffffffffffffffff166200044b576040517fd12d7d8d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082900362000487576040517f2c2fc94100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290528190819060008667ffffffffffffffff811115620004f157620004f162002dfa565b6040519080825280602002602001820160405280156200051b578160200160208202803683370190505b50905060008767ffffffffffffffff8111156200053c576200053c62002dfa565b604051908082528060200260200182016040528015620005d357816020015b604080516101208101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816200055b5790505b50905060008867ffffffffffffffff811115620005f457620005f462002dfa565b6040519080825280602002602001820160405280156200062957816020015b6060815260200190600190039081620006135790505b50905060008967ffffffffffffffff8111156200064a576200064a62002dfa565b6040519080825280602002602001820160405280156200067f57816020015b6060815260200190600190039081620006695790505b50905060008a67ffffffffffffffff811115620006a057620006a062002dfa565b604051908082528060200260200182016040528015620006d557816020015b6060815260200190600190039081620006bf5790505b50905060005b8b81101562000e62578c8c82818110620006f957620006f9620030b2565b602090810292909201356000818152600484526040808220815161012081018352815460ff8082161515835261010080830490911615159883019890985263ffffffff620100008204811694830194909452660100000000000081048416606083015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009091048116608083015260018301546fffffffffffffffffffffffffffffffff811660a08401526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08401527c0100000000000000000000000000000000000000000000000000000000900490931660e082015260029091015490911694810194909452909a5091985050819003620008545760008881526004602052604090206002015460c088015173ffffffffffffffffffffffffffffffffffffffff9091169a506bffffffffffffffffffffffff1698505b8973ffffffffffffffffffffffffffffffffffffffff1687610100015173ffffffffffffffffffffffffffffffffffffffff1614620009145773ffffffffffffffffffffffffffffffffffffffff8a16600090815260216020526040902054620008c0908a9062003110565b73ffffffffffffffffffffffffffffffffffffffff8b16600081815260216020526040902091909155620008f6908c8b62001caf565b86610100015199508660c001516bffffffffffffffffffffffff1698505b6200091f8862001d43565b60808701516040517f1a5da6c800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8d8116600483015290911690631a5da6c890602401600060405180830381600087803b1580156200098f57600080fd5b505af1158015620009a4573d6000803e3d6000fd5b5050505086858281518110620009be57620009be620030b2565b60200260200101819052506005600089815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1686828151811062000a125762000a12620030b2565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091018201526000898152600790915260409020805462000a519062003126565b80601f016020809104026020016040519081016040528092919081815260200182805462000a7f9062003126565b801562000ad05780601f1062000aa45761010080835404028352916020019162000ad0565b820191906000526020600020905b81548152906001019060200180831162000ab257829003601f168201915b505050505084828151811062000aea5762000aea620030b2565b6020026020010181905250601d6000898152602001908152602001600020805462000b159062003126565b80601f016020809104026020016040519081016040528092919081815260200182805462000b439062003126565b801562000b945780601f1062000b685761010080835404028352916020019162000b94565b820191906000526020600020905b81548152906001019060200180831162000b7657829003601f168201915b505050505083828151811062000bae5762000bae620030b2565b6020026020010181905250601e6000898152602001908152602001600020805462000bd99062003126565b80601f016020809104026020016040519081016040528092919081815260200182805462000c079062003126565b801562000c585780601f1062000c2c5761010080835404028352916020019162000c58565b820191906000526020600020905b81548152906001019060200180831162000c3a57829003601f168201915b505050505082828151811062000c725762000c72620030b2565b602090810291909101810191909152600089815260048252604080822080547fffff0000000000000000000000000000000000000000000000000000000000001681556001810183905560020180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055600790925290812062000cf89162002c19565b6000888152601d6020526040812062000d119162002c19565b6000888152601e6020526040812062000d2a9162002c19565b600088815260066020526040902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905562000d6b60028962001dfa565b5060c0870151604080516bffffffffffffffffffffffff909216825273ffffffffffffffffffffffffffffffffffffffff8d16602083015289917fb38647142fbb1ea4c000fc4569b37a4e9a9f6313317b84ee3e5326c1a6cd06ff910160405180910390a262000ddd60018d62003110565b810362000e4d5773ffffffffffffffffffffffffffffffffffffffff8a1660009081526021602052604090205462000e17908a9062003110565b73ffffffffffffffffffffffffffffffffffffffff8b1660008181526021602052604090209190915562000e4d908c8b62001caf565b8062000e59816200317b565b915050620006db565b5060008c8c868167ffffffffffffffff81111562000e845762000e8462002dfa565b60405190808252806020026020018201604052801562000eae578160200160208202803683370190505b508988888860405160200162000ecc989796959493929190620033ad565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282526016547faab9edd6000000000000000000000000000000000000000000000000000000008452915190935073ffffffffffffffffffffffffffffffffffffffff808f1693638e86139b939091169163c71249ab91600491869163aab9edd6918482019160209190819003860181865afa15801562000f7c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000fa291906200348c565b866040518463ffffffff1660e01b815260040162000fc393929190620034b1565b600060405180830381865afa15801562000fe1573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052620010299190810190620034d8565b6040518263ffffffff1660e01b81526004016200104791906200354f565b600060405180830381600087803b1580156200106257600080fd5b505af115801562001077573d6000803e3d6000fd5b5050505050505050505050505050505050565b6002336000908152601c602052604090205460ff166003811115620010b357620010b362003083565b14158015620010e957506003336000908152601c602052604090205460ff166003811115620010e657620010e662003083565b14155b1562001121576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080808080808062001137888a018a62003876565b965096509650965096509650965060005b87518110156200140657600073ffffffffffffffffffffffffffffffffffffffff168782815181106200117f576200117f620030b2565b60200260200101516080015173ffffffffffffffffffffffffffffffffffffffff16036200129357858181518110620011bc57620011bc620030b2565b6020026020010151307f0000000000000000000000000000000000000000000000000000000000000000604051620011f49062002c58565b73ffffffffffffffffffffffffffffffffffffffff938416815291831660208301529091166040820152606001604051809103906000f0801580156200123e573d6000803e3d6000fd5b50878281518110620012545762001254620030b2565b60200260200101516080019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250505b6200134b888281518110620012ac57620012ac620030b2565b6020026020010151888381518110620012c957620012c9620030b2565b6020026020010151878481518110620012e657620012e6620030b2565b6020026020010151878581518110620013035762001303620030b2565b6020026020010151878681518110620013205762001320620030b2565b60200260200101518787815181106200133d576200133d620030b2565b602002602001015162001e11565b878181518110620013605762001360620030b2565b60200260200101517f74931a144e43a50694897f241d973aecb5024c0e910f9bb80a163ea3c1cf5a718883815181106200139e576200139e620030b2565b602002602001015160c0015133604051620013e99291906bffffffffffffffffffffffff92909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a280620013fd816200317b565b91505062001148565b50505050505050505050565b6000805473ffffffffffffffffffffffffffffffffffffffff163314801590620014465750620014446009336200232e565b155b156200147e576040517fd48b678b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8a163b620014cd576040517f09ee12d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b620014d8876200235e565b905060008a307f00000000000000000000000000000000000000000000000000000000000000006040516200150d9062002c58565b73ffffffffffffffffffffffffffffffffffffffff938416815291831660208301529091166040820152606001604051809103906000f08015801562001557573d6000803e3d6000fd5b50905062001648826040518061012001604052806000151581526020016000151581526020018d63ffffffff16815260200163ffffffff801681526020018473ffffffffffffffffffffffffffffffffffffffff16815260200160006fffffffffffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff168152602001600063ffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff168152508b89898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508b92508a915062001e119050565b601680547c0100000000000000000000000000000000000000000000000000000000900463ffffffff1690601c6200168083620039a7565b91906101000a81548163ffffffff021916908363ffffffff16021790555050817fbae366358c023f887e791d7a62f2e4316f1026bd77f6fb49501a917b3bc5d0128b8b604051620016f992919063ffffffff92909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a2817fcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d878760405162001735929190620039cd565b60405180910390a2817f2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d5664856040516200176f91906200354f565b60405180910390a2817f3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf485084604051620017a991906200354f565b60405180910390a2509998505050505050505050565b6000818152600460209081526040808320815161012081018352815460ff8082161515835261010080830490911615159583019590955263ffffffff620100008204811694830194909452660100000000000081048416606083015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009091048116608083015260018301546fffffffffffffffffffffffffffffffff811660a08401526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08401527c0100000000000000000000000000000000000000000000000000000000900490931660e08201526002909101549091169181019190915290620018e360005473ffffffffffffffffffffffffffffffffffffffff1690565b61010083015173ffffffffffffffffffffffffffffffffffffffff90811660009081526022602090815260408083206002015460155482517f57e871e70000000000000000000000000000000000000000000000000000000081529251968616331497506bffffffffffffffffffffffff90911695939416926357e871e7926004808401939192918290030181865afa15801562001985573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620019ab919062003a1a565b9050836060015163ffffffff16600003620019f2576040517ffbc0357800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606084015163ffffffff9081161462001a37576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8215801562001a6a575060008581526005602052604090205473ffffffffffffffffffffffffffffffffffffffff163314155b1562001aa2576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8262001ab85762001ab560328262003a34565b90505b6000858152600460205260409020805463ffffffff8084166601000000000000027fffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffffff9092169190911790915562001b1590600290879062001dfa16565b506000826bffffffffffffffffffffffff168560a001516fffffffffffffffffffffffffffffffff16101562001b885760a085015162001b56908462003a4a565b90508460c001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff16111562001b88575060c08401515b808560c0015162001b9a919062003a4a565b600087815260046020908152604080832060010180547fffffffff000000000000000000000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000006bffffffffffffffffffffffff9687160217905561010089015173ffffffffffffffffffffffffffffffffffffffff168352602190915290205462001c2c9183169062003110565b61010086015173ffffffffffffffffffffffffffffffffffffffff1660009081526021602052604080822092909255905167ffffffffffffffff84169188917f91cb3bb75cfbd718bbfccc56b7f53d92d7048ef4ca39a3b7b7c6d4af1f7911819190a3505050505050565b62001ca1620025fd565b62001cac8162002682565b50565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905262001d3e90849062002779565b505050565b60008181526005602052604090205473ffffffffffffffffffffffffffffffffffffffff16331462001da1576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600460205260409020546601000000000000900463ffffffff9081161462001cac576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600062001e0883836200288c565b90505b92915050565b601454760100000000000000000000000000000000000000000000900460ff161562001e69576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60175483517c010000000000000000000000000000000000000000000000000000000090910463ffffffff16101562001ece576040517fae7235df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108fc856040015163ffffffff16108062001f145750601654604086015163ffffffff780100000000000000000000000000000000000000000000000090920482169116115b1562001f4c576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000868152600460205260409020546a0100000000000000000000900473ffffffffffffffffffffffffffffffffffffffff161562001fb7576040517f6e3b930b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61010085015173ffffffffffffffffffffffffffffffffffffffff90811660009081526022602052604090205467010000000000000090041662002027576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b846004600088815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff02191690831515021790555060408201518160000160026101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160066101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600a6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a08201518160010160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555060c08201518160010160106101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555060e082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050836005600088815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550826007600088815260200190815260200160002090816200226c919062003ac4565b5060c085015161010086015173ffffffffffffffffffffffffffffffffffffffff16600090815260216020526040902054620022b7916bffffffffffffffffffffffff169062003a34565b61010086015173ffffffffffffffffffffffffffffffffffffffff16600090815260216020908152604080832093909355888252601d905220620022fc838262003ac4565b506000868152601e6020526040902062002317828262003ac4565b506200232560028762002997565b50505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600183016020526040812054151562001e08565b601554604080517f57e871e70000000000000000000000000000000000000000000000000000000081529051600092839273ffffffffffffffffffffffffffffffffffffffff90911691839183916385df51fd9160019184916357e871e79160048083019260209291908290030181865afa158015620023e2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002408919062003a1a565b62002414919062003110565b6040518263ffffffff1660e01b81526004016200243391815260200190565b602060405180830381865afa15801562002451573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002477919062003a1a565b60165460408051602081019390935230908301527c0100000000000000000000000000000000000000000000000000000000900463ffffffff166060820152608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201209083015201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060045b600f8110156200258b5783828281518110620025475762002547620030b2565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508062002582816200317b565b91505062002527565b50846001811115620025a157620025a162003083565b60f81b81600f81518110620025ba57620025ba620030b2565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350620025f48162003beb565b95945050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331462002680576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401620002b3565b565b3373ffffffffffffffffffffffffffffffffffffffff82160362002703576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620002b3565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000620027dd826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16620029a59092919063ffffffff16565b80519091501562001d3e5780806020019051810190620027fe919062003c2e565b62001d3e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401620002b3565b6000818152600183016020526040812054801562002985576000620028b360018362003110565b8554909150600090620028c99060019062003110565b905081811462002935576000866000018281548110620028ed57620028ed620030b2565b9060005260206000200154905080876000018481548110620029135762002913620030b2565b6000918252602080832090910192909255918252600188019052604090208390555b855486908062002949576200294962003c4e565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505062001e0b565b600091505062001e0b565b5092915050565b600062001e088383620029be565b6060620029b6848460008562002a10565b949350505050565b600081815260018301602052604081205462002a075750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562001e0b565b50600062001e0b565b60608247101562002aa4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401620002b3565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405162002acf919062003c7d565b60006040518083038185875af1925050503d806000811462002b0e576040519150601f19603f3d011682016040523d82523d6000602084013e62002b13565b606091505b509150915062002b268783838762002b31565b979650505050505050565b6060831562002bcc57825160000362002bc45773ffffffffffffffffffffffffffffffffffffffff85163b62002bc4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620002b3565b5081620029b6565b620029b6838381511562002be35781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620002b391906200354f565b50805462002c279062003126565b6000825580601f1062002c38575050565b601f01602090049060005260206000209081019062001cac919062002c66565b6103ca8062003c9c83390190565b5b8082111562002c7d576000815560010162002c67565b5090565b73ffffffffffffffffffffffffffffffffffffffff8116811462001cac57600080fd5b803562002cb18162002c81565b919050565b60008060006040848603121562002ccc57600080fd5b833567ffffffffffffffff8082111562002ce557600080fd5b818601915086601f83011262002cfa57600080fd5b81358181111562002d0a57600080fd5b8760208260051b850101111562002d2057600080fd5b6020928301955093505084013562002d388162002c81565b809150509250925092565b60008083601f84011262002d5657600080fd5b50813567ffffffffffffffff81111562002d6f57600080fd5b60208301915083602082850101111562002d8857600080fd5b9250929050565b6000806020838503121562002da357600080fd5b823567ffffffffffffffff81111562002dbb57600080fd5b62002dc98582860162002d43565b90969095509350505050565b803563ffffffff8116811462002cb157600080fd5b80356002811062002cb157600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171562002e505762002e5062002dfa565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171562002ea05762002ea062002dfa565b604052919050565b600067ffffffffffffffff82111562002ec55762002ec562002dfa565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011262002f0357600080fd5b813562002f1a62002f148262002ea8565b62002e56565b81815284602083860101111562002f3057600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060008060006101008a8c03121562002f6d57600080fd5b62002f788a62002ca4565b985062002f8860208b0162002dd5565b975062002f9860408b0162002ca4565b965062002fa860608b0162002dea565b955062002fb860808b0162002ca4565b945060a08a013567ffffffffffffffff8082111562002fd657600080fd5b62002fe48d838e0162002d43565b909650945060c08c013591508082111562002ffe57600080fd5b6200300c8d838e0162002ef1565b935060e08c01359150808211156200302357600080fd5b50620030328c828d0162002ef1565b9150509295985092959850929598565b6000602082840312156200305557600080fd5b5035919050565b6000602082840312156200306f57600080fd5b81356200307c8162002c81565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8181038181111562001e0b5762001e0b620030e1565b600181811c908216806200313b57607f821691505b60208210810362003175577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203620031af57620031af620030e1565b5060010190565b600081518084526020808501945080840160005b838110156200328f5781518051151588528381015115158489015260408082015163ffffffff908116918a01919091526060808301518216908a015260808083015173ffffffffffffffffffffffffffffffffffffffff908116918b019190915260a0808401516fffffffffffffffffffffffffffffffff16908b015260c0808401516bffffffffffffffffffffffff16908b015260e080840151909216918a01919091526101009182015116908801526101209096019590820190600101620031ca565b509495945050505050565b600081518084526020808501945080840160005b838110156200328f57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101620032ae565b60005b83811015620032ff578181015183820152602001620032e5565b50506000910152565b6000815180845262003322816020860160208601620032e2565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600081518084526020808501808196508360051b8101915082860160005b85811015620033a05782840389526200338d84835162003308565b9885019893509084019060010162003372565b5091979650505050505050565b60e081528760e082015260006101007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a1115620033ea57600080fd5b8960051b808c838601378301838103820160208501526200340e8282018b620031b6565b91505082810360408401526200342581896200329a565b905082810360608401526200343b81886200329a565b9050828103608084015262003451818762003354565b905082810360a084015262003467818662003354565b905082810360c08401526200347d818562003354565b9b9a5050505050505050505050565b6000602082840312156200349f57600080fd5b815160ff811681146200307c57600080fd5b60ff8416815260ff83166020820152606060408201526000620025f4606083018462003308565b600060208284031215620034eb57600080fd5b815167ffffffffffffffff8111156200350357600080fd5b8201601f810184136200351557600080fd5b80516200352662002f148262002ea8565b8181528560208385010111156200353c57600080fd5b620025f4826020830160208601620032e2565b60208152600062001e08602083018462003308565b600067ffffffffffffffff82111562003581576200358162002dfa565b5060051b60200190565b600082601f8301126200359d57600080fd5b81356020620035b062002f148362003564565b82815260059290921b84018101918181019086841115620035d057600080fd5b8286015b84811015620035ed5780358352918301918301620035d4565b509695505050505050565b801515811462001cac57600080fd5b803562002cb181620035f8565b80356fffffffffffffffffffffffffffffffff8116811462002cb157600080fd5b80356bffffffffffffffffffffffff8116811462002cb157600080fd5b600082601f8301126200366457600080fd5b813560206200367762002f148362003564565b82815261012092830285018201928282019190878511156200369857600080fd5b8387015b85811015620037725781818a031215620036b65760008081fd5b620036c062002e29565b620036cb8262003607565b8152620036da86830162003607565b868201526040620036ed81840162002dd5565b9082015260606200370083820162002dd5565b9082015260806200371383820162002ca4565b9082015260a06200372683820162003614565b9082015260c06200373983820162003635565b9082015260e06200374c83820162002dd5565b908201526101006200376083820162002ca4565b9082015284529284019281016200369c565b5090979650505050505050565b600082601f8301126200379157600080fd5b81356020620037a462002f148362003564565b82815260059290921b84018101918181019086841115620037c457600080fd5b8286015b84811015620035ed578035620037de8162002c81565b8352918301918301620037c8565b600082601f830112620037fe57600080fd5b813560206200381162002f148362003564565b82815260059290921b840181019181810190868411156200383157600080fd5b8286015b84811015620035ed57803567ffffffffffffffff811115620038575760008081fd5b620038678986838b010162002ef1565b84525091830191830162003835565b600080600080600080600060e0888a0312156200389257600080fd5b873567ffffffffffffffff80821115620038ab57600080fd5b620038b98b838c016200358b565b985060208a0135915080821115620038d057600080fd5b620038de8b838c0162003652565b975060408a0135915080821115620038f557600080fd5b620039038b838c016200377f565b965060608a01359150808211156200391a57600080fd5b620039288b838c016200377f565b955060808a01359150808211156200393f57600080fd5b6200394d8b838c01620037ec565b945060a08a01359150808211156200396457600080fd5b620039728b838c01620037ec565b935060c08a01359150808211156200398957600080fd5b50620039988a828b01620037ec565b91505092959891949750929550565b600063ffffffff808316818103620039c357620039c3620030e1565b6001019392505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b60006020828403121562003a2d57600080fd5b5051919050565b8082018082111562001e0b5762001e0b620030e1565b6bffffffffffffffffffffffff828116828216039080821115620029905762002990620030e1565b601f82111562001d3e57600081815260208120601f850160051c8101602086101562003a9b5750805b601f850160051c820191505b8181101562003abc5782815560010162003aa7565b505050505050565b815167ffffffffffffffff81111562003ae15762003ae162002dfa565b62003af98162003af2845462003126565b8462003a72565b602080601f83116001811462003b4f576000841562003b185750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b17855562003abc565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101562003b9e5788860151825594840194600190910190840162003b7d565b508582101562003bdb57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b8051602080830151919081101562003175577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b60006020828403121562003c4157600080fd5b81516200307c81620035f8565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825162003c91818460208701620032e2565b919091019291505056fe60c060405234801561001057600080fd5b506040516103ca3803806103ca83398101604081905261002f91610076565b600080546001600160a01b0319166001600160a01b039384161790559181166080521660a0526100b9565b80516001600160a01b038116811461007157600080fd5b919050565b60008060006060848603121561008b57600080fd5b6100948461005a565b92506100a26020850161005a565b91506100b06040850161005a565b90509250925092565b60805160a0516102e76100e36000396000603801526000818160c4015261011701526102e76000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806379188d161461007b578063f00e6a2a146100aa575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e808015610076573d6000f35b3d6000fd5b61008e6100893660046101c1565b6100ee565b6040805192151583526020830191909152015b60405180910390f35b60405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001681526020016100a1565b60008054819073ffffffffffffffffffffffffffffffffffffffff16331461011557600080fd5b7f00000000000000000000000000000000000000000000000000000000000000005a91505a61138881101561014957600080fd5b61138881039050856040820482031161016157600080fd5b50803b61016d57600080fd5b6000808551602087016000858af192505a610188908361029a565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080604083850312156101d457600080fd5b82359150602083013567ffffffffffffffff808211156101f357600080fd5b818501915085601f83011261020757600080fd5b81358181111561021957610219610192565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561025f5761025f610192565b8160405282815288602084870101111561027857600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b818103818111156102d4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea164736f6c6343000813000aa164736f6c6343000813000a", } var AutomationRegistryLogicAABI = AutomationRegistryLogicAMetaData.ABI @@ -233,18 +240,6 @@ func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) Acce return _AutomationRegistryLogicA.Contract.AcceptOwnership(&_AutomationRegistryLogicA.TransactOpts) } -func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) AddFunds(opts *bind.TransactOpts, id *big.Int, amount *big.Int) (*types.Transaction, error) { - return _AutomationRegistryLogicA.contract.Transact(opts, "addFunds", id, amount) -} - -func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) AddFunds(id *big.Int, amount *big.Int) (*types.Transaction, error) { - return _AutomationRegistryLogicA.Contract.AddFunds(&_AutomationRegistryLogicA.TransactOpts, id, amount) -} - -func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) AddFunds(id *big.Int, amount *big.Int) (*types.Transaction, error) { - return _AutomationRegistryLogicA.Contract.AddFunds(&_AutomationRegistryLogicA.TransactOpts, id, amount) -} - func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) CancelUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { return _AutomationRegistryLogicA.contract.Transact(opts, "cancelUpkeep", id) } @@ -257,54 +252,6 @@ func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) Canc return _AutomationRegistryLogicA.Contract.CancelUpkeep(&_AutomationRegistryLogicA.TransactOpts, id) } -func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) CheckCallback(opts *bind.TransactOpts, id *big.Int, values [][]byte, extraData []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicA.contract.Transact(opts, "checkCallback", id, values, extraData) -} - -func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) CheckCallback(id *big.Int, values [][]byte, extraData []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicA.Contract.CheckCallback(&_AutomationRegistryLogicA.TransactOpts, id, values, extraData) -} - -func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) CheckCallback(id *big.Int, values [][]byte, extraData []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicA.Contract.CheckCallback(&_AutomationRegistryLogicA.TransactOpts, id, values, extraData) -} - -func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) CheckUpkeep(opts *bind.TransactOpts, id *big.Int, triggerData []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicA.contract.Transact(opts, "checkUpkeep", id, triggerData) -} - -func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) CheckUpkeep(id *big.Int, triggerData []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicA.Contract.CheckUpkeep(&_AutomationRegistryLogicA.TransactOpts, id, triggerData) -} - -func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) CheckUpkeep(id *big.Int, triggerData []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicA.Contract.CheckUpkeep(&_AutomationRegistryLogicA.TransactOpts, id, triggerData) -} - -func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) CheckUpkeep0(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { - return _AutomationRegistryLogicA.contract.Transact(opts, "checkUpkeep0", id) -} - -func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) CheckUpkeep0(id *big.Int) (*types.Transaction, error) { - return _AutomationRegistryLogicA.Contract.CheckUpkeep0(&_AutomationRegistryLogicA.TransactOpts, id) -} - -func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) CheckUpkeep0(id *big.Int) (*types.Transaction, error) { - return _AutomationRegistryLogicA.Contract.CheckUpkeep0(&_AutomationRegistryLogicA.TransactOpts, id) -} - -func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) ExecuteCallback(opts *bind.TransactOpts, id *big.Int, payload []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicA.contract.Transact(opts, "executeCallback", id, payload) -} - -func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) ExecuteCallback(id *big.Int, payload []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicA.Contract.ExecuteCallback(&_AutomationRegistryLogicA.TransactOpts, id, payload) -} - -func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) ExecuteCallback(id *big.Int, payload []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicA.Contract.ExecuteCallback(&_AutomationRegistryLogicA.TransactOpts, id, payload) -} - func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) MigrateUpkeeps(opts *bind.TransactOpts, ids []*big.Int, destination common.Address) (*types.Transaction, error) { return _AutomationRegistryLogicA.contract.Transact(opts, "migrateUpkeeps", ids, destination) } @@ -329,40 +276,16 @@ func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) Rece return _AutomationRegistryLogicA.Contract.ReceiveUpkeeps(&_AutomationRegistryLogicA.TransactOpts, encodedUpkeeps) } -func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) RegisterUpkeep(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicA.contract.Transact(opts, "registerUpkeep", target, gasLimit, admin, triggerType, checkData, triggerConfig, offchainConfig) -} - -func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) RegisterUpkeep(target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicA.Contract.RegisterUpkeep(&_AutomationRegistryLogicA.TransactOpts, target, gasLimit, admin, triggerType, checkData, triggerConfig, offchainConfig) -} - -func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) RegisterUpkeep(target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicA.Contract.RegisterUpkeep(&_AutomationRegistryLogicA.TransactOpts, target, gasLimit, admin, triggerType, checkData, triggerConfig, offchainConfig) -} - -func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) RegisterUpkeep0(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicA.contract.Transact(opts, "registerUpkeep0", target, gasLimit, admin, checkData, offchainConfig) +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) RegisterUpkeep(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, billingToken common.Address, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "registerUpkeep", target, gasLimit, admin, triggerType, billingToken, checkData, triggerConfig, offchainConfig) } -func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) RegisterUpkeep0(target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicA.Contract.RegisterUpkeep0(&_AutomationRegistryLogicA.TransactOpts, target, gasLimit, admin, checkData, offchainConfig) +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) RegisterUpkeep(target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, billingToken common.Address, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.RegisterUpkeep(&_AutomationRegistryLogicA.TransactOpts, target, gasLimit, admin, triggerType, billingToken, checkData, triggerConfig, offchainConfig) } -func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) RegisterUpkeep0(target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicA.Contract.RegisterUpkeep0(&_AutomationRegistryLogicA.TransactOpts, target, gasLimit, admin, checkData, offchainConfig) -} - -func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) SetUpkeepTriggerConfig(opts *bind.TransactOpts, id *big.Int, triggerConfig []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicA.contract.Transact(opts, "setUpkeepTriggerConfig", id, triggerConfig) -} - -func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) SetUpkeepTriggerConfig(id *big.Int, triggerConfig []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicA.Contract.SetUpkeepTriggerConfig(&_AutomationRegistryLogicA.TransactOpts, id, triggerConfig) -} - -func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) SetUpkeepTriggerConfig(id *big.Int, triggerConfig []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicA.Contract.SetUpkeepTriggerConfig(&_AutomationRegistryLogicA.TransactOpts, id, triggerConfig) +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) RegisterUpkeep(target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, billingToken common.Address, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.RegisterUpkeep(&_AutomationRegistryLogicA.TransactOpts, target, gasLimit, admin, triggerType, billingToken, checkData, triggerConfig, offchainConfig) } func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { @@ -517,6 +440,261 @@ func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseAdminPri return event, nil } +type AutomationRegistryLogicABillingConfigOverriddenIterator struct { + Event *AutomationRegistryLogicABillingConfigOverridden + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicABillingConfigOverriddenIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicABillingConfigOverridden) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicABillingConfigOverridden) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *AutomationRegistryLogicABillingConfigOverriddenIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicABillingConfigOverriddenIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicABillingConfigOverridden struct { + Id *big.Int + Overrides AutomationRegistryBase23BillingOverrides + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterBillingConfigOverridden(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicABillingConfigOverriddenIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "BillingConfigOverridden", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicABillingConfigOverriddenIterator{contract: _AutomationRegistryLogicA.contract, event: "BillingConfigOverridden", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchBillingConfigOverridden(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicABillingConfigOverridden, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "BillingConfigOverridden", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicABillingConfigOverridden) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "BillingConfigOverridden", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseBillingConfigOverridden(log types.Log) (*AutomationRegistryLogicABillingConfigOverridden, error) { + event := new(AutomationRegistryLogicABillingConfigOverridden) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "BillingConfigOverridden", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicABillingConfigOverrideRemovedIterator struct { + Event *AutomationRegistryLogicABillingConfigOverrideRemoved + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicABillingConfigOverrideRemovedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicABillingConfigOverrideRemoved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicABillingConfigOverrideRemoved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *AutomationRegistryLogicABillingConfigOverrideRemovedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicABillingConfigOverrideRemovedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicABillingConfigOverrideRemoved struct { + Id *big.Int + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterBillingConfigOverrideRemoved(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicABillingConfigOverrideRemovedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "BillingConfigOverrideRemoved", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicABillingConfigOverrideRemovedIterator{contract: _AutomationRegistryLogicA.contract, event: "BillingConfigOverrideRemoved", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchBillingConfigOverrideRemoved(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicABillingConfigOverrideRemoved, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "BillingConfigOverrideRemoved", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicABillingConfigOverrideRemoved) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "BillingConfigOverrideRemoved", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseBillingConfigOverrideRemoved(log types.Log) (*AutomationRegistryLogicABillingConfigOverrideRemoved, error) { + event := new(AutomationRegistryLogicABillingConfigOverrideRemoved) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "BillingConfigOverrideRemoved", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + type AutomationRegistryLogicABillingConfigSetIterator struct { Event *AutomationRegistryLogicABillingConfigSet @@ -1078,42 +1256,42 @@ func (it *AutomationRegistryLogicAFeesWithdrawnIterator) Close() error { } type AutomationRegistryLogicAFeesWithdrawn struct { - Recipient common.Address AssetAddress common.Address + Recipient common.Address Amount *big.Int Raw types.Log } -func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterFeesWithdrawn(opts *bind.FilterOpts, recipient []common.Address, assetAddress []common.Address) (*AutomationRegistryLogicAFeesWithdrawnIterator, error) { +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterFeesWithdrawn(opts *bind.FilterOpts, assetAddress []common.Address, recipient []common.Address) (*AutomationRegistryLogicAFeesWithdrawnIterator, error) { - var recipientRule []interface{} - for _, recipientItem := range recipient { - recipientRule = append(recipientRule, recipientItem) - } var assetAddressRule []interface{} for _, assetAddressItem := range assetAddress { assetAddressRule = append(assetAddressRule, assetAddressItem) } + var recipientRule []interface{} + for _, recipientItem := range recipient { + recipientRule = append(recipientRule, recipientItem) + } - logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "FeesWithdrawn", recipientRule, assetAddressRule) + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "FeesWithdrawn", assetAddressRule, recipientRule) if err != nil { return nil, err } return &AutomationRegistryLogicAFeesWithdrawnIterator{contract: _AutomationRegistryLogicA.contract, event: "FeesWithdrawn", logs: logs, sub: sub}, nil } -func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchFeesWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAFeesWithdrawn, recipient []common.Address, assetAddress []common.Address) (event.Subscription, error) { +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchFeesWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAFeesWithdrawn, assetAddress []common.Address, recipient []common.Address) (event.Subscription, error) { - var recipientRule []interface{} - for _, recipientItem := range recipient { - recipientRule = append(recipientRule, recipientItem) - } var assetAddressRule []interface{} for _, assetAddressItem := range assetAddress { assetAddressRule = append(assetAddressRule, assetAddressItem) } + var recipientRule []interface{} + for _, recipientItem := range recipient { + recipientRule = append(recipientRule, recipientItem) + } - logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "FeesWithdrawn", recipientRule, assetAddressRule) + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "FeesWithdrawn", assetAddressRule, recipientRule) if err != nil { return nil, err } @@ -1548,6 +1726,124 @@ func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseInsuffic return event, nil } +type AutomationRegistryLogicANOPsSettledOffchainIterator struct { + Event *AutomationRegistryLogicANOPsSettledOffchain + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicANOPsSettledOffchainIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicANOPsSettledOffchain) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicANOPsSettledOffchain) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *AutomationRegistryLogicANOPsSettledOffchainIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicANOPsSettledOffchainIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicANOPsSettledOffchain struct { + Payees []common.Address + Payments []*big.Int + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterNOPsSettledOffchain(opts *bind.FilterOpts) (*AutomationRegistryLogicANOPsSettledOffchainIterator, error) { + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "NOPsSettledOffchain") + if err != nil { + return nil, err + } + return &AutomationRegistryLogicANOPsSettledOffchainIterator{contract: _AutomationRegistryLogicA.contract, event: "NOPsSettledOffchain", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchNOPsSettledOffchain(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicANOPsSettledOffchain) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "NOPsSettledOffchain") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicANOPsSettledOffchain) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "NOPsSettledOffchain", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseNOPsSettledOffchain(log types.Log) (*AutomationRegistryLogicANOPsSettledOffchain, error) { + event := new(AutomationRegistryLogicANOPsSettledOffchain) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "NOPsSettledOffchain", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + type AutomationRegistryLogicAOwnershipTransferRequestedIterator struct { Event *AutomationRegistryLogicAOwnershipTransferRequested @@ -4715,6 +5011,10 @@ func (_AutomationRegistryLogicA *AutomationRegistryLogicA) ParseLog(log types.Lo switch log.Topics[0] { case _AutomationRegistryLogicA.abi.Events["AdminPrivilegeConfigSet"].ID: return _AutomationRegistryLogicA.ParseAdminPrivilegeConfigSet(log) + case _AutomationRegistryLogicA.abi.Events["BillingConfigOverridden"].ID: + return _AutomationRegistryLogicA.ParseBillingConfigOverridden(log) + case _AutomationRegistryLogicA.abi.Events["BillingConfigOverrideRemoved"].ID: + return _AutomationRegistryLogicA.ParseBillingConfigOverrideRemoved(log) case _AutomationRegistryLogicA.abi.Events["BillingConfigSet"].ID: return _AutomationRegistryLogicA.ParseBillingConfigSet(log) case _AutomationRegistryLogicA.abi.Events["CancelledUpkeepReport"].ID: @@ -4731,6 +5031,8 @@ func (_AutomationRegistryLogicA *AutomationRegistryLogicA) ParseLog(log types.Lo return _AutomationRegistryLogicA.ParseFundsWithdrawn(log) case _AutomationRegistryLogicA.abi.Events["InsufficientFundsUpkeepReport"].ID: return _AutomationRegistryLogicA.ParseInsufficientFundsUpkeepReport(log) + case _AutomationRegistryLogicA.abi.Events["NOPsSettledOffchain"].ID: + return _AutomationRegistryLogicA.ParseNOPsSettledOffchain(log) case _AutomationRegistryLogicA.abi.Events["OwnershipTransferRequested"].ID: return _AutomationRegistryLogicA.ParseOwnershipTransferRequested(log) case _AutomationRegistryLogicA.abi.Events["OwnershipTransferred"].ID: @@ -4789,8 +5091,16 @@ func (AutomationRegistryLogicAAdminPrivilegeConfigSet) Topic() common.Hash { return common.HexToHash("0x7c44b4eb59ee7873514e7e43e7718c269d872965938b288aa143befca62f99d2") } +func (AutomationRegistryLogicABillingConfigOverridden) Topic() common.Hash { + return common.HexToHash("0xd8a6d79d170a55968079d3a89b960d86b4442aef6aac1d01e644c32b9e38b340") +} + +func (AutomationRegistryLogicABillingConfigOverrideRemoved) Topic() common.Hash { + return common.HexToHash("0x97d0ef3f46a56168af653f547bdb6f77ec2b1d7d9bc6ba0193c2b340ec68064a") +} + func (AutomationRegistryLogicABillingConfigSet) Topic() common.Hash { - return common.HexToHash("0x5ff767a3a5dbf1ef088ebf56e221e9cea40ad357c31ba060c2f31244cefab7c1") + return common.HexToHash("0x720a5849025dc4fd0061aed1bb30efd713cde64ce7f8d807953ecca27c8f143c") } func (AutomationRegistryLogicACancelledUpkeepReport) Topic() common.Hash { @@ -4821,6 +5131,10 @@ func (AutomationRegistryLogicAInsufficientFundsUpkeepReport) Topic() common.Hash return common.HexToHash("0x377c8b0c126ae5248d27aca1c76fac4608aff85673ee3caf09747e1044549e02") } +func (AutomationRegistryLogicANOPsSettledOffchain) Topic() common.Hash { + return common.HexToHash("0x5af23b715253628d12b660b27a4f3fc626562ea8a55040aa99ab3dc178989fad") +} + func (AutomationRegistryLogicAOwnershipTransferRequested) Topic() common.Hash { return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") } @@ -4928,27 +5242,13 @@ type AutomationRegistryLogicAInterface interface { AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) - AddFunds(opts *bind.TransactOpts, id *big.Int, amount *big.Int) (*types.Transaction, error) - CancelUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) - CheckCallback(opts *bind.TransactOpts, id *big.Int, values [][]byte, extraData []byte) (*types.Transaction, error) - - CheckUpkeep(opts *bind.TransactOpts, id *big.Int, triggerData []byte) (*types.Transaction, error) - - CheckUpkeep0(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) - - ExecuteCallback(opts *bind.TransactOpts, id *big.Int, payload []byte) (*types.Transaction, error) - MigrateUpkeeps(opts *bind.TransactOpts, ids []*big.Int, destination common.Address) (*types.Transaction, error) ReceiveUpkeeps(opts *bind.TransactOpts, encodedUpkeeps []byte) (*types.Transaction, error) - RegisterUpkeep(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) - - RegisterUpkeep0(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) - - SetUpkeepTriggerConfig(opts *bind.TransactOpts, id *big.Int, triggerConfig []byte) (*types.Transaction, error) + RegisterUpkeep(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, billingToken common.Address, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) @@ -4960,6 +5260,18 @@ type AutomationRegistryLogicAInterface interface { ParseAdminPrivilegeConfigSet(log types.Log) (*AutomationRegistryLogicAAdminPrivilegeConfigSet, error) + FilterBillingConfigOverridden(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicABillingConfigOverriddenIterator, error) + + WatchBillingConfigOverridden(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicABillingConfigOverridden, id []*big.Int) (event.Subscription, error) + + ParseBillingConfigOverridden(log types.Log) (*AutomationRegistryLogicABillingConfigOverridden, error) + + FilterBillingConfigOverrideRemoved(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicABillingConfigOverrideRemovedIterator, error) + + WatchBillingConfigOverrideRemoved(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicABillingConfigOverrideRemoved, id []*big.Int) (event.Subscription, error) + + ParseBillingConfigOverrideRemoved(log types.Log) (*AutomationRegistryLogicABillingConfigOverrideRemoved, error) + FilterBillingConfigSet(opts *bind.FilterOpts, token []common.Address) (*AutomationRegistryLogicABillingConfigSetIterator, error) WatchBillingConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicABillingConfigSet, token []common.Address) (event.Subscription, error) @@ -4984,9 +5296,9 @@ type AutomationRegistryLogicAInterface interface { ParseDedupKeyAdded(log types.Log) (*AutomationRegistryLogicADedupKeyAdded, error) - FilterFeesWithdrawn(opts *bind.FilterOpts, recipient []common.Address, assetAddress []common.Address) (*AutomationRegistryLogicAFeesWithdrawnIterator, error) + FilterFeesWithdrawn(opts *bind.FilterOpts, assetAddress []common.Address, recipient []common.Address) (*AutomationRegistryLogicAFeesWithdrawnIterator, error) - WatchFeesWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAFeesWithdrawn, recipient []common.Address, assetAddress []common.Address) (event.Subscription, error) + WatchFeesWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAFeesWithdrawn, assetAddress []common.Address, recipient []common.Address) (event.Subscription, error) ParseFeesWithdrawn(log types.Log) (*AutomationRegistryLogicAFeesWithdrawn, error) @@ -5008,6 +5320,12 @@ type AutomationRegistryLogicAInterface interface { ParseInsufficientFundsUpkeepReport(log types.Log) (*AutomationRegistryLogicAInsufficientFundsUpkeepReport, error) + FilterNOPsSettledOffchain(opts *bind.FilterOpts) (*AutomationRegistryLogicANOPsSettledOffchainIterator, error) + + WatchNOPsSettledOffchain(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicANOPsSettledOffchain) (event.Subscription, error) + + ParseNOPsSettledOffchain(log types.Log) (*AutomationRegistryLogicANOPsSettledOffchain, error) + FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryLogicAOwnershipTransferRequestedIterator, error) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) diff --git a/core/gethwrappers/generated/automation_registry_logic_b_wrapper_2_3/automation_registry_logic_b_wrapper_2_3.go b/core/gethwrappers/generated/automation_registry_logic_b_wrapper_2_3/automation_registry_logic_b_wrapper_2_3.go index 4aec8435544..e68a1e0b75b 100644 --- a/core/gethwrappers/generated/automation_registry_logic_b_wrapper_2_3/automation_registry_logic_b_wrapper_2_3.go +++ b/core/gethwrappers/generated/automation_registry_logic_b_wrapper_2_3/automation_registry_logic_b_wrapper_2_3.go @@ -31,65 +31,28 @@ var ( ) type AutomationRegistryBase23BillingConfig struct { - GasFeePPB uint32 - FlatFeeMicroLink *big.Int - PriceFeed common.Address -} - -type AutomationRegistryBase23OnchainConfigLegacy struct { - PaymentPremiumPPB uint32 - FlatFeeMicroLink uint32 - CheckGasLimit uint32 - StalenessSeconds *big.Int - GasCeilingMultiplier uint16 - MinUpkeepSpend *big.Int - MaxPerformGas uint32 - MaxCheckDataSize uint32 - MaxPerformDataSize uint32 - MaxRevertDataSize uint32 - FallbackGasPrice *big.Int - FallbackLinkPrice *big.Int - Transcoder common.Address - Registrars []common.Address - UpkeepPrivilegeManager common.Address -} - -type AutomationRegistryBase23State struct { - Nonce uint32 - OwnerLinkBalance *big.Int - ExpectedLinkBalance *big.Int - TotalPremium *big.Int - NumUpkeeps *big.Int - ConfigCount uint32 - LatestConfigBlockNumber uint32 - LatestConfigDigest [32]byte - LatestEpoch uint32 - Paused bool -} - -type AutomationRegistryBase23UpkeepInfo struct { - Target common.Address - PerformGas uint32 - CheckData []byte - Balance *big.Int - Admin common.Address - MaxValidBlocknumber uint64 - LastPerformedBlockNumber uint32 - AmountSpent *big.Int - Paused bool - OffchainConfig []byte + GasFeePPB uint32 + FlatFeeMilliCents *big.Int + PriceFeed common.Address + FallbackPrice *big.Int + MinSpend *big.Int +} + +type AutomationRegistryBase23BillingOverrides struct { + GasFeePPB uint32 + FlatFeeMilliCents *big.Int } var AutomationRegistryLogicBMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkUSDFeed\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"nativeUSDFeed\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"fastGasFeed\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"automationForwarderLogic\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"allowedReadOnlyAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidFeed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxCheckDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxPerformDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyFinanceAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentGreaterThanAllLINK\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint24\"},{\"internalType\":\"address\",\"name\":\"priceFeed\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"BillingConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newModule\",\"type\":\"address\"}],\"name\":\"ChainSpecificModuleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"acceptPayeeship\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"acceptUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveUpkeepIDs\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"getAdminPrivilegeConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowedReadOnlyAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAutomationForwarderLogic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getBillingTokenConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint24\"},{\"internalType\":\"address\",\"name\":\"priceFeed\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBillingTokens\",\"outputs\":[{\"internalType\":\"contractIERC20[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCancellationDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getChainModule\",\"outputs\":[{\"internalType\":\"contractIChainModule\",\"name\":\"chainModule\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConditionalGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFallbackNativePrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFastGasFeedAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepID\",\"type\":\"uint256\"}],\"name\":\"getForwarder\",\"outputs\":[{\"internalType\":\"contractIAutomationForwarder\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLinkAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLinkUSDFeedAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLogGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"enumAutomationRegistryBase2_3.Trigger\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"getMaxPaymentForGas\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"maxPayment\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getMinBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getMinBalanceForUpkeep\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"minBalance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNativeUSDFeedAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"peer\",\"type\":\"address\"}],\"name\":\"getPeerRegistryMigrationPermission\",\"outputs\":[{\"internalType\":\"enumAutomationRegistryBase2_3.MigrationPermission\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPerPerformByteGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPerSignerGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getReorgProtectionEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"query\",\"type\":\"address\"}],\"name\":\"getSignerInfo\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"index\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"nonce\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"ownerLinkBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"expectedLinkBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"totalPremium\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"numUpkeeps\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"latestConfigBlockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"latestConfigDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"latestEpoch\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"}],\"internalType\":\"structAutomationRegistryBase2_3.State\",\"name\":\"state\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.OnchainConfigLegacy\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTransmitCalldataFixedBytesOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTransmitCalldataPerSignerBytesOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"query\",\"type\":\"address\"}],\"name\":\"getTransmitterInfo\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"index\",\"type\":\"uint8\"},{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"lastCollected\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getTriggerType\",\"outputs\":[{\"internalType\":\"enumAutomationRegistryBase2_3.Trigger\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getUpkeep\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"maxValidBlocknumber\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"lastPerformedBlockNumber\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"amountSpent\",\"type\":\"uint96\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"internalType\":\"structAutomationRegistryBase2_3.UpkeepInfo\",\"name\":\"upkeepInfo\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepPrivilegeConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepTriggerConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"hasDedupKey\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkAvailableForPayment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"pauseUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"newPrivilegeConfig\",\"type\":\"bytes\"}],\"name\":\"setAdminPrivilegeConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"setPayees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"peer\",\"type\":\"address\"},{\"internalType\":\"enumAutomationRegistryBase2_3.MigrationPermission\",\"name\":\"permission\",\"type\":\"uint8\"}],\"name\":\"setPeerRegistryMigrationPermission\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"setUpkeepCheckData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"setUpkeepGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"config\",\"type\":\"bytes\"}],\"name\":\"setUpkeepOffchainConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"newPrivilegeConfig\",\"type\":\"bytes\"}],\"name\":\"setUpkeepPrivilegeConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"transferPayeeship\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"transferUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"unpauseUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepTranscoderVersion\",\"outputs\":[{\"internalType\":\"enumUpkeepFormat\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawERC20Fees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLinkFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawPayment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x6101406040523480156200001257600080fd5b506040516200565c3803806200565c8339810160408190526200003591620002c0565b8585858585853380600081620000925760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c557620000c581620001f8565b5050506001600160a01b0380871660805285811660a05284811660c081905284821660e05283821661010052908216610120526040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa15801562000134573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200015a919062000341565b60ff1660a0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200019e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001c4919062000341565b60ff1614620001e6576040516301f86e1760e41b815260040160405180910390fd5b5050505050505050505050506200036d565b336001600160a01b03821603620002525760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000089565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620002bb57600080fd5b919050565b60008060008060008060c08789031215620002da57600080fd5b620002e587620002a3565b9550620002f560208801620002a3565b94506200030560408801620002a3565b93506200031560608801620002a3565b92506200032560808801620002a3565b91506200033560a08801620002a3565b90509295509295509295565b6000602082840312156200035457600080fd5b815160ff811681146200036657600080fd5b9392505050565b60805160a05160c05160e051610100516101205161524b6200041160003960006107b601526000610610015260008181610682015261370f015260008181610649015281816138c301526140790152600081816104bd01526137e901526000818161095901528181610d5701528181611f7f015281816120010152818161237e0152818161242801528181612816015281816128730152613289015261524b6000f3fe608060405234801561001057600080fd5b50600436106103995760003560e01c806379ea9943116101e9578063b3596c231161010f578063d09dc339116100ad578063ed56b3e11161007c578063ed56b3e1146109c6578063f2fde38b14610a39578063f777ff0614610a4c578063faa3e99614610a5357600080fd5b8063d09dc33914610990578063d763264814610998578063d85aa07c146109ab578063eb5dcd6c146109b357600080fd5b8063ba876668116100e9578063ba87666814610922578063c7c3a19a14610937578063ca30e60314610957578063cd7f71b51461097d57600080fd5b8063b3596c231461083d578063b6511a2a14610908578063b657bc9c1461090f57600080fd5b80639e0a99ed11610187578063aab9edd611610156578063aab9edd614610800578063abc76ae01461080f578063b121e14714610817578063b148ab6b1461082a57600080fd5b80639e0a99ed146107ac578063a08714c0146107b4578063a710b221146107da578063a72aa27e146107ed57600080fd5b80638765ecbe116101c35780638765ecbe146107455780638da5cb5b146107585780638dcf0fe7146107765780638ed02bab1461078957600080fd5b806379ea9943146106e75780638081fadb1461072a5780638456cb591461073d57600080fd5b806343cc055c116102ce5780635b6aa71c1161026c578063671d36ed1161023b578063671d36ed146106a657806368d369d8146106b9578063744bfe61146106cc57806379ba5097146106df57600080fd5b80635b6aa71c14610634578063614486af146106475780636209e1e91461066d5780636709d0e51461068057600080fd5b80634ca16c52116102a85780634ca16c52146105d35780635147cd59146105db5780635165f2f5146105fb5780635425d8ac1461060e57600080fd5b806343cc055c1461058a57806344cb70b8146105a157806348013d7b146105c457600080fd5b80631e0104391161033b578063232c1cc511610315578063232c1cc5146105025780633b9cce59146105095780633f4ba83a1461051c578063421d183b1461052457600080fd5b80631e0104391461044a578063207b6516146104a8578063226cf83c146104bb57600080fd5b80631865c57d116103775780631865c57d146103eb578063187256e81461040457806319d97a94146104175780631a2af0111461043757600080fd5b8063050ee65d1461039e57806306e3b632146103b65780630b7d33e6146103d6575b600080fd5b62014c085b6040519081526020015b60405180910390f35b6103c96103c43660046143c2565b610a99565b6040516103ad91906143e4565b6103e96103e436600461446a565b610bb6565b005b6103f3610c60565b6040516103ad95949392919061466d565b6103e96104123660046147a4565b6110c3565b61042a6104253660046147e1565b611134565b6040516103ad919061485e565b6103e9610445366004614871565b6111d6565b61048b6104583660046147e1565b6000908152600460205260409020600101546c0100000000000000000000000090046bffffffffffffffffffffffff1690565b6040516bffffffffffffffffffffffff90911681526020016103ad565b61042a6104b63660046147e1565b6112dc565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103ad565b60186103a3565b6103e9610517366004614896565b6112f9565b6103e961154f565b61053761053236600461490b565b6115b5565b60408051951515865260ff90941660208601526bffffffffffffffffffffffff9283169385019390935216606083015273ffffffffffffffffffffffffffffffffffffffff16608082015260a0016103ad565b60135460ff165b60405190151581526020016103ad565b6105916105af3660046147e1565b60009081526008602052604090205460ff1690565b60006040516103ad9190614957565b61ea606103a3565b6105ee6105e93660046147e1565b6116d4565b6040516103ad9190614971565b6103e96106093660046147e1565b6116df565b7f00000000000000000000000000000000000000000000000000000000000000006104dd565b61048b61064236600461499e565b611856565b7f00000000000000000000000000000000000000000000000000000000000000006104dd565b61042a61067b36600461490b565b611a00565b7f00000000000000000000000000000000000000000000000000000000000000006104dd565b6103e96106b43660046149d7565b611a33565b6103e96106c7366004614a13565b611afc565b6103e96106da366004614871565b611c94565b6103e9612188565b6104dd6106f53660046147e1565b6000908152600460205260409020546901000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1690565b6103e9610738366004614a54565b61228a565b6103e96124a5565b6103e96107533660046147e1565b612526565b60005473ffffffffffffffffffffffffffffffffffffffff166104dd565b6103e961078436600461446a565b6126a0565b601354610100900473ffffffffffffffffffffffffffffffffffffffff166104dd565b6103a46103a3565b7f00000000000000000000000000000000000000000000000000000000000000006104dd565b6103e96107e8366004614a80565b6126f5565b6103e96107fb366004614aae565b61299a565b604051600381526020016103ad565b6115e06103a3565b6103e961082536600461490b565b612a83565b6103e96108383660046147e1565b612b7b565b6108c561084b36600461490b565b60408051606080820183526000808352602080840182905292840181905273ffffffffffffffffffffffffffffffffffffffff948516815260218352839020835191820184525463ffffffff81168252640100000000810462ffffff16928201929092526701000000000000009091049092169082015290565b60408051825163ffffffff16815260208084015162ffffff16908201529181015173ffffffffffffffffffffffffffffffffffffffff16908201526060016103ad565b60326103a3565b61048b61091d3660046147e1565b612d69565b61092a612d96565b6040516103ad9190614ad1565b61094a6109453660046147e1565b612e05565b6040516103ad9190614b1f565b7f00000000000000000000000000000000000000000000000000000000000000006104dd565b6103e961098b36600461446a565b6131d8565b6103a3613287565b61048b6109a63660046147e1565b613356565b601a546103a3565b6103e96109c1366004614a80565b613361565b610a206109d436600461490b565b73ffffffffffffffffffffffffffffffffffffffff166000908152600c602090815260409182902082518084019093525460ff8082161515808552610100909204169290910182905291565b60408051921515835260ff9091166020830152016103ad565b6103e9610a4736600461490b565b6134bf565b60406103a3565b610a8c610a6136600461490b565b73ffffffffffffffffffffffffffffffffffffffff166000908152601c602052604090205460ff1690565b6040516103ad9190614c56565b60606000610aa760026134d3565b9050808410610ae2576040517f1390f2a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610aee8486614c99565b905081811180610afc575083155b610b065780610b08565b815b90506000610b168683614cac565b67ffffffffffffffff811115610b2e57610b2e614cbf565b604051908082528060200260200182016040528015610b57578160200160208202803683370190505b50905060005b8151811015610baa57610b7b610b738883614c99565b6002906134dd565b828281518110610b8d57610b8d614cee565b602090810291909101015280610ba281614d1d565b915050610b5d565b50925050505b92915050565b60165473ffffffffffffffffffffffffffffffffffffffff163314610c07576040517f77c3599200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152601f60205260409020610c20828483614df7565b50827f2fd8d70753a007014349d4591843cc031c2dd7a260d7dd82eca8253686ae77698383604051610c53929190614f12565b60405180910390a2505050565b6040805161014081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810191909152604080516101e08101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201839052610160820183905261018082018390526101a08201526101c0810191909152604080516101408101825260155468010000000000000000900463ffffffff168152600060208083018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168252601b905282812054928201929092526012546bffffffffffffffffffffffff1660608083019190915291829160808101610dc860026134d3565b81526015546c0100000000000000000000000080820463ffffffff90811660208086019190915270010000000000000000000000000000000080850483166040808801919091526011546060808901919091526012547401000000000000000000000000000000000000000080820487166080808c01919091527e01000000000000000000000000000000000000000000000000000000000000830460ff16151560a09b8c015284516101e0810186528984048916815295830488169686019690965286891693850193909352780100000000000000000000000000000000000000000000000080820462ffffff16928501929092527b01000000000000000000000000000000000000000000000000000000900461ffff16938301939093526014546bffffffffffffffffffffffff8116978301979097526401000000008604841660c08301528504831660e082015290840482166101008201527c01000000000000000000000000000000000000000000000000000000009093041661012083015260185461014083015260195461016083015290910473ffffffffffffffffffffffffffffffffffffffff166101808201529095506101a08101610f8f60096134f0565b815260165473ffffffffffffffffffffffffffffffffffffffff16602091820152601254600d80546040805182860281018601909152818152949850899489949293600e937d01000000000000000000000000000000000000000000000000000000000090910460ff1692859183018282801561104257602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311611017575b50505050509250818054806020026020016040519081016040528092919081815260200182805480156110ab57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311611080575b50505050509150945094509450945094509091929394565b6110cb6134fd565b73ffffffffffffffffffffffffffffffffffffffff82166000908152601c6020526040902080548291907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600183600381111561112b5761112b614928565b02179055505050565b6000818152601f6020526040902080546060919061115190614d55565b80601f016020809104026020016040519081016040528092919081815260200182805461117d90614d55565b80156111ca5780601f1061119f576101008083540402835291602001916111ca565b820191906000526020600020905b8154815290600101906020018083116111ad57829003601f168201915b50505050509050919050565b6111df82613580565b3373ffffffffffffffffffffffffffffffffffffffff82160361122e576040517f8c8728c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526006602052604090205473ffffffffffffffffffffffffffffffffffffffff8281169116146112d85760008281526006602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff851690811790915590519091339185917fb1cbb2c4b8480034c27e06da5f096b8233a8fd4497028593a41ff6df79726b3591a45b5050565b6000818152601d6020526040902080546060919061115190614d55565b6113016134fd565b600e54811461133c576040517fcf54c06a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b600e5481101561150e576000600e828154811061135e5761135e614cee565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff908116808452600f909252604083205491935016908585858181106113a8576113a8614cee565b90506020020160208101906113bd919061490b565b905073ffffffffffffffffffffffffffffffffffffffff81161580611450575073ffffffffffffffffffffffffffffffffffffffff82161580159061142e57508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b8015611450575073ffffffffffffffffffffffffffffffffffffffff81811614155b15611487576040517fb387a23800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff818116146114f85773ffffffffffffffffffffffffffffffffffffffff8381166000908152600f6020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169183169190911790555b505050808061150690614d1d565b91505061133f565b507fa46de38886467c59be07a0675f14781206a5477d871628af46c2443822fcb725600e838360405161154393929190614f5f565b60405180910390a15050565b6115576134fd565b601280547fff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e01000000000000000000000000000090049091166060820152829182918291829190829061167b576060820151601254600091611667916bffffffffffffffffffffffff16615011565b600e549091506116779082615065565b9150505b815160208301516040840151611692908490615090565b6060949094015173ffffffffffffffffffffffffffffffffffffffff9a8b166000908152600f6020526040902054929b919a9499509750921694509092505050565b6000610bb082613634565b6116e881613580565b600081815260046020908152604091829020825160e081018452815460ff8116151580835263ffffffff610100830481169584019590955265010000000000820485169583019590955273ffffffffffffffffffffffffffffffffffffffff69010000000000000000009091041660608201526001909101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490911660c0820152906117e7576040517f1b88a78400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260046020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556118266002836136df565b5060405182907f7bada562044eb163f6b4003c4553e4e62825344c0418eea087bed5ee05a4745690600090a25050565b60408051610160810182526012546bffffffffffffffffffffffff8116825263ffffffff6c010000000000000000000000008204811660208401527001000000000000000000000000000000008204811693830193909352740100000000000000000000000000000000000000008104909216606082015262ffffff7801000000000000000000000000000000000000000000000000830416608082015261ffff7b0100000000000000000000000000000000000000000000000000000083041660a082015260ff7d0100000000000000000000000000000000000000000000000000000000008304811660c08301527e0100000000000000000000000000000000000000000000000000000000000083048116151560e08301527f01000000000000000000000000000000000000000000000000000000000000009092048216151561010080830191909152601354928316151561012083015273ffffffffffffffffffffffffffffffffffffffff9204919091166101408201526000908180806119e1846136eb565b9250925092506119f5848888868686613976565b979650505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602080526040902080546060919061115190614d55565b60165473ffffffffffffffffffffffffffffffffffffffff163314611a84576040517f77c3599200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff831660009081526020805260409020611ab3828483614df7565b508273ffffffffffffffffffffffffffffffffffffffff167f7c44b4eb59ee7873514e7e43e7718c269d872965938b288aa143befca62f99d28383604051610c53929190614f12565b611b04613c44565b73ffffffffffffffffffffffffffffffffffffffff8216611b51576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018390526000919085169063a9059cbb906044016020604051808303816000875af1158015611bca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bee91906150b5565b905080611c27576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f5e110f8bc8a20b65dcc87f224bdf1cc039346e267118bae2739847f07321ffa884604051611c8691815260200190565b60405180910390a350505050565b6012547f0100000000000000000000000000000000000000000000000000000000000000900460ff1615611cf4576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601280547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f010000000000000000000000000000000000000000000000000000000000000017905573ffffffffffffffffffffffffffffffffffffffff8116611d8a576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600460209081526040808320815160e081018352815460ff81161515825263ffffffff610100820481168387015265010000000000820481168386015273ffffffffffffffffffffffffffffffffffffffff6901000000000000000000909204821660608401526001909301546bffffffffffffffffffffffff80821660808501526c0100000000000000000000000082041660a08401527801000000000000000000000000000000000000000000000000900490921660c082015286855260059093529220549091163314611e91576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601260010160019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f2591906150d7565b816040015163ffffffff161115611f68576040517fff84e5dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600460209081526040808320600101547f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168452601b909252909120546c010000000000000000000000009091046bffffffffffffffffffffffff1690611fea908290614cac565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081166000818152601b60209081526040808320959095558882526004908190529084902060010180547fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff16905592517fa9059cbb000000000000000000000000000000000000000000000000000000008152918616928201929092526bffffffffffffffffffffffff8316602482015263a9059cbb906044016020604051808303816000875af11580156120d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120fc91906150b5565b50604080516bffffffffffffffffffffffff8316815273ffffffffffffffffffffffffffffffffffffffff8516602082015285917ff3b5906e5672f3e524854103bcafbbdba80dbdfeca2c35e116127b1060a68318910160405180910390a25050601280547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690555050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461220e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b612292613c44565b73ffffffffffffffffffffffffffffffffffffffff82166122df576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006122e9613287565b90508082111561232f576040517fcf4791810000000000000000000000000000000000000000000000000000000081526004810182905260248101839052604401612205565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490526000917f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af11580156123c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123ed91906150b5565b905080612426576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f5e110f8bc8a20b65dcc87f224bdf1cc039346e267118bae2739847f07321ffa885604051611c8691815260200190565b6124ad6134fd565b601280547fff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e010000000000000000000000000000000000000000000000000000000000001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906020016115ab565b61252f81613580565b600081815260046020908152604091829020825160e081018452815460ff8116158015835263ffffffff610100830481169584019590955265010000000000820485169583019590955273ffffffffffffffffffffffffffffffffffffffff69010000000000000000009091041660608201526001909101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490911660c08201529061262e576040517f514b6c2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260046020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055612670600283613c95565b5060405182907f8ab10247ce168c27748e656ecf852b951fcaac790c18106b19aa0ae57a8b741f90600090a25050565b6126a983613580565b6000838152601e602052604090206126c2828483614df7565b50827f3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf48508383604051610c53929190614f12565b73ffffffffffffffffffffffffffffffffffffffff8116612742576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8281166000908152600f60205260409020541633146127a2576040517fcebf515b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601254600e546000916127c59185916bffffffffffffffffffffffff1690613ca1565b73ffffffffffffffffffffffffffffffffffffffff8085166000908152600b6020908152604080832080547fffffffffffffffffffffffffffffffffffff000000000000000000000000ffff1690557f00000000000000000000000000000000000000000000000000000000000000009093168252601b9052205490915061285c906bffffffffffffffffffffffff831690614cac565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081166000818152601b6020526040908190209390935591517fa9059cbb00000000000000000000000000000000000000000000000000000000815290841660048201526bffffffffffffffffffffffff8316602482015263a9059cbb906044016020604051808303816000875af1158015612911573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061293591906150b5565b5060405133815273ffffffffffffffffffffffffffffffffffffffff808416916bffffffffffffffffffffffff8416918616907f9819093176a1851202c7bcfa46845809b4e47c261866550e94ed3775d2f406989060200160405180910390a4505050565b6108fc8163ffffffff1610806129c3575060155463ffffffff6401000000009091048116908216115b156129fa576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612a0382613580565b60008281526004602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff1661010063ffffffff861690810291909117909155915191825283917fc24c07e655ce79fba8a589778987d3c015bc6af1632bb20cf9182e02a65d972c910160405180910390a25050565b73ffffffffffffffffffffffffffffffffffffffff818116600090815260106020526040902054163314612ae3576040517f6752e7aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8181166000818152600f602090815260408083208054337fffffffffffffffffffffffff000000000000000000000000000000000000000080831682179093556010909452828520805490921690915590519416939092849290917f78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b39190a45050565b600081815260046020908152604091829020825160e081018452815460ff81161515825263ffffffff6101008204811694830194909452650100000000008104841694820185905273ffffffffffffffffffffffffffffffffffffffff69010000000000000000009091041660608201526001909101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a083015278010000000000000000000000000000000000000000000000009004821660c08201529114612c78576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526006602052604090205473ffffffffffffffffffffffffffffffffffffffff163314612cd5576040517f6352a85300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602090815260408083208054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821790935560069094528285208054909216909155905173ffffffffffffffffffffffffffffffffffffffff90911692839186917f5cff4db96bef051785e999f44bfcd21c18823e034fb92dd376e3db4ce0feeb2c91a4505050565b6000610bb0612d7783613634565b600084815260046020526040902054610100900463ffffffff16611856565b60606022805480602002602001604051908101604052809291908181526020018280548015612dfb57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311612dd0575b5050505050905090565b604080516101408101825260008082526020820181905260609282018390528282018190526080820181905260a0820181905260c0820181905260e082018190526101008201526101208101919091526000828152600460209081526040808320815160e081018352815460ff811615158252610100810463ffffffff90811695830195909552650100000000008104851693820193909352690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff16606083018190526001909101546bffffffffffffffffffffffff80821660808501526c0100000000000000000000000082041660a08401527801000000000000000000000000000000000000000000000000900490921660c0820152919015612f9d57816060015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f9891906150f0565b612fa0565b60005b90506040518061014001604052808273ffffffffffffffffffffffffffffffffffffffff168152602001836020015163ffffffff168152602001600760008781526020019081526020016000208054612ff890614d55565b80601f016020809104026020016040519081016040528092919081815260200182805461302490614d55565b80156130715780601f1061304657610100808354040283529160200191613071565b820191906000526020600020905b81548152906001019060200180831161305457829003601f168201915b505050505081526020018360a001516bffffffffffffffffffffffff1681526020016005600087815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001836040015163ffffffff1667ffffffffffffffff1681526020018360c0015163ffffffff16815260200183608001516bffffffffffffffffffffffff168152602001836000015115158152602001601e6000878152602001908152602001600020805461314e90614d55565b80601f016020809104026020016040519081016040528092919081815260200182805461317a90614d55565b80156131c75780601f1061319c576101008083540402835291602001916131c7565b820191906000526020600020905b8154815290600101906020018083116131aa57829003601f168201915b505050505081525092505050919050565b6131e183613580565b60155474010000000000000000000000000000000000000000900463ffffffff1681111561323b576040517fae7235df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600760205260409020613254828483614df7565b50827fcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d8383604051610c53929190614f12565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166000818152601b60205260408082205490517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152919290916370a0823190602401602060405180830381865afa158015613323573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061334791906150d7565b6133519190614cac565b905090565b6000610bb082612d69565b73ffffffffffffffffffffffffffffffffffffffff8281166000908152600f60205260409020541633146133c1576040517fcebf515b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff821603613410576040517f8c8728c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8281166000908152601060205260409020548116908216146112d85773ffffffffffffffffffffffffffffffffffffffff82811660008181526010602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055513392917f84f7c7c80bb8ed2279b4aab5f61cd05e6374073d38f46d7f32de8c30e9e3836791a45050565b6134c76134fd565b6134d081613ea9565b50565b6000610bb0825490565b60006134e98383613f9e565b9392505050565b606060006134e983613fc8565b60005473ffffffffffffffffffffffffffffffffffffffff16331461357e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401612205565b565b60008181526005602052604090205473ffffffffffffffffffffffffffffffffffffffff1633146135dd576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526004602052604090205465010000000000900463ffffffff908116146134d0576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818160045b600f8110156136c1577fff00000000000000000000000000000000000000000000000000000000000000821683826020811061367957613679614cee565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916146136af57506000949350505050565b806136b981614d1d565b91505061363b565b5081600f1a60018111156136d7576136d7614928565b949350505050565b60006134e98383614023565b600080600080846080015162ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613778573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061379c9190615127565b50945090925050506000811315806137b357508142105b806137d457508280156137d457506137cb8242614cac565b8463ffffffff16105b156137e35760185496506137e7565b8096505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613852573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138769190615127565b509450909250505060008113158061388d57508142105b806138ae57508280156138ae57506138a58242614cac565b8463ffffffff16105b156138bd5760195495506138c1565b8095505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801561392c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139509190615127565b5094509092508891508790506139658a614072565b965096509650505050509193909250565b6000808087600181111561398c5761398c614928565b0361399a575061ea606139ef565b60018760018111156139ae576139ae614928565b036139bd575062014c086139ef565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008860c001516001613a029190615177565b613a109060ff166040615190565b601554613a42906103a4907801000000000000000000000000000000000000000000000000900463ffffffff16614c99565b613a4c9190614c99565b601354604080517fde9ee35e00000000000000000000000000000000000000000000000000000000815281519394506000938493610100900473ffffffffffffffffffffffffffffffffffffffff169263de9ee35e92600480820193918290030181865afa158015613ac2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ae691906151a7565b90925090508183613af8836018614c99565b613b029190615190565b60c08d0151613b12906001615177565b613b219060ff166115e0615190565b613b2b9190614c99565b613b359190614c99565b613b3f9085614c99565b935060008b610140015173ffffffffffffffffffffffffffffffffffffffff166312544140856040518263ffffffff1660e01b8152600401613b8391815260200190565b602060405180830381865afa158015613ba0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bc491906150d7565b8c60a0015161ffff16613bd79190615190565b9050600080613c218e6040518060e001604052808f63ffffffff1681526020018a81526020018681526020018e81526020018d81526020018c815260200160001515815250614163565b9092509050613c308183615090565b9750505050505050505b9695505050505050565b60175473ffffffffffffffffffffffffffffffffffffffff16331461357e576040517fb6dfb7a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006134e983836142cf565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e0100000000000000000000000000009004909116606082015290613e9d576000816060015185613d399190615011565b90506000613d478583615065565b90508083604001818151613d5b9190615090565b6bffffffffffffffffffffffff16905250613d7685826151cb565b83606001818151613d879190615090565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b60400151949350505050565b3373ffffffffffffffffffffffffffffffffffffffff821603613f28576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401612205565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000826000018281548110613fb557613fb5614cee565b9060005260206000200154905092915050565b6060816000018054806020026020016040519081016040528092919081815260200182805480156111ca57602002820191906000526020600020905b8154815260200190600101908083116140045750505050509050919050565b600081815260018301602052604081205461406a57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610bb0565b506000610bb0565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156140e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141069190615127565b5093505092505060008213158061411c57508042105b8061414c57506000846080015162ffffff1611801561414c57506141408142614cac565b846080015162ffffff16105b1561415c575050601a5492915050565b5092915050565b60008060008460a0015161ffff1684606001516141809190615190565b90508360c0015180156141925750803a105b1561419a57503a5b600084608001518560a001518660400151876020015188600001516141bf9190614c99565b6141c99086615190565b6141d39190614c99565b6141dd9190615190565b6141e791906151fb565b90506000866040015163ffffffff1664e8d4a510006142069190615190565b608087015161421990633b9aca00615190565b8760a00151896020015163ffffffff1689604001518a600001518861423e9190615190565b6142489190614c99565b6142529190615190565b61425c9190615190565b61426691906151fb565b6142709190614c99565b90506b033b2e3c9fd0803ce80000006142898284614c99565b11156142c1576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9093509150505b9250929050565b600081815260018301602052604081205480156143b85760006142f3600183614cac565b855490915060009061430790600190614cac565b905081811461436c57600086600001828154811061432757614327614cee565b906000526020600020015490508087600001848154811061434a5761434a614cee565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061437d5761437d61520f565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610bb0565b6000915050610bb0565b600080604083850312156143d557600080fd5b50508035926020909101359150565b6020808252825182820181905260009190848201906040850190845b8181101561441c57835183529284019291840191600101614400565b50909695505050505050565b60008083601f84011261443a57600080fd5b50813567ffffffffffffffff81111561445257600080fd5b6020830191508360208285010111156142c857600080fd5b60008060006040848603121561447f57600080fd5b83359250602084013567ffffffffffffffff81111561449d57600080fd5b6144a986828701614428565b9497909650939450505050565b600081518084526020808501945080840160005b838110156144fc57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016144ca565b509495945050505050565b805163ffffffff16825260006101e0602083015161452d602086018263ffffffff169052565b506040830151614545604086018263ffffffff169052565b50606083015161455c606086018262ffffff169052565b506080830151614572608086018261ffff169052565b5060a083015161459260a08601826bffffffffffffffffffffffff169052565b5060c08301516145aa60c086018263ffffffff169052565b5060e08301516145c260e086018263ffffffff169052565b506101008381015163ffffffff908116918601919091526101208085015190911690850152610140808401519085015261016080840151908501526101808084015173ffffffffffffffffffffffffffffffffffffffff16908501526101a080840151818601839052614637838701826144b6565b925050506101c0808401516146638287018273ffffffffffffffffffffffffffffffffffffffff169052565b5090949350505050565b855163ffffffff16815260006101c0602088015161469b60208501826bffffffffffffffffffffffff169052565b506040880151604084015260608801516146c560608501826bffffffffffffffffffffffff169052565b506080880151608084015260a08801516146e760a085018263ffffffff169052565b5060c08801516146ff60c085018263ffffffff169052565b5060e088015160e0840152610100808901516147228286018263ffffffff169052565b505061012088810151151590840152610140830181905261474581840188614507565b905082810361016084015261475a81876144b6565b905082810361018084015261476f81866144b6565b915050613c3a6101a083018460ff169052565b73ffffffffffffffffffffffffffffffffffffffff811681146134d057600080fd5b600080604083850312156147b757600080fd5b82356147c281614782565b91506020830135600481106147d657600080fd5b809150509250929050565b6000602082840312156147f357600080fd5b5035919050565b6000815180845260005b8181101561482057602081850181015186830182015201614804565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006134e960208301846147fa565b6000806040838503121561488457600080fd5b8235915060208301356147d681614782565b600080602083850312156148a957600080fd5b823567ffffffffffffffff808211156148c157600080fd5b818501915085601f8301126148d557600080fd5b8135818111156148e457600080fd5b8660208260051b85010111156148f957600080fd5b60209290920196919550909350505050565b60006020828403121561491d57600080fd5b81356134e981614782565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b602081016003831061496b5761496b614928565b91905290565b602081016002831061496b5761496b614928565b803563ffffffff8116811461499957600080fd5b919050565b600080604083850312156149b157600080fd5b8235600281106149c057600080fd5b91506149ce60208401614985565b90509250929050565b6000806000604084860312156149ec57600080fd5b83356149f781614782565b9250602084013567ffffffffffffffff81111561449d57600080fd5b600080600060608486031215614a2857600080fd5b8335614a3381614782565b92506020840135614a4381614782565b929592945050506040919091013590565b60008060408385031215614a6757600080fd5b8235614a7281614782565b946020939093013593505050565b60008060408385031215614a9357600080fd5b8235614a9e81614782565b915060208301356147d681614782565b60008060408385031215614ac157600080fd5b823591506149ce60208401614985565b6020808252825182820181905260009190848201906040850190845b8181101561441c57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101614aed565b60208152614b4660208201835173ffffffffffffffffffffffffffffffffffffffff169052565b60006020830151614b5f604084018263ffffffff169052565b506040830151610140806060850152614b7c6101608501836147fa565b91506060850151614b9d60808601826bffffffffffffffffffffffff169052565b50608085015173ffffffffffffffffffffffffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015163ffffffff811660e08601525060e0850151610100614c09818701836bffffffffffffffffffffffff169052565b8601519050610120614c1e8682018315159052565b8601518584037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001838701529050613c3a83826147fa565b602081016004831061496b5761496b614928565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610bb057610bb0614c6a565b81810381811115610bb057610bb0614c6a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614d4e57614d4e614c6a565b5060010190565b600181811c90821680614d6957607f821691505b602082108103614da2577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f821115614df257600081815260208120601f850160051c81016020861015614dcf5750805b601f850160051c820191505b81811015614dee57828155600101614ddb565b5050505b505050565b67ffffffffffffffff831115614e0f57614e0f614cbf565b614e2383614e1d8354614d55565b83614da8565b6000601f841160018114614e755760008515614e3f5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614f0b565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b82811015614ec45786850135825560209485019460019092019101614ea4565b5086821015614eff577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b6000604082016040835280865480835260608501915087600052602092508260002060005b82811015614fb657815473ffffffffffffffffffffffffffffffffffffffff1684529284019260019182019101614f84565b505050838103828501528481528590820160005b86811015615005578235614fdd81614782565b73ffffffffffffffffffffffffffffffffffffffff1682529183019190830190600101614fca565b50979650505050505050565b6bffffffffffffffffffffffff82811682821603908082111561415c5761415c614c6a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006bffffffffffffffffffffffff8084168061508457615084615036565b92169190910492915050565b6bffffffffffffffffffffffff81811683821601908082111561415c5761415c614c6a565b6000602082840312156150c757600080fd5b815180151581146134e957600080fd5b6000602082840312156150e957600080fd5b5051919050565b60006020828403121561510257600080fd5b81516134e981614782565b805169ffffffffffffffffffff8116811461499957600080fd5b600080600080600060a0868803121561513f57600080fd5b6151488661510d565b945060208601519350604086015192506060860151915061516b6080870161510d565b90509295509295909350565b60ff8181168382160190811115610bb057610bb0614c6a565b8082028115828204841417610bb057610bb0614c6a565b600080604083850312156151ba57600080fd5b505080516020909101519092909150565b6bffffffffffffffffffffffff8181168382160280821691908281146151f3576151f3614c6a565b505092915050565b60008261520a5761520a615036565b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistryLogicC2_3\",\"name\":\"logicC\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientLinkLiquidity\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidFeed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOffchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOnchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyFinanceAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingOverrides\",\"name\":\"overrides\",\"type\":\"tuple\"}],\"name\":\"BillingConfigOverridden\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"BillingConfigOverrideRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"BillingConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newModule\",\"type\":\"address\"}],\"name\":\"ChainSpecificModuleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"payments\",\"type\":\"uint256[]\"}],\"name\":\"NOPsSettledOffchain\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"acceptUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_3.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_3.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkUSD\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_3.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkUSD\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"executeCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumAutomationRegistryBase2_3.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"pauseUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"removeBillingOverrides\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"}],\"internalType\":\"structAutomationRegistryBase2_3.BillingOverrides\",\"name\":\"billingOverrides\",\"type\":\"tuple\"}],\"name\":\"setBillingOverrides\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"setUpkeepCheckData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"setUpkeepGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"config\",\"type\":\"bytes\"}],\"name\":\"setUpkeepOffchainConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"setUpkeepTriggerConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"simulatePerformUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"transferUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"unpauseUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawERC20Fees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLink\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x6101806040523480156200001257600080fd5b50604051620055fd380380620055fd83398101604081905262000035916200062f565b80816001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b91906200062f565b826001600160a01b031663226cf83c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200010091906200062f565b836001600160a01b031663614486af6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200016591906200062f565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca91906200062f565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f91906200062f565b866001600160a01b031663a08714c06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200026e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200029491906200062f565b876001600160a01b031663c5b964e06040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002f9919062000656565b886001600160a01b031663ac4dc59a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000338573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200035e91906200062f565b3380600081620003b55760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620003e857620003e8816200056b565b5050506001600160a01b0380891660805287811660a05286811660c05285811660e052848116610100528316610120526025805483919060ff19166001838181111562000439576200043962000679565b0217905550806001600160a01b0316610140816001600160a01b03168152505060c0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200049a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004c091906200068f565b60ff1660a0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000504573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200052a91906200068f565b60ff16146200054c576040516301f86e1760e41b815260040160405180910390fd5b5050506001600160a01b039095166101605250620006b4945050505050565b336001600160a01b03821603620005c55760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620003ac565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b03811681146200062c57600080fd5b50565b6000602082840312156200064257600080fd5b81516200064f8162000616565b9392505050565b6000602082840312156200066957600080fd5b8151600281106200064f57600080fd5b634e487b7160e01b600052602160045260246000fd5b600060208284031215620006a257600080fd5b815160ff811681146200064f57600080fd5b60805160a05160c05160e05161010051610120516101405161016051614ecd6200073060003960008181610177015261022401526000505060006127b10152600050506000612aa00152600061370e01526000612b7a015260008181610c2901528181610cea01528181610db501526128720152614ecd6000f3fe6080604052600436106101755760003560e01c80638765ecbe116100cb578063aed2e9291161007f578063ce7dc5b411610059578063ce7dc5b414610493578063f2fde38b146104b3578063f7d334ba146104d357610175565b8063aed2e9291461041c578063b148ab6b14610453578063cd7f71b51461047357610175565b80638dcf0fe7116100b05780638dcf0fe7146103bc578063a72aa27e146103dc578063a86e1781146103fc57610175565b80638765ecbe146103715780638da5cb5b1461039157610175565b806354b7faae1161012d57806371fae17f1161010757806371fae17f1461031c578063744bfe611461033c57806379ba50971461035c57610175565b806354b7faae146102a957806368d369d8146102c957806371791aa0146102e957610175565b8063349e8cca1161015e578063349e8cca146102155780634ee88d35146102695780635165f2f51461028957610175565b80631a2af011146101bc57806329c5efad146101dc575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e8080156101b5573d6000f35b3d6000fd5b005b3480156101c857600080fd5b506101ba6101d7366004613ed7565b6104f3565b3480156101e857600080fd5b506101fc6101f736600461404b565b6105f9565b60405161020c949392919061416a565b60405180910390f35b34801561022157600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161020c565b34801561027557600080fd5b506101ba6102843660046141ec565b6108d7565b34801561029557600080fd5b506101ba6102a4366004614238565b610939565b3480156102b557600080fd5b506101ba6102c4366004614251565b610aeb565b3480156102d557600080fd5b506101ba6102e436600461427d565b610d5e565b3480156102f557600080fd5b5061030961030436600461404b565b610fea565b60405161020c97969594939291906142be565b34801561032857600080fd5b506101ba610337366004614238565b61174e565b34801561034857600080fd5b506101ba610357366004613ed7565b6117e4565b34801561036857600080fd5b506101ba611c5c565b34801561037d57600080fd5b506101ba61038c366004614238565b611d59565b34801561039d57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610244565b3480156103c857600080fd5b506101ba6103d73660046141ec565b611f0e565b3480156103e857600080fd5b506101ba6103f736600461431e565b611f63565b34801561040857600080fd5b506101ba610417366004614343565b612062565b34801561042857600080fd5b5061043c6104373660046141ec565b612143565b60408051921515835260208301919091520161020c565b34801561045f57600080fd5b506101ba61046e366004614238565b6122ee565b34801561047f57600080fd5b506101ba61048e3660046141ec565b61251b565b34801561049f57600080fd5b506101fc6104ae3660046143bd565b6125d2565b3480156104bf57600080fd5b506101ba6104ce36600461449f565b612694565b3480156104df57600080fd5b506103096104ee366004614238565b6126a8565b6104fc826126e4565b3373ffffffffffffffffffffffffffffffffffffffff82160361054b576040517f8c8728c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526006602052604090205473ffffffffffffffffffffffffffffffffffffffff8281169116146105f55760008281526006602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff851690811790915590519091339185917fb1cbb2c4b8480034c27e06da5f096b8233a8fd4497028593a41ff6df79726b3591a45b5050565b60006060600080610608612799565b600086815260046020908152604091829020825161012081018452815460ff8082161515835261010080830490911615159483019490945263ffffffff620100008204811695830195909552660100000000000081048516606083015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009091048116608083015260018301546fffffffffffffffffffffffffffffffff811660a08401526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08401527c0100000000000000000000000000000000000000000000000000000000900490941660e0820152600290910154909216908201525a9150600080826080015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561075e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078291906144cc565b73ffffffffffffffffffffffffffffffffffffffff16601660000160149054906101000a900463ffffffff1663ffffffff16896040516107c291906144e9565b60006040518083038160008787f1925050503d8060008114610800576040519150601f19603f3d011682016040523d82523d6000602084013e610805565b606091505b50915091505a6108159085614534565b93508161083e5760006040518060200160405280600081525060079650965096505050506108ce565b80806020019051810190610852919061459c565b90975095508661087e5760006040518060200160405280600081525060049650965096505050506108ce565b60185486517401000000000000000000000000000000000000000090910463ffffffff1610156108ca5760006040518060200160405280600081525060059650965096505050506108ce565b5050505b92959194509250565b6108e0836126e4565b6000838152601d602052604090206108f9828483614681565b50827f2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d5664838360405161092c9291906147e5565b60405180910390a2505050565b610942816126e4565b600081815260046020908152604091829020825161012081018452815460ff808216151580845261010080840490921615159584019590955262010000820463ffffffff9081169684019690965266010000000000008204861660608401526a010000000000000000000090910473ffffffffffffffffffffffffffffffffffffffff908116608084015260018401546fffffffffffffffffffffffffffffffff811660a085015270010000000000000000000000000000000081046bffffffffffffffffffffffff1660c08501527c0100000000000000000000000000000000000000000000000000000000900490951660e083015260029092015490931690830152610a7c576040517f1b88a78400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260046020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055610abb60028361280a565b5060405182907f7bada562044eb163f6b4003c4553e4e62825344c0418eea087bed5ee05a4745690600090a25050565b610af361281f565b73ffffffffffffffffffffffffffffffffffffffff8216610b40576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610b4a612870565b90506000811215610b96576040517fcf47918100000000000000000000000000000000000000000000000000000000815260006004820152602481018390526044015b60405180910390fd5b80821115610bda576040517fcf4791810000000000000000000000000000000000000000000000000000000081526004810182905260248101839052604401610b8d565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490526000917f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af1158015610c74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c9891906147f9565b905080610cd1576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff167f5e110f8bc8a20b65dcc87f224bdf1cc039346e267118bae2739847f07321ffa885604051610d5091815260200190565b60405180910390a350505050565b610d6661281f565b73ffffffffffffffffffffffffffffffffffffffff8216610db3576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610e38576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610e42612870565b1215610e7a576040517f981bb6a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83166000818152602160205260408082205490517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152919290916370a0823190602401602060405180830381865afa158015610ef6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1a9190614814565b610f249190614534565b905080821115610f6a576040517fcf4791810000000000000000000000000000000000000000000000000000000081526004810182905260248101839052604401610b8d565b610f8b73ffffffffffffffffffffffffffffffffffffffff8516848461293f565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f5e110f8bc8a20b65dcc87f224bdf1cc039346e267118bae2739847f07321ffa884604051610d5091815260200190565b600060606000806000806000610ffe612799565b60006110098a6129d1565b905060006014604051806101200160405290816000820160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160008201600c9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160109054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160139054906101000a900461ffff1661ffff1661ffff1681526020016000820160159054906101000a900460ff1660ff1660ff1681526020016000820160169054906101000a900460ff161515151581526020016000820160179054906101000a900460ff161515151581526020016000820160189054906101000a900460ff161515151581526020016001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505090506000600460008d8152602001908152602001600020604051806101200160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900460ff161515151581526020016000820160029054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160069054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201600a9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1681526020016001820160109054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160018201601c9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505090506000808360a00151156113cc5750506040805160208101825260008082529290910151919a5098506009975089965063ffffffff169450859350839250611742915050565b606083015163ffffffff908116146114165750506040805160208101825260008082529290910151919a5098506001975089965063ffffffff169450859350839250611742915050565b8251156114555750506040805160208101825260008082529290910151919a5098506002975089965063ffffffff169450859350839250611742915050565b61145e84612a7c565b8094508198508299505050506114838e858786604001518b8b888a6101000151612c6e565b9050806bffffffffffffffffffffffff168360c001516bffffffffffffffffffffffff1610156114e55750506040805160208101825260008082529290910151919a5098506006975089965063ffffffff169450859350839250611742915050565b505060006114f48d858e612fde565b90505a9750600080836080015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561154b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156f91906144cc565b73ffffffffffffffffffffffffffffffffffffffff16601660000160149054906101000a900463ffffffff1663ffffffff16846040516115af91906144e9565b60006040518083038160008787f1925050503d80600081146115ed576040519150601f19603f3d011682016040523d82523d6000602084013e6115f2565b606091505b50915091505a611602908b614534565b995081611688576018548151780100000000000000000000000000000000000000000000000090910463ffffffff1610156116675750506040805160208101825260008082529390910151929b509950600898505063ffffffff169450611742915050565b604090930151929a50600399505063ffffffff909116955061174292505050565b8080602001905181019061169c919061459c565b909d509b508c6116d65750506040805160208101825260008082529390910151929b509950600498505063ffffffff169450611742915050565b6018548c517401000000000000000000000000000000000000000090910463ffffffff1610156117305750506040805160208101825260008082529390910151929b509950600598505063ffffffff169450611742915050565b5050506040015163ffffffff16945050505b92959891949750929550565b6117566131be565b600081815260046020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055602390915280822080547fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000001690555182917f97d0ef3f46a56168af653f547bdb6f77ec2b1d7d9bc6ba0193c2b340ec68064a91a250565b60145477010000000000000000000000000000000000000000000000900460ff161561183c576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff167701000000000000000000000000000000000000000000000017905573ffffffffffffffffffffffffffffffffffffffff81166118cb576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600460209081526040808320815161012081018352815460ff8082161515835261010080830490911615158387015263ffffffff620100008304811684870152660100000000000083048116606085015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009093048316608085015260018501546fffffffffffffffffffffffffffffffff811660a08601526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08601527c010000000000000000000000000000000000000000000000000000000090041660e084015260029093015481169282019290925286855260059093529220549091163314611a0b576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601554604080517f57e871e7000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff909216916357e871e7916004808201926020929091908290030181865afa158015611a7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a9f9190614814565b816060015163ffffffff161115611ae2576040517fff84e5dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526004602090815260408083206001015461010085015173ffffffffffffffffffffffffffffffffffffffff1684526021909252909120547001000000000000000000000000000000009091046bffffffffffffffffffffffff1690611b4d908290614534565b6101008301805173ffffffffffffffffffffffffffffffffffffffff908116600090815260216020908152604080832095909555888252600490529290922060010180547fffffffff000000000000000000000000ffffffffffffffffffffffffffffffff16905551611bd09116846bffffffffffffffffffffffff841661293f565b604080516bffffffffffffffffffffffff8316815273ffffffffffffffffffffffffffffffffffffffff8516602082015285917ff3b5906e5672f3e524854103bcafbbdba80dbdfeca2c35e116127b1060a68318910160405180910390a25050601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff1690555050565b60015473ffffffffffffffffffffffffffffffffffffffff163314611cdd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610b8d565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b611d62816126e4565b600081815260046020908152604091829020825161012081018452815460ff808216158015845261010080840490921615159584019590955262010000820463ffffffff9081169684019690965266010000000000008204861660608401526a010000000000000000000090910473ffffffffffffffffffffffffffffffffffffffff908116608084015260018401546fffffffffffffffffffffffffffffffff811660a085015270010000000000000000000000000000000081046bffffffffffffffffffffffff1660c08501527c0100000000000000000000000000000000000000000000000000000000900490951660e083015260029092015490931690830152611e9c576040517f514b6c2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260046020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055611ede60028361320f565b5060405182907f8ab10247ce168c27748e656ecf852b951fcaac790c18106b19aa0ae57a8b741f90600090a25050565b611f17836126e4565b6000838152601e60205260409020611f30828483614681565b50827f3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf4850838360405161092c9291906147e5565b6108fc8163ffffffff161080611fa0575060165463ffffffff78010000000000000000000000000000000000000000000000009091048116908216115b15611fd7576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611fe0826126e4565b60008281526004602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffff166201000063ffffffff861690810291909117909155915191825283917fc24c07e655ce79fba8a589778987d3c015bc6af1632bb20cf9182e02a65d972c91015b60405180910390a25050565b61206a6131be565b6000828152600460205260409020546601000000000000900463ffffffff908116146120c2576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260046020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055602390915290208190612110828261483e565b905050817fd8a6d79d170a55968079d3a89b960d86b4442aef6aac1d01e644c32b9e38b3408260405161205691906148c5565b60008061214e612799565b601454760100000000000000000000000000000000000000000000900460ff16156121a5576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600085815260046020908152604091829020825161012081018452815460ff8082161515835261010080830490911615158386015262010000820463ffffffff90811684880181905266010000000000008404821660608601526a010000000000000000000090930473ffffffffffffffffffffffffffffffffffffffff9081166080860181905260018701546fffffffffffffffffffffffffffffffff811660a088015270010000000000000000000000000000000081046bffffffffffffffffffffffff1660c08801527c0100000000000000000000000000000000000000000000000000000000900490921660e0860152600290950154909416908301528451601f890185900485028101850190955287855290936122e193899089908190840183828082843760009201919091525061321b92505050565b9097909650945050505050565b600081815260046020908152604091829020825161012081018452815460ff8082161515835261010080830490911615159483019490945263ffffffff6201000082048116958301959095526601000000000000810485166060830181905273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009092048216608084015260018401546fffffffffffffffffffffffffffffffff811660a08501526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08501527c01000000000000000000000000000000000000000000000000000000009004861660e0840152600290930154169281019290925290911461242a576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526006602052604090205473ffffffffffffffffffffffffffffffffffffffff163314612487576040517f6352a85300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602090815260408083208054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821790935560069094528285208054909216909155905173ffffffffffffffffffffffffffffffffffffffff90911692839186917f5cff4db96bef051785e999f44bfcd21c18823e034fb92dd376e3db4ce0feeb2c91a4505050565b612524836126e4565b6017547c0100000000000000000000000000000000000000000000000000000000900463ffffffff16811115612586576040517fae7235df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083815260076020526040902061259f828483614681565b50827fcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d838360405161092c9291906147e5565b600060606000806000634b56a42e60e01b8888886040516024016125f8939291906148fc565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152905061268189826105f9565b929c919b50995090975095505050505050565b61269c613436565b6126a5816134b7565b50565b6000606060008060008060006126cd8860405180602001604052806000815250610fea565b959e949d50929b5090995097509550909350915050565b60008181526005602052604090205473ffffffffffffffffffffffffffffffffffffffff163314612741576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600460205260409020546601000000000000900463ffffffff908116146126a5576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614612808576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b600061281683836135ac565b90505b92915050565b60185473ffffffffffffffffffffffffffffffffffffffff163314612808576040517fb6dfb7a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166000818152602160205260408082205490517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152919290916370a0823190602401602060405180830381865afa15801561290c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129309190614814565b61293a9190614992565b905090565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526129cc9084906135fb565b505050565b6000818160045b600f811015612a5e577fff000000000000000000000000000000000000000000000000000000000000008216838260208110612a1657612a166149b2565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614612a4c57506000949350505050565b80612a56816149e1565b9150506129d8565b5081600f1a6001811115612a7457612a74614100565b949350505050565b600080600080846040015162ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015612b09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b2d9190614a33565b5094509092505050600081131580612b4457508142105b80612b655750828015612b655750612b5c8242614534565b8463ffffffff16105b15612b74576019549650612b78565b8096505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015612be3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c079190614a33565b5094509092505050600081131580612c1e57508142105b80612c3f5750828015612c3f5750612c368242614534565b8463ffffffff16105b15612c4e57601a549550612c52565b8095505b8686612c5d8a613707565b965096509650505050509193909250565b6000808080896001811115612c8557612c85614100565b03612c94575062016b48612ce9565b6001896001811115612ca857612ca8614100565b03612cb757506201ccf0612ce9565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008a608001516001612cfc9190614a83565b612d0a9060ff166040614a9c565b601854612d38906103a49074010000000000000000000000000000000000000000900463ffffffff16614ab3565b612d429190614ab3565b601554604080517fde9ee35e0000000000000000000000000000000000000000000000000000000081528151939450600093849373ffffffffffffffffffffffffffffffffffffffff169263de9ee35e92600480820193918290030181865afa158015612db3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dd79190614ac6565b90925090508183612de9836018614ab3565b612df39190614a9c565b60808f0151612e03906001614a83565b612e129060ff166115e0614a9c565b612e1c9190614ab3565b612e269190614ab3565b612e309085614ab3565b6101008e01516040517f125441400000000000000000000000000000000000000000000000000000000081526004810186905291955073ffffffffffffffffffffffffffffffffffffffff1690631254414090602401602060405180830381865afa158015612ea3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ec79190614814565b8d6060015161ffff16612eda9190614a9c565b94505050506000612eeb8b866137f8565b60008d815260046020526040902054909150610100900460ff1615612f505760008c81526023602090815260409182902082518084019093525463ffffffff811680845262ffffff640100000000909204821693830193845284529151909116908201525b6000612fba8c6040518061012001604052808d63ffffffff1681526020018681526020018781526020018c81526020018b81526020018a81526020018973ffffffffffffffffffffffffffffffffffffffff16815260200185815260200160001515815250613949565b60208101518151919250612fcd91614aea565b9d9c50505050505050505050505050565b60606000836001811115612ff457612ff4614100565b036130bd576000848152600760205260409081902090517f6e04ff0d000000000000000000000000000000000000000000000000000000009161303991602401614baa565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290506131b7565b60018360018111156130d1576130d1614100565b03612cb7576000828060200190518101906130ec9190614c23565b6000868152600760205260409081902090519192507f40691db40000000000000000000000000000000000000000000000000000000091613131918491602401614d33565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915291506131b79050565b9392505050565b60175473ffffffffffffffffffffffffffffffffffffffff163314612808576040517f77c3599200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006128168383613b19565b601454600090819077010000000000000000000000000000000000000000000000900460ff1615613278576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16770100000000000000000000000000000000000000000000001790556040517f4585e33b00000000000000000000000000000000000000000000000000000000906132ed908590602401614dfe565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d16906133c09087908790600401614e11565b60408051808303816000875af11580156133de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134029190614e2a565b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16905590969095509350505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314612808576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610b8d565b3373ffffffffffffffffffffffffffffffffffffffff821603613536576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610b8d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008181526001830160205260408120546135f357508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155612819565b506000612819565b600061365d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16613c0c9092919063ffffffff16565b8051909150156129cc578080602001905181019061367b91906147f9565b6129cc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b8d565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613777573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061379b9190614a33565b509350509250506000821315806137b157508042105b806137e157506000846040015162ffffff161180156137e157506137d58142614534565b846040015162ffffff16105b156137f1575050601b5492915050565b5092915050565b604080516060810182526000808252602080830182815283850183905273ffffffffffffffffffffffffffffffffffffffff868116845260229092528483208054640100000000810462ffffff1690925263ffffffff8216855285517ffeaf968c00000000000000000000000000000000000000000000000000000000815295519495909484936701000000000000009093049092169163feaf968c9160048082019260a0929091908290030181865afa1580156138ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138de9190614a33565b509350509250506000821315806138f457508042105b8061392457506000866040015162ffffff1611801561392457506139188142614534565b866040015162ffffff16105b156139385760018301546040850152613940565b604084018290525b50505092915050565b6040805160808101825260008082526020820181905291810182905260608101919091526000836060015161ffff1683606001516139879190614a9c565b9050826101000151801561399a5750803a105b156139a257503a5b60008360a001518460400151856020015186600001516139c29190614ab3565b6139cc9085614a9c565b6139d69190614ab3565b6139e09190614a9c565b90506139fe8460e0015160400151826139f99190614e56565b613c1b565b6bffffffffffffffffffffffff1683526080840151613a21906139f99083614e56565b6bffffffffffffffffffffffff16604084015260e084015160200151600090613a589062ffffff16683635c9adc5dea00000614a9c565b9050600081633b9aca008760a001518860e001516000015163ffffffff1689604001518a6000015189613a8b9190614a9c565b613a959190614ab3565b613a9f9190614a9c565b613aa99190614a9c565b613ab39190614e56565b613abd9190614ab3565b9050613ad68660e0015160400151826139f99190614e56565b6bffffffffffffffffffffffff1660208601526080860151613afc906139f99083614e56565b6bffffffffffffffffffffffff1660608601525050505092915050565b60008181526001830160205260408120548015613c02576000613b3d600183614534565b8554909150600090613b5190600190614534565b9050818114613bb6576000866000018281548110613b7157613b716149b2565b9060005260206000200154905080876000018481548110613b9457613b946149b2565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613bc757613bc7614e91565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612819565b6000915050612819565b6060612a748484600085613cbd565b60006bffffffffffffffffffffffff821115613cb9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610b8d565b5090565b606082471015613d4f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b8d565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051613d7891906144e9565b60006040518083038185875af1925050503d8060008114613db5576040519150601f19603f3d011682016040523d82523d6000602084013e613dba565b606091505b5091509150613dcb87838387613dd6565b979650505050505050565b60608315613e6c578251600003613e655773ffffffffffffffffffffffffffffffffffffffff85163b613e65576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b8d565b5081612a74565b612a748383815115613e815781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b8d9190614dfe565b73ffffffffffffffffffffffffffffffffffffffff811681146126a557600080fd5b60008060408385031215613eea57600080fd5b823591506020830135613efc81613eb5565b809150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610100810167ffffffffffffffff81118282101715613f5a57613f5a613f07565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613fa757613fa7613f07565b604052919050565b600067ffffffffffffffff821115613fc957613fc9613f07565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261400657600080fd5b813561401961401482613faf565b613f60565b81815284602083860101111561402e57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561405e57600080fd5b82359150602083013567ffffffffffffffff81111561407c57600080fd5b61408885828601613ff5565b9150509250929050565b60005b838110156140ad578181015183820152602001614095565b50506000910152565b600081518084526140ce816020860160208601614092565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600a8110614166577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b841515815260806020820152600061418560808301866140b6565b9050614194604083018561412f565b82606083015295945050505050565b60008083601f8401126141b557600080fd5b50813567ffffffffffffffff8111156141cd57600080fd5b6020830191508360208285010111156141e557600080fd5b9250929050565b60008060006040848603121561420157600080fd5b83359250602084013567ffffffffffffffff81111561421f57600080fd5b61422b868287016141a3565b9497909650939450505050565b60006020828403121561424a57600080fd5b5035919050565b6000806040838503121561426457600080fd5b823561426f81613eb5565b946020939093013593505050565b60008060006060848603121561429257600080fd5b833561429d81613eb5565b925060208401356142ad81613eb5565b929592945050506040919091013590565b871515815260e0602082015260006142d960e08301896140b6565b90506142e8604083018861412f565b8560608301528460808301528360a08301528260c083015298975050505050505050565b63ffffffff811681146126a557600080fd5b6000806040838503121561433157600080fd5b823591506020830135613efc8161430c565b600080828403606081121561435757600080fd5b8335925060407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08201121561438b57600080fd5b506020830190509250929050565b600067ffffffffffffffff8211156143b3576143b3613f07565b5060051b60200190565b600080600080606085870312156143d357600080fd5b8435935060208086013567ffffffffffffffff808211156143f357600080fd5b818801915088601f83011261440757600080fd5b813561441561401482614399565b81815260059190911b8301840190848101908b83111561443457600080fd5b8585015b8381101561446c578035858111156144505760008081fd5b61445e8e89838a0101613ff5565b845250918601918601614438565b5097505050604088013592508083111561448557600080fd5b5050614493878288016141a3565b95989497509550505050565b6000602082840312156144b157600080fd5b81356131b781613eb5565b80516144c781613eb5565b919050565b6000602082840312156144de57600080fd5b81516131b781613eb5565b600082516144fb818460208701614092565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8181038181111561281957612819614505565b805180151581146144c757600080fd5b600082601f83011261456857600080fd5b815161457661401482613faf565b81815284602083860101111561458b57600080fd5b612a74826020830160208701614092565b600080604083850312156145af57600080fd5b6145b883614547565b9150602083015167ffffffffffffffff8111156145d457600080fd5b61408885828601614557565b600181811c908216806145f457607f821691505b60208210810361462d577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156129cc57600081815260208120601f850160051c8101602086101561465a5750805b601f850160051c820191505b8181101561467957828155600101614666565b505050505050565b67ffffffffffffffff83111561469957614699613f07565b6146ad836146a783546145e0565b83614633565b6000601f8411600181146146ff57600085156146c95750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614795565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b8281101561474e578685013582556020948501946001909201910161472e565b5086821015614789577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b602081526000612a7460208301848661479c565b60006020828403121561480b57600080fd5b61281682614547565b60006020828403121561482657600080fd5b5051919050565b62ffffff811681146126a557600080fd5b81356148498161430c565b63ffffffff811690508154817fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000821617835560208401356148898161482d565b66ffffff000000008160201b16837fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000008416171784555050505050565b6040810182356148d48161430c565b63ffffffff16825260208301356148ea8161482d565b62ffffff811660208401525092915050565b6000604082016040835280865180835260608501915060608160051b8601019250602080890160005b83811015614971577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa088870301855261495f8683516140b6565b95509382019390820190600101614925565b50508584038187015250505061498881858761479c565b9695505050505050565b81810360008312801583831316838312821617156137f1576137f1614505565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614a1257614a12614505565b5060010190565b805169ffffffffffffffffffff811681146144c757600080fd5b600080600080600060a08688031215614a4b57600080fd5b614a5486614a19565b9450602086015193506040860151925060608601519150614a7760808701614a19565b90509295509295909350565b60ff818116838216019081111561281957612819614505565b808202811582820484141761281957612819614505565b8082018082111561281957612819614505565b60008060408385031215614ad957600080fd5b505080516020909101519092909150565b6bffffffffffffffffffffffff8181168382160190808211156137f1576137f1614505565b60008154614b1c816145e0565b808552602060018381168015614b395760018114614b7157614b9f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b8901019550614b9f565b866000528260002060005b85811015614b975781548a8201860152908301908401614b7c565b890184019650505b505050505092915050565b6020815260006128166020830184614b0f565b600082601f830112614bce57600080fd5b81516020614bde61401483614399565b82815260059290921b84018101918181019086841115614bfd57600080fd5b8286015b84811015614c185780518352918301918301614c01565b509695505050505050565b600060208284031215614c3557600080fd5b815167ffffffffffffffff80821115614c4d57600080fd5b908301906101008286031215614c6257600080fd5b614c6a613f36565b8251815260208301516020820152604083015160408201526060830151606082015260808301516080820152614ca260a084016144bc565b60a082015260c083015182811115614cb957600080fd5b614cc587828601614bbd565b60c08301525060e083015182811115614cdd57600080fd5b614ce987828601614557565b60e08301525095945050505050565b600081518084526020808501945080840160005b83811015614d2857815187529582019590820190600101614d0c565b509495945050505050565b60408152825160408201526020830151606082015260408301516080820152606083015160a0820152608083015160c082015273ffffffffffffffffffffffffffffffffffffffff60a08401511660e0820152600060c0840151610100808185015250614da4610140840182614cf8565b905060e08501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc084830301610120850152614de082826140b6565b9150508281036020840152614df58185614b0f565b95945050505050565b60208152600061281660208301846140b6565b828152604060208201526000612a7460408301846140b6565b60008060408385031215614e3d57600080fd5b614e4683614547565b9150602083015190509250929050565b600082614e8c577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000813000a", } var AutomationRegistryLogicBABI = AutomationRegistryLogicBMetaData.ABI var AutomationRegistryLogicBBin = AutomationRegistryLogicBMetaData.Bin -func DeployAutomationRegistryLogicB(auth *bind.TransactOpts, backend bind.ContractBackend, link common.Address, linkUSDFeed common.Address, nativeUSDFeed common.Address, fastGasFeed common.Address, automationForwarderLogic common.Address, allowedReadOnlyAddress common.Address) (common.Address, *types.Transaction, *AutomationRegistryLogicB, error) { +func DeployAutomationRegistryLogicB(auth *bind.TransactOpts, backend bind.ContractBackend, logicC common.Address) (common.Address, *types.Transaction, *AutomationRegistryLogicB, error) { parsed, err := AutomationRegistryLogicBMetaData.GetAbi() if err != nil { return common.Address{}, nil, nil, err @@ -98,7 +61,7 @@ func DeployAutomationRegistryLogicB(auth *bind.TransactOpts, backend bind.Contra return common.Address{}, nil, nil, errors.New("GetABI returned nil") } - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(AutomationRegistryLogicBBin), backend, link, linkUSDFeed, nativeUSDFeed, fastGasFeed, automationForwarderLogic, allowedReadOnlyAddress) + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(AutomationRegistryLogicBBin), backend, logicC) if err != nil { return common.Address{}, nil, nil, err } @@ -221,1126 +184,560 @@ func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorRaw) Transact return _AutomationRegistryLogicB.Contract.contract.Transact(opts, method, params...) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetActiveUpkeepIDs(opts *bind.CallOpts, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) { +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) FallbackTo(opts *bind.CallOpts) (common.Address, error) { var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getActiveUpkeepIDs", startIndex, maxCount) + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "fallbackTo") if err != nil { - return *new([]*big.Int), err + return *new(common.Address), err } - out0 := *abi.ConvertType(out[0], new([]*big.Int)).(*[]*big.Int) + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) return out0, err } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetActiveUpkeepIDs(startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetActiveUpkeepIDs(&_AutomationRegistryLogicB.CallOpts, startIndex, maxCount) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) FallbackTo() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.FallbackTo(&_AutomationRegistryLogicB.CallOpts) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetActiveUpkeepIDs(startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetActiveUpkeepIDs(&_AutomationRegistryLogicB.CallOpts, startIndex, maxCount) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) FallbackTo() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.FallbackTo(&_AutomationRegistryLogicB.CallOpts) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetAdminPrivilegeConfig(opts *bind.CallOpts, admin common.Address) ([]byte, error) { +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) Owner(opts *bind.CallOpts) (common.Address, error) { var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getAdminPrivilegeConfig", admin) + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "owner") if err != nil { - return *new([]byte), err + return *new(common.Address), err } - out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) return out0, err } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetAdminPrivilegeConfig(admin common.Address) ([]byte, error) { - return _AutomationRegistryLogicB.Contract.GetAdminPrivilegeConfig(&_AutomationRegistryLogicB.CallOpts, admin) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) Owner() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.Owner(&_AutomationRegistryLogicB.CallOpts) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetAdminPrivilegeConfig(admin common.Address) ([]byte, error) { - return _AutomationRegistryLogicB.Contract.GetAdminPrivilegeConfig(&_AutomationRegistryLogicB.CallOpts, admin) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) Owner() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.Owner(&_AutomationRegistryLogicB.CallOpts) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetAllowedReadOnlyAddress(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getAllowedReadOnlyAddress") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "acceptOwnership") } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetAllowedReadOnlyAddress() (common.Address, error) { - return _AutomationRegistryLogicB.Contract.GetAllowedReadOnlyAddress(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) AcceptOwnership() (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.AcceptOwnership(&_AutomationRegistryLogicB.TransactOpts) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetAllowedReadOnlyAddress() (common.Address, error) { - return _AutomationRegistryLogicB.Contract.GetAllowedReadOnlyAddress(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) AcceptOwnership() (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.AcceptOwnership(&_AutomationRegistryLogicB.TransactOpts) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetAutomationForwarderLogic(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getAutomationForwarderLogic") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) AcceptUpkeepAdmin(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "acceptUpkeepAdmin", id) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetAutomationForwarderLogic() (common.Address, error) { - return _AutomationRegistryLogicB.Contract.GetAutomationForwarderLogic(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) AcceptUpkeepAdmin(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.AcceptUpkeepAdmin(&_AutomationRegistryLogicB.TransactOpts, id) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetAutomationForwarderLogic() (common.Address, error) { - return _AutomationRegistryLogicB.Contract.GetAutomationForwarderLogic(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) AcceptUpkeepAdmin(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.AcceptUpkeepAdmin(&_AutomationRegistryLogicB.TransactOpts, id) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetBalance(opts *bind.CallOpts, id *big.Int) (*big.Int, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getBalance", id) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) CheckCallback(opts *bind.TransactOpts, id *big.Int, values [][]byte, extraData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "checkCallback", id, values, extraData) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetBalance(id *big.Int) (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetBalance(&_AutomationRegistryLogicB.CallOpts, id) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) CheckCallback(id *big.Int, values [][]byte, extraData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.CheckCallback(&_AutomationRegistryLogicB.TransactOpts, id, values, extraData) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetBalance(id *big.Int) (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetBalance(&_AutomationRegistryLogicB.CallOpts, id) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) CheckCallback(id *big.Int, values [][]byte, extraData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.CheckCallback(&_AutomationRegistryLogicB.TransactOpts, id, values, extraData) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetBillingTokenConfig(opts *bind.CallOpts, token common.Address) (AutomationRegistryBase23BillingConfig, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getBillingTokenConfig", token) - - if err != nil { - return *new(AutomationRegistryBase23BillingConfig), err - } - - out0 := *abi.ConvertType(out[0], new(AutomationRegistryBase23BillingConfig)).(*AutomationRegistryBase23BillingConfig) - - return out0, err - +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) CheckUpkeep(opts *bind.TransactOpts, id *big.Int, triggerData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "checkUpkeep", id, triggerData) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetBillingTokenConfig(token common.Address) (AutomationRegistryBase23BillingConfig, error) { - return _AutomationRegistryLogicB.Contract.GetBillingTokenConfig(&_AutomationRegistryLogicB.CallOpts, token) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) CheckUpkeep(id *big.Int, triggerData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.CheckUpkeep(&_AutomationRegistryLogicB.TransactOpts, id, triggerData) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetBillingTokenConfig(token common.Address) (AutomationRegistryBase23BillingConfig, error) { - return _AutomationRegistryLogicB.Contract.GetBillingTokenConfig(&_AutomationRegistryLogicB.CallOpts, token) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) CheckUpkeep(id *big.Int, triggerData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.CheckUpkeep(&_AutomationRegistryLogicB.TransactOpts, id, triggerData) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetBillingTokens(opts *bind.CallOpts) ([]common.Address, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getBillingTokens") - - if err != nil { - return *new([]common.Address), err - } - - out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) - - return out0, err - +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) CheckUpkeep0(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "checkUpkeep0", id) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetBillingTokens() ([]common.Address, error) { - return _AutomationRegistryLogicB.Contract.GetBillingTokens(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) CheckUpkeep0(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.CheckUpkeep0(&_AutomationRegistryLogicB.TransactOpts, id) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetBillingTokens() ([]common.Address, error) { - return _AutomationRegistryLogicB.Contract.GetBillingTokens(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) CheckUpkeep0(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.CheckUpkeep0(&_AutomationRegistryLogicB.TransactOpts, id) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetCancellationDelay(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getCancellationDelay") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) ExecuteCallback(opts *bind.TransactOpts, id *big.Int, payload []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "executeCallback", id, payload) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetCancellationDelay() (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetCancellationDelay(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) ExecuteCallback(id *big.Int, payload []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.ExecuteCallback(&_AutomationRegistryLogicB.TransactOpts, id, payload) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetCancellationDelay() (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetCancellationDelay(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) ExecuteCallback(id *big.Int, payload []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.ExecuteCallback(&_AutomationRegistryLogicB.TransactOpts, id, payload) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetChainModule(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getChainModule") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) PauseUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "pauseUpkeep", id) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetChainModule() (common.Address, error) { - return _AutomationRegistryLogicB.Contract.GetChainModule(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) PauseUpkeep(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.PauseUpkeep(&_AutomationRegistryLogicB.TransactOpts, id) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetChainModule() (common.Address, error) { - return _AutomationRegistryLogicB.Contract.GetChainModule(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) PauseUpkeep(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.PauseUpkeep(&_AutomationRegistryLogicB.TransactOpts, id) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetConditionalGasOverhead(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getConditionalGasOverhead") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) RemoveBillingOverrides(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "removeBillingOverrides", id) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetConditionalGasOverhead() (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetConditionalGasOverhead(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) RemoveBillingOverrides(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.RemoveBillingOverrides(&_AutomationRegistryLogicB.TransactOpts, id) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetConditionalGasOverhead() (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetConditionalGasOverhead(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) RemoveBillingOverrides(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.RemoveBillingOverrides(&_AutomationRegistryLogicB.TransactOpts, id) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetFallbackNativePrice(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getFallbackNativePrice") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetBillingOverrides(opts *bind.TransactOpts, id *big.Int, billingOverrides AutomationRegistryBase23BillingOverrides) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "setBillingOverrides", id, billingOverrides) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetFallbackNativePrice() (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetFallbackNativePrice(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetBillingOverrides(id *big.Int, billingOverrides AutomationRegistryBase23BillingOverrides) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetBillingOverrides(&_AutomationRegistryLogicB.TransactOpts, id, billingOverrides) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetFallbackNativePrice() (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetFallbackNativePrice(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetBillingOverrides(id *big.Int, billingOverrides AutomationRegistryBase23BillingOverrides) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetBillingOverrides(&_AutomationRegistryLogicB.TransactOpts, id, billingOverrides) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetFastGasFeedAddress(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getFastGasFeedAddress") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetUpkeepCheckData(opts *bind.TransactOpts, id *big.Int, newCheckData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "setUpkeepCheckData", id, newCheckData) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetFastGasFeedAddress() (common.Address, error) { - return _AutomationRegistryLogicB.Contract.GetFastGasFeedAddress(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetUpkeepCheckData(id *big.Int, newCheckData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepCheckData(&_AutomationRegistryLogicB.TransactOpts, id, newCheckData) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetFastGasFeedAddress() (common.Address, error) { - return _AutomationRegistryLogicB.Contract.GetFastGasFeedAddress(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetUpkeepCheckData(id *big.Int, newCheckData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepCheckData(&_AutomationRegistryLogicB.TransactOpts, id, newCheckData) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetForwarder(opts *bind.CallOpts, upkeepID *big.Int) (common.Address, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getForwarder", upkeepID) - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetUpkeepGasLimit(opts *bind.TransactOpts, id *big.Int, gasLimit uint32) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "setUpkeepGasLimit", id, gasLimit) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetForwarder(upkeepID *big.Int) (common.Address, error) { - return _AutomationRegistryLogicB.Contract.GetForwarder(&_AutomationRegistryLogicB.CallOpts, upkeepID) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetUpkeepGasLimit(id *big.Int, gasLimit uint32) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepGasLimit(&_AutomationRegistryLogicB.TransactOpts, id, gasLimit) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetForwarder(upkeepID *big.Int) (common.Address, error) { - return _AutomationRegistryLogicB.Contract.GetForwarder(&_AutomationRegistryLogicB.CallOpts, upkeepID) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetUpkeepGasLimit(id *big.Int, gasLimit uint32) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepGasLimit(&_AutomationRegistryLogicB.TransactOpts, id, gasLimit) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetLinkAddress(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getLinkAddress") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetUpkeepOffchainConfig(opts *bind.TransactOpts, id *big.Int, config []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "setUpkeepOffchainConfig", id, config) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetLinkAddress() (common.Address, error) { - return _AutomationRegistryLogicB.Contract.GetLinkAddress(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetUpkeepOffchainConfig(id *big.Int, config []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepOffchainConfig(&_AutomationRegistryLogicB.TransactOpts, id, config) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetLinkAddress() (common.Address, error) { - return _AutomationRegistryLogicB.Contract.GetLinkAddress(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetUpkeepOffchainConfig(id *big.Int, config []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepOffchainConfig(&_AutomationRegistryLogicB.TransactOpts, id, config) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetLinkUSDFeedAddress(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getLinkUSDFeedAddress") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetUpkeepTriggerConfig(opts *bind.TransactOpts, id *big.Int, triggerConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "setUpkeepTriggerConfig", id, triggerConfig) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetLinkUSDFeedAddress() (common.Address, error) { - return _AutomationRegistryLogicB.Contract.GetLinkUSDFeedAddress(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetUpkeepTriggerConfig(id *big.Int, triggerConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepTriggerConfig(&_AutomationRegistryLogicB.TransactOpts, id, triggerConfig) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetLinkUSDFeedAddress() (common.Address, error) { - return _AutomationRegistryLogicB.Contract.GetLinkUSDFeedAddress(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetUpkeepTriggerConfig(id *big.Int, triggerConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepTriggerConfig(&_AutomationRegistryLogicB.TransactOpts, id, triggerConfig) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetLogGasOverhead(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getLogGasOverhead") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SimulatePerformUpkeep(opts *bind.TransactOpts, id *big.Int, performData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "simulatePerformUpkeep", id, performData) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetLogGasOverhead() (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetLogGasOverhead(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SimulatePerformUpkeep(id *big.Int, performData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SimulatePerformUpkeep(&_AutomationRegistryLogicB.TransactOpts, id, performData) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetLogGasOverhead() (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetLogGasOverhead(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SimulatePerformUpkeep(id *big.Int, performData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SimulatePerformUpkeep(&_AutomationRegistryLogicB.TransactOpts, id, performData) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetMaxPaymentForGas(opts *bind.CallOpts, triggerType uint8, gasLimit uint32) (*big.Int, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getMaxPaymentForGas", triggerType, gasLimit) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "transferOwnership", to) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetMaxPaymentForGas(triggerType uint8, gasLimit uint32) (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetMaxPaymentForGas(&_AutomationRegistryLogicB.CallOpts, triggerType, gasLimit) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.TransferOwnership(&_AutomationRegistryLogicB.TransactOpts, to) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetMaxPaymentForGas(triggerType uint8, gasLimit uint32) (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetMaxPaymentForGas(&_AutomationRegistryLogicB.CallOpts, triggerType, gasLimit) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.TransferOwnership(&_AutomationRegistryLogicB.TransactOpts, to) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetMinBalance(opts *bind.CallOpts, id *big.Int) (*big.Int, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getMinBalance", id) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) TransferUpkeepAdmin(opts *bind.TransactOpts, id *big.Int, proposed common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "transferUpkeepAdmin", id, proposed) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetMinBalance(id *big.Int) (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetMinBalance(&_AutomationRegistryLogicB.CallOpts, id) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) TransferUpkeepAdmin(id *big.Int, proposed common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.TransferUpkeepAdmin(&_AutomationRegistryLogicB.TransactOpts, id, proposed) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetMinBalance(id *big.Int) (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetMinBalance(&_AutomationRegistryLogicB.CallOpts, id) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) TransferUpkeepAdmin(id *big.Int, proposed common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.TransferUpkeepAdmin(&_AutomationRegistryLogicB.TransactOpts, id, proposed) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetMinBalanceForUpkeep(opts *bind.CallOpts, id *big.Int) (*big.Int, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getMinBalanceForUpkeep", id) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) UnpauseUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "unpauseUpkeep", id) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetMinBalanceForUpkeep(id *big.Int) (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetMinBalanceForUpkeep(&_AutomationRegistryLogicB.CallOpts, id) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) UnpauseUpkeep(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.UnpauseUpkeep(&_AutomationRegistryLogicB.TransactOpts, id) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetMinBalanceForUpkeep(id *big.Int) (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetMinBalanceForUpkeep(&_AutomationRegistryLogicB.CallOpts, id) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) UnpauseUpkeep(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.UnpauseUpkeep(&_AutomationRegistryLogicB.TransactOpts, id) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetNativeUSDFeedAddress(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getNativeUSDFeedAddress") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) WithdrawERC20Fees(opts *bind.TransactOpts, asset common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "withdrawERC20Fees", asset, to, amount) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetNativeUSDFeedAddress() (common.Address, error) { - return _AutomationRegistryLogicB.Contract.GetNativeUSDFeedAddress(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) WithdrawERC20Fees(asset common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.WithdrawERC20Fees(&_AutomationRegistryLogicB.TransactOpts, asset, to, amount) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetNativeUSDFeedAddress() (common.Address, error) { - return _AutomationRegistryLogicB.Contract.GetNativeUSDFeedAddress(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) WithdrawERC20Fees(asset common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.WithdrawERC20Fees(&_AutomationRegistryLogicB.TransactOpts, asset, to, amount) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetPeerRegistryMigrationPermission(opts *bind.CallOpts, peer common.Address) (uint8, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getPeerRegistryMigrationPermission", peer) - - if err != nil { - return *new(uint8), err - } - - out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) - - return out0, err - +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) WithdrawFunds(opts *bind.TransactOpts, id *big.Int, to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "withdrawFunds", id, to) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetPeerRegistryMigrationPermission(peer common.Address) (uint8, error) { - return _AutomationRegistryLogicB.Contract.GetPeerRegistryMigrationPermission(&_AutomationRegistryLogicB.CallOpts, peer) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) WithdrawFunds(id *big.Int, to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.WithdrawFunds(&_AutomationRegistryLogicB.TransactOpts, id, to) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetPeerRegistryMigrationPermission(peer common.Address) (uint8, error) { - return _AutomationRegistryLogicB.Contract.GetPeerRegistryMigrationPermission(&_AutomationRegistryLogicB.CallOpts, peer) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) WithdrawFunds(id *big.Int, to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.WithdrawFunds(&_AutomationRegistryLogicB.TransactOpts, id, to) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetPerPerformByteGasOverhead(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getPerPerformByteGasOverhead") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) WithdrawLink(opts *bind.TransactOpts, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "withdrawLink", to, amount) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetPerPerformByteGasOverhead() (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetPerPerformByteGasOverhead(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) WithdrawLink(to common.Address, amount *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.WithdrawLink(&_AutomationRegistryLogicB.TransactOpts, to, amount) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetPerPerformByteGasOverhead() (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetPerPerformByteGasOverhead(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) WithdrawLink(to common.Address, amount *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.WithdrawLink(&_AutomationRegistryLogicB.TransactOpts, to, amount) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetPerSignerGasOverhead(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getPerSignerGasOverhead") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.RawTransact(opts, calldata) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetPerSignerGasOverhead() (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetPerSignerGasOverhead(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) Fallback(calldata []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.Fallback(&_AutomationRegistryLogicB.TransactOpts, calldata) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetPerSignerGasOverhead() (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetPerSignerGasOverhead(&_AutomationRegistryLogicB.CallOpts) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) Fallback(calldata []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.Fallback(&_AutomationRegistryLogicB.TransactOpts, calldata) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetReorgProtectionEnabled(opts *bind.CallOpts) (bool, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getReorgProtectionEnabled") - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetReorgProtectionEnabled() (bool, error) { - return _AutomationRegistryLogicB.Contract.GetReorgProtectionEnabled(&_AutomationRegistryLogicB.CallOpts) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetReorgProtectionEnabled() (bool, error) { - return _AutomationRegistryLogicB.Contract.GetReorgProtectionEnabled(&_AutomationRegistryLogicB.CallOpts) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetSignerInfo(opts *bind.CallOpts, query common.Address) (GetSignerInfo, - - error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getSignerInfo", query) - - outstruct := new(GetSignerInfo) - if err != nil { - return *outstruct, err - } - - outstruct.Active = *abi.ConvertType(out[0], new(bool)).(*bool) - outstruct.Index = *abi.ConvertType(out[1], new(uint8)).(*uint8) - - return *outstruct, err - -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetSignerInfo(query common.Address) (GetSignerInfo, - - error) { - return _AutomationRegistryLogicB.Contract.GetSignerInfo(&_AutomationRegistryLogicB.CallOpts, query) -} +type AutomationRegistryLogicBAdminPrivilegeConfigSetIterator struct { + Event *AutomationRegistryLogicBAdminPrivilegeConfigSet -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetSignerInfo(query common.Address) (GetSignerInfo, + contract *bind.BoundContract + event string - error) { - return _AutomationRegistryLogicB.Contract.GetSignerInfo(&_AutomationRegistryLogicB.CallOpts, query) + logs chan types.Log + sub ethereum.Subscription + done bool + fail error } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetState(opts *bind.CallOpts) (GetState, - - error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getState") +func (it *AutomationRegistryLogicBAdminPrivilegeConfigSetIterator) Next() bool { - outstruct := new(GetState) - if err != nil { - return *outstruct, err + if it.fail != nil { + return false } - outstruct.State = *abi.ConvertType(out[0], new(AutomationRegistryBase23State)).(*AutomationRegistryBase23State) - outstruct.Config = *abi.ConvertType(out[1], new(AutomationRegistryBase23OnchainConfigLegacy)).(*AutomationRegistryBase23OnchainConfigLegacy) - outstruct.Signers = *abi.ConvertType(out[2], new([]common.Address)).(*[]common.Address) - outstruct.Transmitters = *abi.ConvertType(out[3], new([]common.Address)).(*[]common.Address) - outstruct.F = *abi.ConvertType(out[4], new(uint8)).(*uint8) - - return *outstruct, err - -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetState() (GetState, - - error) { - return _AutomationRegistryLogicB.Contract.GetState(&_AutomationRegistryLogicB.CallOpts) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetState() (GetState, - - error) { - return _AutomationRegistryLogicB.Contract.GetState(&_AutomationRegistryLogicB.CallOpts) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetTransmitCalldataFixedBytesOverhead(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getTransmitCalldataFixedBytesOverhead") + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBAdminPrivilegeConfigSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true - if err != nil { - return *new(*big.Int), err + default: + return false + } } - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetTransmitCalldataFixedBytesOverhead() (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetTransmitCalldataFixedBytesOverhead(&_AutomationRegistryLogicB.CallOpts) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetTransmitCalldataFixedBytesOverhead() (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetTransmitCalldataFixedBytesOverhead(&_AutomationRegistryLogicB.CallOpts) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetTransmitCalldataPerSignerBytesOverhead(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getTransmitCalldataPerSignerBytesOverhead") + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBAdminPrivilegeConfigSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true - if err != nil { - return *new(*big.Int), err + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetTransmitCalldataPerSignerBytesOverhead() (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetTransmitCalldataPerSignerBytesOverhead(&_AutomationRegistryLogicB.CallOpts) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetTransmitCalldataPerSignerBytesOverhead() (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.GetTransmitCalldataPerSignerBytesOverhead(&_AutomationRegistryLogicB.CallOpts) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetTransmitterInfo(opts *bind.CallOpts, query common.Address) (GetTransmitterInfo, - - error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getTransmitterInfo", query) - - outstruct := new(GetTransmitterInfo) - if err != nil { - return *outstruct, err - } - - outstruct.Active = *abi.ConvertType(out[0], new(bool)).(*bool) - outstruct.Index = *abi.ConvertType(out[1], new(uint8)).(*uint8) - outstruct.Balance = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) - outstruct.LastCollected = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) - outstruct.Payee = *abi.ConvertType(out[4], new(common.Address)).(*common.Address) - - return *outstruct, err - +func (it *AutomationRegistryLogicBAdminPrivilegeConfigSetIterator) Error() error { + return it.fail } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetTransmitterInfo(query common.Address) (GetTransmitterInfo, - - error) { - return _AutomationRegistryLogicB.Contract.GetTransmitterInfo(&_AutomationRegistryLogicB.CallOpts, query) +func (it *AutomationRegistryLogicBAdminPrivilegeConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetTransmitterInfo(query common.Address) (GetTransmitterInfo, - - error) { - return _AutomationRegistryLogicB.Contract.GetTransmitterInfo(&_AutomationRegistryLogicB.CallOpts, query) +type AutomationRegistryLogicBAdminPrivilegeConfigSet struct { + Admin common.Address + PrivilegeConfig []byte + Raw types.Log } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetTriggerType(opts *bind.CallOpts, upkeepId *big.Int) (uint8, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getTriggerType", upkeepId) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterAdminPrivilegeConfigSet(opts *bind.FilterOpts, admin []common.Address) (*AutomationRegistryLogicBAdminPrivilegeConfigSetIterator, error) { - if err != nil { - return *new(uint8), err + var adminRule []interface{} + for _, adminItem := range admin { + adminRule = append(adminRule, adminItem) } - out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) - - return out0, err - -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetTriggerType(upkeepId *big.Int) (uint8, error) { - return _AutomationRegistryLogicB.Contract.GetTriggerType(&_AutomationRegistryLogicB.CallOpts, upkeepId) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetTriggerType(upkeepId *big.Int) (uint8, error) { - return _AutomationRegistryLogicB.Contract.GetTriggerType(&_AutomationRegistryLogicB.CallOpts, upkeepId) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetUpkeep(opts *bind.CallOpts, id *big.Int) (AutomationRegistryBase23UpkeepInfo, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getUpkeep", id) - + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "AdminPrivilegeConfigSet", adminRule) if err != nil { - return *new(AutomationRegistryBase23UpkeepInfo), err + return nil, err } - - out0 := *abi.ConvertType(out[0], new(AutomationRegistryBase23UpkeepInfo)).(*AutomationRegistryBase23UpkeepInfo) - - return out0, err - -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetUpkeep(id *big.Int) (AutomationRegistryBase23UpkeepInfo, error) { - return _AutomationRegistryLogicB.Contract.GetUpkeep(&_AutomationRegistryLogicB.CallOpts, id) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetUpkeep(id *big.Int) (AutomationRegistryBase23UpkeepInfo, error) { - return _AutomationRegistryLogicB.Contract.GetUpkeep(&_AutomationRegistryLogicB.CallOpts, id) + return &AutomationRegistryLogicBAdminPrivilegeConfigSetIterator{contract: _AutomationRegistryLogicB.contract, event: "AdminPrivilegeConfigSet", logs: logs, sub: sub}, nil } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetUpkeepPrivilegeConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getUpkeepPrivilegeConfig", upkeepId) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchAdminPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBAdminPrivilegeConfigSet, admin []common.Address) (event.Subscription, error) { - if err != nil { - return *new([]byte), err + var adminRule []interface{} + for _, adminItem := range admin { + adminRule = append(adminRule, adminItem) } - out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) - - return out0, err - -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) { - return _AutomationRegistryLogicB.Contract.GetUpkeepPrivilegeConfig(&_AutomationRegistryLogicB.CallOpts, upkeepId) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) { - return _AutomationRegistryLogicB.Contract.GetUpkeepPrivilegeConfig(&_AutomationRegistryLogicB.CallOpts, upkeepId) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetUpkeepTriggerConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getUpkeepTriggerConfig", upkeepId) - + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "AdminPrivilegeConfigSet", adminRule) if err != nil { - return *new([]byte), err + return nil, err } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: - out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) - - return out0, err - -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetUpkeepTriggerConfig(upkeepId *big.Int) ([]byte, error) { - return _AutomationRegistryLogicB.Contract.GetUpkeepTriggerConfig(&_AutomationRegistryLogicB.CallOpts, upkeepId) -} + event := new(AutomationRegistryLogicBAdminPrivilegeConfigSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "AdminPrivilegeConfigSet", log); err != nil { + return err + } + event.Raw = log -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetUpkeepTriggerConfig(upkeepId *big.Int) ([]byte, error) { - return _AutomationRegistryLogicB.Contract.GetUpkeepTriggerConfig(&_AutomationRegistryLogicB.CallOpts, upkeepId) + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) HasDedupKey(opts *bind.CallOpts, dedupKey [32]byte) (bool, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "hasDedupKey", dedupKey) - - if err != nil { - return *new(bool), err +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseAdminPrivilegeConfigSet(log types.Log) (*AutomationRegistryLogicBAdminPrivilegeConfigSet, error) { + event := new(AutomationRegistryLogicBAdminPrivilegeConfigSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "AdminPrivilegeConfigSet", log); err != nil { + return nil, err } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) HasDedupKey(dedupKey [32]byte) (bool, error) { - return _AutomationRegistryLogicB.Contract.HasDedupKey(&_AutomationRegistryLogicB.CallOpts, dedupKey) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) HasDedupKey(dedupKey [32]byte) (bool, error) { - return _AutomationRegistryLogicB.Contract.HasDedupKey(&_AutomationRegistryLogicB.CallOpts, dedupKey) + event.Raw = log + return event, nil } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) LinkAvailableForPayment(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "linkAvailableForPayment") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} +type AutomationRegistryLogicBBillingConfigOverriddenIterator struct { + Event *AutomationRegistryLogicBBillingConfigOverridden -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) LinkAvailableForPayment() (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.LinkAvailableForPayment(&_AutomationRegistryLogicB.CallOpts) -} + contract *bind.BoundContract + event string -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) LinkAvailableForPayment() (*big.Int, error) { - return _AutomationRegistryLogicB.Contract.LinkAvailableForPayment(&_AutomationRegistryLogicB.CallOpts) + logs chan types.Log + sub ethereum.Subscription + done bool + fail error } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) Owner(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "owner") +func (it *AutomationRegistryLogicBBillingConfigOverriddenIterator) Next() bool { - if err != nil { - return *new(common.Address), err + if it.fail != nil { + return false } - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) Owner() (common.Address, error) { - return _AutomationRegistryLogicB.Contract.Owner(&_AutomationRegistryLogicB.CallOpts) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) Owner() (common.Address, error) { - return _AutomationRegistryLogicB.Contract.Owner(&_AutomationRegistryLogicB.CallOpts) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) UpkeepTranscoderVersion(opts *bind.CallOpts) (uint8, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "upkeepTranscoderVersion") + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBBillingConfigOverridden) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true - if err != nil { - return *new(uint8), err + default: + return false + } } - out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) - - return out0, err - -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) UpkeepTranscoderVersion() (uint8, error) { - return _AutomationRegistryLogicB.Contract.UpkeepTranscoderVersion(&_AutomationRegistryLogicB.CallOpts) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) UpkeepTranscoderVersion() (uint8, error) { - return _AutomationRegistryLogicB.Contract.UpkeepTranscoderVersion(&_AutomationRegistryLogicB.CallOpts) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) UpkeepVersion(opts *bind.CallOpts) (uint8, error) { - var out []interface{} - err := _AutomationRegistryLogicB.contract.Call(opts, &out, "upkeepVersion") + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBBillingConfigOverridden) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true - if err != nil { - return *new(uint8), err + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() } - - out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) - - return out0, err - -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) UpkeepVersion() (uint8, error) { - return _AutomationRegistryLogicB.Contract.UpkeepVersion(&_AutomationRegistryLogicB.CallOpts) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) UpkeepVersion() (uint8, error) { - return _AutomationRegistryLogicB.Contract.UpkeepVersion(&_AutomationRegistryLogicB.CallOpts) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { - return _AutomationRegistryLogicB.contract.Transact(opts, "acceptOwnership") -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) AcceptOwnership() (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.AcceptOwnership(&_AutomationRegistryLogicB.TransactOpts) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) AcceptOwnership() (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.AcceptOwnership(&_AutomationRegistryLogicB.TransactOpts) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) AcceptPayeeship(opts *bind.TransactOpts, transmitter common.Address) (*types.Transaction, error) { - return _AutomationRegistryLogicB.contract.Transact(opts, "acceptPayeeship", transmitter) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) AcceptPayeeship(transmitter common.Address) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.AcceptPayeeship(&_AutomationRegistryLogicB.TransactOpts, transmitter) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) AcceptPayeeship(transmitter common.Address) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.AcceptPayeeship(&_AutomationRegistryLogicB.TransactOpts, transmitter) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) AcceptUpkeepAdmin(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { - return _AutomationRegistryLogicB.contract.Transact(opts, "acceptUpkeepAdmin", id) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) AcceptUpkeepAdmin(id *big.Int) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.AcceptUpkeepAdmin(&_AutomationRegistryLogicB.TransactOpts, id) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) AcceptUpkeepAdmin(id *big.Int) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.AcceptUpkeepAdmin(&_AutomationRegistryLogicB.TransactOpts, id) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) Pause(opts *bind.TransactOpts) (*types.Transaction, error) { - return _AutomationRegistryLogicB.contract.Transact(opts, "pause") -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) Pause() (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.Pause(&_AutomationRegistryLogicB.TransactOpts) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) Pause() (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.Pause(&_AutomationRegistryLogicB.TransactOpts) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) PauseUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { - return _AutomationRegistryLogicB.contract.Transact(opts, "pauseUpkeep", id) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) PauseUpkeep(id *big.Int) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.PauseUpkeep(&_AutomationRegistryLogicB.TransactOpts, id) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) PauseUpkeep(id *big.Int) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.PauseUpkeep(&_AutomationRegistryLogicB.TransactOpts, id) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetAdminPrivilegeConfig(opts *bind.TransactOpts, admin common.Address, newPrivilegeConfig []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicB.contract.Transact(opts, "setAdminPrivilegeConfig", admin, newPrivilegeConfig) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetAdminPrivilegeConfig(admin common.Address, newPrivilegeConfig []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.SetAdminPrivilegeConfig(&_AutomationRegistryLogicB.TransactOpts, admin, newPrivilegeConfig) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetAdminPrivilegeConfig(admin common.Address, newPrivilegeConfig []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.SetAdminPrivilegeConfig(&_AutomationRegistryLogicB.TransactOpts, admin, newPrivilegeConfig) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetPayees(opts *bind.TransactOpts, payees []common.Address) (*types.Transaction, error) { - return _AutomationRegistryLogicB.contract.Transact(opts, "setPayees", payees) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetPayees(payees []common.Address) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.SetPayees(&_AutomationRegistryLogicB.TransactOpts, payees) } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetPayees(payees []common.Address) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.SetPayees(&_AutomationRegistryLogicB.TransactOpts, payees) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetPeerRegistryMigrationPermission(opts *bind.TransactOpts, peer common.Address, permission uint8) (*types.Transaction, error) { - return _AutomationRegistryLogicB.contract.Transact(opts, "setPeerRegistryMigrationPermission", peer, permission) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetPeerRegistryMigrationPermission(peer common.Address, permission uint8) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.SetPeerRegistryMigrationPermission(&_AutomationRegistryLogicB.TransactOpts, peer, permission) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetPeerRegistryMigrationPermission(peer common.Address, permission uint8) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.SetPeerRegistryMigrationPermission(&_AutomationRegistryLogicB.TransactOpts, peer, permission) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetUpkeepCheckData(opts *bind.TransactOpts, id *big.Int, newCheckData []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicB.contract.Transact(opts, "setUpkeepCheckData", id, newCheckData) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetUpkeepCheckData(id *big.Int, newCheckData []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.SetUpkeepCheckData(&_AutomationRegistryLogicB.TransactOpts, id, newCheckData) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetUpkeepCheckData(id *big.Int, newCheckData []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.SetUpkeepCheckData(&_AutomationRegistryLogicB.TransactOpts, id, newCheckData) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetUpkeepGasLimit(opts *bind.TransactOpts, id *big.Int, gasLimit uint32) (*types.Transaction, error) { - return _AutomationRegistryLogicB.contract.Transact(opts, "setUpkeepGasLimit", id, gasLimit) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetUpkeepGasLimit(id *big.Int, gasLimit uint32) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.SetUpkeepGasLimit(&_AutomationRegistryLogicB.TransactOpts, id, gasLimit) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetUpkeepGasLimit(id *big.Int, gasLimit uint32) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.SetUpkeepGasLimit(&_AutomationRegistryLogicB.TransactOpts, id, gasLimit) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetUpkeepOffchainConfig(opts *bind.TransactOpts, id *big.Int, config []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicB.contract.Transact(opts, "setUpkeepOffchainConfig", id, config) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetUpkeepOffchainConfig(id *big.Int, config []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.SetUpkeepOffchainConfig(&_AutomationRegistryLogicB.TransactOpts, id, config) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetUpkeepOffchainConfig(id *big.Int, config []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.SetUpkeepOffchainConfig(&_AutomationRegistryLogicB.TransactOpts, id, config) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetUpkeepPrivilegeConfig(opts *bind.TransactOpts, upkeepId *big.Int, newPrivilegeConfig []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicB.contract.Transact(opts, "setUpkeepPrivilegeConfig", upkeepId, newPrivilegeConfig) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetUpkeepPrivilegeConfig(upkeepId *big.Int, newPrivilegeConfig []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.SetUpkeepPrivilegeConfig(&_AutomationRegistryLogicB.TransactOpts, upkeepId, newPrivilegeConfig) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetUpkeepPrivilegeConfig(upkeepId *big.Int, newPrivilegeConfig []byte) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.SetUpkeepPrivilegeConfig(&_AutomationRegistryLogicB.TransactOpts, upkeepId, newPrivilegeConfig) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { - return _AutomationRegistryLogicB.contract.Transact(opts, "transferOwnership", to) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) TransferOwnership(to common.Address) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.TransferOwnership(&_AutomationRegistryLogicB.TransactOpts, to) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.TransferOwnership(&_AutomationRegistryLogicB.TransactOpts, to) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) TransferPayeeship(opts *bind.TransactOpts, transmitter common.Address, proposed common.Address) (*types.Transaction, error) { - return _AutomationRegistryLogicB.contract.Transact(opts, "transferPayeeship", transmitter, proposed) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) TransferPayeeship(transmitter common.Address, proposed common.Address) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.TransferPayeeship(&_AutomationRegistryLogicB.TransactOpts, transmitter, proposed) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) TransferPayeeship(transmitter common.Address, proposed common.Address) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.TransferPayeeship(&_AutomationRegistryLogicB.TransactOpts, transmitter, proposed) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) TransferUpkeepAdmin(opts *bind.TransactOpts, id *big.Int, proposed common.Address) (*types.Transaction, error) { - return _AutomationRegistryLogicB.contract.Transact(opts, "transferUpkeepAdmin", id, proposed) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) TransferUpkeepAdmin(id *big.Int, proposed common.Address) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.TransferUpkeepAdmin(&_AutomationRegistryLogicB.TransactOpts, id, proposed) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) TransferUpkeepAdmin(id *big.Int, proposed common.Address) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.TransferUpkeepAdmin(&_AutomationRegistryLogicB.TransactOpts, id, proposed) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) Unpause(opts *bind.TransactOpts) (*types.Transaction, error) { - return _AutomationRegistryLogicB.contract.Transact(opts, "unpause") -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) Unpause() (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.Unpause(&_AutomationRegistryLogicB.TransactOpts) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) Unpause() (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.Unpause(&_AutomationRegistryLogicB.TransactOpts) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) UnpauseUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { - return _AutomationRegistryLogicB.contract.Transact(opts, "unpauseUpkeep", id) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) UnpauseUpkeep(id *big.Int) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.UnpauseUpkeep(&_AutomationRegistryLogicB.TransactOpts, id) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) UnpauseUpkeep(id *big.Int) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.UnpauseUpkeep(&_AutomationRegistryLogicB.TransactOpts, id) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) WithdrawERC20Fees(opts *bind.TransactOpts, assetAddress common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { - return _AutomationRegistryLogicB.contract.Transact(opts, "withdrawERC20Fees", assetAddress, to, amount) -} - -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) WithdrawERC20Fees(assetAddress common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.WithdrawERC20Fees(&_AutomationRegistryLogicB.TransactOpts, assetAddress, to, amount) +func (it *AutomationRegistryLogicBBillingConfigOverriddenIterator) Error() error { + return it.fail } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) WithdrawERC20Fees(assetAddress common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.WithdrawERC20Fees(&_AutomationRegistryLogicB.TransactOpts, assetAddress, to, amount) +func (it *AutomationRegistryLogicBBillingConfigOverriddenIterator) Close() error { + it.sub.Unsubscribe() + return nil } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) WithdrawFunds(opts *bind.TransactOpts, id *big.Int, to common.Address) (*types.Transaction, error) { - return _AutomationRegistryLogicB.contract.Transact(opts, "withdrawFunds", id, to) +type AutomationRegistryLogicBBillingConfigOverridden struct { + Id *big.Int + Overrides AutomationRegistryBase23BillingOverrides + Raw types.Log } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) WithdrawFunds(id *big.Int, to common.Address) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.WithdrawFunds(&_AutomationRegistryLogicB.TransactOpts, id, to) -} +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterBillingConfigOverridden(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBBillingConfigOverriddenIterator, error) { -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) WithdrawFunds(id *big.Int, to common.Address) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.WithdrawFunds(&_AutomationRegistryLogicB.TransactOpts, id, to) -} + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) WithdrawLinkFees(opts *bind.TransactOpts, to common.Address, amount *big.Int) (*types.Transaction, error) { - return _AutomationRegistryLogicB.contract.Transact(opts, "withdrawLinkFees", to, amount) + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "BillingConfigOverridden", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBBillingConfigOverriddenIterator{contract: _AutomationRegistryLogicB.contract, event: "BillingConfigOverridden", logs: logs, sub: sub}, nil } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) WithdrawLinkFees(to common.Address, amount *big.Int) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.WithdrawLinkFees(&_AutomationRegistryLogicB.TransactOpts, to, amount) -} +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchBillingConfigOverridden(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBBillingConfigOverridden, id []*big.Int) (event.Subscription, error) { -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) WithdrawLinkFees(to common.Address, amount *big.Int) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.WithdrawLinkFees(&_AutomationRegistryLogicB.TransactOpts, to, amount) -} + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) WithdrawPayment(opts *bind.TransactOpts, from common.Address, to common.Address) (*types.Transaction, error) { - return _AutomationRegistryLogicB.contract.Transact(opts, "withdrawPayment", from, to) -} + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "BillingConfigOverridden", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBBillingConfigOverridden) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "BillingConfigOverridden", log); err != nil { + return err + } + event.Raw = log -func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) WithdrawPayment(from common.Address, to common.Address) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.WithdrawPayment(&_AutomationRegistryLogicB.TransactOpts, from, to) + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) WithdrawPayment(from common.Address, to common.Address) (*types.Transaction, error) { - return _AutomationRegistryLogicB.Contract.WithdrawPayment(&_AutomationRegistryLogicB.TransactOpts, from, to) +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseBillingConfigOverridden(log types.Log) (*AutomationRegistryLogicBBillingConfigOverridden, error) { + event := new(AutomationRegistryLogicBBillingConfigOverridden) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "BillingConfigOverridden", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil } -type AutomationRegistryLogicBAdminPrivilegeConfigSetIterator struct { - Event *AutomationRegistryLogicBAdminPrivilegeConfigSet +type AutomationRegistryLogicBBillingConfigOverrideRemovedIterator struct { + Event *AutomationRegistryLogicBBillingConfigOverrideRemoved contract *bind.BoundContract event string @@ -1351,7 +748,7 @@ type AutomationRegistryLogicBAdminPrivilegeConfigSetIterator struct { fail error } -func (it *AutomationRegistryLogicBAdminPrivilegeConfigSetIterator) Next() bool { +func (it *AutomationRegistryLogicBBillingConfigOverrideRemovedIterator) Next() bool { if it.fail != nil { return false @@ -1360,7 +757,7 @@ func (it *AutomationRegistryLogicBAdminPrivilegeConfigSetIterator) Next() bool { if it.done { select { case log := <-it.logs: - it.Event = new(AutomationRegistryLogicBAdminPrivilegeConfigSet) + it.Event = new(AutomationRegistryLogicBBillingConfigOverrideRemoved) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -1375,7 +772,7 @@ func (it *AutomationRegistryLogicBAdminPrivilegeConfigSetIterator) Next() bool { select { case log := <-it.logs: - it.Event = new(AutomationRegistryLogicBAdminPrivilegeConfigSet) + it.Event = new(AutomationRegistryLogicBBillingConfigOverrideRemoved) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -1390,43 +787,42 @@ func (it *AutomationRegistryLogicBAdminPrivilegeConfigSetIterator) Next() bool { } } -func (it *AutomationRegistryLogicBAdminPrivilegeConfigSetIterator) Error() error { +func (it *AutomationRegistryLogicBBillingConfigOverrideRemovedIterator) Error() error { return it.fail } -func (it *AutomationRegistryLogicBAdminPrivilegeConfigSetIterator) Close() error { +func (it *AutomationRegistryLogicBBillingConfigOverrideRemovedIterator) Close() error { it.sub.Unsubscribe() return nil } -type AutomationRegistryLogicBAdminPrivilegeConfigSet struct { - Admin common.Address - PrivilegeConfig []byte - Raw types.Log +type AutomationRegistryLogicBBillingConfigOverrideRemoved struct { + Id *big.Int + Raw types.Log } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterAdminPrivilegeConfigSet(opts *bind.FilterOpts, admin []common.Address) (*AutomationRegistryLogicBAdminPrivilegeConfigSetIterator, error) { +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterBillingConfigOverrideRemoved(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBBillingConfigOverrideRemovedIterator, error) { - var adminRule []interface{} - for _, adminItem := range admin { - adminRule = append(adminRule, adminItem) + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) } - logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "AdminPrivilegeConfigSet", adminRule) + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "BillingConfigOverrideRemoved", idRule) if err != nil { return nil, err } - return &AutomationRegistryLogicBAdminPrivilegeConfigSetIterator{contract: _AutomationRegistryLogicB.contract, event: "AdminPrivilegeConfigSet", logs: logs, sub: sub}, nil + return &AutomationRegistryLogicBBillingConfigOverrideRemovedIterator{contract: _AutomationRegistryLogicB.contract, event: "BillingConfigOverrideRemoved", logs: logs, sub: sub}, nil } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchAdminPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBAdminPrivilegeConfigSet, admin []common.Address) (event.Subscription, error) { +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchBillingConfigOverrideRemoved(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBBillingConfigOverrideRemoved, id []*big.Int) (event.Subscription, error) { - var adminRule []interface{} - for _, adminItem := range admin { - adminRule = append(adminRule, adminItem) + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) } - logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "AdminPrivilegeConfigSet", adminRule) + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "BillingConfigOverrideRemoved", idRule) if err != nil { return nil, err } @@ -1436,8 +832,8 @@ func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchAdminPri select { case log := <-logs: - event := new(AutomationRegistryLogicBAdminPrivilegeConfigSet) - if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "AdminPrivilegeConfigSet", log); err != nil { + event := new(AutomationRegistryLogicBBillingConfigOverrideRemoved) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "BillingConfigOverrideRemoved", log); err != nil { return err } event.Raw = log @@ -1458,9 +854,9 @@ func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchAdminPri }), nil } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseAdminPrivilegeConfigSet(log types.Log) (*AutomationRegistryLogicBAdminPrivilegeConfigSet, error) { - event := new(AutomationRegistryLogicBAdminPrivilegeConfigSet) - if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "AdminPrivilegeConfigSet", log); err != nil { +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseBillingConfigOverrideRemoved(log types.Log) (*AutomationRegistryLogicBBillingConfigOverrideRemoved, error) { + event := new(AutomationRegistryLogicBBillingConfigOverrideRemoved) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "BillingConfigOverrideRemoved", log); err != nil { return nil, err } event.Raw = log @@ -2028,42 +1424,42 @@ func (it *AutomationRegistryLogicBFeesWithdrawnIterator) Close() error { } type AutomationRegistryLogicBFeesWithdrawn struct { - Recipient common.Address AssetAddress common.Address + Recipient common.Address Amount *big.Int Raw types.Log } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterFeesWithdrawn(opts *bind.FilterOpts, recipient []common.Address, assetAddress []common.Address) (*AutomationRegistryLogicBFeesWithdrawnIterator, error) { +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterFeesWithdrawn(opts *bind.FilterOpts, assetAddress []common.Address, recipient []common.Address) (*AutomationRegistryLogicBFeesWithdrawnIterator, error) { - var recipientRule []interface{} - for _, recipientItem := range recipient { - recipientRule = append(recipientRule, recipientItem) - } var assetAddressRule []interface{} for _, assetAddressItem := range assetAddress { assetAddressRule = append(assetAddressRule, assetAddressItem) } + var recipientRule []interface{} + for _, recipientItem := range recipient { + recipientRule = append(recipientRule, recipientItem) + } - logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "FeesWithdrawn", recipientRule, assetAddressRule) + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "FeesWithdrawn", assetAddressRule, recipientRule) if err != nil { return nil, err } return &AutomationRegistryLogicBFeesWithdrawnIterator{contract: _AutomationRegistryLogicB.contract, event: "FeesWithdrawn", logs: logs, sub: sub}, nil } -func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchFeesWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBFeesWithdrawn, recipient []common.Address, assetAddress []common.Address) (event.Subscription, error) { +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchFeesWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBFeesWithdrawn, assetAddress []common.Address, recipient []common.Address) (event.Subscription, error) { - var recipientRule []interface{} - for _, recipientItem := range recipient { - recipientRule = append(recipientRule, recipientItem) - } var assetAddressRule []interface{} for _, assetAddressItem := range assetAddress { assetAddressRule = append(assetAddressRule, assetAddressItem) } + var recipientRule []interface{} + for _, recipientItem := range recipient { + recipientRule = append(recipientRule, recipientItem) + } - logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "FeesWithdrawn", recipientRule, assetAddressRule) + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "FeesWithdrawn", assetAddressRule, recipientRule) if err != nil { return nil, err } @@ -2498,6 +1894,124 @@ func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseInsuffic return event, nil } +type AutomationRegistryLogicBNOPsSettledOffchainIterator struct { + Event *AutomationRegistryLogicBNOPsSettledOffchain + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBNOPsSettledOffchainIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBNOPsSettledOffchain) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBNOPsSettledOffchain) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *AutomationRegistryLogicBNOPsSettledOffchainIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBNOPsSettledOffchainIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBNOPsSettledOffchain struct { + Payees []common.Address + Payments []*big.Int + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterNOPsSettledOffchain(opts *bind.FilterOpts) (*AutomationRegistryLogicBNOPsSettledOffchainIterator, error) { + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "NOPsSettledOffchain") + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBNOPsSettledOffchainIterator{contract: _AutomationRegistryLogicB.contract, event: "NOPsSettledOffchain", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchNOPsSettledOffchain(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBNOPsSettledOffchain) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "NOPsSettledOffchain") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBNOPsSettledOffchain) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "NOPsSettledOffchain", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseNOPsSettledOffchain(log types.Log) (*AutomationRegistryLogicBNOPsSettledOffchain, error) { + event := new(AutomationRegistryLogicBNOPsSettledOffchain) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "NOPsSettledOffchain", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + type AutomationRegistryLogicBOwnershipTransferRequestedIterator struct { Event *AutomationRegistryLogicBOwnershipTransferRequested @@ -5661,29 +5175,14 @@ func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepUn return event, nil } -type GetSignerInfo struct { - Active bool - Index uint8 -} -type GetState struct { - State AutomationRegistryBase23State - Config AutomationRegistryBase23OnchainConfigLegacy - Signers []common.Address - Transmitters []common.Address - F uint8 -} -type GetTransmitterInfo struct { - Active bool - Index uint8 - Balance *big.Int - LastCollected *big.Int - Payee common.Address -} - func (_AutomationRegistryLogicB *AutomationRegistryLogicB) ParseLog(log types.Log) (generated.AbigenLog, error) { switch log.Topics[0] { case _AutomationRegistryLogicB.abi.Events["AdminPrivilegeConfigSet"].ID: return _AutomationRegistryLogicB.ParseAdminPrivilegeConfigSet(log) + case _AutomationRegistryLogicB.abi.Events["BillingConfigOverridden"].ID: + return _AutomationRegistryLogicB.ParseBillingConfigOverridden(log) + case _AutomationRegistryLogicB.abi.Events["BillingConfigOverrideRemoved"].ID: + return _AutomationRegistryLogicB.ParseBillingConfigOverrideRemoved(log) case _AutomationRegistryLogicB.abi.Events["BillingConfigSet"].ID: return _AutomationRegistryLogicB.ParseBillingConfigSet(log) case _AutomationRegistryLogicB.abi.Events["CancelledUpkeepReport"].ID: @@ -5700,6 +5199,8 @@ func (_AutomationRegistryLogicB *AutomationRegistryLogicB) ParseLog(log types.Lo return _AutomationRegistryLogicB.ParseFundsWithdrawn(log) case _AutomationRegistryLogicB.abi.Events["InsufficientFundsUpkeepReport"].ID: return _AutomationRegistryLogicB.ParseInsufficientFundsUpkeepReport(log) + case _AutomationRegistryLogicB.abi.Events["NOPsSettledOffchain"].ID: + return _AutomationRegistryLogicB.ParseNOPsSettledOffchain(log) case _AutomationRegistryLogicB.abi.Events["OwnershipTransferRequested"].ID: return _AutomationRegistryLogicB.ParseOwnershipTransferRequested(log) case _AutomationRegistryLogicB.abi.Events["OwnershipTransferred"].ID: @@ -5758,8 +5259,16 @@ func (AutomationRegistryLogicBAdminPrivilegeConfigSet) Topic() common.Hash { return common.HexToHash("0x7c44b4eb59ee7873514e7e43e7718c269d872965938b288aa143befca62f99d2") } +func (AutomationRegistryLogicBBillingConfigOverridden) Topic() common.Hash { + return common.HexToHash("0xd8a6d79d170a55968079d3a89b960d86b4442aef6aac1d01e644c32b9e38b340") +} + +func (AutomationRegistryLogicBBillingConfigOverrideRemoved) Topic() common.Hash { + return common.HexToHash("0x97d0ef3f46a56168af653f547bdb6f77ec2b1d7d9bc6ba0193c2b340ec68064a") +} + func (AutomationRegistryLogicBBillingConfigSet) Topic() common.Hash { - return common.HexToHash("0x5ff767a3a5dbf1ef088ebf56e221e9cea40ad357c31ba060c2f31244cefab7c1") + return common.HexToHash("0x720a5849025dc4fd0061aed1bb30efd713cde64ce7f8d807953ecca27c8f143c") } func (AutomationRegistryLogicBCancelledUpkeepReport) Topic() common.Hash { @@ -5790,6 +5299,10 @@ func (AutomationRegistryLogicBInsufficientFundsUpkeepReport) Topic() common.Hash return common.HexToHash("0x377c8b0c126ae5248d27aca1c76fac4608aff85673ee3caf09747e1044549e02") } +func (AutomationRegistryLogicBNOPsSettledOffchain) Topic() common.Hash { + return common.HexToHash("0x5af23b715253628d12b660b27a4f3fc626562ea8a55040aa99ab3dc178989fad") +} + func (AutomationRegistryLogicBOwnershipTransferRequested) Topic() common.Hash { return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") } @@ -5891,103 +5404,27 @@ func (_AutomationRegistryLogicB *AutomationRegistryLogicB) Address() common.Addr } type AutomationRegistryLogicBInterface interface { - GetActiveUpkeepIDs(opts *bind.CallOpts, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) - - GetAdminPrivilegeConfig(opts *bind.CallOpts, admin common.Address) ([]byte, error) - - GetAllowedReadOnlyAddress(opts *bind.CallOpts) (common.Address, error) - - GetAutomationForwarderLogic(opts *bind.CallOpts) (common.Address, error) - - GetBalance(opts *bind.CallOpts, id *big.Int) (*big.Int, error) - - GetBillingTokenConfig(opts *bind.CallOpts, token common.Address) (AutomationRegistryBase23BillingConfig, error) - - GetBillingTokens(opts *bind.CallOpts) ([]common.Address, error) - - GetCancellationDelay(opts *bind.CallOpts) (*big.Int, error) - - GetChainModule(opts *bind.CallOpts) (common.Address, error) - - GetConditionalGasOverhead(opts *bind.CallOpts) (*big.Int, error) - - GetFallbackNativePrice(opts *bind.CallOpts) (*big.Int, error) - - GetFastGasFeedAddress(opts *bind.CallOpts) (common.Address, error) - - GetForwarder(opts *bind.CallOpts, upkeepID *big.Int) (common.Address, error) - - GetLinkAddress(opts *bind.CallOpts) (common.Address, error) - - GetLinkUSDFeedAddress(opts *bind.CallOpts) (common.Address, error) - - GetLogGasOverhead(opts *bind.CallOpts) (*big.Int, error) - - GetMaxPaymentForGas(opts *bind.CallOpts, triggerType uint8, gasLimit uint32) (*big.Int, error) - - GetMinBalance(opts *bind.CallOpts, id *big.Int) (*big.Int, error) - - GetMinBalanceForUpkeep(opts *bind.CallOpts, id *big.Int) (*big.Int, error) - - GetNativeUSDFeedAddress(opts *bind.CallOpts) (common.Address, error) - - GetPeerRegistryMigrationPermission(opts *bind.CallOpts, peer common.Address) (uint8, error) - - GetPerPerformByteGasOverhead(opts *bind.CallOpts) (*big.Int, error) - - GetPerSignerGasOverhead(opts *bind.CallOpts) (*big.Int, error) - - GetReorgProtectionEnabled(opts *bind.CallOpts) (bool, error) - - GetSignerInfo(opts *bind.CallOpts, query common.Address) (GetSignerInfo, - - error) - - GetState(opts *bind.CallOpts) (GetState, - - error) - - GetTransmitCalldataFixedBytesOverhead(opts *bind.CallOpts) (*big.Int, error) - - GetTransmitCalldataPerSignerBytesOverhead(opts *bind.CallOpts) (*big.Int, error) - - GetTransmitterInfo(opts *bind.CallOpts, query common.Address) (GetTransmitterInfo, - - error) - - GetTriggerType(opts *bind.CallOpts, upkeepId *big.Int) (uint8, error) - - GetUpkeep(opts *bind.CallOpts, id *big.Int) (AutomationRegistryBase23UpkeepInfo, error) - - GetUpkeepPrivilegeConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) - - GetUpkeepTriggerConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) - - HasDedupKey(opts *bind.CallOpts, dedupKey [32]byte) (bool, error) - - LinkAvailableForPayment(opts *bind.CallOpts) (*big.Int, error) + FallbackTo(opts *bind.CallOpts) (common.Address, error) Owner(opts *bind.CallOpts) (common.Address, error) - UpkeepTranscoderVersion(opts *bind.CallOpts) (uint8, error) + AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) - UpkeepVersion(opts *bind.CallOpts) (uint8, error) + AcceptUpkeepAdmin(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) - AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) + CheckCallback(opts *bind.TransactOpts, id *big.Int, values [][]byte, extraData []byte) (*types.Transaction, error) - AcceptPayeeship(opts *bind.TransactOpts, transmitter common.Address) (*types.Transaction, error) + CheckUpkeep(opts *bind.TransactOpts, id *big.Int, triggerData []byte) (*types.Transaction, error) - AcceptUpkeepAdmin(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) + CheckUpkeep0(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) - Pause(opts *bind.TransactOpts) (*types.Transaction, error) + ExecuteCallback(opts *bind.TransactOpts, id *big.Int, payload []byte) (*types.Transaction, error) PauseUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) - SetAdminPrivilegeConfig(opts *bind.TransactOpts, admin common.Address, newPrivilegeConfig []byte) (*types.Transaction, error) - - SetPayees(opts *bind.TransactOpts, payees []common.Address) (*types.Transaction, error) + RemoveBillingOverrides(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) - SetPeerRegistryMigrationPermission(opts *bind.TransactOpts, peer common.Address, permission uint8) (*types.Transaction, error) + SetBillingOverrides(opts *bind.TransactOpts, id *big.Int, billingOverrides AutomationRegistryBase23BillingOverrides) (*types.Transaction, error) SetUpkeepCheckData(opts *bind.TransactOpts, id *big.Int, newCheckData []byte) (*types.Transaction, error) @@ -5995,25 +5432,23 @@ type AutomationRegistryLogicBInterface interface { SetUpkeepOffchainConfig(opts *bind.TransactOpts, id *big.Int, config []byte) (*types.Transaction, error) - SetUpkeepPrivilegeConfig(opts *bind.TransactOpts, upkeepId *big.Int, newPrivilegeConfig []byte) (*types.Transaction, error) + SetUpkeepTriggerConfig(opts *bind.TransactOpts, id *big.Int, triggerConfig []byte) (*types.Transaction, error) - TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) + SimulatePerformUpkeep(opts *bind.TransactOpts, id *big.Int, performData []byte) (*types.Transaction, error) - TransferPayeeship(opts *bind.TransactOpts, transmitter common.Address, proposed common.Address) (*types.Transaction, error) + TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) TransferUpkeepAdmin(opts *bind.TransactOpts, id *big.Int, proposed common.Address) (*types.Transaction, error) - Unpause(opts *bind.TransactOpts) (*types.Transaction, error) - UnpauseUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) - WithdrawERC20Fees(opts *bind.TransactOpts, assetAddress common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) + WithdrawERC20Fees(opts *bind.TransactOpts, asset common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) WithdrawFunds(opts *bind.TransactOpts, id *big.Int, to common.Address) (*types.Transaction, error) - WithdrawLinkFees(opts *bind.TransactOpts, to common.Address, amount *big.Int) (*types.Transaction, error) + WithdrawLink(opts *bind.TransactOpts, to common.Address, amount *big.Int) (*types.Transaction, error) - WithdrawPayment(opts *bind.TransactOpts, from common.Address, to common.Address) (*types.Transaction, error) + Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) FilterAdminPrivilegeConfigSet(opts *bind.FilterOpts, admin []common.Address) (*AutomationRegistryLogicBAdminPrivilegeConfigSetIterator, error) @@ -6021,6 +5456,18 @@ type AutomationRegistryLogicBInterface interface { ParseAdminPrivilegeConfigSet(log types.Log) (*AutomationRegistryLogicBAdminPrivilegeConfigSet, error) + FilterBillingConfigOverridden(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBBillingConfigOverriddenIterator, error) + + WatchBillingConfigOverridden(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBBillingConfigOverridden, id []*big.Int) (event.Subscription, error) + + ParseBillingConfigOverridden(log types.Log) (*AutomationRegistryLogicBBillingConfigOverridden, error) + + FilterBillingConfigOverrideRemoved(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBBillingConfigOverrideRemovedIterator, error) + + WatchBillingConfigOverrideRemoved(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBBillingConfigOverrideRemoved, id []*big.Int) (event.Subscription, error) + + ParseBillingConfigOverrideRemoved(log types.Log) (*AutomationRegistryLogicBBillingConfigOverrideRemoved, error) + FilterBillingConfigSet(opts *bind.FilterOpts, token []common.Address) (*AutomationRegistryLogicBBillingConfigSetIterator, error) WatchBillingConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBBillingConfigSet, token []common.Address) (event.Subscription, error) @@ -6045,9 +5492,9 @@ type AutomationRegistryLogicBInterface interface { ParseDedupKeyAdded(log types.Log) (*AutomationRegistryLogicBDedupKeyAdded, error) - FilterFeesWithdrawn(opts *bind.FilterOpts, recipient []common.Address, assetAddress []common.Address) (*AutomationRegistryLogicBFeesWithdrawnIterator, error) + FilterFeesWithdrawn(opts *bind.FilterOpts, assetAddress []common.Address, recipient []common.Address) (*AutomationRegistryLogicBFeesWithdrawnIterator, error) - WatchFeesWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBFeesWithdrawn, recipient []common.Address, assetAddress []common.Address) (event.Subscription, error) + WatchFeesWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBFeesWithdrawn, assetAddress []common.Address, recipient []common.Address) (event.Subscription, error) ParseFeesWithdrawn(log types.Log) (*AutomationRegistryLogicBFeesWithdrawn, error) @@ -6069,6 +5516,12 @@ type AutomationRegistryLogicBInterface interface { ParseInsufficientFundsUpkeepReport(log types.Log) (*AutomationRegistryLogicBInsufficientFundsUpkeepReport, error) + FilterNOPsSettledOffchain(opts *bind.FilterOpts) (*AutomationRegistryLogicBNOPsSettledOffchainIterator, error) + + WatchNOPsSettledOffchain(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBNOPsSettledOffchain) (event.Subscription, error) + + ParseNOPsSettledOffchain(log types.Log) (*AutomationRegistryLogicBNOPsSettledOffchain, error) + FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryLogicBOwnershipTransferRequestedIterator, error) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) diff --git a/core/gethwrappers/generated/automation_registry_wrapper_2_2/automation_registry_wrapper_2_2.go b/core/gethwrappers/generated/automation_registry_wrapper_2_2/automation_registry_wrapper_2_2.go index 229096b1517..eb385cf7b03 100644 --- a/core/gethwrappers/generated/automation_registry_wrapper_2_2/automation_registry_wrapper_2_2.go +++ b/core/gethwrappers/generated/automation_registry_wrapper_2_2/automation_registry_wrapper_2_2.go @@ -51,8 +51,8 @@ type AutomationRegistryBase22OnchainConfig struct { } var AutomationRegistryMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistryLogicB2_2\",\"name\":\"logicA\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxCheckDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxPerformDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentGreaterThanAllLINK\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newModule\",\"type\":\"address\"}],\"name\":\"ChainSpecificModuleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"OwnerFundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"onchainConfigBytes\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"},{\"internalType\":\"contractIChainModule\",\"name\":\"chainModule\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"}],\"internalType\":\"structAutomationRegistryBase2_2.OnchainConfig\",\"name\":\"onchainConfig\",\"type\":\"tuple\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfigTypeSafe\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"simulatePerformUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"rawReport\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x6101406040523480156200001257600080fd5b50604051620051bb380380620051bb8339810160408190526200003591620003b1565b80816001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b9190620003b1565b826001600160a01b031663b10b673c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001009190620003b1565b836001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001659190620003b1565b846001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca9190620003b1565b856001600160a01b031663a08714c06040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f9190620003b1565b3380600081620002865760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620002b957620002b981620002ed565b5050506001600160a01b0394851660805292841660a05290831660c052821660e052811661010052166101205250620003d8565b336001600160a01b03821603620003475760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200027d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b0381168114620003ae57600080fd5b50565b600060208284031215620003c457600080fd5b8151620003d18162000398565b9392505050565b60805160a05160c05160e0516101005161012051614d96620004256000396000818160d6015261016f01526000611b29015260005050600050506000505060006104330152614d966000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c8063aed2e92911610081578063e3d0e7121161005b578063e3d0e712146102e0578063f2fde38b146102f3578063f75f6b1114610306576100d4565b8063aed2e92914610262578063afcb95d71461028c578063b1dc65a4146102cd576100d4565b806381ff7048116100b257806381ff7048146101bc5780638da5cb5b14610231578063a4c0ed361461024f576100d4565b8063181f5a771461011b578063349e8cca1461016d57806379ba5097146101b4575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e808015610114573d6000f35b3d6000fd5b005b6101576040518060400160405280601881526020017f4175746f6d6174696f6e526567697374727920322e322e30000000000000000081525081565b6040516101649190613a92565b60405180910390f35b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610164565b610119610319565b61020e60155460115463ffffffff780100000000000000000000000000000000000000000000000083048116937c01000000000000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610164565b60005473ffffffffffffffffffffffffffffffffffffffff1661018f565b61011961025d366004613b20565b61041b565b610275610270366004613b7c565b610637565b604080519215158352602083019190915201610164565b601154601254604080516000815260208101939093527401000000000000000000000000000000000000000090910463ffffffff1690820152606001610164565b6101196102db366004613c0d565b6107ad565b6101196102ee366004613ede565b610ae8565b610119610301366004613fab565b610b11565b6101196103143660046141af565b610b25565b60015473ffffffffffffffffffffffffffffffffffffffff16331461039f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461048a576040517fc8bad78d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602081146104c4576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006104d28284018461423e565b60008181526004602052604090205490915065010000000000900463ffffffff9081161461052c576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600460205260409020600101546105679085906c0100000000000000000000000090046bffffffffffffffffffffffff16614286565b600082815260046020526040902060010180546bffffffffffffffffffffffff929092166c01000000000000000000000000027fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff9092169190911790556019546105d29085906142ab565b6019556040516bffffffffffffffffffffffff8516815273ffffffffffffffffffffffffffffffffffffffff86169082907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a35050505050565b600080610642611b11565b6012547e01000000000000000000000000000000000000000000000000000000000000900460ff16156106a1576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600085815260046020908152604091829020825160e081018452815460ff811615158252610100810463ffffffff908116838601819052650100000000008304821684880152690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff16606084018190526001909401546bffffffffffffffffffffffff80821660808601526c0100000000000000000000000082041660a0850152780100000000000000000000000000000000000000000000000090041660c08301528451601f890185900485028101850190955287855290936107a0938990899081908401838280828437600092019190915250611b8292505050565b9097909650945050505050565b60005a60408051610160810182526012546bffffffffffffffffffffffff8116825263ffffffff6c010000000000000000000000008204811660208401527001000000000000000000000000000000008204811693830193909352740100000000000000000000000000000000000000008104909216606082015262ffffff7801000000000000000000000000000000000000000000000000830416608082015261ffff7b0100000000000000000000000000000000000000000000000000000083041660a082015260ff7d0100000000000000000000000000000000000000000000000000000000008304811660c08301527e010000000000000000000000000000000000000000000000000000000000008304811615801560e08401527f01000000000000000000000000000000000000000000000000000000000000009093048116151561010080840191909152601354918216151561012084015273ffffffffffffffffffffffffffffffffffffffff910416610140820152919250610963576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600b602052604090205460ff166109ac576040517f1099ed7500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6011548a35146109e8576040517fdfdcf8e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60c08101516109f89060016142ed565b60ff1686141580610a095750858414155b15610a40576040517f0244f71a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a508a8a8a8a8a8a8a8a611dab565b6000610a5c8a8a612014565b905060208b0135600881901c63ffffffff16610a798484876120cf565b836060015163ffffffff168163ffffffff161115610ad957601280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416021790555b50505050505050505050505050565b610b0986868686806020019051810190610b0291906143ac565b8686610b25565b505050505050565b610b19612a4e565b610b2281612acf565b50565b610b2d612a4e565b601f86511115610b69576040517f25d0209c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8360ff16600003610ba6576040517fe77dba5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84518651141580610bc55750610bbd84600361452e565b60ff16865111155b15610bfc576040517f1d2d1c5800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601254600e546bffffffffffffffffffffffff9091169060005b816bffffffffffffffffffffffff16811015610c7e57610c6b600e8281548110610c4257610c426142be565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff168484612bc4565b5080610c768161454a565b915050610c16565b5060008060005b836bffffffffffffffffffffffff16811015610d8757600d8181548110610cae57610cae6142be565b600091825260209091200154600e805473ffffffffffffffffffffffffffffffffffffffff90921694509082908110610ce957610ce96142be565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff8681168452600c8352604080852080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690559116808452600b90925290912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055915080610d7f8161454a565b915050610c85565b50610d94600d6000613971565b610da0600e6000613971565b604080516080810182526000808252602082018190529181018290526060810182905290805b8c5181101561120957600c60008e8381518110610de557610de56142be565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000205460ff1615610e50576040517f77cea0fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168d8281518110610e7a57610e7a6142be565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603610ecf576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180604001604052806001151581526020018260ff16815250600c60008f8481518110610f0057610f006142be565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528181019290925260400160002082518154939092015160ff16610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909316929092171790558b518c9082908110610fa857610fa86142be565b60200260200101519150600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611018576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166000908152600b60209081526040918290208251608081018452905460ff80821615801584526101008304909116938301939093526bffffffffffffffffffffffff6201000082048116948301949094526e010000000000000000000000000000900490921660608301529093506110d3576040517f6a7281ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001835260ff80821660208086019182526bffffffffffffffffffffffff808b166060880190815273ffffffffffffffffffffffffffffffffffffffff87166000908152600b909352604092839020885181549551948a0151925184166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff939094166201000002929092167fffffffffffff000000000000000000000000000000000000000000000000ffff94909616610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090951694909417179190911692909217919091179055806112018161454a565b915050610dc6565b50508a5161121f9150600d9060208d019061398f565b50885161123390600e9060208c019061398f565b50604051806101600160405280856bffffffffffffffffffffffff168152602001886000015163ffffffff168152602001886020015163ffffffff168152602001600063ffffffff168152602001886060015162ffffff168152602001886080015161ffff1681526020018960ff1681526020016012600001601e9054906101000a900460ff16151581526020016012600001601f9054906101000a900460ff161515815260200188610200015115158152602001886101e0015173ffffffffffffffffffffffffffffffffffffffff16815250601260008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060808201518160000160186101000a81548162ffffff021916908362ffffff16021790555060a082015181600001601b6101000a81548161ffff021916908361ffff16021790555060c082015181600001601d6101000a81548160ff021916908360ff16021790555060e082015181600001601e6101000a81548160ff02191690831515021790555061010082015181600001601f6101000a81548160ff0219169083151502179055506101208201518160010160006101000a81548160ff0219169083151502179055506101408201518160010160016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050506040518061018001604052808860a001516bffffffffffffffffffffffff16815260200188610180015173ffffffffffffffffffffffffffffffffffffffff168152602001601460010160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff168152602001886040015163ffffffff1681526020018860c0015163ffffffff168152602001601460010160149054906101000a900463ffffffff1663ffffffff168152602001601460010160189054906101000a900463ffffffff1663ffffffff1681526020016014600101601c9054906101000a900463ffffffff1663ffffffff1681526020018860e0015163ffffffff16815260200188610100015163ffffffff16815260200188610120015163ffffffff168152602001886101c0015173ffffffffffffffffffffffffffffffffffffffff16815250601460008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160010160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550606082015181600101600c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160106101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160010160146101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555060e082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160020160006101000a81548163ffffffff021916908363ffffffff1602179055506101208201518160020160046101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160086101000a81548163ffffffff021916908363ffffffff16021790555061016082015181600201600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555090505086610140015160178190555086610160015160188190555060006014600101601c9054906101000a900463ffffffff169050876101e0015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f89190614582565b601580547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff9384160217808255600192601891611973918591780100000000000000000000000000000000000000000000000090041661459b565b92506101000a81548163ffffffff021916908363ffffffff1602179055506000886040516020016119a49190614609565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152919052601554909150611a0d90469030907801000000000000000000000000000000000000000000000000900463ffffffff168f8f8f878f8f612dcc565b60115560005b611a1d6009612e76565b811015611a4d57611a3a611a32600983612e80565b600990612e93565b5080611a458161454a565b915050611a13565b5060005b896101a0015151811015611aa457611a918a6101a001518281518110611a7957611a796142be565b60200260200101516009612eb590919063ffffffff16565b5080611a9c8161454a565b915050611a51565b507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0582601154601460010160189054906101000a900463ffffffff168f8f8f878f8f604051611afb999897969594939291906147ad565b60405180910390a1505050505050505050505050565b3273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611b80576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60125460009081907f0100000000000000000000000000000000000000000000000000000000000000900460ff1615611be7576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601280547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01000000000000000000000000000000000000000000000000000000000000001790556040517f4585e33b0000000000000000000000000000000000000000000000000000000090611c63908590602401613a92565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d1690611d369087908790600401614843565b60408051808303816000875af1158015611d54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d78919061485c565b601280547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16905590969095509350505050565b60008787604051611dbd92919061488a565b604051908190038120611dd4918b9060200161489a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201208383019092526000808452908301819052909250906000805b88811015611fab57600185878360208110611e4057611e406142be565b611e4d91901a601b6142ed565b8c8c85818110611e5f57611e5f6142be565b905060200201358b8b86818110611e7857611e786142be565b9050602002013560405160008152602001604052604051611eb5949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611ed7573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff81166000908152600c602090815290849020838501909452925460ff8082161515808552610100909204169383019390935290955093509050611f85576040517f0f4c073700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015160080260ff166001901b840193508080611fa39061454a565b915050611e23565b50827e01010101010101010101010101010101010101010101010101010101010101841614612006576040517fc103be2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050505050565b61204d6040518060c001604052806000815260200160008152602001606081526020016060815260200160608152602001606081525090565b600061205b8385018561498b565b604081015151606082015151919250908114158061207e57508082608001515114155b8061208e5750808260a001515114155b156120c5576040517fb55ac75400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090505b92915050565b600082604001515167ffffffffffffffff8111156120ef576120ef613cc4565b6040519080825280602002602001820160405280156121ab57816020015b604080516101c081018252600060e08201818152610100830182905261012083018290526101408301829052610160830182905261018083018290526101a0830182905282526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161210d5790505b50905060006040518060800160405280600061ffff1681526020016000815260200160006bffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff168152509050600085610140015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612249573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061226d9190614582565b9050600086610140015173ffffffffffffffffffffffffffffffffffffffff166318b8f6136040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122e59190614582565b905060005b866040015151811015612734576004600088604001518381518110612311576123116142be565b6020908102919091018101518252818101929092526040908101600020815160e081018352815460ff811615158252610100810463ffffffff90811695830195909552650100000000008104851693820193909352690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff166060830152600101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490911660c082015285518690839081106123f6576123f66142be565b60200260200101516000018190525061242b8760400151828151811061241e5761241e6142be565b6020026020010151612ed7565b85828151811061243d5761243d6142be565b602002602001015160600190600181111561245a5761245a614a78565b9081600181111561246d5761246d614a78565b815250506124d18760400151828151811061248a5761248a6142be565b602002602001015184896080015184815181106124a9576124a96142be565b60200260200101518885815181106124c3576124c36142be565b60200260200101518c612f82565b8683815181106124e3576124e36142be565b6020026020010151602001878481518110612500576125006142be565b602002602001015160c001828152508215151515815250505084818151811061252b5761252b6142be565b6020026020010151602001511561255b5760018460000181815161254f9190614aa7565b61ffff16905250612560565b612722565b6125c6858281518110612575576125756142be565b602002602001015160000151606001518860600151838151811061259b5761259b6142be565b60200260200101518960a0015184815181106125b9576125b96142be565b6020026020010151611b82565b8683815181106125d8576125d86142be565b60200260200101516040018784815181106125f5576125f56142be565b602090810291909101015160800191909152901515905260c088015161261c9060016142ed565b61262a9060ff166040614ac2565b6103a48860a001518381518110612643576126436142be565b60200260200101515161265691906142ab565b61266091906142ab565b858281518110612672576126726142be565b602002602001015160a0018181525050848181518110612694576126946142be565b602002602001015160a00151846020018181516126b191906142ab565b90525084518590829081106126c8576126c86142be565b602002602001015160800151866126df9190614ad9565b9550612722876040015182815181106126fa576126fa6142be565b602002602001015184878481518110612715576127156142be565b60200260200101516130a1565b8061272c8161454a565b9150506122ea565b50825161ffff1660000361274b5750505050505050565b6155f0612759366010614ac2565b5a6127649088614ad9565b61276e91906142ab565b61277891906142ab565b8351909550611b589061278f9061ffff1687614b1b565b61279991906142ab565b945060008060005b88604001515181101561297d578681815181106127c0576127c06142be565b6020026020010151602001511561296b576128598a8a6040015183815181106127eb576127eb6142be565b6020026020010151898481518110612805576128056142be565b6020026020010151608001518c600001518d602001518d8c602001518e8981518110612833576128336142be565b602002602001015160a001518c61284a9190614ac2565b6128549190614b1b565b6131a6565b6060880180519295509093508391612872908390614286565b6bffffffffffffffffffffffff16905250604086018051849190612897908390614286565b6bffffffffffffffffffffffff1690525086518790829081106128bc576128bc6142be565b6020026020010151604001511515896040015182815181106128e0576128e06142be565b60200260200101517fad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b84866129159190614286565b8a8581518110612927576129276142be565b6020026020010151608001518c8e60800151878151811061294a5761294a6142be565b60200260200101516040516129629493929190614b2f565b60405180910390a35b806129758161454a565b9150506127a1565b505050604083810151336000908152600b6020529190912080546002906129b99084906201000090046bffffffffffffffffffffffff16614286565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508260600151601260000160008282829054906101000a90046bffffffffffffffffffffffff16612a179190614286565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555050505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611b80576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610396565b3373ffffffffffffffffffffffffffffffffffffffff821603612b4e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610396565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e0100000000000000000000000000009004909116606082015290612dc0576000816060015185612c5c9190614b6c565b90506000612c6a8583614b91565b90508083604001818151612c7e9190614286565b6bffffffffffffffffffffffff16905250612c998582614bbc565b83606001818151612caa9190614286565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b60400151949350505050565b6000808a8a8a8a8a8a8a8a8a604051602001612df099989796959493929190614bec565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179b9a5050505050505050505050565b60006120c9825490565b6000612e8c8383613329565b9392505050565b6000612e8c8373ffffffffffffffffffffffffffffffffffffffff8416613353565b6000612e8c8373ffffffffffffffffffffffffffffffffffffffff841661344d565b6000818160045b600f811015612f64577fff000000000000000000000000000000000000000000000000000000000000008216838260208110612f1c57612f1c6142be565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614612f5257506000949350505050565b80612f5c8161454a565b915050612ede565b5081600f1a6001811115612f7a57612f7a614a78565b949350505050565b600080808085606001516001811115612f9d57612f9d614a78565b03612fc357612faf888888888861349c565b612fbe57600092509050613097565b61303b565b600185606001516001811115612fdb57612fdb614a78565b03613009576000612fee89898988613627565b92509050806130035750600092509050613097565b5061303b565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84516040015163ffffffff16871061309057877fc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd56368760405161307d9190613a92565b60405180910390a2600092509050613097565b6001925090505b9550959350505050565b6000816060015160018111156130b9576130b9614a78565b0361311d57600083815260046020526040902060010180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000063ffffffff851602179055505050565b60018160600151600181111561313557613135614a78565b036131a15760c08101805160009081526008602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055915191517fa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f29190a25b505050565b6000806131b9898886868a8a6001613835565b60008a8152600460205260408120600101549294509092506c010000000000000000000000009091046bffffffffffffffffffffffff16906131fb8385614286565b9050836bffffffffffffffffffffffff16826bffffffffffffffffffffffff16101561322f57509150600090508180613262565b806bffffffffffffffffffffffff16826bffffffffffffffffffffffff16101561326257508061325f8482614b6c565b92505b60008a81526004602052604090206001018054829190600c906132a49084906c0100000000000000000000000090046bffffffffffffffffffffffff16614b6c565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008c8152600460205260408120600101805485945090926132ed91859116614286565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550505097509795505050505050565b6000826000018281548110613340576133406142be565b9060005260206000200154905092915050565b6000818152600183016020526040812054801561343c576000613377600183614ad9565b855490915060009061338b90600190614ad9565b90508181146133f05760008660000182815481106133ab576133ab6142be565b90600052602060002001549050808760000184815481106133ce576133ce6142be565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061340157613401614c81565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506120c9565b60009150506120c9565b5092915050565b6000818152600183016020526040812054613494575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556120c9565b5060006120c9565b600080848060200190518101906134b39190614cb0565b845160c00151815191925063ffffffff9081169116101561351057867f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8866040516134fe9190613a92565b60405180910390a2600091505061361e565b82610120015180156135d157506020810151158015906135d15750602081015161014084015182516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa1580156135aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135ce9190614582565b14155b806135e35750805163ffffffff168611155b1561361857867f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301866040516134fe9190613a92565b60019150505b95945050505050565b6000806000848060200190518101906136409190614d08565b90506000878260000151836020015184604001516040516020016136a294939291909384526020840192909252604083015260e01b7fffffffff0000000000000000000000000000000000000000000000000000000016606082015260640190565b604051602081830303815290604052805190602001209050846101200151801561377e575060808201511580159061377e5750608082015161014086015160608401516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa158015613757573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061377b9190614582565b14155b80613793575086826060015163ffffffff1610155b156137dd57877f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301876040516137c89190613a92565b60405180910390a260009350915061382c9050565b60008181526008602052604090205460ff161561382457877f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8876040516137c89190613a92565b600193509150505b94509492505050565b60008060008960a0015161ffff168661384e9190614ac2565b905083801561385c5750803a105b1561386457503a5b600085886138728b8d6142ab565b61387c9085614ac2565b61388691906142ab565b61389890670de0b6b3a7640000614ac2565b6138a29190614b1b565b905060008b6040015163ffffffff1664e8d4a510006138c19190614ac2565b60208d0151889063ffffffff168b6138d98f88614ac2565b6138e391906142ab565b6138f190633b9aca00614ac2565b6138fb9190614ac2565b6139059190614b1b565b61390f91906142ab565b90506b033b2e3c9fd0803ce800000061392882846142ab565b1115613960576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b909b909a5098505050505050505050565b5080546000825590600052602060002090810190610b229190613a19565b828054828255906000526020600020908101928215613a09579160200282015b82811115613a0957825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9091161782556020909201916001909101906139af565b50613a15929150613a19565b5090565b5b80821115613a155760008155600101613a1a565b6000815180845260005b81811015613a5457602081850181015186830182015201613a38565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000612e8c6020830184613a2e565b73ffffffffffffffffffffffffffffffffffffffff81168114610b2257600080fd5b8035613ad281613aa5565b919050565b60008083601f840112613ae957600080fd5b50813567ffffffffffffffff811115613b0157600080fd5b602083019150836020828501011115613b1957600080fd5b9250929050565b60008060008060608587031215613b3657600080fd5b8435613b4181613aa5565b935060208501359250604085013567ffffffffffffffff811115613b6457600080fd5b613b7087828801613ad7565b95989497509550505050565b600080600060408486031215613b9157600080fd5b83359250602084013567ffffffffffffffff811115613baf57600080fd5b613bbb86828701613ad7565b9497909650939450505050565b60008083601f840112613bda57600080fd5b50813567ffffffffffffffff811115613bf257600080fd5b6020830191508360208260051b8501011115613b1957600080fd5b60008060008060008060008060e0898b031215613c2957600080fd5b606089018a811115613c3a57600080fd5b8998503567ffffffffffffffff80821115613c5457600080fd5b613c608c838d01613ad7565b909950975060808b0135915080821115613c7957600080fd5b613c858c838d01613bc8565b909750955060a08b0135915080821115613c9e57600080fd5b50613cab8b828c01613bc8565b999c989b50969995989497949560c00135949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610220810167ffffffffffffffff81118282101715613d1757613d17613cc4565b60405290565b60405160c0810167ffffffffffffffff81118282101715613d1757613d17613cc4565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613d8757613d87613cc4565b604052919050565b600067ffffffffffffffff821115613da957613da9613cc4565b5060051b60200190565b600082601f830112613dc457600080fd5b81356020613dd9613dd483613d8f565b613d40565b82815260059290921b84018101918181019086841115613df857600080fd5b8286015b84811015613e1c578035613e0f81613aa5565b8352918301918301613dfc565b509695505050505050565b803560ff81168114613ad257600080fd5b600082601f830112613e4957600080fd5b813567ffffffffffffffff811115613e6357613e63613cc4565b613e9460207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613d40565b818152846020838601011115613ea957600080fd5b816020850160208301376000918101602001919091529392505050565b803567ffffffffffffffff81168114613ad257600080fd5b60008060008060008060c08789031215613ef757600080fd5b863567ffffffffffffffff80821115613f0f57600080fd5b613f1b8a838b01613db3565b97506020890135915080821115613f3157600080fd5b613f3d8a838b01613db3565b9650613f4b60408a01613e27565b95506060890135915080821115613f6157600080fd5b613f6d8a838b01613e38565b9450613f7b60808a01613ec6565b935060a0890135915080821115613f9157600080fd5b50613f9e89828a01613e38565b9150509295509295509295565b600060208284031215613fbd57600080fd5b8135612e8c81613aa5565b63ffffffff81168114610b2257600080fd5b8035613ad281613fc8565b62ffffff81168114610b2257600080fd5b8035613ad281613fe5565b61ffff81168114610b2257600080fd5b8035613ad281614001565b6bffffffffffffffffffffffff81168114610b2257600080fd5b8035613ad28161401c565b8015158114610b2257600080fd5b8035613ad281614041565b6000610220828403121561406d57600080fd5b614075613cf3565b905061408082613fda565b815261408e60208301613fda565b602082015261409f60408301613fda565b60408201526140b060608301613ff6565b60608201526140c160808301614011565b60808201526140d260a08301614036565b60a08201526140e360c08301613fda565b60c08201526140f460e08301613fda565b60e0820152610100614107818401613fda565b90820152610120614119838201613fda565b9082015261014082810135908201526101608083013590820152610180614141818401613ac7565b908201526101a08281013567ffffffffffffffff81111561416157600080fd5b61416d85828601613db3565b8284015250506101c0614181818401613ac7565b908201526101e0614193838201613ac7565b908201526102006141a583820161404f565b9082015292915050565b60008060008060008060c087890312156141c857600080fd5b863567ffffffffffffffff808211156141e057600080fd5b6141ec8a838b01613db3565b9750602089013591508082111561420257600080fd5b61420e8a838b01613db3565b965061421c60408a01613e27565b9550606089013591508082111561423257600080fd5b613f6d8a838b0161405a565b60006020828403121561425057600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff81811683821601908082111561344657613446614257565b808201808211156120c9576120c9614257565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60ff81811683821601908111156120c9576120c9614257565b8051613ad281613fc8565b8051613ad281613fe5565b8051613ad281614001565b8051613ad28161401c565b8051613ad281613aa5565b600082601f83011261434e57600080fd5b8151602061435e613dd483613d8f565b82815260059290921b8401810191818101908684111561437d57600080fd5b8286015b84811015613e1c57805161439481613aa5565b8352918301918301614381565b8051613ad281614041565b6000602082840312156143be57600080fd5b815167ffffffffffffffff808211156143d657600080fd5b9083019061022082860312156143eb57600080fd5b6143f3613cf3565b6143fc83614306565b815261440a60208401614306565b602082015261441b60408401614306565b604082015261442c60608401614311565b606082015261443d6080840161431c565b608082015261444e60a08401614327565b60a082015261445f60c08401614306565b60c082015261447060e08401614306565b60e0820152610100614483818501614306565b90820152610120614495848201614306565b90820152610140838101519082015261016080840151908201526101806144bd818501614332565b908201526101a083810151838111156144d557600080fd5b6144e18882870161433d565b8284015250506101c091506144f7828401614332565b828201526101e0915061450b828401614332565b82820152610200915061451f8284016143a1565b91810191909152949350505050565b60ff818116838216029081169081811461344657613446614257565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361457b5761457b614257565b5060010190565b60006020828403121561459457600080fd5b5051919050565b63ffffffff81811683821601908082111561344657613446614257565b600081518084526020808501945080840160005b838110156145fe57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016145cc565b509495945050505050565b6020815261462060208201835163ffffffff169052565b60006020830151614639604084018263ffffffff169052565b50604083015163ffffffff8116606084015250606083015162ffffff8116608084015250608083015161ffff811660a08401525060a08301516bffffffffffffffffffffffff811660c08401525060c083015163ffffffff811660e08401525060e08301516101006146b28185018363ffffffff169052565b84015190506101206146cb8482018363ffffffff169052565b84015190506101406146e48482018363ffffffff169052565b840151610160848101919091528401516101808085019190915284015190506101a06147278185018373ffffffffffffffffffffffffffffffffffffffff169052565b808501519150506102206101c081818601526147476102408601846145b8565b908601519092506101e06147728682018373ffffffffffffffffffffffffffffffffffffffff169052565b860151905061020061479b8682018373ffffffffffffffffffffffffffffffffffffffff169052565b90950151151593019290925250919050565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526147dd8184018a6145b8565b905082810360808401526147f181896145b8565b905060ff871660a084015282810360c084015261480e8187613a2e565b905067ffffffffffffffff851660e08401528281036101008401526148338185613a2e565b9c9b505050505050505050505050565b828152604060208201526000612f7a6040830184613a2e565b6000806040838503121561486f57600080fd5b825161487a81614041565b6020939093015192949293505050565b8183823760009101908152919050565b8281526080810160608360208401379392505050565b600082601f8301126148c157600080fd5b813560206148d1613dd483613d8f565b82815260059290921b840181019181810190868411156148f057600080fd5b8286015b84811015613e1c57803583529183019183016148f4565b600082601f83011261491c57600080fd5b8135602061492c613dd483613d8f565b82815260059290921b8401810191818101908684111561494b57600080fd5b8286015b84811015613e1c57803567ffffffffffffffff81111561496f5760008081fd5b61497d8986838b0101613e38565b84525091830191830161494f565b60006020828403121561499d57600080fd5b813567ffffffffffffffff808211156149b557600080fd5b9083019060c082860312156149c957600080fd5b6149d1613d1d565b82358152602083013560208201526040830135828111156149f157600080fd5b6149fd878286016148b0565b604083015250606083013582811115614a1557600080fd5b614a21878286016148b0565b606083015250608083013582811115614a3957600080fd5b614a458782860161490b565b60808301525060a083013582811115614a5d57600080fd5b614a698782860161490b565b60a08301525095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b61ffff81811683821601908082111561344657613446614257565b80820281158282048414176120c9576120c9614257565b818103818111156120c9576120c9614257565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082614b2a57614b2a614aec565b500490565b6bffffffffffffffffffffffff85168152836020820152826040820152608060608201526000614b626080830184613a2e565b9695505050505050565b6bffffffffffffffffffffffff82811682821603908082111561344657613446614257565b60006bffffffffffffffffffffffff80841680614bb057614bb0614aec565b92169190910492915050565b6bffffffffffffffffffffffff818116838216028082169190828114614be457614be4614257565b505092915050565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152614c338285018b6145b8565b91508382036080850152614c47828a6145b8565b915060ff881660a085015283820360c0850152614c648288613a2e565b90861660e085015283810361010085015290506148338185613a2e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600060408284031215614cc257600080fd5b6040516040810181811067ffffffffffffffff82111715614ce557614ce5613cc4565b6040528251614cf381613fc8565b81526020928301519281019290925250919050565b600060a08284031215614d1a57600080fd5b60405160a0810181811067ffffffffffffffff82111715614d3d57614d3d613cc4565b806040525082518152602083015160208201526040830151614d5e81613fc8565b60408201526060830151614d7181613fc8565b6060820152608092830151928101929092525091905056fea164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistryLogicB2_2\",\"name\":\"logicA\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxCheckDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxPerformDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentGreaterThanAllLINK\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newModule\",\"type\":\"address\"}],\"name\":\"ChainSpecificModuleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"OwnerFundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"onchainConfigBytes\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"},{\"internalType\":\"contractIChainModule\",\"name\":\"chainModule\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"}],\"internalType\":\"structAutomationRegistryBase2_2.OnchainConfig\",\"name\":\"onchainConfig\",\"type\":\"tuple\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfigTypeSafe\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"simulatePerformUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"rawReport\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x6101406040523480156200001257600080fd5b506040516200524a3803806200524a8339810160408190526200003591620003b1565b80816001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b9190620003b1565b826001600160a01b031663b10b673c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001009190620003b1565b836001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001659190620003b1565b846001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca9190620003b1565b856001600160a01b031663a08714c06040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f9190620003b1565b3380600081620002865760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620002b957620002b981620002ed565b5050506001600160a01b0394851660805292841660a05290831660c052821660e052811661010052166101205250620003d8565b336001600160a01b03821603620003475760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200027d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b0381168114620003ae57600080fd5b50565b600060208284031215620003c457600080fd5b8151620003d18162000398565b9392505050565b60805160a05160c05160e0516101005161012051614e25620004256000396000818160c9015261017c01526000611bb8015260005050600050506000505060006104c20152614e256000f3fe6080604052600436106100c75760003560e01c8063aed2e92911610074578063e3d0e7121161004e578063e3d0e71214610348578063f2fde38b14610368578063f75f6b1114610388576100c7565b8063aed2e929146102a3578063afcb95d7146102da578063b1dc65a414610328576100c7565b806381ff7048116100a557806381ff7048146101d65780638da5cb5b14610258578063a4c0ed3614610283576100c7565b8063181f5a771461010e578063349e8cca1461016d57806379ba5097146101c1575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e808015610107573d6000f35b3d6000fd5b005b34801561011a57600080fd5b506101576040518060400160405280601881526020017f4175746f6d6174696f6e526567697374727920322e322e30000000000000000081525081565b6040516101649190613b21565b60405180910390f35b34801561017957600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610164565b3480156101cd57600080fd5b5061010c6103a8565b3480156101e257600080fd5b5061023560155460115463ffffffff780100000000000000000000000000000000000000000000000083048116937c01000000000000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610164565b34801561026457600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff1661019c565b34801561028f57600080fd5b5061010c61029e366004613baf565b6104aa565b3480156102af57600080fd5b506102c36102be366004613c0b565b6106c6565b604080519215158352602083019190915201610164565b3480156102e657600080fd5b50601154601254604080516000815260208101939093527401000000000000000000000000000000000000000090910463ffffffff1690820152606001610164565b34801561033457600080fd5b5061010c610343366004613c9c565b61083c565b34801561035457600080fd5b5061010c610363366004613f6d565b610b77565b34801561037457600080fd5b5061010c61038336600461403a565b610ba0565b34801561039457600080fd5b5061010c6103a336600461423e565b610bb4565b60015473ffffffffffffffffffffffffffffffffffffffff16331461042e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610519576040517fc8bad78d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208114610553576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610561828401846142cd565b60008181526004602052604090205490915065010000000000900463ffffffff908116146105bb576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600460205260409020600101546105f69085906c0100000000000000000000000090046bffffffffffffffffffffffff16614315565b600082815260046020526040902060010180546bffffffffffffffffffffffff929092166c01000000000000000000000000027fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff90921691909117905560195461066190859061433a565b6019556040516bffffffffffffffffffffffff8516815273ffffffffffffffffffffffffffffffffffffffff86169082907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a35050505050565b6000806106d1611ba0565b6012547e01000000000000000000000000000000000000000000000000000000000000900460ff1615610730576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600085815260046020908152604091829020825160e081018452815460ff811615158252610100810463ffffffff908116838601819052650100000000008304821684880152690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff16606084018190526001909401546bffffffffffffffffffffffff80821660808601526c0100000000000000000000000082041660a0850152780100000000000000000000000000000000000000000000000090041660c08301528451601f8901859004850281018501909552878552909361082f938990899081908401838280828437600092019190915250611c1192505050565b9097909650945050505050565b60005a60408051610160810182526012546bffffffffffffffffffffffff8116825263ffffffff6c010000000000000000000000008204811660208401527001000000000000000000000000000000008204811693830193909352740100000000000000000000000000000000000000008104909216606082015262ffffff7801000000000000000000000000000000000000000000000000830416608082015261ffff7b0100000000000000000000000000000000000000000000000000000083041660a082015260ff7d0100000000000000000000000000000000000000000000000000000000008304811660c08301527e010000000000000000000000000000000000000000000000000000000000008304811615801560e08401527f01000000000000000000000000000000000000000000000000000000000000009093048116151561010080840191909152601354918216151561012084015273ffffffffffffffffffffffffffffffffffffffff9104166101408201529192506109f2576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600b602052604090205460ff16610a3b576040517f1099ed7500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6011548a3514610a77576040517fdfdcf8e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60c0810151610a8790600161437c565b60ff1686141580610a985750858414155b15610acf576040517f0244f71a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610adf8a8a8a8a8a8a8a8a611e3a565b6000610aeb8a8a6120a3565b905060208b0135600881901c63ffffffff16610b0884848761215e565b836060015163ffffffff168163ffffffff161115610b6857601280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416021790555b50505050505050505050505050565b610b9886868686806020019051810190610b91919061443b565b8686610bb4565b505050505050565b610ba8612add565b610bb181612b5e565b50565b610bbc612add565b601f86511115610bf8576040517f25d0209c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8360ff16600003610c35576040517fe77dba5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84518651141580610c545750610c4c8460036145bd565b60ff16865111155b15610c8b576040517f1d2d1c5800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601254600e546bffffffffffffffffffffffff9091169060005b816bffffffffffffffffffffffff16811015610d0d57610cfa600e8281548110610cd157610cd161434d565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff168484612c53565b5080610d05816145d9565b915050610ca5565b5060008060005b836bffffffffffffffffffffffff16811015610e1657600d8181548110610d3d57610d3d61434d565b600091825260209091200154600e805473ffffffffffffffffffffffffffffffffffffffff90921694509082908110610d7857610d7861434d565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff8681168452600c8352604080852080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690559116808452600b90925290912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055915080610e0e816145d9565b915050610d14565b50610e23600d6000613a00565b610e2f600e6000613a00565b604080516080810182526000808252602082018190529181018290526060810182905290805b8c5181101561129857600c60008e8381518110610e7457610e7461434d565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000205460ff1615610edf576040517f77cea0fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168d8281518110610f0957610f0961434d565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603610f5e576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180604001604052806001151581526020018260ff16815250600c60008f8481518110610f8f57610f8f61434d565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528181019290925260400160002082518154939092015160ff16610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909316929092171790558b518c90829081106110375761103761434d565b60200260200101519150600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036110a7576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166000908152600b60209081526040918290208251608081018452905460ff80821615801584526101008304909116938301939093526bffffffffffffffffffffffff6201000082048116948301949094526e01000000000000000000000000000090049092166060830152909350611162576040517f6a7281ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001835260ff80821660208086019182526bffffffffffffffffffffffff808b166060880190815273ffffffffffffffffffffffffffffffffffffffff87166000908152600b909352604092839020885181549551948a0151925184166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff939094166201000002929092167fffffffffffff000000000000000000000000000000000000000000000000ffff94909616610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009095169490941717919091169290921791909117905580611290816145d9565b915050610e55565b50508a516112ae9150600d9060208d0190613a1e565b5088516112c290600e9060208c0190613a1e565b50604051806101600160405280856bffffffffffffffffffffffff168152602001886000015163ffffffff168152602001886020015163ffffffff168152602001600063ffffffff168152602001886060015162ffffff168152602001886080015161ffff1681526020018960ff1681526020016012600001601e9054906101000a900460ff16151581526020016012600001601f9054906101000a900460ff161515815260200188610200015115158152602001886101e0015173ffffffffffffffffffffffffffffffffffffffff16815250601260008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060808201518160000160186101000a81548162ffffff021916908362ffffff16021790555060a082015181600001601b6101000a81548161ffff021916908361ffff16021790555060c082015181600001601d6101000a81548160ff021916908360ff16021790555060e082015181600001601e6101000a81548160ff02191690831515021790555061010082015181600001601f6101000a81548160ff0219169083151502179055506101208201518160010160006101000a81548160ff0219169083151502179055506101408201518160010160016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050506040518061018001604052808860a001516bffffffffffffffffffffffff16815260200188610180015173ffffffffffffffffffffffffffffffffffffffff168152602001601460010160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff168152602001886040015163ffffffff1681526020018860c0015163ffffffff168152602001601460010160149054906101000a900463ffffffff1663ffffffff168152602001601460010160189054906101000a900463ffffffff1663ffffffff1681526020016014600101601c9054906101000a900463ffffffff1663ffffffff1681526020018860e0015163ffffffff16815260200188610100015163ffffffff16815260200188610120015163ffffffff168152602001886101c0015173ffffffffffffffffffffffffffffffffffffffff16815250601460008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160010160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550606082015181600101600c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160106101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160010160146101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555060e082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160020160006101000a81548163ffffffff021916908363ffffffff1602179055506101208201518160020160046101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160086101000a81548163ffffffff021916908363ffffffff16021790555061016082015181600201600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555090505086610140015160178190555086610160015160188190555060006014600101601c9054906101000a900463ffffffff169050876101e0015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611963573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119879190614611565b601580547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff9384160217808255600192601891611a02918591780100000000000000000000000000000000000000000000000090041661462a565b92506101000a81548163ffffffff021916908363ffffffff160217905550600088604051602001611a339190614698565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152919052601554909150611a9c90469030907801000000000000000000000000000000000000000000000000900463ffffffff168f8f8f878f8f612e5b565b60115560005b611aac6009612f05565b811015611adc57611ac9611ac1600983612f0f565b600990612f22565b5080611ad4816145d9565b915050611aa2565b5060005b896101a0015151811015611b3357611b208a6101a001518281518110611b0857611b0861434d565b60200260200101516009612f4490919063ffffffff16565b5080611b2b816145d9565b915050611ae0565b507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0582601154601460010160189054906101000a900463ffffffff168f8f8f878f8f604051611b8a9998979695949392919061483c565b60405180910390a1505050505050505050505050565b3273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611c0f576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60125460009081907f0100000000000000000000000000000000000000000000000000000000000000900460ff1615611c76576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601280547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01000000000000000000000000000000000000000000000000000000000000001790556040517f4585e33b0000000000000000000000000000000000000000000000000000000090611cf2908590602401613b21565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d1690611dc590879087906004016148d2565b60408051808303816000875af1158015611de3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e0791906148eb565b601280547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16905590969095509350505050565b60008787604051611e4c929190614919565b604051908190038120611e63918b90602001614929565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201208383019092526000808452908301819052909250906000805b8881101561203a57600185878360208110611ecf57611ecf61434d565b611edc91901a601b61437c565b8c8c85818110611eee57611eee61434d565b905060200201358b8b86818110611f0757611f0761434d565b9050602002013560405160008152602001604052604051611f44949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611f66573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff81166000908152600c602090815290849020838501909452925460ff8082161515808552610100909204169383019390935290955093509050612014576040517f0f4c073700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015160080260ff166001901b840193508080612032906145d9565b915050611eb2565b50827e01010101010101010101010101010101010101010101010101010101010101841614612095576040517fc103be2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050505050565b6120dc6040518060c001604052806000815260200160008152602001606081526020016060815260200160608152602001606081525090565b60006120ea83850185614a1a565b604081015151606082015151919250908114158061210d57508082608001515114155b8061211d5750808260a001515114155b15612154576040517fb55ac75400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090505b92915050565b600082604001515167ffffffffffffffff81111561217e5761217e613d53565b60405190808252806020026020018201604052801561223a57816020015b604080516101c081018252600060e08201818152610100830182905261012083018290526101408301829052610160830182905261018083018290526101a0830182905282526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161219c5790505b50905060006040518060800160405280600061ffff1681526020016000815260200160006bffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff168152509050600085610140015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122fc9190614611565b9050600086610140015173ffffffffffffffffffffffffffffffffffffffff166318b8f6136040518163ffffffff1660e01b8152600401602060405180830381865afa158015612350573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123749190614611565b905060005b8660400151518110156127c35760046000886040015183815181106123a0576123a061434d565b6020908102919091018101518252818101929092526040908101600020815160e081018352815460ff811615158252610100810463ffffffff90811695830195909552650100000000008104851693820193909352690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff166060830152600101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490911660c082015285518690839081106124855761248561434d565b6020026020010151600001819052506124ba876040015182815181106124ad576124ad61434d565b6020026020010151612f66565b8582815181106124cc576124cc61434d565b60200260200101516060019060018111156124e9576124e9614b07565b908160018111156124fc576124fc614b07565b81525050612560876040015182815181106125195761251961434d565b602002602001015184896080015184815181106125385761253861434d565b60200260200101518885815181106125525761255261434d565b60200260200101518c613011565b8683815181106125725761257261434d565b602002602001015160200187848151811061258f5761258f61434d565b602002602001015160c00182815250821515151581525050508481815181106125ba576125ba61434d565b602002602001015160200151156125ea576001846000018181516125de9190614b36565b61ffff169052506125ef565b6127b1565b6126558582815181106126045761260461434d565b602002602001015160000151606001518860600151838151811061262a5761262a61434d565b60200260200101518960a0015184815181106126485761264861434d565b6020026020010151611c11565b8683815181106126675761266761434d565b60200260200101516040018784815181106126845761268461434d565b602090810291909101015160800191909152901515905260c08801516126ab90600161437c565b6126b99060ff166040614b51565b6103a48860a0015183815181106126d2576126d261434d565b6020026020010151516126e5919061433a565b6126ef919061433a565b8582815181106127015761270161434d565b602002602001015160a00181815250508481815181106127235761272361434d565b602002602001015160a0015184602001818151612740919061433a565b90525084518590829081106127575761275761434d565b6020026020010151608001518661276e9190614b68565b95506127b1876040015182815181106127895761278961434d565b6020026020010151848784815181106127a4576127a461434d565b6020026020010151613130565b806127bb816145d9565b915050612379565b50825161ffff166000036127da5750505050505050565b6155f06127e8366010614b51565b5a6127f39088614b68565b6127fd919061433a565b612807919061433a565b8351909550611b589061281e9061ffff1687614baa565b612828919061433a565b945060008060005b886040015151811015612a0c5786818151811061284f5761284f61434d565b602002602001015160200151156129fa576128e88a8a60400151838151811061287a5761287a61434d565b60200260200101518984815181106128945761289461434d565b6020026020010151608001518c600001518d602001518d8c602001518e89815181106128c2576128c261434d565b602002602001015160a001518c6128d99190614b51565b6128e39190614baa565b613235565b6060880180519295509093508391612901908390614315565b6bffffffffffffffffffffffff16905250604086018051849190612926908390614315565b6bffffffffffffffffffffffff16905250865187908290811061294b5761294b61434d565b60200260200101516040015115158960400151828151811061296f5761296f61434d565b60200260200101517fad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b84866129a49190614315565b8a85815181106129b6576129b661434d565b6020026020010151608001518c8e6080015187815181106129d9576129d961434d565b60200260200101516040516129f19493929190614bbe565b60405180910390a35b80612a04816145d9565b915050612830565b505050604083810151336000908152600b602052919091208054600290612a489084906201000090046bffffffffffffffffffffffff16614315565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508260600151601260000160008282829054906101000a90046bffffffffffffffffffffffff16612aa69190614315565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555050505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611c0f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610425565b3373ffffffffffffffffffffffffffffffffffffffff821603612bdd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610425565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e0100000000000000000000000000009004909116606082015290612e4f576000816060015185612ceb9190614bfb565b90506000612cf98583614c20565b90508083604001818151612d0d9190614315565b6bffffffffffffffffffffffff16905250612d288582614c4b565b83606001818151612d399190614315565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b60400151949350505050565b6000808a8a8a8a8a8a8a8a8a604051602001612e7f99989796959493929190614c7b565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179b9a5050505050505050505050565b6000612158825490565b6000612f1b83836133b8565b9392505050565b6000612f1b8373ffffffffffffffffffffffffffffffffffffffff84166133e2565b6000612f1b8373ffffffffffffffffffffffffffffffffffffffff84166134dc565b6000818160045b600f811015612ff3577fff000000000000000000000000000000000000000000000000000000000000008216838260208110612fab57612fab61434d565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614612fe157506000949350505050565b80612feb816145d9565b915050612f6d565b5081600f1a600181111561300957613009614b07565b949350505050565b60008080808560600151600181111561302c5761302c614b07565b036130525761303e888888888861352b565b61304d57600092509050613126565b6130ca565b60018560600151600181111561306a5761306a614b07565b0361309857600061307d898989886136b6565b92509050806130925750600092509050613126565b506130ca565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84516040015163ffffffff16871061311f57877fc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd56368760405161310c9190613b21565b60405180910390a2600092509050613126565b6001925090505b9550959350505050565b60008160600151600181111561314857613148614b07565b036131ac57600083815260046020526040902060010180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000063ffffffff851602179055505050565b6001816060015160018111156131c4576131c4614b07565b036132305760c08101805160009081526008602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055915191517fa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f29190a25b505050565b600080613248898886868a8a60016138c4565b60008a8152600460205260408120600101549294509092506c010000000000000000000000009091046bffffffffffffffffffffffff169061328a8385614315565b9050836bffffffffffffffffffffffff16826bffffffffffffffffffffffff1610156132be575091506000905081806132f1565b806bffffffffffffffffffffffff16826bffffffffffffffffffffffff1610156132f15750806132ee8482614bfb565b92505b60008a81526004602052604090206001018054829190600c906133339084906c0100000000000000000000000090046bffffffffffffffffffffffff16614bfb565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008c81526004602052604081206001018054859450909261337c91859116614315565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550505097509795505050505050565b60008260000182815481106133cf576133cf61434d565b9060005260206000200154905092915050565b600081815260018301602052604081205480156134cb576000613406600183614b68565b855490915060009061341a90600190614b68565b905081811461347f57600086600001828154811061343a5761343a61434d565b906000526020600020015490508087600001848154811061345d5761345d61434d565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061349057613490614d10565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612158565b6000915050612158565b5092915050565b600081815260018301602052604081205461352357508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155612158565b506000612158565b600080848060200190518101906135429190614d3f565b845160c00151815191925063ffffffff9081169116101561359f57867f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e88660405161358d9190613b21565b60405180910390a260009150506136ad565b826101200151801561366057506020810151158015906136605750602081015161014084015182516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa158015613639573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061365d9190614611565b14155b806136725750805163ffffffff168611155b156136a757867f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc3018660405161358d9190613b21565b60019150505b95945050505050565b6000806000848060200190518101906136cf9190614d97565b905060008782600001518360200151846040015160405160200161373194939291909384526020840192909252604083015260e01b7fffffffff0000000000000000000000000000000000000000000000000000000016606082015260640190565b604051602081830303815290604052805190602001209050846101200151801561380d575060808201511580159061380d5750608082015161014086015160608401516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa1580156137e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061380a9190614611565b14155b80613822575086826060015163ffffffff1610155b1561386c57877f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301876040516138579190613b21565b60405180910390a26000935091506138bb9050565b60008181526008602052604090205460ff16156138b357877f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8876040516138579190613b21565b600193509150505b94509492505050565b60008060008960a0015161ffff16866138dd9190614b51565b90508380156138eb5750803a105b156138f357503a5b600085886139018b8d61433a565b61390b9085614b51565b613915919061433a565b61392790670de0b6b3a7640000614b51565b6139319190614baa565b905060008b6040015163ffffffff1664e8d4a510006139509190614b51565b60208d0151889063ffffffff168b6139688f88614b51565b613972919061433a565b61398090633b9aca00614b51565b61398a9190614b51565b6139949190614baa565b61399e919061433a565b90506b033b2e3c9fd0803ce80000006139b7828461433a565b11156139ef576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b909b909a5098505050505050505050565b5080546000825590600052602060002090810190610bb19190613aa8565b828054828255906000526020600020908101928215613a98579160200282015b82811115613a9857825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190613a3e565b50613aa4929150613aa8565b5090565b5b80821115613aa45760008155600101613aa9565b6000815180845260005b81811015613ae357602081850181015186830182015201613ac7565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000612f1b6020830184613abd565b73ffffffffffffffffffffffffffffffffffffffff81168114610bb157600080fd5b8035613b6181613b34565b919050565b60008083601f840112613b7857600080fd5b50813567ffffffffffffffff811115613b9057600080fd5b602083019150836020828501011115613ba857600080fd5b9250929050565b60008060008060608587031215613bc557600080fd5b8435613bd081613b34565b935060208501359250604085013567ffffffffffffffff811115613bf357600080fd5b613bff87828801613b66565b95989497509550505050565b600080600060408486031215613c2057600080fd5b83359250602084013567ffffffffffffffff811115613c3e57600080fd5b613c4a86828701613b66565b9497909650939450505050565b60008083601f840112613c6957600080fd5b50813567ffffffffffffffff811115613c8157600080fd5b6020830191508360208260051b8501011115613ba857600080fd5b60008060008060008060008060e0898b031215613cb857600080fd5b606089018a811115613cc957600080fd5b8998503567ffffffffffffffff80821115613ce357600080fd5b613cef8c838d01613b66565b909950975060808b0135915080821115613d0857600080fd5b613d148c838d01613c57565b909750955060a08b0135915080821115613d2d57600080fd5b50613d3a8b828c01613c57565b999c989b50969995989497949560c00135949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610220810167ffffffffffffffff81118282101715613da657613da6613d53565b60405290565b60405160c0810167ffffffffffffffff81118282101715613da657613da6613d53565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613e1657613e16613d53565b604052919050565b600067ffffffffffffffff821115613e3857613e38613d53565b5060051b60200190565b600082601f830112613e5357600080fd5b81356020613e68613e6383613e1e565b613dcf565b82815260059290921b84018101918181019086841115613e8757600080fd5b8286015b84811015613eab578035613e9e81613b34565b8352918301918301613e8b565b509695505050505050565b803560ff81168114613b6157600080fd5b600082601f830112613ed857600080fd5b813567ffffffffffffffff811115613ef257613ef2613d53565b613f2360207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613dcf565b818152846020838601011115613f3857600080fd5b816020850160208301376000918101602001919091529392505050565b803567ffffffffffffffff81168114613b6157600080fd5b60008060008060008060c08789031215613f8657600080fd5b863567ffffffffffffffff80821115613f9e57600080fd5b613faa8a838b01613e42565b97506020890135915080821115613fc057600080fd5b613fcc8a838b01613e42565b9650613fda60408a01613eb6565b95506060890135915080821115613ff057600080fd5b613ffc8a838b01613ec7565b945061400a60808a01613f55565b935060a089013591508082111561402057600080fd5b5061402d89828a01613ec7565b9150509295509295509295565b60006020828403121561404c57600080fd5b8135612f1b81613b34565b63ffffffff81168114610bb157600080fd5b8035613b6181614057565b62ffffff81168114610bb157600080fd5b8035613b6181614074565b61ffff81168114610bb157600080fd5b8035613b6181614090565b6bffffffffffffffffffffffff81168114610bb157600080fd5b8035613b61816140ab565b8015158114610bb157600080fd5b8035613b61816140d0565b600061022082840312156140fc57600080fd5b614104613d82565b905061410f82614069565b815261411d60208301614069565b602082015261412e60408301614069565b604082015261413f60608301614085565b6060820152614150608083016140a0565b608082015261416160a083016140c5565b60a082015261417260c08301614069565b60c082015261418360e08301614069565b60e0820152610100614196818401614069565b908201526101206141a8838201614069565b90820152610140828101359082015261016080830135908201526101806141d0818401613b56565b908201526101a08281013567ffffffffffffffff8111156141f057600080fd5b6141fc85828601613e42565b8284015250506101c0614210818401613b56565b908201526101e0614222838201613b56565b908201526102006142348382016140de565b9082015292915050565b60008060008060008060c0878903121561425757600080fd5b863567ffffffffffffffff8082111561426f57600080fd5b61427b8a838b01613e42565b9750602089013591508082111561429157600080fd5b61429d8a838b01613e42565b96506142ab60408a01613eb6565b955060608901359150808211156142c157600080fd5b613ffc8a838b016140e9565b6000602082840312156142df57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff8181168382160190808211156134d5576134d56142e6565b80820180821115612158576121586142e6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60ff8181168382160190811115612158576121586142e6565b8051613b6181614057565b8051613b6181614074565b8051613b6181614090565b8051613b61816140ab565b8051613b6181613b34565b600082601f8301126143dd57600080fd5b815160206143ed613e6383613e1e565b82815260059290921b8401810191818101908684111561440c57600080fd5b8286015b84811015613eab57805161442381613b34565b8352918301918301614410565b8051613b61816140d0565b60006020828403121561444d57600080fd5b815167ffffffffffffffff8082111561446557600080fd5b90830190610220828603121561447a57600080fd5b614482613d82565b61448b83614395565b815261449960208401614395565b60208201526144aa60408401614395565b60408201526144bb606084016143a0565b60608201526144cc608084016143ab565b60808201526144dd60a084016143b6565b60a08201526144ee60c08401614395565b60c08201526144ff60e08401614395565b60e0820152610100614512818501614395565b90820152610120614524848201614395565b908201526101408381015190820152610160808401519082015261018061454c8185016143c1565b908201526101a0838101518381111561456457600080fd5b614570888287016143cc565b8284015250506101c091506145868284016143c1565b828201526101e0915061459a8284016143c1565b8282015261020091506145ae828401614430565b91810191909152949350505050565b60ff81811683821602908116908181146134d5576134d56142e6565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361460a5761460a6142e6565b5060010190565b60006020828403121561462357600080fd5b5051919050565b63ffffffff8181168382160190808211156134d5576134d56142e6565b600081518084526020808501945080840160005b8381101561468d57815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161465b565b509495945050505050565b602081526146af60208201835163ffffffff169052565b600060208301516146c8604084018263ffffffff169052565b50604083015163ffffffff8116606084015250606083015162ffffff8116608084015250608083015161ffff811660a08401525060a08301516bffffffffffffffffffffffff811660c08401525060c083015163ffffffff811660e08401525060e08301516101006147418185018363ffffffff169052565b840151905061012061475a8482018363ffffffff169052565b84015190506101406147738482018363ffffffff169052565b840151610160848101919091528401516101808085019190915284015190506101a06147b68185018373ffffffffffffffffffffffffffffffffffffffff169052565b808501519150506102206101c081818601526147d6610240860184614647565b908601519092506101e06148018682018373ffffffffffffffffffffffffffffffffffffffff169052565b860151905061020061482a8682018373ffffffffffffffffffffffffffffffffffffffff169052565b90950151151593019290925250919050565b600061012063ffffffff808d1684528b6020850152808b1660408501525080606084015261486c8184018a614647565b905082810360808401526148808189614647565b905060ff871660a084015282810360c084015261489d8187613abd565b905067ffffffffffffffff851660e08401528281036101008401526148c28185613abd565b9c9b505050505050505050505050565b8281526040602082015260006130096040830184613abd565b600080604083850312156148fe57600080fd5b8251614909816140d0565b6020939093015192949293505050565b8183823760009101908152919050565b8281526080810160608360208401379392505050565b600082601f83011261495057600080fd5b81356020614960613e6383613e1e565b82815260059290921b8401810191818101908684111561497f57600080fd5b8286015b84811015613eab5780358352918301918301614983565b600082601f8301126149ab57600080fd5b813560206149bb613e6383613e1e565b82815260059290921b840181019181810190868411156149da57600080fd5b8286015b84811015613eab57803567ffffffffffffffff8111156149fe5760008081fd5b614a0c8986838b0101613ec7565b8452509183019183016149de565b600060208284031215614a2c57600080fd5b813567ffffffffffffffff80821115614a4457600080fd5b9083019060c08286031215614a5857600080fd5b614a60613dac565b8235815260208301356020820152604083013582811115614a8057600080fd5b614a8c8782860161493f565b604083015250606083013582811115614aa457600080fd5b614ab08782860161493f565b606083015250608083013582811115614ac857600080fd5b614ad48782860161499a565b60808301525060a083013582811115614aec57600080fd5b614af88782860161499a565b60a08301525095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b61ffff8181168382160190808211156134d5576134d56142e6565b8082028115828204841417612158576121586142e6565b81810381811115612158576121586142e6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082614bb957614bb9614b7b565b500490565b6bffffffffffffffffffffffff85168152836020820152826040820152608060608201526000614bf16080830184613abd565b9695505050505050565b6bffffffffffffffffffffffff8281168282160390808211156134d5576134d56142e6565b60006bffffffffffffffffffffffff80841680614c3f57614c3f614b7b565b92169190910492915050565b6bffffffffffffffffffffffff818116838216028082169190828114614c7357614c736142e6565b505092915050565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152614cc28285018b614647565b91508382036080850152614cd6828a614647565b915060ff881660a085015283820360c0850152614cf38288613abd565b90861660e085015283810361010085015290506148c28185613abd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600060408284031215614d5157600080fd5b6040516040810181811067ffffffffffffffff82111715614d7457614d74613d53565b6040528251614d8281614057565b81526020928301519281019290925250919050565b600060a08284031215614da957600080fd5b60405160a0810181811067ffffffffffffffff82111715614dcc57614dcc613d53565b806040525082518152602083015160208201526040830151614ded81614057565b60408201526060830151614e0081614057565b6060820152608092830151928101929092525091905056fea164736f6c6343000813000a", } var AutomationRegistryABI = AutomationRegistryMetaData.ABI diff --git a/core/gethwrappers/generated/automation_registry_wrapper_2_3/automation_registry_wrapper_2_3.go b/core/gethwrappers/generated/automation_registry_wrapper_2_3/automation_registry_wrapper_2_3.go index 8250fac766e..71ef298db95 100644 --- a/core/gethwrappers/generated/automation_registry_wrapper_2_3/automation_registry_wrapper_2_3.go +++ b/core/gethwrappers/generated/automation_registry_wrapper_2_3/automation_registry_wrapper_2_3.go @@ -31,36 +31,40 @@ var ( ) type AutomationRegistryBase23BillingConfig struct { - GasFeePPB uint32 - FlatFeeMicroLink *big.Int - PriceFeed common.Address + GasFeePPB uint32 + FlatFeeMilliCents *big.Int + PriceFeed common.Address + FallbackPrice *big.Int + MinSpend *big.Int +} + +type AutomationRegistryBase23BillingOverrides struct { + GasFeePPB uint32 + FlatFeeMilliCents *big.Int } type AutomationRegistryBase23OnchainConfig struct { - PaymentPremiumPPB uint32 - FlatFeeMicroLink uint32 CheckGasLimit uint32 - StalenessSeconds *big.Int - GasCeilingMultiplier uint16 - MinUpkeepSpend *big.Int MaxPerformGas uint32 MaxCheckDataSize uint32 + Transcoder common.Address + ReorgProtectionEnabled bool + StalenessSeconds *big.Int MaxPerformDataSize uint32 MaxRevertDataSize uint32 + UpkeepPrivilegeManager common.Address + GasCeilingMultiplier uint16 + FinanceAdmin common.Address FallbackGasPrice *big.Int FallbackLinkPrice *big.Int FallbackNativePrice *big.Int - Transcoder common.Address Registrars []common.Address - UpkeepPrivilegeManager common.Address ChainModule common.Address - ReorgProtectionEnabled bool - FinanceAdmin common.Address } var AutomationRegistryMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistryLogicB2_3\",\"name\":\"logicA\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidFeed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxCheckDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxPerformDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyFinanceAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentGreaterThanAllLINK\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint24\"},{\"internalType\":\"address\",\"name\":\"priceFeed\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"BillingConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newModule\",\"type\":\"address\"}],\"name\":\"ChainSpecificModuleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"onchainConfigBytes\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackNativePrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"},{\"internalType\":\"contractIChainModule\",\"name\":\"chainModule\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"financeAdmin\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.OnchainConfig\",\"name\":\"onchainConfig\",\"type\":\"tuple\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"contractIERC20[]\",\"name\":\"billingTokens\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint24\"},{\"internalType\":\"address\",\"name\":\"priceFeed\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig[]\",\"name\":\"billingConfigs\",\"type\":\"tuple[]\"}],\"name\":\"setConfigTypeSafe\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"simulatePerformUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"rawReport\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x6101606040523480156200001257600080fd5b5060405162005bf538038062005bf5833981016040819052620000359162000520565b80816001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b919062000520565b826001600160a01b031663226cf83c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000100919062000520565b836001600160a01b031663614486af6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000165919062000520565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca919062000520565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f919062000520565b866001600160a01b031663a08714c06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200026e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000294919062000520565b3380600081620002eb5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156200031e576200031e816200045c565b5050506001600160a01b0380871660805285811660a05284811660c081905284821660e05283821661010052908216610120526040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa1580156200038d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003b3919062000547565b60ff1660a0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620003f7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200041d919062000547565b60ff16146200043f576040516301f86e1760e41b815260040160405180910390fd5b5050506001600160a01b0390931661014052506200056c92505050565b336001600160a01b03821603620004b65760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620002e2565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b03811681146200051d57600080fd5b50565b6000602082840312156200053357600080fd5b8151620005408162000507565b9392505050565b6000602082840312156200055a57600080fd5b815160ff811681146200054057600080fd5b60805160a05160c05160e051610100516101205161014051615623620005d26000396000818160d6015261016f015260006122a701526000505060005050600061374301526000505060008181611441015281816115ed015261163701526156236000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c8063a4c0ed3611610081578063b1dc65a41161005b578063b1dc65a4146102c8578063e3d0e712146102db578063f2fde38b146102ee576100d4565b8063a4c0ed361461024a578063aed2e9291461025d578063afcb95d714610287576100d4565b806379ba5097116100b257806379ba5097146101c757806381ff7048146101cf5780638da5cb5b1461022c576100d4565b8063181f5a771461011b578063349e8cca1461016d57806335aefd19146101b4575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e808015610114573d6000f35b3d6000fd5b005b6101576040518060400160405280601881526020017f4175746f6d6174696f6e526567697374727920322e332e30000000000000000081525081565b604051610164919061400d565b60405180910390f35b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610164565b6101196101c2366004614542565b610301565b610119611327565b61020960155460115463ffffffff6c0100000000000000000000000083048116937001000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610164565b60005473ffffffffffffffffffffffffffffffffffffffff1661018f565b61011961025836600461469c565b611429565b61027061026b3660046146f8565b6116b8565b604080519215158352602083019190915201610164565b601154601254604080516000815260208101939093527401000000000000000000000000000000000000000090910463ffffffff1690820152606001610164565b6101196102d6366004614789565b61182e565b6101196102e9366004614840565b611b69565b6101196102fc36600461490d565b611ba3565b610309611bb7565b601f88511115610345576040517f25d0209c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8560ff16600003610382576040517fe77dba5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b865188511415806103a15750610399866003614959565b60ff16885111155b156103d8576040517f1d2d1c5800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051825114610413576040517fcf54c06a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61041d8282611c3a565b60005b600e5481101561049457610481600e828154811061044057610440614975565b600091825260209091200154601254600e5473ffffffffffffffffffffffffffffffffffffffff909216916bffffffffffffffffffffffff90911690611f76565b508061048c816149a4565b915050610420565b5060008060005b600e5481101561059157600d81815481106104b8576104b8614975565b600091825260209091200154600e805473ffffffffffffffffffffffffffffffffffffffff909216945090829081106104f3576104f3614975565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff8681168452600c8352604080852080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690559116808452600b90925290912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055915080610589816149a4565b91505061049b565b5061059e600d6000613eec565b6105aa600e6000613eec565b604080516080810182526000808252602082018190529181018290526060810182905290805b8c51811015610a1657600c60008e83815181106105ef576105ef614975565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000205460ff161561065a576040517f77cea0fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168d828151811061068457610684614975565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16036106d9576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180604001604052806001151581526020018260ff16815250600c60008f848151811061070a5761070a614975565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528181019290925260400160002082518154939092015160ff16610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909316929092171790558b518c90829081106107b2576107b2614975565b60200260200101519150600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610822576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166000908152600b60209081526040918290208251608081018452905460ff80821615801584526101008304909116938301939093526bffffffffffffffffffffffff6201000082048116948301949094526e010000000000000000000000000000900490921660608301529093506108dd576040517f6a7281ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001835260ff80821660208086019182526012546bffffffffffffffffffffffff9081166060880190815273ffffffffffffffffffffffffffffffffffffffff87166000908152600b909352604092839020885181549551948a0151925184166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff939094166201000002929092167fffffffffffff000000000000000000000000000000000000000000000000ffff94909616610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009095169490941717919091169290921791909117905580610a0e816149a4565b9150506105d0565b50508a51610a2c9150600d9060208d0190613f0a565b508851610a4090600e9060208c0190613f0a565b50604051806101600160405280601260000160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff168152602001886000015163ffffffff168152602001886020015163ffffffff168152602001600063ffffffff168152602001886060015162ffffff168152602001886080015161ffff1681526020018960ff1681526020016012600001601e9054906101000a900460ff16151581526020016012600001601f9054906101000a900460ff16151581526020018861022001511515815260200188610200015173ffffffffffffffffffffffffffffffffffffffff16815250601260008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060808201518160000160186101000a81548162ffffff021916908362ffffff16021790555060a082015181600001601b6101000a81548161ffff021916908361ffff16021790555060c082015181600001601d6101000a81548160ff021916908360ff16021790555060e082015181600001601e6101000a81548160ff02191690831515021790555061010082015181600001601f6101000a81548160ff0219169083151502179055506101208201518160010160006101000a81548160ff0219169083151502179055506101408201518160010160016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050506040518061018001604052808860a001516bffffffffffffffffffffffff168152602001886101a0015173ffffffffffffffffffffffffffffffffffffffff168152602001886040015163ffffffff1681526020018860c0015163ffffffff168152602001601460010160089054906101000a900463ffffffff1663ffffffff1681526020016014600101600c9054906101000a900463ffffffff1663ffffffff168152602001601460010160109054906101000a900463ffffffff1663ffffffff1681526020018860e0015163ffffffff16815260200188610100015163ffffffff16815260200188610120015163ffffffff168152602001886101e0015173ffffffffffffffffffffffffffffffffffffffff16815260200188610240015173ffffffffffffffffffffffffffffffffffffffff16815250601460008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160010160006101000a81548163ffffffff021916908363ffffffff16021790555060608201518160010160046101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160086101000a81548163ffffffff021916908363ffffffff16021790555060a082015181600101600c6101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160010160106101000a81548163ffffffff021916908363ffffffff16021790555060e08201518160010160146101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555061012082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101608201518160030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050866101400151601881905550866101600151601981905550866101800151601a819055506000601460010160109054906101000a900463ffffffff16905087610200015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa15801561110a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112e91906149dc565b601580547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff1670010000000000000000000000000000000063ffffffff9384160217808255600192600c916111959185916c010000000000000000000000009004166149f5565b92506101000a81548163ffffffff021916908363ffffffff1602179055506000886040516020016111c69190614a63565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905260155490915061122390469030906c01000000000000000000000000900463ffffffff168f8f8f878f8f61217e565b60115560005b6112336009612228565b81101561126357611250611248600983612238565b60099061224b565b508061125b816149a4565b915050611229565b5060005b896101c00151518110156112ba576112a78a6101c00151828151811061128f5761128f614975565b6020026020010151600961226d90919063ffffffff16565b50806112b2816149a4565b915050611267565b507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05826011546014600101600c9054906101000a900463ffffffff168f8f8f878f8f60405161131199989796959493929190614c3d565b60405180910390a1505050505050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146113ad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611498576040517fc8bad78d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602081146114d2576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006114e082840184614cd3565b60008181526004602052604090205490915065010000000000900463ffffffff9081161461153a576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600460205260409020600101546115759085906c0100000000000000000000000090046bffffffffffffffffffffffff16614cec565b600082815260046020908152604080832060010180546bffffffffffffffffffffffff959095166c01000000000000000000000000027fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff9095169490941790935573ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168252601b90522054611620908590614d11565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081166000908152601b602090815260409182902093909355516bffffffffffffffffffffffff871681529087169183917fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa734891506203910160405180910390a35050505050565b6000806116c361228f565b6012547e01000000000000000000000000000000000000000000000000000000000000900460ff1615611722576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600085815260046020908152604091829020825160e081018452815460ff811615158252610100810463ffffffff908116838601819052650100000000008304821684880152690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff16606084018190526001909401546bffffffffffffffffffffffff80821660808601526c0100000000000000000000000082041660a0850152780100000000000000000000000000000000000000000000000090041660c08301528451601f890185900485028101850190955287855290936118219389908990819084018382808284376000920191909152506122fe92505050565b9097909650945050505050565b60005a60408051610160810182526012546bffffffffffffffffffffffff8116825263ffffffff6c010000000000000000000000008204811660208401527001000000000000000000000000000000008204811693830193909352740100000000000000000000000000000000000000008104909216606082015262ffffff7801000000000000000000000000000000000000000000000000830416608082015261ffff7b0100000000000000000000000000000000000000000000000000000083041660a082015260ff7d0100000000000000000000000000000000000000000000000000000000008304811660c08301527e010000000000000000000000000000000000000000000000000000000000008304811615801560e08401527f01000000000000000000000000000000000000000000000000000000000000009093048116151561010080840191909152601354918216151561012084015273ffffffffffffffffffffffffffffffffffffffff9104166101408201529192506119e4576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600b602052604090205460ff16611a2d576040517f1099ed7500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6011548a3514611a69576040517fdfdcf8e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60c0810151611a79906001614d24565b60ff1686141580611a8a5750858414155b15611ac1576040517f0244f71a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ad18a8a8a8a8a8a8a8a612527565b6000611add8a8a612790565b905060208b0135600881901c63ffffffff16611afa848487612849565b836060015163ffffffff168163ffffffff161115611b5a57601280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416021790555b50505050505050505050505050565b600080600085806020019051810190611b829190614e85565b925092509250611b988989898689898888610301565b505050505050505050565b611bab611bb7565b611bb481613204565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314611c38576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016113a4565b565b60005b602254811015611cc7576021600060228381548110611c5e57611c5e614975565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffff00000000000000000000000000000000000000000000000000000016905580611cbf816149a4565b915050611c3d565b50611cd460226000613eec565b60005b8251811015611f71576000838281518110611cf457611cf4614975565b602002602001015190506000838381518110611d1257611d12614975565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161480611d6f5750604081015173ffffffffffffffffffffffffffffffffffffffff16155b15611da6576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82811660009081526021602052604090205467010000000000000090041615611e10576040517f357d0cc400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60228054600181019091557f61035b26e3e9eee00e0d72fd1ee8ddca6894550dca6916ea2ac6baa90d11e5100180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff848116918217909255600081815260216020908152604091829020855181548784018051898701805163ffffffff9095167fffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000909416841764010000000062ffffff93841602177fffffffffff0000000000000000000000000000000000000000ffffffffffffff16670100000000000000958b16959095029490941790945585519182525190921692820192909252905190931690830152907f5ff767a3a5dbf1ef088ebf56e221e9cea40ad357c31ba060c2f31244cefab7c19060600160405180910390a250508080611f69906149a4565b915050611cd7565b505050565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e010000000000000000000000000000900490911660608201529061217257600081606001518561200e9190615066565b9050600061201c85836150ba565b905080836040018181516120309190614cec565b6bffffffffffffffffffffffff1690525061204b85826150e5565b8360600181815161205c9190614cec565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b60400151949350505050565b6000808a8a8a8a8a8a8a8a8a6040516020016121a299989796959493929190615115565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179b9a5050505050505050505050565b6000612232825490565b92915050565b600061224483836132f9565b9392505050565b60006122448373ffffffffffffffffffffffffffffffffffffffff8416613323565b60006122448373ffffffffffffffffffffffffffffffffffffffff841661341d565b3273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611c38576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60125460009081907f0100000000000000000000000000000000000000000000000000000000000000900460ff1615612363576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601280547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01000000000000000000000000000000000000000000000000000000000000001790556040517f4585e33b00000000000000000000000000000000000000000000000000000000906123df90859060240161400d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d16906124b290879087906004016151aa565b60408051808303816000875af11580156124d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124f491906151c3565b601280547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16905590969095509350505050565b600087876040516125399291906151f1565b604051908190038120612550918b90602001615201565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201208383019092526000808452908301819052909250906000805b88811015612727576001858783602081106125bc576125bc614975565b6125c991901a601b614d24565b8c8c858181106125db576125db614975565b905060200201358b8b868181106125f4576125f4614975565b9050602002013560405160008152602001604052604051612631949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015612653573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff81166000908152600c602090815290849020838501909452925460ff8082161515808552610100909204169383019390935290955093509050612701576040517f0f4c073700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015160080260ff166001901b84019350808061271f906149a4565b91505061259f565b50827e01010101010101010101010101010101010101010101010101010101010101841614612782576040517fc103be2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050505050565b6127c96040518060c001604052806000815260200160008152602001606081526020016060815260200160608152602001606081525090565b60006127d7838501856152f2565b60408101515160608201515191925090811415806127fa57508082608001515114155b8061280a5750808260a001515114155b15612841576040517fb55ac75400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b509392505050565b600082604001515167ffffffffffffffff81111561286957612869614020565b60405190808252806020026020018201604052801561292557816020015b604080516101c081018252600060e08201818152610100830182905261012083018290526101408301829052610160830182905261018083018290526101a0830182905282526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816128875790505b50905060006040518060800160405280600061ffff1681526020016000815260200160006bffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff168152509050600085610140015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156129c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129e791906149dc565b9050600086610140015173ffffffffffffffffffffffffffffffffffffffff166318b8f6136040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a5f91906149dc565b905060005b866040015151811015612eae576004600088604001518381518110612a8b57612a8b614975565b6020908102919091018101518252818101929092526040908101600020815160e081018352815460ff811615158252610100810463ffffffff90811695830195909552650100000000008104851693820193909352690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff166060830152600101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490911660c08201528551869083908110612b7057612b70614975565b602002602001015160000181905250612ba587604001518281518110612b9857612b98614975565b602002602001015161346c565b858281518110612bb757612bb7614975565b6020026020010151606001906001811115612bd457612bd46153df565b90816001811115612be757612be76153df565b81525050612c4b87604001518281518110612c0457612c04614975565b60200260200101518489608001518481518110612c2357612c23614975565b6020026020010151888581518110612c3d57612c3d614975565b60200260200101518c613517565b868381518110612c5d57612c5d614975565b6020026020010151602001878481518110612c7a57612c7a614975565b602002602001015160c0018281525082151515158152505050848181518110612ca557612ca5614975565b60200260200101516020015115612cd557600184600001818151612cc9919061540e565b61ffff16905250612cda565b612e9c565b612d40858281518110612cef57612cef614975565b6020026020010151600001516060015188606001518381518110612d1557612d15614975565b60200260200101518960a001518481518110612d3357612d33614975565b60200260200101516122fe565b868381518110612d5257612d52614975565b6020026020010151604001878481518110612d6f57612d6f614975565b602090810291909101015160800191909152901515905260c0880151612d96906001614d24565b612da49060ff166040615429565b6103a48860a001518381518110612dbd57612dbd614975565b602002602001015151612dd09190614d11565b612dda9190614d11565b858281518110612dec57612dec614975565b602002602001015160a0018181525050848181518110612e0e57612e0e614975565b602002602001015160a0015184602001818151612e2b9190614d11565b9052508451859082908110612e4257612e42614975565b60200260200101516080015186612e599190615440565b9550612e9c87604001518281518110612e7457612e74614975565b602002602001015184878481518110612e8f57612e8f614975565b6020026020010151613636565b80612ea6816149a4565b915050612a64565b50825161ffff16600003612ec55750505050505050565b6155f0612ed3366010615429565b5a612ede9088615440565b612ee89190614d11565b612ef29190614d11565b8351909550611b5890612f099061ffff1687615453565b612f139190614d11565b945060005b86604001515181101561313557848181518110612f3757612f37614975565b6020026020010151602001511561312357600061300a896040518060e00160405280898681518110612f6b57612f6b614975565b60200260200101516080015181526020018a815260200188602001518a8781518110612f9957612f99614975565b602002602001015160a0015188612fb09190615429565b612fba9190615453565b81526020018b6000015181526020018b602001518152602001612fdc8d61373c565b8152600160209091015260408b0151805186908110612ffd57612ffd614975565b6020026020010151613826565b90508060200151856060018181516130229190614cec565b6bffffffffffffffffffffffff169052508051604086018051613046908390614cec565b6bffffffffffffffffffffffff16905250855186908390811061306b5761306b614975565b60200260200101516040015115158860400151838151811061308f5761308f614975565b60200260200101517fad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b836020015184600001516130cc9190614cec565b8986815181106130de576130de614975565b6020026020010151608001518b8d60800151888151811061310157613101614975565b60200260200101516040516131199493929190615467565b60405180910390a3505b8061312d816149a4565b915050612f18565b50604083810151336000908152600b60205291909120805460029061316f9084906201000090046bffffffffffffffffffffffff16614cec565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508260600151601260000160008282829054906101000a90046bffffffffffffffffffffffff166131cd9190614cec565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603613283576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016113a4565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600082600001828154811061331057613310614975565b9060005260206000200154905092915050565b6000818152600183016020526040812054801561340c576000613347600183615440565b855490915060009061335b90600190615440565b90508181146133c057600086600001828154811061337b5761337b614975565b906000526020600020015490508087600001848154811061339e5761339e614975565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806133d1576133d16154a4565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612232565b6000915050612232565b5092915050565b600081815260018301602052604081205461346457508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155612232565b506000612232565b6000818160045b600f8110156134f9577fff0000000000000000000000000000000000000000000000000000000000000082168382602081106134b1576134b1614975565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916146134e757506000949350505050565b806134f1816149a4565b915050613473565b5081600f1a600181111561350f5761350f6153df565b949350505050565b600080808085606001516001811115613532576135326153df565b036135585761354488888888886139e7565b6135535760009250905061362c565b6135d0565b600185606001516001811115613570576135706153df565b0361359e57600061358389898988613b72565b9250905080613598575060009250905061362c565b506135d0565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84516040015163ffffffff16871061362557877fc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd563687604051613612919061400d565b60405180910390a260009250905061362c565b6001925090505b9550959350505050565b60008160600151600181111561364e5761364e6153df565b036136b4576000838152600460205260409020600101805463ffffffff84167801000000000000000000000000000000000000000000000000027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff909116179055505050565b6001816060015160018111156136cc576136cc6153df565b03611f715760c08101805160009081526008602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055915191517fa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f29190a2505050565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156137ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137d091906154ed565b509350509250506000821315806137e657508042105b8061381657506000846080015162ffffff16118015613816575061380a8142615440565b846080015162ffffff16105b15613416575050601a5492915050565b60408051808201909152600080825260208201526000806138478686613d80565b6000868152600460205260408120600101549294509092506c010000000000000000000000009091046bffffffffffffffffffffffff16906138898385614cec565b9050836bffffffffffffffffffffffff16826bffffffffffffffffffffffff1610156138bd575091506000905081806138f0565b806bffffffffffffffffffffffff16826bffffffffffffffffffffffff1610156138f05750806138ed8482615066565b92505b60008681526004602052604090206001018054829190600c906139329084906c0100000000000000000000000090046bffffffffffffffffffffffff16615066565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008881526004602052604081206001018054859450909261397b91859116614cec565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506040518060400160405280856bffffffffffffffffffffffff168152602001846bffffffffffffffffffffffff168152509450505050509392505050565b600080848060200190518101906139fe919061553d565b845160c00151815191925063ffffffff90811691161015613a5b57867f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e886604051613a49919061400d565b60405180910390a26000915050613b69565b8261012001518015613b1c5750602081015115801590613b1c5750602081015161014084015182516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa158015613af5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b1991906149dc565b14155b80613b2e5750805163ffffffff168611155b15613b6357867f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc30186604051613a49919061400d565b60019150505b95945050505050565b600080600084806020019051810190613b8b9190615595565b9050600087826000015183602001518460400151604051602001613bed94939291909384526020840192909252604083015260e01b7fffffffff0000000000000000000000000000000000000000000000000000000016606082015260640190565b6040516020818303038152906040528051906020012090508461012001518015613cc95750608082015115801590613cc95750608082015161014086015160608401516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa158015613ca2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cc691906149dc565b14155b80613cde575086826060015163ffffffff1610155b15613d2857877f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc30187604051613d13919061400d565b60405180910390a2600093509150613d779050565b60008181526008602052604090205460ff1615613d6f57877f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e887604051613d13919061400d565b600193509150505b94509492505050565b60008060008460a0015161ffff168460600151613d9d9190615429565b90508360c001518015613daf5750803a105b15613db757503a5b600084608001518560a00151866040015187602001518860000151613ddc9190614d11565b613de69086615429565b613df09190614d11565b613dfa9190615429565b613e049190615453565b90506000866040015163ffffffff1664e8d4a51000613e239190615429565b6080870151613e3690633b9aca00615429565b8760a00151896020015163ffffffff1689604001518a6000015188613e5b9190615429565b613e659190614d11565b613e6f9190615429565b613e799190615429565b613e839190615453565b613e8d9190614d11565b90506b033b2e3c9fd0803ce8000000613ea68284614d11565b1115613ede576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9093509150505b9250929050565b5080546000825590600052602060002090810190611bb49190613f94565b828054828255906000526020600020908101928215613f84579160200282015b82811115613f8457825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190613f2a565b50613f90929150613f94565b5090565b5b80821115613f905760008155600101613f95565b6000815180845260005b81811015613fcf57602081850181015186830182015201613fb3565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006122446020830184613fa9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610260810167ffffffffffffffff8111828210171561407357614073614020565b60405290565b6040516060810167ffffffffffffffff8111828210171561407357614073614020565b60405160c0810167ffffffffffffffff8111828210171561407357614073614020565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561410657614106614020565b604052919050565b600067ffffffffffffffff82111561412857614128614020565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff81168114611bb457600080fd5b803561415f81614132565b919050565b600082601f83011261417557600080fd5b8135602061418a6141858361410e565b6140bf565b82815260059290921b840181019181810190868411156141a957600080fd5b8286015b848110156141cd5780356141c081614132565b83529183019183016141ad565b509695505050505050565b803560ff8116811461415f57600080fd5b63ffffffff81168114611bb457600080fd5b803561415f816141e9565b62ffffff81168114611bb457600080fd5b803561415f81614206565b61ffff81168114611bb457600080fd5b803561415f81614222565b6bffffffffffffffffffffffff81168114611bb457600080fd5b803561415f8161423d565b8015158114611bb457600080fd5b803561415f81614262565b6000610260828403121561428e57600080fd5b61429661404f565b90506142a1826141fb565b81526142af602083016141fb565b60208201526142c0604083016141fb565b60408201526142d160608301614217565b60608201526142e260808301614232565b60808201526142f360a08301614257565b60a082015261430460c083016141fb565b60c082015261431560e083016141fb565b60e08201526101006143288184016141fb565b9082015261012061433a8382016141fb565b908201526101408281013590820152610160808301359082015261018080830135908201526101a061436d818401614154565b908201526101c08281013567ffffffffffffffff81111561438d57600080fd5b61439985828601614164565b8284015250506101e06143ad818401614154565b908201526102006143bf838201614154565b908201526102206143d1838201614270565b908201526102406143e3838201614154565b9082015292915050565b803567ffffffffffffffff8116811461415f57600080fd5b600082601f83011261441657600080fd5b813567ffffffffffffffff81111561443057614430614020565b61446160207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016140bf565b81815284602083860101111561447657600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f8301126144a457600080fd5b813560206144b46141858361410e565b828152606092830285018201928282019190878511156144d357600080fd5b8387015b858110156145355781818a0312156144ef5760008081fd5b6144f7614079565b8135614502816141e9565b81528186013561451181614206565b8187015260408281013561452481614132565b9082015284529284019281016144d7565b5090979650505050505050565b600080600080600080600080610100898b03121561455f57600080fd5b883567ffffffffffffffff8082111561457757600080fd5b6145838c838d01614164565b995060208b013591508082111561459957600080fd5b6145a58c838d01614164565b98506145b360408c016141d8565b975060608b01359150808211156145c957600080fd5b6145d58c838d0161427b565b96506145e360808c016143ed565b955060a08b01359150808211156145f957600080fd5b6146058c838d01614405565b945060c08b013591508082111561461b57600080fd5b6146278c838d01614164565b935060e08b013591508082111561463d57600080fd5b5061464a8b828c01614493565b9150509295985092959890939650565b60008083601f84011261466c57600080fd5b50813567ffffffffffffffff81111561468457600080fd5b602083019150836020828501011115613ee557600080fd5b600080600080606085870312156146b257600080fd5b84356146bd81614132565b935060208501359250604085013567ffffffffffffffff8111156146e057600080fd5b6146ec8782880161465a565b95989497509550505050565b60008060006040848603121561470d57600080fd5b83359250602084013567ffffffffffffffff81111561472b57600080fd5b6147378682870161465a565b9497909650939450505050565b60008083601f84011261475657600080fd5b50813567ffffffffffffffff81111561476e57600080fd5b6020830191508360208260051b8501011115613ee557600080fd5b60008060008060008060008060e0898b0312156147a557600080fd5b606089018a8111156147b657600080fd5b8998503567ffffffffffffffff808211156147d057600080fd5b6147dc8c838d0161465a565b909950975060808b01359150808211156147f557600080fd5b6148018c838d01614744565b909750955060a08b013591508082111561481a57600080fd5b506148278b828c01614744565b999c989b50969995989497949560c00135949350505050565b60008060008060008060c0878903121561485957600080fd5b863567ffffffffffffffff8082111561487157600080fd5b61487d8a838b01614164565b9750602089013591508082111561489357600080fd5b61489f8a838b01614164565b96506148ad60408a016141d8565b955060608901359150808211156148c357600080fd5b6148cf8a838b01614405565b94506148dd60808a016143ed565b935060a08901359150808211156148f357600080fd5b5061490089828a01614405565b9150509295509295509295565b60006020828403121561491f57600080fd5b813561224481614132565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60ff81811683821602908116908181146134165761341661492a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036149d5576149d561492a565b5060010190565b6000602082840312156149ee57600080fd5b5051919050565b63ffffffff8181168382160190808211156134165761341661492a565b600081518084526020808501945080840160005b83811015614a5857815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614a26565b509495945050505050565b60208152614a7a60208201835163ffffffff169052565b60006020830151614a93604084018263ffffffff169052565b50604083015163ffffffff8116606084015250606083015162ffffff8116608084015250608083015161ffff811660a08401525060a08301516bffffffffffffffffffffffff811660c08401525060c083015163ffffffff811660e08401525060e0830151610100614b0c8185018363ffffffff169052565b8401519050610120614b258482018363ffffffff169052565b8401519050610140614b3e8482018363ffffffff169052565b84015161016084810191909152840151610180808501919091528401516101a08085019190915284015190506101c0614b8e8185018373ffffffffffffffffffffffffffffffffffffffff169052565b808501519150506102606101e08181860152614bae610280860184614a12565b90860151909250610200614bd98682018373ffffffffffffffffffffffffffffffffffffffff169052565b8601519050610220614c028682018373ffffffffffffffffffffffffffffffffffffffff169052565b8601519050610240614c178682018315159052565b9095015173ffffffffffffffffffffffffffffffffffffffff1693019290925250919050565b600061012063ffffffff808d1684528b6020850152808b16604085015250806060840152614c6d8184018a614a12565b90508281036080840152614c818189614a12565b905060ff871660a084015282810360c0840152614c9e8187613fa9565b905067ffffffffffffffff851660e0840152828103610100840152614cc38185613fa9565b9c9b505050505050505050505050565b600060208284031215614ce557600080fd5b5035919050565b6bffffffffffffffffffffffff8181168382160190808211156134165761341661492a565b808201808211156122325761223261492a565b60ff81811683821601908111156122325761223261492a565b805161415f816141e9565b805161415f81614206565b805161415f81614222565b805161415f8161423d565b805161415f81614132565b600082601f830112614d8557600080fd5b81516020614d956141858361410e565b82815260059290921b84018101918181019086841115614db457600080fd5b8286015b848110156141cd578051614dcb81614132565b8352918301918301614db8565b805161415f81614262565b600082601f830112614df457600080fd5b81516020614e046141858361410e565b82815260609283028501820192828201919087851115614e2357600080fd5b8387015b858110156145355781818a031215614e3f5760008081fd5b614e47614079565b8151614e52816141e9565b815281860151614e6181614206565b81870152604082810151614e7481614132565b908201528452928401928101614e27565b600080600060608486031215614e9a57600080fd5b835167ffffffffffffffff80821115614eb257600080fd5b908501906102608288031215614ec757600080fd5b614ecf61404f565b614ed883614d3d565b8152614ee660208401614d3d565b6020820152614ef760408401614d3d565b6040820152614f0860608401614d48565b6060820152614f1960808401614d53565b6080820152614f2a60a08401614d5e565b60a0820152614f3b60c08401614d3d565b60c0820152614f4c60e08401614d3d565b60e0820152610100614f5f818501614d3d565b90820152610120614f71848201614d3d565b908201526101408381015190820152610160808401519082015261018080840151908201526101a0614fa4818501614d69565b908201526101c08381015183811115614fbc57600080fd5b614fc88a828701614d74565b8284015250506101e0614fdc818501614d69565b90820152610200614fee848201614d69565b90820152610220615000848201614dd8565b90820152610240615012848201614d69565b90820152602087015190955091508082111561502d57600080fd5b61503987838801614d74565b9350604086015191508082111561504f57600080fd5b5061505c86828701614de3565b9150509250925092565b6bffffffffffffffffffffffff8281168282160390808211156134165761341661492a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006bffffffffffffffffffffffff808416806150d9576150d961508b565b92169190910492915050565b6bffffffffffffffffffffffff81811683821602808216919082811461510d5761510d61492a565b505092915050565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b16604085015281606085015261515c8285018b614a12565b91508382036080850152615170828a614a12565b915060ff881660a085015283820360c085015261518d8288613fa9565b90861660e08501528381036101008501529050614cc38185613fa9565b82815260406020820152600061350f6040830184613fa9565b600080604083850312156151d657600080fd5b82516151e181614262565b6020939093015192949293505050565b8183823760009101908152919050565b8281526080810160608360208401379392505050565b600082601f83011261522857600080fd5b813560206152386141858361410e565b82815260059290921b8401810191818101908684111561525757600080fd5b8286015b848110156141cd578035835291830191830161525b565b600082601f83011261528357600080fd5b813560206152936141858361410e565b82815260059290921b840181019181810190868411156152b257600080fd5b8286015b848110156141cd57803567ffffffffffffffff8111156152d65760008081fd5b6152e48986838b0101614405565b8452509183019183016152b6565b60006020828403121561530457600080fd5b813567ffffffffffffffff8082111561531c57600080fd5b9083019060c0828603121561533057600080fd5b61533861409c565b823581526020830135602082015260408301358281111561535857600080fd5b61536487828601615217565b60408301525060608301358281111561537c57600080fd5b61538887828601615217565b6060830152506080830135828111156153a057600080fd5b6153ac87828601615272565b60808301525060a0830135828111156153c457600080fd5b6153d087828601615272565b60a08301525095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b61ffff8181168382160190808211156134165761341661492a565b80820281158282048414176122325761223261492a565b818103818111156122325761223261492a565b6000826154625761546261508b565b500490565b6bffffffffffffffffffffffff8516815283602082015282604082015260806060820152600061549a6080830184613fa9565b9695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b805169ffffffffffffffffffff8116811461415f57600080fd5b600080600080600060a0868803121561550557600080fd5b61550e866154d3565b9450602086015193506040860151925060608601519150615531608087016154d3565b90509295509295909350565b60006040828403121561554f57600080fd5b6040516040810181811067ffffffffffffffff8211171561557257615572614020565b6040528251615580816141e9565b81526020928301519281019290925250919050565b600060a082840312156155a757600080fd5b60405160a0810181811067ffffffffffffffff821117156155ca576155ca614020565b8060405250825181526020830151602082015260408301516155eb816141e9565b604082015260608301516155fe816141e9565b6060820152608092830151928101929092525091905056fea164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistryLogicA2_3\",\"name\":\"logicA\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientLinkLiquidity\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidFeed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOffchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOnchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyFinanceAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingOverrides\",\"name\":\"overrides\",\"type\":\"tuple\"}],\"name\":\"BillingConfigOverridden\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"BillingConfigOverrideRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"BillingConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newModule\",\"type\":\"address\"}],\"name\":\"ChainSpecificModuleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"payments\",\"type\":\"uint256[]\"}],\"name\":\"NOPsSettledOffchain\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"onchainConfigBytes\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"financeAdmin\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackNativePrice\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"contractIChainModule\",\"name\":\"chainModule\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.OnchainConfig\",\"name\":\"onchainConfig\",\"type\":\"tuple\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"contractIERC20[]\",\"name\":\"billingTokens\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig[]\",\"name\":\"billingConfigs\",\"type\":\"tuple[]\"}],\"name\":\"setConfigTypeSafe\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"rawReport\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x6101806040523480156200001257600080fd5b50604051620066dd380380620066dd83398101604081905262000035916200062f565b80816001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b91906200062f565b826001600160a01b031663226cf83c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200010091906200062f565b836001600160a01b031663614486af6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200016591906200062f565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca91906200062f565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f91906200062f565b866001600160a01b031663a08714c06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200026e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200029491906200062f565b876001600160a01b031663c5b964e06040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002f9919062000656565b886001600160a01b031663ac4dc59a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000338573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200035e91906200062f565b3380600081620003b55760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620003e857620003e8816200056b565b5050506001600160a01b0380891660805287811660a05286811660c05285811660e052848116610100528316610120526025805483919060ff19166001838181111562000439576200043962000679565b0217905550806001600160a01b0316610140816001600160a01b03168152505060c0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200049a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004c091906200068f565b60ff1660a0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000504573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200052a91906200068f565b60ff16146200054c576040516301f86e1760e41b815260040160405180910390fd5b5050506001600160a01b039095166101605250620006b4945050505050565b336001600160a01b03821603620005c55760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620003ac565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b03811681146200062c57600080fd5b50565b6000602082840312156200064257600080fd5b81516200064f8162000616565b9392505050565b6000602082840312156200066957600080fd5b8151600281106200064f57600080fd5b634e487b7160e01b600052602160045260246000fd5b600060208284031215620006a257600080fd5b815160ff811681146200064f57600080fd5b60805160a05160c05160e05161010051610120516101405161016051615f9f6200073e6000396000818160c9015261017c015260008181610efb015261115701526000505060005050600050506000613d04015260005050600081816112470152818161135501528181611480015281816114ca01528181611a18015261342f0152615f9f6000f3fe6080604052600436106100c75760003560e01c8063948108f711610074578063b1dc65a41161004e578063b1dc65a414610314578063e3d0e71214610334578063f2fde38b14610354576100c7565b8063948108f71461029b578063a4c0ed36146102ae578063afcb95d7146102ce576100c7565b80637bee169d116100a55780637bee169d146101d657806381ff7048146101f65780638da5cb5b14610270576100c7565b8063181f5a771461010e578063349e8cca1461016d57806379ba5097146101c1575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e808015610107573d6000f35b3d6000fd5b005b34801561011a57600080fd5b506101576040518060400160405280601881526020017f4175746f6d6174696f6e526567697374727920322e332e30000000000000000081525081565b60405161016491906149a9565b60405180910390f35b34801561017957600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610164565b3480156101cd57600080fd5b5061010c610374565b3480156101e257600080fd5b5061010c6101f1366004614f1e565b610476565b34801561020257600080fd5b5061024d60175460135463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610164565b34801561027c57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff1661019c565b61010c6102a9366004615036565b610db7565b3480156102ba57600080fd5b5061010c6102c93660046150af565b61122f565b3480156102da57600080fd5b50601354601454604080516000815260208101939093526c0100000000000000000000000090910463ffffffff1690820152606001610164565b34801561032057600080fd5b5061010c61032f366004615150565b61154b565b34801561034057600080fd5b5061010c61034f366004615207565b61182c565b34801561036057600080fd5b5061010c61036f3660046152d4565b611866565b60015473ffffffffffffffffffffffffffffffffffffffff1633146103fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b61047e61187a565b601f885111156104ba576040517f25d0209c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8560ff166000036104f7576040517fe77dba5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b86518851141580610516575061050e866003615327565b60ff16885111155b1561054d576040517f1d2d1c5800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051825114610588576040517fcf54c06a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61059282826118fd565b61059c8888611d65565b604051806101200160405280601460000160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff168152602001600063ffffffff1681526020018660a0015162ffffff16815260200186610120015161ffff1681526020018760ff168152602001601460000160169054906101000a900460ff1615158152602001601460000160179054906101000a900460ff1615158152602001866080015115158152602001866101e0015173ffffffffffffffffffffffffffffffffffffffff16815250601460008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160106101000a81548162ffffff021916908362ffffff16021790555060608201518160000160136101000a81548161ffff021916908361ffff16021790555060808201518160000160156101000a81548160ff021916908360ff16021790555060a08201518160000160166101000a81548160ff02191690831515021790555060c08201518160000160176101000a81548160ff02191690831515021790555060e08201518160000160186101000a81548160ff0219169083151502179055506101008201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050604051806101600160405280866060015173ffffffffffffffffffffffffffffffffffffffff168152602001866000015163ffffffff168152602001866020015163ffffffff1681526020016016600001601c9054906101000a900463ffffffff1663ffffffff16815260200186610100015173ffffffffffffffffffffffffffffffffffffffff168152602001601660010160149054906101000a900463ffffffff1663ffffffff168152602001601660010160189054906101000a900463ffffffff1663ffffffff168152602001866040015163ffffffff16815260200186610140015173ffffffffffffffffffffffffffffffffffffffff1681526020018660c0015163ffffffff1681526020018660e0015163ffffffff16815250601660008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a08201518160010160146101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555060e082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101208201518160020160146101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160186101000a81548163ffffffff021916908363ffffffff160217905550905050846101600151601981905550846101800151601a81905550846101a00151601b819055506000601660010160189054906101000a900463ffffffff169050856101e0015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ba2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc69190615343565b601780547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000063ffffffff9384160217808255600192601491610c3d9185917401000000000000000000000000000000000000000090041661535c565b92506101000a81548163ffffffff021916908363ffffffff160217905550600086604051602001610c6e91906153ca565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152919052601754909150610cd3904690309074010000000000000000000000000000000000000000900463ffffffff168d8d8d878d8d612426565b601355600960008181610ce68282614890565b5050505060005b876101c0015151811015610d4057610d2d886101c001518281518110610d1557610d15615550565b602002602001015160096124d090919063ffffffff16565b5080610d388161557f565b915050610ced565b506013546017546040517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0592610da39286927401000000000000000000000000000000000000000090910463ffffffff16908f908f908f9089908f908f906155b7565b60405180910390a150505050505050505050565b600082815260046020908152604091829020825161012081018452815460ff8082161515835261010080830490911615159483019490945263ffffffff6201000082048116958301959095526601000000000000810485166060830181905273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009092048216608084015260018401546fffffffffffffffffffffffffffffffff811660a08501526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08501527c01000000000000000000000000000000000000000000000000000000009004861660e08401526002909301541692810192909252909114610ef3576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3415610f8f577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681610100015173ffffffffffffffffffffffffffffffffffffffff1614610f83576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f8c346124fb565b91505b818160c00151610f9f919061564d565b600084815260046020908152604080832060010180547fffffffff000000000000000000000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000006bffffffffffffffffffffffff9687160217905561010085015173ffffffffffffffffffffffffffffffffffffffff168352602190915290205461102f91841690615672565b61010082015173ffffffffffffffffffffffffffffffffffffffff16600090815260216020526040812091909155349003611155576101008101516040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526bffffffffffffffffffffffff8416604482015260009173ffffffffffffffffffffffffffffffffffffffff16906323b872dd906064016020604051808303816000875af11580156110f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111169190615690565b90508061114f576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506111e5565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0836bffffffffffffffffffffffff166040518263ffffffff1660e01b81526004016000604051808303818588803b1580156111cb57600080fd5b505af11580156111df573d6000803e3d6000fd5b50505050505b6040516bffffffffffffffffffffffff83168152339084907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a3505050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461129e576040517fc8bad78d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602081146112d8576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006112e6828401846156ad565b6000818152600460205260409020549091506601000000000000900463ffffffff90811614611341576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600460205260409020600201547f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff9081169116146113c5576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526004602052604090206001015461140490859070010000000000000000000000000000000090046bffffffffffffffffffffffff1661564d565b600082815260046020908152604080832060010180546bffffffffffffffffffffffff95909516700100000000000000000000000000000000027fffffffff000000000000000000000000ffffffffffffffffffffffffffffffff9095169490941790935573ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001682526021905220546114b3908590615672565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660009081526021602090815260409182902093909355516bffffffffffffffffffffffff871681529087169183917fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa734891506203910160405180910390a35050505050565b60005a60408051610120810182526014546bffffffffffffffffffffffff8116825263ffffffff6c01000000000000000000000000820416602083015262ffffff7001000000000000000000000000000000008204169282019290925261ffff730100000000000000000000000000000000000000830416606082015260ff75010000000000000000000000000000000000000000008304811660808301527601000000000000000000000000000000000000000000008304811615801560a08401527701000000000000000000000000000000000000000000000084048216151560c0840152780100000000000000000000000000000000000000000000000090930416151560e082015260155473ffffffffffffffffffffffffffffffffffffffff166101008201529192506116af576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600b602052604090205460ff166116f8576040517f1099ed7500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6013548a3514611734576040517fdfdcf8e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60808101516117449060016156c6565b60ff16861415806117555750858414155b1561178c576040517f0244f71a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61179c8a8a8a8a8a8a8a8a61259d565b60006117a88a8a612806565b905060208b0135600881901c63ffffffff166117c58484876128bf565b836020015163ffffffff168163ffffffff16111561181d57601480547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff8416021790555b50505050505050505050505050565b600080600085806020019051810190611845919061582e565b92509250925061185b8989898689898888610476565b505050505050505050565b61186e61187a565b611877816134a5565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146118fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016103f1565b565b60005b6024548110156119bb57602260006024838154811061192157611921615550565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812080547fffffffffff000000000000000000000000000000000000000000000000000000168155600181019190915560020180547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000169055806119b38161557f565b915050611900565b506119c860246000614890565b60255460ff1660005b8351811015611d5f5760008482815181106119ee576119ee615550565b602002602001015190506000848381518110611a0c57611a0c615550565b602002602001015190507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16148015611a8257506001846001811115611a8057611a806159d9565b145b15611ab9576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82161580611af45750604081015173ffffffffffffffffffffffffffffffffffffffff16155b15611b2b576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82811660009081526022602052604090205467010000000000000090041615611b95576040517f357d0cc400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6024805460018082019092557f7cd332d19b93bcabe3cce7ca0c18a052f57e5fd03b4758a09f30f5ddc4b22ec40180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8581169182179092556000818152602260209081526040918290208651815488840180518a8701805163ffffffff9095167fffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000909416841764010000000062ffffff93841602177fffffffffff0000000000000000000000000000000000000000ffffffffffffff16670100000000000000958b16959095029490941785556060808c0180519b87019b909b556080808d018051600290980180547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff998a1617905589519586529351909216968401969096529251909716948101949094529551918301919091529251909216928201929092527f720a5849025dc4fd0061aed1bb30efd713cde64ce7f8d807953ecca27c8f143c9060a00160405180910390a250508080611d579061557f565b9150506119d1565b50505050565b60005b600e54811015611ddc57611dc9600e8281548110611d8857611d88615550565b600091825260209091200154601454600e5473ffffffffffffffffffffffffffffffffffffffff909216916bffffffffffffffffffffffff9091169061359a565b5080611dd48161557f565b915050611d68565b5060255460009060ff16815b600e54811015611f4d57600e8181548110611e0557611e05615550565b6000918252602082200154600d805473ffffffffffffffffffffffffffffffffffffffff9092169550600c929184908110611e4257611e42615550565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff9081168452838201949094526040928301822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690559286168152600b909252902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556001826001811115611ee457611ee46159d9565b148015611f29575073ffffffffffffffffffffffffffffffffffffffff83166000908152600b60205260409020546201000090046bffffffffffffffffffffffff1615155b15611f3b57611f39600f846124d0565b505b80611f458161557f565b915050611de8565b50611f5a600d6000614890565b611f66600e6000614890565b6040805160808101825260008082526020820181905291810182905260608101829052905b85518110156123f657600c6000878381518110611faa57611faa615550565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000205460ff1615612015576040517f77cea0fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff1686828151811061203f5761203f615550565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603612094576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180604001604052806001151581526020018260ff16815250600c60008884815181106120c5576120c5615550565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528181019290925260400160002082518154939092015160ff16610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090931692909217179055845185908290811061216d5761216d615550565b60200260200101519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036121dd576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff84166000908152600b60209081526040918290208251608081018452905460ff80821615801584526101008304909116938301939093526bffffffffffffffffffffffff6201000082048116948301949094526e01000000000000000000000000000090049092166060830152909250612298576040517f6a7281ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180835260ff80831660208086019182526014546bffffffffffffffffffffffff9081166060880190815273ffffffffffffffffffffffffffffffffffffffff8a166000908152600b909352604092839020885181549551948a0151925184166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff939094166201000002929092167fffffffffffff000000000000000000000000000000000000000000000000ffff94909616610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909516949094171791909116929092179190911790558360018111156123d2576123d26159d9565b036123e4576123e2600f856137a2565b505b806123ee8161557f565b915050611f8b565b50845161240a90600d9060208801906148ae565b50835161241e90600e9060208701906148ae565b505050505050565b6000808a8a8a8a8a8a8a8a8a60405160200161244a99989796959493929190615a08565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179b9a5050505050505050505050565b60006124f28373ffffffffffffffffffffffffffffffffffffffff84166137c4565b90505b92915050565b60006bffffffffffffffffffffffff821115612599576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f362062697473000000000000000000000000000000000000000000000000000060648201526084016103f1565b5090565b600087876040516125af929190615a9d565b6040519081900381206125c6918b90602001615aad565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201208383019092526000808452908301819052909250906000805b8881101561279d5760018587836020811061263257612632615550565b61263f91901a601b6156c6565b8c8c8581811061265157612651615550565b905060200201358b8b8681811061266a5761266a615550565b90506020020135604051600081526020016040526040516126a7949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa1580156126c9573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff81166000908152600c602090815290849020838501909452925460ff8082161515808552610100909204169383019390935290955093509050612777576040517f0f4c073700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015160080260ff166001901b8401935080806127959061557f565b915050612615565b50827e010101010101010101010101010101010101010101010101010101010101018416146127f8576040517fc103be2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050505050565b61283f6040518060c001604052806000815260200160008152602001606081526020016060815260200160608152602001606081525090565b600061284d83850185615b9e565b604081015151606082015151919250908114158061287057508082608001515114155b806128805750808260a001515114155b156128b7576040517fb55ac75400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b509392505050565b600082604001515167ffffffffffffffff8111156128df576128df6149bc565b6040519080825280602002602001820160405280156129ab57816020015b6040805161020081018252600060e08201818152610100830182905261012083018290526101408301829052610160830182905261018083018290526101a083018290526101c083018290526101e0830182905282526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816128fd5790505b50905060006040518060800160405280600061ffff16815260200160006bffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff16815260200160008152509050600085610100015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a6d9190615343565b9050600086610100015173ffffffffffffffffffffffffffffffffffffffff166318b8f6136040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ac1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ae59190615343565b905060005b866040015151811015612f75576004600088604001518381518110612b1157612b11615550565b6020908102919091018101518252818101929092526040908101600020815161012081018352815460ff8082161515835261010080830490911615159583019590955263ffffffff620100008204811694830194909452660100000000000081048416606083015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009091048116608083015260018301546fffffffffffffffffffffffffffffffff811660a08401526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08401527c0100000000000000000000000000000000000000000000000000000000900490931660e0820152600290910154909116918101919091528551869083908110612c3457612c34615550565b602002602001015160000181905250612c6987604001518281518110612c5c57612c5c615550565b6020026020010151613813565b858281518110612c7b57612c7b615550565b6020026020010151606001906001811115612c9857612c986159d9565b90816001811115612cab57612cab6159d9565b81525050612d0f87604001518281518110612cc857612cc8615550565b60200260200101518489608001518481518110612ce757612ce7615550565b6020026020010151888581518110612d0157612d01615550565b60200260200101518c6138be565b868381518110612d2157612d21615550565b6020026020010151602001878481518110612d3e57612d3e615550565b602002602001015160c0018281525082151515158152505050848181518110612d6957612d69615550565b60200260200101516020015115612d9957600184600001818151612d8d9190615c8b565b61ffff16905250612d9e565b612f63565b612e04858281518110612db357612db3615550565b6020026020010151600001516080015188606001518381518110612dd957612dd9615550565b60200260200101518960a001518481518110612df757612df7615550565b60200260200101516139dd565b868381518110612e1657612e16615550565b6020026020010151604001878481518110612e3357612e33615550565b6020026020010151608001828152508215151515815250505087608001516001612e5d91906156c6565b612e6b9060ff166040615ca6565b6103a48860a001518381518110612e8457612e84615550565b602002602001015151612e979190615672565b612ea19190615672565b858281518110612eb357612eb3615550565b602002602001015160a0018181525050848181518110612ed557612ed5615550565b602002602001015160a0015184606001818151612ef29190615672565b9052508451859082908110612f0957612f09615550565b60200260200101516080015186612f209190615cbd565b9550612f6387604001518281518110612f3b57612f3b615550565b602002602001015184878481518110612f5657612f56615550565b6020026020010151613bf8565b80612f6d8161557f565b915050612aea565b50825161ffff16600003612f8c5750505050505050565b61c738612f9a366010615ca6565b5a612fa59088615cbd565b612faf9190615672565b612fb99190615672565b835190955061232890612fd09061ffff1687615cff565b612fda9190615672565b6040805160608101825260008082526020820181905291810182905291965061300289613cfd565b905060005b88604001515181101561333e5786818151811061302657613026615550565b6020026020010151602001511561332c578015806130be57508661304b600183615cbd565b8151811061305b5761305b615550565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff1687828151811061309457613094615550565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff1614155b156130f2576130ef8a8883815181106130d9576130d9615550565b6020026020010151600001516101000151613dee565b92505b60006132108b6040518061012001604052808b868151811061311657613116615550565b60200260200101516080015181526020018c81526020018a606001518c878151811061314457613144615550565b602002602001015160a001518a61315b9190615ca6565b6131659190615cff565b81526020018d6000015181526020018d6020015181526020018681526020018b868151811061319657613196615550565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff168152602001878152602001600115158152508c6040015185815181106131e5576131e5615550565b60200260200101518b86815181106131ff576131ff615550565b602002602001015160000151613f3f565b9050806060015187604001818151613228919061564d565b6bffffffffffffffffffffffff16905250604081015160208801805161324f90839061564d565b6bffffffffffffffffffffffff16905250875188908390811061327457613274615550565b60200260200101516040015115158a60400151838151811061329857613298615550565b60200260200101517fad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b836060015184604001516132d5919061564d565b8b86815181106132e7576132e7615550565b6020026020010151608001518d8f60800151888151811061330a5761330a615550565b60200260200101516040516133229493929190615d13565b60405180910390a3505b806133368161557f565b915050613007565b505050602083810151336000908152600b9092526040909120805460029061337b9084906201000090046bffffffffffffffffffffffff1661564d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508260400151601460000160008282829054906101000a90046bffffffffffffffffffffffff166133d9919061564d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508260400151836020015161341b919061564d565b6bffffffffffffffffffffffff16602160007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546134979190615672565b909155505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603613524576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016103f1565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e01000000000000000000000000000090049091166060820152906137965760008160600151856136329190615d50565b905060006136408583615d75565b90508083604001818151613654919061564d565b6bffffffffffffffffffffffff1690525061366f8582615da0565b83606001818151613680919061564d565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b60400151949350505050565b60006124f28373ffffffffffffffffffffffffffffffffffffffff841661423b565b600081815260018301602052604081205461380b575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556124f5565b5060006124f5565b6000818160045b600f8110156138a0577fff00000000000000000000000000000000000000000000000000000000000000821683826020811061385857613858615550565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461388e57506000949350505050565b806138988161557f565b91505061381a565b5081600f1a60018111156138b6576138b66159d9565b949350505050565b6000808080856060015160018111156138d9576138d96159d9565b036138ff576138eb888888888861432e565b6138fa576000925090506139d3565b613977565b600185606001516001811115613917576139176159d9565b0361394557600061392a898989886144b8565b925090508061393f57506000925090506139d3565b50613977565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84516060015163ffffffff1687106139cc57877fc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd5636876040516139b991906149a9565b60405180910390a26000925090506139d3565b6001925090505b9550959350505050565b601454600090819077010000000000000000000000000000000000000000000000900460ff1615613a3a576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16770100000000000000000000000000000000000000000000001790556040517f4585e33b0000000000000000000000000000000000000000000000000000000090613aaf9085906024016149a9565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d1690613b829087908790600401615dd0565b60408051808303816000875af1158015613ba0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bc49190615de9565b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16905590969095509350505050565b600081606001516001811115613c1057613c106159d9565b03613c7457600083815260046020526040902060010180547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff851602179055505050565b600181606001516001811115613c8c57613c8c6159d9565b03613cf85760c08101805160009081526008602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055915191517fa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f29190a25b505050565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613d6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d919190615e31565b50935050925050600082131580613da757508042105b80613dd757506000846040015162ffffff16118015613dd75750613dcb8142615cbd565b846040015162ffffff16105b15613de7575050601b5492915050565b5092915050565b604080516060810182526000808252602080830182815283850183905273ffffffffffffffffffffffffffffffffffffffff868116845260229092528483208054640100000000810462ffffff1690925263ffffffff8216855285517ffeaf968c00000000000000000000000000000000000000000000000000000000815295519495909484936701000000000000009093049092169163feaf968c9160048082019260a0929091908290030181865afa158015613eb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ed49190615e31565b50935050925050600082131580613eea57508042105b80613f1a57506000866040015162ffffff16118015613f1a5750613f0e8142615cbd565b866040015162ffffff16105b15613f2e5760018301546040850152613f36565b604084018290525b50505092915050565b604080516080810182526000808252602080830182905292820181905260608201529082015115613fb85760008381526023602090815260409182902082518084019093525463ffffffff811680845262ffffff640100000000909204821693830193845260e088018051919091529251925192169101525b6000613fc486866146c5565b60c0840151602082015182519293509091600091613fe19161564d565b905082600001516bffffffffffffffffffffffff16826bffffffffffffffffffffffff1610156140665781905061404787608001518860e0015160400151846bffffffffffffffffffffffff166140389190615ca6565b6140429190615cff565b6124fb565b6bffffffffffffffffffffffff166040840152600060608401526140f2565b806bffffffffffffffffffffffff16826bffffffffffffffffffffffff1610156140f2578190506140de83604001516bffffffffffffffffffffffff1688608001518960e0015160400151856bffffffffffffffffffffffff166140ca9190615ca6565b6140d49190615cff565b6140429190615cbd565b6bffffffffffffffffffffffff1660608401525b6000868152600460205260409020600101805482919060109061413890849070010000000000000000000000000000000090046bffffffffffffffffffffffff16615d50565b82546101009290920a6bffffffffffffffffffffffff818102199093169183160217909155600088815260046020526040812060010180549285169350916141939084906fffffffffffffffffffffffffffffffff16615e81565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff160217905550806bffffffffffffffffffffffff16602160008960c0015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461422a9190615cbd565b909155509298975050505050505050565b6000818152600183016020526040812054801561432457600061425f600183615cbd565b855490915060009061427390600190615cbd565b90508181146142d857600086600001828154811061429357614293615550565b90600052602060002001549050808760000184815481106142b6576142b6615550565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806142e9576142e9615eaa565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506124f5565b60009150506124f5565b600080848060200190518101906143459190615ed9565b845160e00151815191925063ffffffff908116911610156143a257867f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e88660405161439091906149a9565b60405180910390a260009150506144af565b8260e00151801561446257506020810151158015906144625750602081015161010084015182516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa15801561443b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061445f9190615343565b14155b806144745750805163ffffffff168611155b156144a957867f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc3018660405161439091906149a9565b60019150505b95945050505050565b6000806000848060200190518101906144d19190615f31565b905060008782600001518360200151846040015160405160200161453394939291909384526020840192909252604083015260e01b7fffffffff0000000000000000000000000000000000000000000000000000000016606082015260640190565b6040516020818303038152906040528051906020012090508460e00151801561460e575060808201511580159061460e5750608082015161010086015160608401516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa1580156145e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061460b9190615343565b14155b80614623575086826060015163ffffffff1610155b1561466d57877f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc3018760405161465891906149a9565b60405180910390a26000935091506146bc9050565b60008181526008602052604090205460ff16156146b457877f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e88760405161465891906149a9565b600193509150505b94509492505050565b6040805160808101825260008082526020820181905291810182905260608101919091526000836060015161ffff1683606001516147039190615ca6565b905082610100015180156147165750803a105b1561471e57503a5b60008360a0015184604001518560200151866000015161473e9190615672565b6147489085615ca6565b6147529190615672565b61475c9190615ca6565b90506147758460e0015160400151826140429190615cff565b6bffffffffffffffffffffffff1683526080840151614798906140429083615cff565b6bffffffffffffffffffffffff16604084015260e0840151602001516000906147cf9062ffffff16683635c9adc5dea00000615ca6565b9050600081633b9aca008760a001518860e001516000015163ffffffff1689604001518a60000151896148029190615ca6565b61480c9190615672565b6148169190615ca6565b6148209190615ca6565b61482a9190615cff565b6148349190615672565b905061484d8660e0015160400151826140429190615cff565b6bffffffffffffffffffffffff1660208601526080860151614873906140429083615cff565b6bffffffffffffffffffffffff1660608601525050505092915050565b50805460008255906000526020600020908101906118779190614930565b828054828255906000526020600020908101928215614928579160200282015b8281111561492857825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9091161782556020909201916001909101906148ce565b506125999291505b5b808211156125995760008155600101614931565b6000815180845260005b8181101561496b5760208185018101518683018201520161494f565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006124f26020830184614945565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610200810167ffffffffffffffff81118282101715614a0f57614a0f6149bc565b60405290565b60405160a0810167ffffffffffffffff81118282101715614a0f57614a0f6149bc565b60405160c0810167ffffffffffffffff81118282101715614a0f57614a0f6149bc565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614aa257614aa26149bc565b604052919050565b600067ffffffffffffffff821115614ac457614ac46149bc565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff8116811461187757600080fd5b8035614afb81614ace565b919050565b600082601f830112614b1157600080fd5b81356020614b26614b2183614aaa565b614a5b565b82815260059290921b84018101918181019086841115614b4557600080fd5b8286015b84811015614b69578035614b5c81614ace565b8352918301918301614b49565b509695505050505050565b803560ff81168114614afb57600080fd5b63ffffffff8116811461187757600080fd5b8035614afb81614b85565b801515811461187757600080fd5b8035614afb81614ba2565b62ffffff8116811461187757600080fd5b8035614afb81614bbb565b61ffff8116811461187757600080fd5b8035614afb81614bd7565b60006102008284031215614c0557600080fd5b614c0d6149eb565b9050614c1882614b97565b8152614c2660208301614b97565b6020820152614c3760408301614b97565b6040820152614c4860608301614af0565b6060820152614c5960808301614bb0565b6080820152614c6a60a08301614bcc565b60a0820152614c7b60c08301614b97565b60c0820152614c8c60e08301614b97565b60e0820152610100614c9f818401614af0565b90820152610120614cb1838201614be7565b90820152610140614cc3838201614af0565b90820152610160828101359082015261018080830135908201526101a080830135908201526101c08083013567ffffffffffffffff811115614d0457600080fd5b614d1085828601614b00565b8284015250506101e0614d24818401614af0565b9082015292915050565b803567ffffffffffffffff81168114614afb57600080fd5b600082601f830112614d5757600080fd5b813567ffffffffffffffff811115614d7157614d716149bc565b614da260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614a5b565b818152846020838601011115614db757600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f830112614de557600080fd5b81356020614df5614b2183614aaa565b82815260059290921b84018101918181019086841115614e1457600080fd5b8286015b84811015614b69578035614e2b81614ace565b8352918301918301614e18565b6bffffffffffffffffffffffff8116811461187757600080fd5b600082601f830112614e6357600080fd5b81356020614e73614b2183614aaa565b82815260a09283028501820192828201919087851115614e9257600080fd5b8387015b85811015614f115781818a031215614eae5760008081fd5b614eb6614a15565b8135614ec181614b85565b815281860135614ed081614bbb565b81870152604082810135614ee381614ace565b9082015260608281013590820152608080830135614f0081614e38565b908201528452928401928101614e96565b5090979650505050505050565b600080600080600080600080610100898b031215614f3b57600080fd5b883567ffffffffffffffff80821115614f5357600080fd5b614f5f8c838d01614b00565b995060208b0135915080821115614f7557600080fd5b614f818c838d01614b00565b9850614f8f60408c01614b74565b975060608b0135915080821115614fa557600080fd5b614fb18c838d01614bf2565b9650614fbf60808c01614d2e565b955060a08b0135915080821115614fd557600080fd5b614fe18c838d01614d46565b945060c08b0135915080821115614ff757600080fd5b6150038c838d01614dd4565b935060e08b013591508082111561501957600080fd5b506150268b828c01614e52565b9150509295985092959890939650565b6000806040838503121561504957600080fd5b82359150602083013561505b81614e38565b809150509250929050565b60008083601f84011261507857600080fd5b50813567ffffffffffffffff81111561509057600080fd5b6020830191508360208285010111156150a857600080fd5b9250929050565b600080600080606085870312156150c557600080fd5b84356150d081614ace565b935060208501359250604085013567ffffffffffffffff8111156150f357600080fd5b6150ff87828801615066565b95989497509550505050565b60008083601f84011261511d57600080fd5b50813567ffffffffffffffff81111561513557600080fd5b6020830191508360208260051b85010111156150a857600080fd5b60008060008060008060008060e0898b03121561516c57600080fd5b606089018a81111561517d57600080fd5b8998503567ffffffffffffffff8082111561519757600080fd5b6151a38c838d01615066565b909950975060808b01359150808211156151bc57600080fd5b6151c88c838d0161510b565b909750955060a08b01359150808211156151e157600080fd5b506151ee8b828c0161510b565b999c989b50969995989497949560c00135949350505050565b60008060008060008060c0878903121561522057600080fd5b863567ffffffffffffffff8082111561523857600080fd5b6152448a838b01614b00565b9750602089013591508082111561525a57600080fd5b6152668a838b01614b00565b965061527460408a01614b74565b9550606089013591508082111561528a57600080fd5b6152968a838b01614d46565b94506152a460808a01614d2e565b935060a08901359150808211156152ba57600080fd5b506152c789828a01614d46565b9150509295509295509295565b6000602082840312156152e657600080fd5b81356152f181614ace565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60ff8181168382160290811690818114613de757613de76152f8565b60006020828403121561535557600080fd5b5051919050565b63ffffffff818116838216019080821115613de757613de76152f8565b600081518084526020808501945080840160005b838110156153bf57815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161538d565b509495945050505050565b602081526153e160208201835163ffffffff169052565b600060208301516153fa604084018263ffffffff169052565b50604083015163ffffffff8116606084015250606083015173ffffffffffffffffffffffffffffffffffffffff8116608084015250608083015180151560a08401525060a083015162ffffff811660c08401525060c083015163ffffffff811660e08401525060e08301516101006154798185018363ffffffff169052565b84015190506101206154a28482018373ffffffffffffffffffffffffffffffffffffffff169052565b84015190506101406154b98482018361ffff169052565b84015190506101606154e28482018373ffffffffffffffffffffffffffffffffffffffff169052565b840151610180848101919091528401516101a0808501919091528401516101c0808501919091528401516102006101e08086018290529192509061552a610220860184615379565b95015173ffffffffffffffffffffffffffffffffffffffff169301929092525090919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036155b0576155b06152f8565b5060010190565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526155e78184018a615379565b905082810360808401526155fb8189615379565b905060ff871660a084015282810360c08401526156188187614945565b905067ffffffffffffffff851660e084015282810361010084015261563d8185614945565b9c9b505050505050505050505050565b6bffffffffffffffffffffffff818116838216019080821115613de757613de76152f8565b808201808211156124f5576124f56152f8565b8051614afb81614ba2565b6000602082840312156156a257600080fd5b81516152f181614ba2565b6000602082840312156156bf57600080fd5b5035919050565b60ff81811683821601908111156124f5576124f56152f8565b8051614afb81614b85565b8051614afb81614ace565b8051614afb81614bbb565b8051614afb81614bd7565b600082601f83011261571c57600080fd5b8151602061572c614b2183614aaa565b82815260059290921b8401810191818101908684111561574b57600080fd5b8286015b84811015614b6957805161576281614ace565b835291830191830161574f565b600082601f83011261578057600080fd5b81516020615790614b2183614aaa565b82815260a092830285018201928282019190878511156157af57600080fd5b8387015b85811015614f115781818a0312156157cb5760008081fd5b6157d3614a15565b81516157de81614b85565b8152818601516157ed81614bbb565b8187015260408281015161580081614ace565b908201526060828101519082015260808083015161581d81614e38565b9082015284529284019281016157b3565b60008060006060848603121561584357600080fd5b835167ffffffffffffffff8082111561585b57600080fd5b90850190610200828803121561587057600080fd5b6158786149eb565b615881836156df565b815261588f602084016156df565b60208201526158a0604084016156df565b60408201526158b1606084016156ea565b60608201526158c260808401615685565b60808201526158d360a084016156f5565b60a08201526158e460c084016156df565b60c08201526158f560e084016156df565b60e08201526101006159088185016156ea565b9082015261012061591a848201615700565b9082015261014061592c8482016156ea565b90820152610160838101519082015261018080840151908201526101a080840151908201526101c0808401518381111561596557600080fd5b6159718a82870161570b565b8284015250506101e06159858185016156ea565b9082015260208701519095509150808211156159a057600080fd5b6159ac8783880161570b565b935060408601519150808211156159c257600080fd5b506159cf8682870161576f565b9150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152615a4f8285018b615379565b91508382036080850152615a63828a615379565b915060ff881660a085015283820360c0850152615a808288614945565b90861660e0850152838103610100850152905061563d8185614945565b8183823760009101908152919050565b8281526080810160608360208401379392505050565b600082601f830112615ad457600080fd5b81356020615ae4614b2183614aaa565b82815260059290921b84018101918181019086841115615b0357600080fd5b8286015b84811015614b695780358352918301918301615b07565b600082601f830112615b2f57600080fd5b81356020615b3f614b2183614aaa565b82815260059290921b84018101918181019086841115615b5e57600080fd5b8286015b84811015614b6957803567ffffffffffffffff811115615b825760008081fd5b615b908986838b0101614d46565b845250918301918301615b62565b600060208284031215615bb057600080fd5b813567ffffffffffffffff80821115615bc857600080fd5b9083019060c08286031215615bdc57600080fd5b615be4614a38565b8235815260208301356020820152604083013582811115615c0457600080fd5b615c1087828601615ac3565b604083015250606083013582811115615c2857600080fd5b615c3487828601615ac3565b606083015250608083013582811115615c4c57600080fd5b615c5887828601615b1e565b60808301525060a083013582811115615c7057600080fd5b615c7c87828601615b1e565b60a08301525095945050505050565b61ffff818116838216019080821115613de757613de76152f8565b80820281158282048414176124f5576124f56152f8565b818103818111156124f5576124f56152f8565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082615d0e57615d0e615cd0565b500490565b6bffffffffffffffffffffffff85168152836020820152826040820152608060608201526000615d466080830184614945565b9695505050505050565b6bffffffffffffffffffffffff828116828216039080821115613de757613de76152f8565b60006bffffffffffffffffffffffff80841680615d9457615d94615cd0565b92169190910492915050565b6bffffffffffffffffffffffff818116838216028082169190828114615dc857615dc86152f8565b505092915050565b8281526040602082015260006138b66040830184614945565b60008060408385031215615dfc57600080fd5b8251615e0781614ba2565b6020939093015192949293505050565b805169ffffffffffffffffffff81168114614afb57600080fd5b600080600080600060a08688031215615e4957600080fd5b615e5286615e17565b9450602086015193506040860151925060608601519150615e7560808701615e17565b90509295509295909350565b6fffffffffffffffffffffffffffffffff818116838216019080821115613de757613de76152f8565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600060408284031215615eeb57600080fd5b6040516040810181811067ffffffffffffffff82111715615f0e57615f0e6149bc565b6040528251615f1c81614b85565b81526020928301519281019290925250919050565b600060a08284031215615f4357600080fd5b615f4b614a15565b82518152602083015160208201526040830151615f6781614b85565b60408201526060830151615f7a81614b85565b6060820152608092830151928101929092525091905056fea164736f6c6343000813000a", } var AutomationRegistryABI = AutomationRegistryMetaData.ABI @@ -339,6 +343,18 @@ func (_AutomationRegistry *AutomationRegistryTransactorSession) AcceptOwnership( return _AutomationRegistry.Contract.AcceptOwnership(&_AutomationRegistry.TransactOpts) } +func (_AutomationRegistry *AutomationRegistryTransactor) AddFunds(opts *bind.TransactOpts, id *big.Int, amount *big.Int) (*types.Transaction, error) { + return _AutomationRegistry.contract.Transact(opts, "addFunds", id, amount) +} + +func (_AutomationRegistry *AutomationRegistrySession) AddFunds(id *big.Int, amount *big.Int) (*types.Transaction, error) { + return _AutomationRegistry.Contract.AddFunds(&_AutomationRegistry.TransactOpts, id, amount) +} + +func (_AutomationRegistry *AutomationRegistryTransactorSession) AddFunds(id *big.Int, amount *big.Int) (*types.Transaction, error) { + return _AutomationRegistry.Contract.AddFunds(&_AutomationRegistry.TransactOpts, id, amount) +} + func (_AutomationRegistry *AutomationRegistryTransactor) OnTokenTransfer(opts *bind.TransactOpts, sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { return _AutomationRegistry.contract.Transact(opts, "onTokenTransfer", sender, amount, data) } @@ -375,18 +391,6 @@ func (_AutomationRegistry *AutomationRegistryTransactorSession) SetConfigTypeSaf return _AutomationRegistry.Contract.SetConfigTypeSafe(&_AutomationRegistry.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig, billingTokens, billingConfigs) } -func (_AutomationRegistry *AutomationRegistryTransactor) SimulatePerformUpkeep(opts *bind.TransactOpts, id *big.Int, performData []byte) (*types.Transaction, error) { - return _AutomationRegistry.contract.Transact(opts, "simulatePerformUpkeep", id, performData) -} - -func (_AutomationRegistry *AutomationRegistrySession) SimulatePerformUpkeep(id *big.Int, performData []byte) (*types.Transaction, error) { - return _AutomationRegistry.Contract.SimulatePerformUpkeep(&_AutomationRegistry.TransactOpts, id, performData) -} - -func (_AutomationRegistry *AutomationRegistryTransactorSession) SimulatePerformUpkeep(id *big.Int, performData []byte) (*types.Transaction, error) { - return _AutomationRegistry.Contract.SimulatePerformUpkeep(&_AutomationRegistry.TransactOpts, id, performData) -} - func (_AutomationRegistry *AutomationRegistryTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { return _AutomationRegistry.contract.Transact(opts, "transferOwnership", to) } @@ -551,6 +555,261 @@ func (_AutomationRegistry *AutomationRegistryFilterer) ParseAdminPrivilegeConfig return event, nil } +type AutomationRegistryBillingConfigOverriddenIterator struct { + Event *AutomationRegistryBillingConfigOverridden + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryBillingConfigOverriddenIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryBillingConfigOverridden) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryBillingConfigOverridden) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *AutomationRegistryBillingConfigOverriddenIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryBillingConfigOverriddenIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryBillingConfigOverridden struct { + Id *big.Int + Overrides AutomationRegistryBase23BillingOverrides + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterBillingConfigOverridden(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryBillingConfigOverriddenIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "BillingConfigOverridden", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryBillingConfigOverriddenIterator{contract: _AutomationRegistry.contract, event: "BillingConfigOverridden", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchBillingConfigOverridden(opts *bind.WatchOpts, sink chan<- *AutomationRegistryBillingConfigOverridden, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "BillingConfigOverridden", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryBillingConfigOverridden) + if err := _AutomationRegistry.contract.UnpackLog(event, "BillingConfigOverridden", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) ParseBillingConfigOverridden(log types.Log) (*AutomationRegistryBillingConfigOverridden, error) { + event := new(AutomationRegistryBillingConfigOverridden) + if err := _AutomationRegistry.contract.UnpackLog(event, "BillingConfigOverridden", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryBillingConfigOverrideRemovedIterator struct { + Event *AutomationRegistryBillingConfigOverrideRemoved + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryBillingConfigOverrideRemovedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryBillingConfigOverrideRemoved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryBillingConfigOverrideRemoved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *AutomationRegistryBillingConfigOverrideRemovedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryBillingConfigOverrideRemovedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryBillingConfigOverrideRemoved struct { + Id *big.Int + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterBillingConfigOverrideRemoved(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryBillingConfigOverrideRemovedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "BillingConfigOverrideRemoved", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryBillingConfigOverrideRemovedIterator{contract: _AutomationRegistry.contract, event: "BillingConfigOverrideRemoved", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchBillingConfigOverrideRemoved(opts *bind.WatchOpts, sink chan<- *AutomationRegistryBillingConfigOverrideRemoved, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "BillingConfigOverrideRemoved", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryBillingConfigOverrideRemoved) + if err := _AutomationRegistry.contract.UnpackLog(event, "BillingConfigOverrideRemoved", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) ParseBillingConfigOverrideRemoved(log types.Log) (*AutomationRegistryBillingConfigOverrideRemoved, error) { + event := new(AutomationRegistryBillingConfigOverrideRemoved) + if err := _AutomationRegistry.contract.UnpackLog(event, "BillingConfigOverrideRemoved", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + type AutomationRegistryBillingConfigSetIterator struct { Event *AutomationRegistryBillingConfigSet @@ -1237,42 +1496,42 @@ func (it *AutomationRegistryFeesWithdrawnIterator) Close() error { } type AutomationRegistryFeesWithdrawn struct { - Recipient common.Address AssetAddress common.Address + Recipient common.Address Amount *big.Int Raw types.Log } -func (_AutomationRegistry *AutomationRegistryFilterer) FilterFeesWithdrawn(opts *bind.FilterOpts, recipient []common.Address, assetAddress []common.Address) (*AutomationRegistryFeesWithdrawnIterator, error) { +func (_AutomationRegistry *AutomationRegistryFilterer) FilterFeesWithdrawn(opts *bind.FilterOpts, assetAddress []common.Address, recipient []common.Address) (*AutomationRegistryFeesWithdrawnIterator, error) { - var recipientRule []interface{} - for _, recipientItem := range recipient { - recipientRule = append(recipientRule, recipientItem) - } var assetAddressRule []interface{} for _, assetAddressItem := range assetAddress { assetAddressRule = append(assetAddressRule, assetAddressItem) } + var recipientRule []interface{} + for _, recipientItem := range recipient { + recipientRule = append(recipientRule, recipientItem) + } - logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "FeesWithdrawn", recipientRule, assetAddressRule) + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "FeesWithdrawn", assetAddressRule, recipientRule) if err != nil { return nil, err } return &AutomationRegistryFeesWithdrawnIterator{contract: _AutomationRegistry.contract, event: "FeesWithdrawn", logs: logs, sub: sub}, nil } -func (_AutomationRegistry *AutomationRegistryFilterer) WatchFeesWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryFeesWithdrawn, recipient []common.Address, assetAddress []common.Address) (event.Subscription, error) { +func (_AutomationRegistry *AutomationRegistryFilterer) WatchFeesWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryFeesWithdrawn, assetAddress []common.Address, recipient []common.Address) (event.Subscription, error) { - var recipientRule []interface{} - for _, recipientItem := range recipient { - recipientRule = append(recipientRule, recipientItem) - } var assetAddressRule []interface{} for _, assetAddressItem := range assetAddress { assetAddressRule = append(assetAddressRule, assetAddressItem) } + var recipientRule []interface{} + for _, recipientItem := range recipient { + recipientRule = append(recipientRule, recipientItem) + } - logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "FeesWithdrawn", recipientRule, assetAddressRule) + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "FeesWithdrawn", assetAddressRule, recipientRule) if err != nil { return nil, err } @@ -1707,6 +1966,124 @@ func (_AutomationRegistry *AutomationRegistryFilterer) ParseInsufficientFundsUpk return event, nil } +type AutomationRegistryNOPsSettledOffchainIterator struct { + Event *AutomationRegistryNOPsSettledOffchain + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryNOPsSettledOffchainIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryNOPsSettledOffchain) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryNOPsSettledOffchain) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *AutomationRegistryNOPsSettledOffchainIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryNOPsSettledOffchainIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryNOPsSettledOffchain struct { + Payees []common.Address + Payments []*big.Int + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterNOPsSettledOffchain(opts *bind.FilterOpts) (*AutomationRegistryNOPsSettledOffchainIterator, error) { + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "NOPsSettledOffchain") + if err != nil { + return nil, err + } + return &AutomationRegistryNOPsSettledOffchainIterator{contract: _AutomationRegistry.contract, event: "NOPsSettledOffchain", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchNOPsSettledOffchain(opts *bind.WatchOpts, sink chan<- *AutomationRegistryNOPsSettledOffchain) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "NOPsSettledOffchain") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryNOPsSettledOffchain) + if err := _AutomationRegistry.contract.UnpackLog(event, "NOPsSettledOffchain", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) ParseNOPsSettledOffchain(log types.Log) (*AutomationRegistryNOPsSettledOffchain, error) { + event := new(AutomationRegistryNOPsSettledOffchain) + if err := _AutomationRegistry.contract.UnpackLog(event, "NOPsSettledOffchain", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + type AutomationRegistryOwnershipTransferRequestedIterator struct { Event *AutomationRegistryOwnershipTransferRequested @@ -5003,6 +5380,10 @@ func (_AutomationRegistry *AutomationRegistry) ParseLog(log types.Log) (generate switch log.Topics[0] { case _AutomationRegistry.abi.Events["AdminPrivilegeConfigSet"].ID: return _AutomationRegistry.ParseAdminPrivilegeConfigSet(log) + case _AutomationRegistry.abi.Events["BillingConfigOverridden"].ID: + return _AutomationRegistry.ParseBillingConfigOverridden(log) + case _AutomationRegistry.abi.Events["BillingConfigOverrideRemoved"].ID: + return _AutomationRegistry.ParseBillingConfigOverrideRemoved(log) case _AutomationRegistry.abi.Events["BillingConfigSet"].ID: return _AutomationRegistry.ParseBillingConfigSet(log) case _AutomationRegistry.abi.Events["CancelledUpkeepReport"].ID: @@ -5021,6 +5402,8 @@ func (_AutomationRegistry *AutomationRegistry) ParseLog(log types.Log) (generate return _AutomationRegistry.ParseFundsWithdrawn(log) case _AutomationRegistry.abi.Events["InsufficientFundsUpkeepReport"].ID: return _AutomationRegistry.ParseInsufficientFundsUpkeepReport(log) + case _AutomationRegistry.abi.Events["NOPsSettledOffchain"].ID: + return _AutomationRegistry.ParseNOPsSettledOffchain(log) case _AutomationRegistry.abi.Events["OwnershipTransferRequested"].ID: return _AutomationRegistry.ParseOwnershipTransferRequested(log) case _AutomationRegistry.abi.Events["OwnershipTransferred"].ID: @@ -5081,8 +5464,16 @@ func (AutomationRegistryAdminPrivilegeConfigSet) Topic() common.Hash { return common.HexToHash("0x7c44b4eb59ee7873514e7e43e7718c269d872965938b288aa143befca62f99d2") } +func (AutomationRegistryBillingConfigOverridden) Topic() common.Hash { + return common.HexToHash("0xd8a6d79d170a55968079d3a89b960d86b4442aef6aac1d01e644c32b9e38b340") +} + +func (AutomationRegistryBillingConfigOverrideRemoved) Topic() common.Hash { + return common.HexToHash("0x97d0ef3f46a56168af653f547bdb6f77ec2b1d7d9bc6ba0193c2b340ec68064a") +} + func (AutomationRegistryBillingConfigSet) Topic() common.Hash { - return common.HexToHash("0x5ff767a3a5dbf1ef088ebf56e221e9cea40ad357c31ba060c2f31244cefab7c1") + return common.HexToHash("0x720a5849025dc4fd0061aed1bb30efd713cde64ce7f8d807953ecca27c8f143c") } func (AutomationRegistryCancelledUpkeepReport) Topic() common.Hash { @@ -5117,6 +5508,10 @@ func (AutomationRegistryInsufficientFundsUpkeepReport) Topic() common.Hash { return common.HexToHash("0x377c8b0c126ae5248d27aca1c76fac4608aff85673ee3caf09747e1044549e02") } +func (AutomationRegistryNOPsSettledOffchain) Topic() common.Hash { + return common.HexToHash("0x5af23b715253628d12b660b27a4f3fc626562ea8a55040aa99ab3dc178989fad") +} + func (AutomationRegistryOwnershipTransferRequested) Topic() common.Hash { return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") } @@ -5238,14 +5633,14 @@ type AutomationRegistryInterface interface { AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) + AddFunds(opts *bind.TransactOpts, id *big.Int, amount *big.Int) (*types.Transaction, error) + OnTokenTransfer(opts *bind.TransactOpts, sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) SetConfig(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfigBytes []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) SetConfigTypeSafe(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig AutomationRegistryBase23OnchainConfig, offchainConfigVersion uint64, offchainConfig []byte, billingTokens []common.Address, billingConfigs []AutomationRegistryBase23BillingConfig) (*types.Transaction, error) - SimulatePerformUpkeep(opts *bind.TransactOpts, id *big.Int, performData []byte) (*types.Transaction, error) - TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, rawReport []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) @@ -5258,6 +5653,18 @@ type AutomationRegistryInterface interface { ParseAdminPrivilegeConfigSet(log types.Log) (*AutomationRegistryAdminPrivilegeConfigSet, error) + FilterBillingConfigOverridden(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryBillingConfigOverriddenIterator, error) + + WatchBillingConfigOverridden(opts *bind.WatchOpts, sink chan<- *AutomationRegistryBillingConfigOverridden, id []*big.Int) (event.Subscription, error) + + ParseBillingConfigOverridden(log types.Log) (*AutomationRegistryBillingConfigOverridden, error) + + FilterBillingConfigOverrideRemoved(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryBillingConfigOverrideRemovedIterator, error) + + WatchBillingConfigOverrideRemoved(opts *bind.WatchOpts, sink chan<- *AutomationRegistryBillingConfigOverrideRemoved, id []*big.Int) (event.Subscription, error) + + ParseBillingConfigOverrideRemoved(log types.Log) (*AutomationRegistryBillingConfigOverrideRemoved, error) + FilterBillingConfigSet(opts *bind.FilterOpts, token []common.Address) (*AutomationRegistryBillingConfigSetIterator, error) WatchBillingConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryBillingConfigSet, token []common.Address) (event.Subscription, error) @@ -5288,9 +5695,9 @@ type AutomationRegistryInterface interface { ParseDedupKeyAdded(log types.Log) (*AutomationRegistryDedupKeyAdded, error) - FilterFeesWithdrawn(opts *bind.FilterOpts, recipient []common.Address, assetAddress []common.Address) (*AutomationRegistryFeesWithdrawnIterator, error) + FilterFeesWithdrawn(opts *bind.FilterOpts, assetAddress []common.Address, recipient []common.Address) (*AutomationRegistryFeesWithdrawnIterator, error) - WatchFeesWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryFeesWithdrawn, recipient []common.Address, assetAddress []common.Address) (event.Subscription, error) + WatchFeesWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryFeesWithdrawn, assetAddress []common.Address, recipient []common.Address) (event.Subscription, error) ParseFeesWithdrawn(log types.Log) (*AutomationRegistryFeesWithdrawn, error) @@ -5312,6 +5719,12 @@ type AutomationRegistryInterface interface { ParseInsufficientFundsUpkeepReport(log types.Log) (*AutomationRegistryInsufficientFundsUpkeepReport, error) + FilterNOPsSettledOffchain(opts *bind.FilterOpts) (*AutomationRegistryNOPsSettledOffchainIterator, error) + + WatchNOPsSettledOffchain(opts *bind.WatchOpts, sink chan<- *AutomationRegistryNOPsSettledOffchain) (event.Subscription, error) + + ParseNOPsSettledOffchain(log types.Log) (*AutomationRegistryNOPsSettledOffchain, error) + FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryOwnershipTransferRequestedIterator, error) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) diff --git a/core/gethwrappers/generated/automation_utils_2_3/automation_utils_2_3.go b/core/gethwrappers/generated/automation_utils_2_3/automation_utils_2_3.go index 91e36381ba7..aafaf3f2657 100644 --- a/core/gethwrappers/generated/automation_utils_2_3/automation_utils_2_3.go +++ b/core/gethwrappers/generated/automation_utils_2_3/automation_utils_2_3.go @@ -28,47 +28,6 @@ var ( _ = abi.ConvertType ) -type AutomationRegistryBase23BillingConfig struct { - GasFeePPB uint32 - FlatFeeMicroLink *big.Int - PriceFeed common.Address -} - -type AutomationRegistryBase23ConditionalTrigger struct { - BlockNum uint32 - BlockHash [32]byte -} - -type AutomationRegistryBase23LogTrigger struct { - LogBlockHash [32]byte - TxHash [32]byte - LogIndex uint32 - BlockNum uint32 - BlockHash [32]byte -} - -type AutomationRegistryBase23OnchainConfig struct { - PaymentPremiumPPB uint32 - FlatFeeMicroLink uint32 - CheckGasLimit uint32 - StalenessSeconds *big.Int - GasCeilingMultiplier uint16 - MinUpkeepSpend *big.Int - MaxPerformGas uint32 - MaxCheckDataSize uint32 - MaxPerformDataSize uint32 - MaxRevertDataSize uint32 - FallbackGasPrice *big.Int - FallbackLinkPrice *big.Int - FallbackNativePrice *big.Int - Transcoder common.Address - Registrars []common.Address - UpkeepPrivilegeManager common.Address - ChainModule common.Address - ReorgProtectionEnabled bool - FinanceAdmin common.Address -} - type AutomationRegistryBase23Report struct { FastGasWei *big.Int LinkUSD *big.Int @@ -78,29 +37,9 @@ type AutomationRegistryBase23Report struct { PerformDatas [][]byte } -type Log struct { - Index *big.Int - Timestamp *big.Int - TxHash [32]byte - BlockNumber *big.Int - BlockHash [32]byte - Source common.Address - Topics [][32]byte - Data []byte -} - -type LogTriggerConfig struct { - ContractAddress common.Address - FilterSelector uint8 - Topic0 [32]byte - Topic1 [32]byte - Topic2 [32]byte - Topic3 [32]byte -} - var AutomationUtilsMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"blockNum\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"internalType\":\"structAutomationRegistryBase2_3.ConditionalTrigger\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_conditionalTrigger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"txHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"source\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"topics\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structLog\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_log\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"logBlockHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"txHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"logIndex\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNum\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"internalType\":\"structAutomationRegistryBase2_3.LogTrigger\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_logTrigger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"contractAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"filterSelector\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"topic0\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic1\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic2\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic3\",\"type\":\"bytes32\"}],\"internalType\":\"structLogTriggerConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_logTriggerConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackNativePrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"},{\"internalType\":\"contractIChainModule\",\"name\":\"chainModule\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"financeAdmin\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.OnchainConfig\",\"name\":\"\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint24\"},{\"internalType\":\"address\",\"name\":\"priceFeed\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"name\":\"_onChainConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkUSD\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"gasLimits\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes[]\",\"name\":\"triggers\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes[]\",\"name\":\"performDatas\",\"type\":\"bytes[]\"}],\"internalType\":\"structAutomationRegistryBase2_3.Report\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_report\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b50610a22806100206000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c8063dc94dc5c11610050578063dc94dc5c146100a6578063e65d6546146100b9578063e9720a49146100c757600080fd5b806321f373d7146100775780634b6df2941461008a578063776f306114610098575b600080fd5b610088610085366004610219565b50565b005b6100886100853660046102a1565b6100886100853660046102f8565b6100886100b436600461050a565b505050565b610088610085366004610853565b610088610085366004610940565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715610127576101276100d5565b60405290565b6040516060810167ffffffffffffffff81118282101715610127576101276100d5565b604051610260810167ffffffffffffffff81118282101715610127576101276100d5565b604051610100810167ffffffffffffffff81118282101715610127576101276100d5565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156101df576101df6100d5565b604052919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461008557600080fd5b8035610214816101e7565b919050565b600060c0828403121561022b57600080fd5b610233610104565b823561023e816101e7565b8152602083013560ff8116811461025457600080fd5b8060208301525060408301356040820152606083013560608201526080830135608082015260a083013560a08201528091505092915050565b803563ffffffff8116811461021457600080fd5b6000604082840312156102b357600080fd5b6040516040810181811067ffffffffffffffff821117156102d6576102d66100d5565b6040526102e28361028d565b8152602083013560208201528091505092915050565b600060a0828403121561030a57600080fd5b60405160a0810181811067ffffffffffffffff8211171561032d5761032d6100d5565b8060405250823581526020830135602082015261034c6040840161028d565b604082015261035d6060840161028d565b6060820152608083013560808201528091505092915050565b803562ffffff8116811461021457600080fd5b803561ffff8116811461021457600080fd5b80356bffffffffffffffffffffffff8116811461021457600080fd5b600067ffffffffffffffff8211156103d1576103d16100d5565b5060051b60200190565b600082601f8301126103ec57600080fd5b813560206104016103fc836103b7565b610198565b82815260059290921b8401810191818101908684111561042057600080fd5b8286015b84811015610444578035610437816101e7565b8352918301918301610424565b509695505050505050565b8035801515811461021457600080fd5b600082601f83011261047057600080fd5b813560206104806103fc836103b7565b8281526060928302850182019282820191908785111561049f57600080fd5b8387015b858110156104fd5781818a0312156104bb5760008081fd5b6104c361012d565b6104cc8261028d565b81526104d9868301610376565b868201526040808301356104ec816101e7565b9082015284529284019281016104a3565b5090979650505050505050565b60008060006060848603121561051f57600080fd5b833567ffffffffffffffff8082111561053757600080fd5b90850190610260828803121561054c57600080fd5b610554610150565b61055d8361028d565b815261056b6020840161028d565b602082015261057c6040840161028d565b604082015261058d60608401610376565b606082015261059e60808401610389565b60808201526105af60a0840161039b565b60a08201526105c060c0840161028d565b60c08201526105d160e0840161028d565b60e08201526101006105e481850161028d565b908201526101206105f684820161028d565b908201526101408381013590820152610160808401359082015261018080840135908201526101a0610629818501610209565b908201526101c0838101358381111561064157600080fd5b61064d8a8287016103db565b8284015250506101e0610661818501610209565b90820152610200610673848201610209565b9082015261022061068584820161044f565b90820152610240610697848201610209565b90820152945060208601359150808211156106b157600080fd5b6106bd878388016103db565b935060408601359150808211156106d357600080fd5b506106e08682870161045f565b9150509250925092565b600082601f8301126106fb57600080fd5b8135602061070b6103fc836103b7565b82815260059290921b8401810191818101908684111561072a57600080fd5b8286015b84811015610444578035835291830191830161072e565b600082601f83011261075657600080fd5b813567ffffffffffffffff811115610770576107706100d5565b6107a160207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601610198565b8181528460208386010111156107b657600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f8301126107e457600080fd5b813560206107f46103fc836103b7565b82815260059290921b8401810191818101908684111561081357600080fd5b8286015b8481101561044457803567ffffffffffffffff8111156108375760008081fd5b6108458986838b0101610745565b845250918301918301610817565b60006020828403121561086557600080fd5b813567ffffffffffffffff8082111561087d57600080fd5b9083019060c0828603121561089157600080fd5b610899610104565b82358152602083013560208201526040830135828111156108b957600080fd5b6108c5878286016106ea565b6040830152506060830135828111156108dd57600080fd5b6108e9878286016106ea565b60608301525060808301358281111561090157600080fd5b61090d878286016107d3565b60808301525060a08301358281111561092557600080fd5b610931878286016107d3565b60a08301525095945050505050565b60006020828403121561095257600080fd5b813567ffffffffffffffff8082111561096a57600080fd5b90830190610100828603121561097f57600080fd5b610987610174565b82358152602083013560208201526040830135604082015260608301356060820152608083013560808201526109bf60a08401610209565b60a082015260c0830135828111156109d657600080fd5b6109e2878286016106ea565b60c08301525060e0830135828111156109fa57600080fd5b610a0687828601610745565b60e0830152509594505050505056fea164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkUSD\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"gasLimits\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes[]\",\"name\":\"triggers\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes[]\",\"name\":\"performDatas\",\"type\":\"bytes[]\"}],\"internalType\":\"structAutomationRegistryBase2_3.Report\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_report\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b50610375806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063e65d654614610030575b600080fd5b61004161003e36600461027b565b50565b005b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff8111828210171561009557610095610043565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156100e2576100e2610043565b604052919050565b600067ffffffffffffffff82111561010457610104610043565b5060051b60200190565b600082601f83011261011f57600080fd5b8135602061013461012f836100ea565b61009b565b82815260059290921b8401810191818101908684111561015357600080fd5b8286015b8481101561016e5780358352918301918301610157565b509695505050505050565b6000601f838184011261018b57600080fd5b8235602061019b61012f836100ea565b82815260059290921b850181019181810190878411156101ba57600080fd5b8287015b8481101561026f57803567ffffffffffffffff808211156101df5760008081fd5b818a0191508a603f8301126101f45760008081fd5b8582013560408282111561020a5761020a610043565b610239887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08c8501160161009b565b92508183528c818386010111156102505760008081fd5b81818501898501375060009082018701528452509183019183016101be565b50979650505050505050565b60006020828403121561028d57600080fd5b813567ffffffffffffffff808211156102a557600080fd5b9083019060c082860312156102b957600080fd5b6102c1610072565b82358152602083013560208201526040830135828111156102e157600080fd5b6102ed8782860161010e565b60408301525060608301358281111561030557600080fd5b6103118782860161010e565b60608301525060808301358281111561032957600080fd5b61033587828601610179565b60808301525060a08301358281111561034d57600080fd5b61035987828601610179565b60a0830152509594505050505056fea164736f6c6343000813000a", } var AutomationUtilsABI = AutomationUtilsMetaData.ABI @@ -239,66 +178,6 @@ func (_AutomationUtils *AutomationUtilsTransactorRaw) Transact(opts *bind.Transa return _AutomationUtils.Contract.contract.Transact(opts, method, params...) } -func (_AutomationUtils *AutomationUtilsTransactor) ConditionalTrigger(opts *bind.TransactOpts, arg0 AutomationRegistryBase23ConditionalTrigger) (*types.Transaction, error) { - return _AutomationUtils.contract.Transact(opts, "_conditionalTrigger", arg0) -} - -func (_AutomationUtils *AutomationUtilsSession) ConditionalTrigger(arg0 AutomationRegistryBase23ConditionalTrigger) (*types.Transaction, error) { - return _AutomationUtils.Contract.ConditionalTrigger(&_AutomationUtils.TransactOpts, arg0) -} - -func (_AutomationUtils *AutomationUtilsTransactorSession) ConditionalTrigger(arg0 AutomationRegistryBase23ConditionalTrigger) (*types.Transaction, error) { - return _AutomationUtils.Contract.ConditionalTrigger(&_AutomationUtils.TransactOpts, arg0) -} - -func (_AutomationUtils *AutomationUtilsTransactor) Log(opts *bind.TransactOpts, arg0 Log) (*types.Transaction, error) { - return _AutomationUtils.contract.Transact(opts, "_log", arg0) -} - -func (_AutomationUtils *AutomationUtilsSession) Log(arg0 Log) (*types.Transaction, error) { - return _AutomationUtils.Contract.Log(&_AutomationUtils.TransactOpts, arg0) -} - -func (_AutomationUtils *AutomationUtilsTransactorSession) Log(arg0 Log) (*types.Transaction, error) { - return _AutomationUtils.Contract.Log(&_AutomationUtils.TransactOpts, arg0) -} - -func (_AutomationUtils *AutomationUtilsTransactor) LogTrigger(opts *bind.TransactOpts, arg0 AutomationRegistryBase23LogTrigger) (*types.Transaction, error) { - return _AutomationUtils.contract.Transact(opts, "_logTrigger", arg0) -} - -func (_AutomationUtils *AutomationUtilsSession) LogTrigger(arg0 AutomationRegistryBase23LogTrigger) (*types.Transaction, error) { - return _AutomationUtils.Contract.LogTrigger(&_AutomationUtils.TransactOpts, arg0) -} - -func (_AutomationUtils *AutomationUtilsTransactorSession) LogTrigger(arg0 AutomationRegistryBase23LogTrigger) (*types.Transaction, error) { - return _AutomationUtils.Contract.LogTrigger(&_AutomationUtils.TransactOpts, arg0) -} - -func (_AutomationUtils *AutomationUtilsTransactor) LogTriggerConfig(opts *bind.TransactOpts, arg0 LogTriggerConfig) (*types.Transaction, error) { - return _AutomationUtils.contract.Transact(opts, "_logTriggerConfig", arg0) -} - -func (_AutomationUtils *AutomationUtilsSession) LogTriggerConfig(arg0 LogTriggerConfig) (*types.Transaction, error) { - return _AutomationUtils.Contract.LogTriggerConfig(&_AutomationUtils.TransactOpts, arg0) -} - -func (_AutomationUtils *AutomationUtilsTransactorSession) LogTriggerConfig(arg0 LogTriggerConfig) (*types.Transaction, error) { - return _AutomationUtils.Contract.LogTriggerConfig(&_AutomationUtils.TransactOpts, arg0) -} - -func (_AutomationUtils *AutomationUtilsTransactor) OnChainConfig(opts *bind.TransactOpts, arg0 AutomationRegistryBase23OnchainConfig, arg1 []common.Address, arg2 []AutomationRegistryBase23BillingConfig) (*types.Transaction, error) { - return _AutomationUtils.contract.Transact(opts, "_onChainConfig", arg0, arg1, arg2) -} - -func (_AutomationUtils *AutomationUtilsSession) OnChainConfig(arg0 AutomationRegistryBase23OnchainConfig, arg1 []common.Address, arg2 []AutomationRegistryBase23BillingConfig) (*types.Transaction, error) { - return _AutomationUtils.Contract.OnChainConfig(&_AutomationUtils.TransactOpts, arg0, arg1, arg2) -} - -func (_AutomationUtils *AutomationUtilsTransactorSession) OnChainConfig(arg0 AutomationRegistryBase23OnchainConfig, arg1 []common.Address, arg2 []AutomationRegistryBase23BillingConfig) (*types.Transaction, error) { - return _AutomationUtils.Contract.OnChainConfig(&_AutomationUtils.TransactOpts, arg0, arg1, arg2) -} - func (_AutomationUtils *AutomationUtilsTransactor) Report(opts *bind.TransactOpts, arg0 AutomationRegistryBase23Report) (*types.Transaction, error) { return _AutomationUtils.contract.Transact(opts, "_report", arg0) } @@ -316,16 +195,6 @@ func (_AutomationUtils *AutomationUtils) Address() common.Address { } type AutomationUtilsInterface interface { - ConditionalTrigger(opts *bind.TransactOpts, arg0 AutomationRegistryBase23ConditionalTrigger) (*types.Transaction, error) - - Log(opts *bind.TransactOpts, arg0 Log) (*types.Transaction, error) - - LogTrigger(opts *bind.TransactOpts, arg0 AutomationRegistryBase23LogTrigger) (*types.Transaction, error) - - LogTriggerConfig(opts *bind.TransactOpts, arg0 LogTriggerConfig) (*types.Transaction, error) - - OnChainConfig(opts *bind.TransactOpts, arg0 AutomationRegistryBase23OnchainConfig, arg1 []common.Address, arg2 []AutomationRegistryBase23BillingConfig) (*types.Transaction, error) - Report(opts *bind.TransactOpts, arg0 AutomationRegistryBase23Report) (*types.Transaction, error) Address() common.Address diff --git a/core/gethwrappers/generated/batch_blockhash_store/batch_blockhash_store.go b/core/gethwrappers/generated/batch_blockhash_store/batch_blockhash_store.go index 1a43287d748..cd072e4e103 100644 --- a/core/gethwrappers/generated/batch_blockhash_store/batch_blockhash_store.go +++ b/core/gethwrappers/generated/batch_blockhash_store/batch_blockhash_store.go @@ -30,7 +30,7 @@ var ( var BatchBlockhashStoreMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"blockhashStoreAddr\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"BHS\",\"outputs\":[{\"internalType\":\"contractBlockhashStore\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"blockNumbers\",\"type\":\"uint256[]\"}],\"name\":\"getBlockhashes\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"blockNumbers\",\"type\":\"uint256[]\"}],\"name\":\"store\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"blockNumbers\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes[]\",\"name\":\"headers\",\"type\":\"bytes[]\"}],\"name\":\"storeVerifyHeader\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a060405234801561001057600080fd5b50604051610b9b380380610b9b83398101604081905261002f91610044565b60601b6001600160601b031916608052610074565b60006020828403121561005657600080fd5b81516001600160a01b038116811461006d57600080fd5b9392505050565b60805160601c610af56100a66000396000818160a7015281816101270152818161023a01526104290152610af56000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806306bd010d146100515780631f600f86146100665780635d290e211461008f578063f745eafb146100a2575b600080fd5b61006461005f36600461066e565b6100ee565b005b61007961007436600461066e565b6101e2565b6040516100869190610819565b60405180910390f35b61006461009d3660046106ab565b6103ac565b6100c97f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610086565b60005b81518110156101de5761011c82828151811061010f5761010f6109c6565b60200260200101516104fe565b610125576101cc565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16636057361d838381518110610173576101736109c6565b60200260200101516040518263ffffffff1660e01b815260040161019991815260200190565b600060405180830381600087803b1580156101b357600080fd5b505af11580156101c7573d6000803e3d6000fd5b505050505b806101d68161095e565b9150506100f1565b5050565b60606000825167ffffffffffffffff811115610200576102006109f5565b604051908082528060200260200182016040528015610229578160200160208202803683370190505b50905060005b83518110156103a5577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663e9413d38858381518110610286576102866109c6565b60200260200101516040518263ffffffff1660e01b81526004016102ac91815260200190565b60206040518083038186803b1580156102c457600080fd5b505afa925050508015610312575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261030f91810190610800565b60015b6103725761031e610a24565b806308c379a014156103665750610333610a40565b8061033e5750610368565b6000801b838381518110610354576103546109c6565b60200260200101818152505050610393565b505b3d6000803e3d6000fd5b80838381518110610385576103856109c6565b602002602001018181525050505b8061039d8161095e565b91505061022f565b5092915050565b805182511461041b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f696e70757420617272617920617267206c656e67746873206d69736d61746368604482015260640160405180910390fd5b60005b82518110156104f9577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663fadff0e1848381518110610475576104756109c6565b602002602001015184848151811061048f5761048f6109c6565b60200260200101516040518363ffffffff1660e01b81526004016104b492919061085d565b600060405180830381600087803b1580156104ce57600080fd5b505af11580156104e2573d6000803e3d6000fd5b5050505080806104f19061095e565b91505061041e565b505050565b600061010061050b610537565b111561052e5761010061051c610537565b61052691906108fc565b821015610531565b60015b92915050565b600046610543816105d4565b156105cd57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561058f57600080fd5b505afa1580156105a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c79190610800565b91505090565b4391505090565b600061a4b18214806105e8575062066eed82145b8061053157505062066eee1490565b600082601f83011261060857600080fd5b81356020610615826108d8565b6040516106228282610913565b8381528281019150858301600585901b8701840188101561064257600080fd5b60005b8581101561066157813584529284019290840190600101610645565b5090979650505050505050565b60006020828403121561068057600080fd5b813567ffffffffffffffff81111561069757600080fd5b6106a3848285016105f7565b949350505050565b60008060408084860312156106bf57600080fd5b833567ffffffffffffffff808211156106d757600080fd5b6106e3878388016105f7565b94506020915081860135818111156106fa57600080fd5b8601601f8101881361070b57600080fd5b8035610716816108d8565b85516107228282610913565b8281528581019150838601600584901b850187018c101561074257600080fd5b60005b848110156107ee5781358781111561075c57600080fd5b8601603f81018e1361076d57600080fd5b8881013588811115610781576107816109f5565b8a516107b48b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160182610913565b8181528f8c8385010111156107c857600080fd5b818c84018c83013760009181018b01919091528552509287019290870190600101610745565b50989b909a5098505050505050505050565b60006020828403121561081257600080fd5b5051919050565b6020808252825182820181905260009190848201906040850190845b8181101561085157835183529284019291840191600101610835565b50909695505050505050565b82815260006020604081840152835180604085015260005b8181101561089157858101830151858201606001528201610875565b818111156108a3576000606083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201606001949350505050565b600067ffffffffffffffff8211156108f2576108f26109f5565b5060051b60200190565b60008282101561090e5761090e610997565b500390565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116810181811067ffffffffffffffff82111715610957576109576109f5565b6040525050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561099057610990610997565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060033d1115610a3d5760046000803e5060005160e01c5b90565b600060443d1015610a4e5790565b6040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc803d016004833e81513d67ffffffffffffffff8160248401118184111715610a9c57505050505090565b8285019150815181811115610ab45750505050505090565b843d8701016020828501011115610ace5750505050505090565b610add60208286010187610913565b50909594505050505056fea164736f6c6343000806000a", + Bin: "0x60a060405234801561001057600080fd5b50604051610b5f380380610b5f83398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b608051610ac061009f6000396000818160a7015281816101230152818161023601526104150152610ac06000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806306bd010d146100515780631f600f86146100665780635d290e211461008f578063f745eafb146100a2575b600080fd5b61006461005f3660046106e3565b6100ee565b005b6100796100743660046106e3565b6101de565b6040516100869190610720565b60405180910390f35b61006461009d366004610764565b610398565b6100c97f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610086565b60005b81518110156101da5761011c82828151811061010f5761010f6108b9565b60200260200101516104ea565b156101c8577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16636057361d83838151811061016f5761016f6108b9565b60200260200101516040518263ffffffff1660e01b815260040161019591815260200190565b600060405180830381600087803b1580156101af57600080fd5b505af11580156101c3573d6000803e3d6000fd5b505050505b806101d281610917565b9150506100f1565b5050565b60606000825167ffffffffffffffff8111156101fc576101fc6105d4565b604051908082528060200260200182016040528015610225578160200160208202803683370190505b50905060005b8351811015610391577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663e9413d38858381518110610282576102826108b9565b60200260200101516040518263ffffffff1660e01b81526004016102a891815260200190565b602060405180830381865afa9250505080156102ff575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526102fc9181019061094f565b60015b61035e5761030b610968565b806308c379a003610352575061031f610984565b8061032a5750610354565b6000801b838381518110610340576103406108b9565b6020026020010181815250505061037f565b505b3d6000803e3d6000fd5b80838381518110610371576103716108b9565b602002602001018181525050505b8061038981610917565b91505061022b565b5092915050565b8051825114610407576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f696e70757420617272617920617267206c656e67746873206d69736d61746368604482015260640160405180910390fd5b60005b82518110156104e5577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663fadff0e1848381518110610461576104616108b9565b602002602001015184848151811061047b5761047b6108b9565b60200260200101516040518363ffffffff1660e01b81526004016104a0929190610a2c565b600060405180830381600087803b1580156104ba57600080fd5b505af11580156104ce573d6000803e3d6000fd5b5050505080806104dd90610917565b91505061040a565b505050565b60006101006104f7610523565b111561051a57610100610508610523565b6105129190610aa0565b82101561051d565b60015b92915050565b60004661052f816105b1565b156105aa57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610580573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a4919061094f565b91505090565b4391505090565b600061a4b18214806105c5575062066eed82145b8061051d57505062066eee1490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116810181811067ffffffffffffffff82111715610647576106476105d4565b6040525050565b600067ffffffffffffffff821115610668576106686105d4565b5060051b60200190565b600082601f83011261068357600080fd5b813560206106908261064e565b60405161069d8282610603565b83815260059390931b85018201928281019150868411156106bd57600080fd5b8286015b848110156106d857803583529183019183016106c1565b509695505050505050565b6000602082840312156106f557600080fd5b813567ffffffffffffffff81111561070c57600080fd5b61071884828501610672565b949350505050565b6020808252825182820181905260009190848201906040850190845b818110156107585783518352928401929184019160010161073c565b50909695505050505050565b600080604080848603121561077857600080fd5b833567ffffffffffffffff8082111561079057600080fd5b61079c87838801610672565b94506020915081860135818111156107b357600080fd5b8601601f80820189136107c557600080fd5b81356107d08161064e565b86516107dc8282610603565b82815260059290921b840186019186810191508b8311156107fc57600080fd5b8685015b838110156108a6578035878111156108185760008081fd5b8601603f81018e1361082a5760008081fd5b888101358881111561083e5761083e6105d4565b8a516108708b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08a8501160182610603565b8181528f8c8385010111156108855760008081fd5b818c84018c83013760009181018b0191909152845250918701918701610800565b5080985050505050505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610948576109486108e8565b5060010190565b60006020828403121561096157600080fd5b5051919050565b600060033d11156109815760046000803e5060005160e01c5b90565b600060443d10156109925790565b6040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc803d016004833e81513d67ffffffffffffffff81602484011181841117156109e057505050505090565b82850191508151818111156109f85750505050505090565b843d8701016020828501011115610a125750505050505090565b610a2160208286010187610603565b509095945050505050565b82815260006020604081840152835180604085015260005b81811015610a6057858101830151858201606001528201610a44565b5060006060828601015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116850101925050509392505050565b8181038181111561051d5761051d6108e856fea164736f6c6343000813000a", } var BatchBlockhashStoreABI = BatchBlockhashStoreMetaData.ABI diff --git a/core/gethwrappers/generated/batch_vrf_coordinator_v2plus/batch_vrf_coordinator_v2plus.go b/core/gethwrappers/generated/batch_vrf_coordinator_v2plus/batch_vrf_coordinator_v2plus.go index fa2892f5dce..49056ab784c 100644 --- a/core/gethwrappers/generated/batch_vrf_coordinator_v2plus/batch_vrf_coordinator_v2plus.go +++ b/core/gethwrappers/generated/batch_vrf_coordinator_v2plus/batch_vrf_coordinator_v2plus.go @@ -52,8 +52,8 @@ type VRFTypesRequestCommitmentV2Plus struct { } var BatchVRFCoordinatorV2PlusMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddr\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"reason\",\"type\":\"string\"}],\"name\":\"ErrorReturned\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"lowLevelData\",\"type\":\"bytes\"}],\"name\":\"RawErrorReturned\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"COORDINATOR\",\"outputs\":[{\"internalType\":\"contractIVRFCoordinatorV2Plus\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256[2]\",\"name\":\"pk\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"gamma\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"c\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"s\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"uWitness\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"cGammaWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"sHashWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"zInv\",\"type\":\"uint256\"}],\"internalType\":\"structVRFTypes.Proof[]\",\"name\":\"proofs\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"blockNum\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFTypes.RequestCommitmentV2Plus[]\",\"name\":\"rcs\",\"type\":\"tuple[]\"}],\"name\":\"fulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a060405234801561001057600080fd5b50604051610cd3380380610cd383398101604081905261002f91610044565b60601b6001600160601b031916608052610074565b60006020828403121561005657600080fd5b81516001600160a01b038116811461006d57600080fd5b9392505050565b60805160601c610c3b610098600039600081816040015261011d0152610c3b6000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80633b2bcbf11461003b5780636abb17211461008b575b600080fd5b6100627f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b61009e610099366004610668565b6100a0565b005b805182511461010f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f696e70757420617272617920617267206c656e67746873206d69736d61746368604482015260640160405180910390fd5b60005b8251811015610333577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663301f42e984838151811061016957610169610b0c565b602002602001015184848151811061018357610183610b0c565b602002602001015160006040518463ffffffff1660e01b81526004016101ab93929190610933565b602060405180830381600087803b1580156101c557600080fd5b505af1925050508015610213575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252610210918101906107c8565b60015b61031f5761021f610b6a565b806308c379a014156102a45750610234610b86565b8061023f57506102a6565b600061026385848151811061025657610256610b0c565b6020026020010151610338565b9050807f4dcab4ce0e741a040f7e0f9b880557f8de685a9520d4bfac272a81c3c3802b2e836040516102959190610920565b60405180910390a25050610321565b505b3d8080156102d0576040519150601f19603f3d011682016040523d82523d6000602084013e6102d5565b606091505b5060006102ed85848151811061025657610256610b0c565b9050807fbfd42bb5a1bf8153ea750f66ea4944f23f7b9ae51d0462177b9769aa652b61b5836040516102959190610920565b505b8061032b81610aac565b915050610112565b505050565b60008061034883600001516103a7565b905080836080015160405160200161036a929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101209392505050565b6000816040516020016103ba919061090c565b604051602081830303815290604052805190602001209050919050565b803573ffffffffffffffffffffffffffffffffffffffff811681146103fb57600080fd5b919050565b600082601f83011261041157600080fd5b8135602061041e82610a17565b6040805161042c8382610a61565b8481528381019250868401600586901b8801850189101561044c57600080fd5b60005b8681101561053c57813567ffffffffffffffff8082111561046f57600080fd5b818b01915060c0807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848f030112156104a757600080fd5b86516104b281610a3b565b8984013583811681146104c457600080fd5b8152838801358a82015260606104db818601610654565b8983015260806104ec818701610654565b8284015260a091506104ff8287016103d7565b9083015291840135918383111561051557600080fd5b6105238f8c858801016105c2565b908201528852505050938501939085019060010161044f565b509098975050505050505050565b600082601f83011261055b57600080fd5b6040516040810181811067ffffffffffffffff8211171561057e5761057e610b3b565b806040525080838560408601111561059557600080fd5b60005b60028110156105b7578135835260209283019290910190600101610598565b509195945050505050565b600082601f8301126105d357600080fd5b813567ffffffffffffffff8111156105ed576105ed610b3b565b60405161062260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160182610a61565b81815284602083860101111561063757600080fd5b816020850160208301376000918101602001919091529392505050565b803563ffffffff811681146103fb57600080fd5b600080604080848603121561067c57600080fd5b833567ffffffffffffffff8082111561069457600080fd5b818601915086601f8301126106a857600080fd5b813560206106b582610a17565b85516106c18282610a61565b83815282810191508583016101a0808602880185018d10156106e257600080fd5b600097505b858810156107975780828e0312156106fe57600080fd5b6107066109ed565b6107108e8461054a565b815261071e8e8b850161054a565b8682015260808301358a82015260a0830135606082015260c0830135608082015261074b60e084016103d7565b60a082015261010061075f8f82860161054a565b60c08301526107728f610140860161054a565b60e08301526101808401359082015284526001979097019692840192908101906106e7565b509098505050870135935050808311156107b057600080fd5b50506107be85828601610400565b9150509250929050565b6000602082840312156107da57600080fd5b81516bffffffffffffffffffffffff811681146107f657600080fd5b9392505050565b8060005b6002811015610820578151845260209384019390910190600101610801565b50505050565b6000815180845260005b8181101561084c57602081850181015186830182015201610830565b8181111561085e576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b67ffffffffffffffff8151168252602081015160208301526000604082015163ffffffff8082166040860152806060850151166060860152505073ffffffffffffffffffffffffffffffffffffffff608083015116608084015260a082015160c060a085015261090460c0850182610826565b949350505050565b6040810161091a82846107fd565b92915050565b6020815260006107f66020830184610826565b60006101e06109438387516107fd565b602086015161095560408501826107fd565b5060408601516080840152606086015160a0840152608086015160c084015273ffffffffffffffffffffffffffffffffffffffff60a08701511660e084015260c08601516101006109a8818601836107fd565b60e088015191506109bd6101408601836107fd565b870151610180850152506101a083018190526109db81840186610891565b9150506109046101c083018415159052565b604051610120810167ffffffffffffffff81118282101715610a1157610a11610b3b565b60405290565b600067ffffffffffffffff821115610a3157610a31610b3b565b5060051b60200190565b60c0810181811067ffffffffffffffff82111715610a5b57610a5b610b3b565b60405250565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116810181811067ffffffffffffffff82111715610aa557610aa5610b3b565b6040525050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610b05577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060033d1115610b835760046000803e5060005160e01c5b90565b600060443d1015610b945790565b6040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc803d016004833e81513d67ffffffffffffffff8160248401118184111715610be257505050505090565b8285019150815181811115610bfa5750505050505090565b843d8701016020828501011115610c145750505050505090565b610c2360208286010187610a61565b50909594505050505056fea164736f6c6343000806000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddr\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"reason\",\"type\":\"string\"}],\"name\":\"ErrorReturned\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"lowLevelData\",\"type\":\"bytes\"}],\"name\":\"RawErrorReturned\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"COORDINATOR\",\"outputs\":[{\"internalType\":\"contractIVRFCoordinatorV2PlusFulfill\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256[2]\",\"name\":\"pk\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"gamma\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"c\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"s\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"uWitness\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"cGammaWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"sHashWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"zInv\",\"type\":\"uint256\"}],\"internalType\":\"structVRFTypes.Proof[]\",\"name\":\"proofs\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"blockNum\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFTypes.RequestCommitmentV2Plus[]\",\"name\":\"rcs\",\"type\":\"tuple[]\"}],\"name\":\"fulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60a060405234801561001057600080fd5b50604051610cc4380380610cc483398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b608051610c33610091600039600081816040015261011d0152610c336000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80633b2bcbf11461003b5780636abb17211461008b575b600080fd5b6100627f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b61009e61009936600461073a565b6100a0565b005b805182511461010f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f696e70757420617272617920617267206c656e67746873206d69736d61746368604482015260640160405180910390fd5b60005b8251811015610321577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663301f42e984838151811061016957610169610899565b602002602001015184848151811061018357610183610899565b602002602001015160006040518463ffffffff1660e01b81526004016101ab939291906109d0565b6020604051808303816000875af1925050508015610204575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261020191810190610a8a565b60015b61030f57610210610abf565b806308c379a0036102945750610224610adb565b8061022f5750610296565b600061025385848151811061024657610246610899565b6020026020010151610326565b9050807f4dcab4ce0e741a040f7e0f9b880557f8de685a9520d4bfac272a81c3c3802b2e836040516102859190610b83565b60405180910390a25050610311565b505b3d8080156102c0576040519150601f19603f3d011682016040523d82523d6000602084013e6102c5565b606091505b5060006102dd85848151811061024657610246610899565b9050807fbfd42bb5a1bf8153ea750f66ea4944f23f7b9ae51d0462177b9769aa652b61b5836040516102859190610b83565b505b61031a81610b96565b9050610112565b505050565b6000806103368360000151610395565b9050808360800151604051602001610358929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101209392505050565b6000816040516020016103a89190610bf5565b604051602081830303815290604052805190602001209050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60c0810181811067ffffffffffffffff82111715610414576104146103c5565b60405250565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116810181811067ffffffffffffffff8211171561045e5761045e6103c5565b6040525050565b604051610120810167ffffffffffffffff81118282101715610489576104896103c5565b60405290565b600067ffffffffffffffff8211156104a9576104a96103c5565b5060051b60200190565b600082601f8301126104c457600080fd5b6040516040810181811067ffffffffffffffff821117156104e7576104e76103c5565b80604052508060408401858111156104fe57600080fd5b845b81811015610518578035835260209283019201610500565b509195945050505050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461054757600080fd5b919050565b803563ffffffff8116811461054757600080fd5b600082601f83011261057157600080fd5b813567ffffffffffffffff81111561058b5761058b6103c5565b6040516105c060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f850116018261041a565b8181528460208386010111156105d557600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f83011261060357600080fd5b813560206106108261048f565b6040805161061e838261041a565b84815260059490941b860183019383810192508785111561063e57600080fd5b8387015b8581101561072e57803567ffffffffffffffff808211156106635760008081fd5b818a01915060c0807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848e0301121561069c5760008081fd5b85516106a7816103f4565b8884013583811681146106ba5760008081fd5b8152838701358982015260606106d181860161054c565b8883015260806106e281870161054c565b8284015260a091506106f5828701610523565b9083015291840135918383111561070c5760008081fd5b61071a8e8b85880101610560565b908201528752505050928401928401610642565b50979650505050505050565b6000806040838503121561074d57600080fd5b823567ffffffffffffffff8082111561076557600080fd5b818501915085601f83011261077957600080fd5b813560206107868261048f565b604051610793828261041a565b8381526101a0938402860183019383820192508a8511156107b357600080fd5b958301955b8487101561086b5780878c0312156107d05760008081fd5b6107d8610465565b6107e28c896104b3565b81526107f18c60408a016104b3565b85820152608080890135604083015260a0808a0135606084015260c0808b01358385015260e09250610824838c01610523565b8285015261010091506108398f838d016104b3565b9084015261084b8e6101408c016104b3565b9183019190915261018089013590820152835295860195918301916107b8565b509650508601359250508082111561088257600080fd5b5061088f858286016105f2565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8060005b60028110156108eb5781518452602093840193909101906001016108cc565b50505050565b6000815180845260005b81811015610917576020818501810151868301820152016108fb565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b67ffffffffffffffff8151168252602081015160208301526000604082015163ffffffff8082166040860152806060850151166060860152505073ffffffffffffffffffffffffffffffffffffffff608083015116608084015260a082015160c060a08501526109c860c08501826108f1565b949350505050565b60006101e06109e08387516108c8565b60208601516109f260408501826108c8565b5060408601516080840152606086015160a0840152608086015160c084015273ffffffffffffffffffffffffffffffffffffffff60a08701511660e084015260c0860151610100610a45818601836108c8565b60e08801519150610a5a6101408601836108c8565b870151610180850152506101a08301819052610a7881840186610955565b9150506109c86101c083018415159052565b600060208284031215610a9c57600080fd5b81516bffffffffffffffffffffffff81168114610ab857600080fd5b9392505050565b600060033d1115610ad85760046000803e5060005160e01c5b90565b600060443d1015610ae95790565b6040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc803d016004833e81513d67ffffffffffffffff8160248401118184111715610b3757505050505090565b8285019150815181811115610b4f5750505050505090565b843d8701016020828501011115610b695750505050505090565b610b786020828601018761041a565b509095945050505050565b602081526000610ab860208301846108f1565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610bee577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b60408101818360005b6002811015610c1d578151835260209283019290910190600101610bfe565b5050509291505056fea164736f6c6343000813000a", } var BatchVRFCoordinatorV2PlusABI = BatchVRFCoordinatorV2PlusMetaData.ABI diff --git a/core/gethwrappers/generated/blockhash_store/blockhash_store.go b/core/gethwrappers/generated/blockhash_store/blockhash_store.go index e43f9f450eb..f82b0fa4f88 100644 --- a/core/gethwrappers/generated/blockhash_store/blockhash_store.go +++ b/core/gethwrappers/generated/blockhash_store/blockhash_store.go @@ -30,7 +30,7 @@ var ( var BlockhashStoreMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"getBlockhash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"store\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"storeEarliest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"header\",\"type\":\"bytes\"}],\"name\":\"storeVerifyHeader\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b506105d3806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80636057361d1461005157806383b6d6b714610066578063e9413d381461006e578063fadff0e114610093575b600080fd5b61006461005f366004610447565b6100a6565b005b610064610131565b61008161007c366004610447565b61014b565b60405190815260200160405180910390f35b6100646100a1366004610460565b6101c7565b60006100b182610269565b90508061011f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f626c6f636b68617368286e29206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b60009182526020829052604090912055565b61014961010061013f61036e565b61005f9190610551565b565b600081815260208190526040812054806101c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f626c6f636b68617368206e6f7420666f756e6420696e2073746f7265000000006044820152606401610116565b92915050565b6000806101d5846001610539565b815260200190815260200160002054818051906020012014610253576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f6865616465722068617320756e6b6e6f776e20626c6f636b68617368000000006044820152606401610116565b6024015160009182526020829052604090912055565b6000466102758161040b565b1561035e576101008367ffffffffffffffff1661029061036e565b61029a9190610551565b11806102b757506102a961036e565b8367ffffffffffffffff1610155b156102c55750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152606490632b407a829060240160206040518083038186803b15801561031f57600080fd5b505afa158015610333573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610357919061042e565b9392505050565b505067ffffffffffffffff164090565b60004661037a8161040b565b1561040457606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156103c657600080fd5b505afa1580156103da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103fe919061042e565b91505090565b4391505090565b600061a4b182148061041f575062066eed82145b806101c157505062066eee1490565b60006020828403121561044057600080fd5b5051919050565b60006020828403121561045957600080fd5b5035919050565b6000806040838503121561047357600080fd5b82359150602083013567ffffffffffffffff8082111561049257600080fd5b818501915085601f8301126104a657600080fd5b8135818111156104b8576104b8610597565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156104fe576104fe610597565b8160405282815288602084870101111561051757600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b6000821982111561054c5761054c610568565b500190565b60008282101561056357610563610568565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + Bin: "0x608060405234801561001057600080fd5b506105b2806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80636057361d1461005157806383b6d6b714610066578063e9413d381461006e578063fadff0e114610093575b600080fd5b61006461005f366004610416565b6100a6565b005b610064610135565b61008161007c366004610416565b61014f565b60405190815260200160405180910390f35b6100646100a136600461045e565b6101cd565b60006100b18261026f565b90506000819003610123576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f626c6f636b68617368286e29206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b60009182526020829052604090912055565b61014d610100610143610365565b61005f9190610566565b565b6000818152602081905260408120548082036101c7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f626c6f636b68617368206e6f7420666f756e6420696e2073746f726500000000604482015260640161011a565b92915050565b6000806101db846001610579565b815260200190815260200160002054818051906020012014610259576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f6865616465722068617320756e6b6e6f776e20626c6f636b6861736800000000604482015260640161011a565b6024015160009182526020829052604090912055565b60004661027b816103f3565b15610355576101008367ffffffffffffffff16610296610365565b6102a09190610566565b11806102bd57506102af610365565b8367ffffffffffffffff1610155b156102cb5750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152606490632b407a8290602401602060405180830381865afa15801561032a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061034e919061058c565b9392505050565b505067ffffffffffffffff164090565b600046610371816103f3565b156103ec57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103e6919061058c565b91505090565b4391505090565b600061a4b1821480610407575062066eed82145b806101c757505062066eee1490565b60006020828403121561042857600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806040838503121561047157600080fd5b82359150602083013567ffffffffffffffff8082111561049057600080fd5b818501915085601f8301126104a457600080fd5b8135818111156104b6576104b661042f565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156104fc576104fc61042f565b8160405282815288602084870101111561051557600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156101c7576101c7610537565b808201808211156101c7576101c7610537565b60006020828403121561059e57600080fd5b505191905056fea164736f6c6343000813000a", } var BlockhashStoreABI = BlockhashStoreMetaData.ABI diff --git a/core/gethwrappers/generated/i_automation_registry_master_wrapper_2_3/i_automation_registry_master_wrapper_2_3.go b/core/gethwrappers/generated/i_automation_registry_master_wrapper_2_3/i_automation_registry_master_wrapper_2_3.go index 8769bb436bd..7ff232e0239 100644 --- a/core/gethwrappers/generated/i_automation_registry_master_wrapper_2_3/i_automation_registry_master_wrapper_2_3.go +++ b/core/gethwrappers/generated/i_automation_registry_master_wrapper_2_3/i_automation_registry_master_wrapper_2_3.go @@ -31,34 +31,64 @@ var ( ) type AutomationRegistryBase23BillingConfig struct { - GasFeePPB uint32 - FlatFeeMicroLink *big.Int - PriceFeed common.Address + GasFeePPB uint32 + FlatFeeMilliCents *big.Int + PriceFeed common.Address + FallbackPrice *big.Int + MinSpend *big.Int } -type AutomationRegistryBase23OnchainConfig struct { - PaymentPremiumPPB uint32 - FlatFeeMicroLink uint32 - CheckGasLimit uint32 +type AutomationRegistryBase23BillingOverrides struct { + GasFeePPB uint32 + FlatFeeMilliCents *big.Int +} + +type AutomationRegistryBase23HotVars struct { + TotalPremium *big.Int + LatestEpoch uint32 StalenessSeconds *big.Int GasCeilingMultiplier uint16 - MinUpkeepSpend *big.Int + F uint8 + Paused bool + ReentrancyGuard bool + ReorgProtectionEnabled bool + ChainModule common.Address +} + +type AutomationRegistryBase23OnchainConfig struct { + CheckGasLimit uint32 MaxPerformGas uint32 MaxCheckDataSize uint32 + Transcoder common.Address + ReorgProtectionEnabled bool + StalenessSeconds *big.Int MaxPerformDataSize uint32 MaxRevertDataSize uint32 + UpkeepPrivilegeManager common.Address + GasCeilingMultiplier uint16 + FinanceAdmin common.Address FallbackGasPrice *big.Int FallbackLinkPrice *big.Int FallbackNativePrice *big.Int - Transcoder common.Address Registrars []common.Address - UpkeepPrivilegeManager common.Address ChainModule common.Address - ReorgProtectionEnabled bool - FinanceAdmin common.Address } -type AutomationRegistryBase23OnchainConfigLegacy struct { +type AutomationRegistryBase23Storage struct { + Transcoder common.Address + CheckGasLimit uint32 + MaxPerformGas uint32 + Nonce uint32 + UpkeepPrivilegeManager common.Address + ConfigCount uint32 + LatestConfigBlockNumber uint32 + MaxCheckDataSize uint32 + FinanceAdmin common.Address + MaxPerformDataSize uint32 + MaxRevertDataSize uint32 +} + +type IAutomationV21PlusCommonOnchainConfigLegacy struct { PaymentPremiumPPB uint32 FlatFeeMicroLink uint32 CheckGasLimit uint32 @@ -76,7 +106,7 @@ type AutomationRegistryBase23OnchainConfigLegacy struct { UpkeepPrivilegeManager common.Address } -type AutomationRegistryBase23State struct { +type IAutomationV21PlusCommonStateLegacy struct { Nonce uint32 OwnerLinkBalance *big.Int ExpectedLinkBalance *big.Int @@ -89,7 +119,7 @@ type AutomationRegistryBase23State struct { Paused bool } -type AutomationRegistryBase23UpkeepInfo struct { +type IAutomationV21PlusCommonUpkeepInfoLegacy struct { Target common.Address PerformGas uint32 CheckData []byte @@ -103,7 +133,7 @@ type AutomationRegistryBase23UpkeepInfo struct { } var IAutomationRegistryMaster23MetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidFeed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxCheckDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxPerformDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyFinanceAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentGreaterThanAllLINK\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint24\"},{\"internalType\":\"address\",\"name\":\"priceFeed\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"BillingConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newModule\",\"type\":\"address\"}],\"name\":\"ChainSpecificModuleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"acceptPayeeship\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"acceptUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"cancelUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkUSD\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkUSD\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"executeCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveUpkeepIDs\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"getAdminPrivilegeConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowedReadOnlyAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAutomationForwarderLogic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getBillingTokenConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint24\"},{\"internalType\":\"address\",\"name\":\"priceFeed\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBillingTokens\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCancellationDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getChainModule\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"chainModule\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConditionalGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFallbackNativePrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFastGasFeedAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepID\",\"type\":\"uint256\"}],\"name\":\"getForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLinkAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLinkUSDFeedAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLogGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"getMaxPaymentForGas\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"maxPayment\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getMinBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getMinBalanceForUpkeep\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"minBalance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNativeUSDFeedAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"peer\",\"type\":\"address\"}],\"name\":\"getPeerRegistryMigrationPermission\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPerPerformByteGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPerSignerGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getReorgProtectionEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"query\",\"type\":\"address\"}],\"name\":\"getSignerInfo\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"index\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"nonce\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"ownerLinkBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"expectedLinkBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"totalPremium\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"numUpkeeps\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"latestConfigBlockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"latestConfigDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"latestEpoch\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"}],\"internalType\":\"structAutomationRegistryBase2_3.State\",\"name\":\"state\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.OnchainConfigLegacy\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTransmitCalldataFixedBytesOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTransmitCalldataPerSignerBytesOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"query\",\"type\":\"address\"}],\"name\":\"getTransmitterInfo\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"index\",\"type\":\"uint8\"},{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"lastCollected\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getTriggerType\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getUpkeep\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"maxValidBlocknumber\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"lastPerformedBlockNumber\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"amountSpent\",\"type\":\"uint96\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"internalType\":\"structAutomationRegistryBase2_3.UpkeepInfo\",\"name\":\"upkeepInfo\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepPrivilegeConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepTriggerConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"hasDedupKey\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkAvailableForPayment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"migrateUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"pauseUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedUpkeeps\",\"type\":\"bytes\"}],\"name\":\"receiveUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"newPrivilegeConfig\",\"type\":\"bytes\"}],\"name\":\"setAdminPrivilegeConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"onchainConfigBytes\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackNativePrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"chainModule\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"financeAdmin\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.OnchainConfig\",\"name\":\"onchainConfig\",\"type\":\"tuple\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"address[]\",\"name\":\"billingTokens\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint24\"},{\"internalType\":\"address\",\"name\":\"priceFeed\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig[]\",\"name\":\"billingConfigs\",\"type\":\"tuple[]\"}],\"name\":\"setConfigTypeSafe\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"setPayees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"peer\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"permission\",\"type\":\"uint8\"}],\"name\":\"setPeerRegistryMigrationPermission\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"setUpkeepCheckData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"setUpkeepGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"config\",\"type\":\"bytes\"}],\"name\":\"setUpkeepOffchainConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"newPrivilegeConfig\",\"type\":\"bytes\"}],\"name\":\"setUpkeepPrivilegeConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"setUpkeepTriggerConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"simulatePerformUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"transferPayeeship\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"transferUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"rawReport\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"unpauseUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepTranscoderVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawERC20Fees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLinkFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawPayment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientLinkLiquidity\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidFeed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOffchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustSettleOnchain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyFinanceAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingOverrides\",\"name\":\"overrides\",\"type\":\"tuple\"}],\"name\":\"BillingConfigOverridden\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"BillingConfigOverrideRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"address\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"BillingConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newModule\",\"type\":\"address\"}],\"name\":\"ChainSpecificModuleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"payments\",\"type\":\"uint256[]\"}],\"name\":\"NOPsSettledOffchain\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"acceptPayeeship\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"acceptUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"cancelUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkUSD\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkUSD\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"disableOffchainPayments\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"executeCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveUpkeepIDs\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"getAdminPrivilegeConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowedReadOnlyAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAutomationForwarderLogic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepID\",\"type\":\"uint256\"}],\"name\":\"getBillingToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getBillingTokenConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"address\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBillingTokens\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCancellationDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getChainModule\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"chainModule\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConditionalGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"financeAdmin\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackNativePrice\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"chainModule\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.OnchainConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFallbackNativePrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFastGasFeedAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepID\",\"type\":\"uint256\"}],\"name\":\"getForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getHotVars\",\"outputs\":[{\"components\":[{\"internalType\":\"uint96\",\"name\":\"totalPremium\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"latestEpoch\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"reentrancyGuard\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"chainModule\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.HotVars\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLinkAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLinkUSDFeedAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLogGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"billingToken\",\"type\":\"address\"}],\"name\":\"getMaxPaymentForGas\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"maxPayment\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getMinBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getMinBalanceForUpkeep\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"minBalance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNativeUSDFeedAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNumUpkeeps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPayoutMode\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"peer\",\"type\":\"address\"}],\"name\":\"getPeerRegistryMigrationPermission\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPerPerformByteGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPerSignerGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getReorgProtectionEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"billingToken\",\"type\":\"address\"}],\"name\":\"getReserveAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"query\",\"type\":\"address\"}],\"name\":\"getSignerInfo\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"index\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"nonce\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"ownerLinkBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"expectedLinkBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"totalPremium\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"numUpkeeps\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"latestConfigBlockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"latestConfigDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"latestEpoch\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"}],\"internalType\":\"structIAutomationV21PlusCommon.StateLegacy\",\"name\":\"state\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"}],\"internalType\":\"structIAutomationV21PlusCommon.OnchainConfigLegacy\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStorage\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"nonce\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"latestConfigBlockNumber\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"financeAdmin\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"}],\"internalType\":\"structAutomationRegistryBase2_3.Storage\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTransmitCalldataFixedBytesOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTransmitCalldataPerSignerBytesOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"query\",\"type\":\"address\"}],\"name\":\"getTransmitterInfo\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"index\",\"type\":\"uint8\"},{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"lastCollected\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getTriggerType\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getUpkeep\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"maxValidBlocknumber\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"lastPerformedBlockNumber\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"amountSpent\",\"type\":\"uint96\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"internalType\":\"structIAutomationV21PlusCommon.UpkeepInfoLegacy\",\"name\":\"upkeepInfo\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepPrivilegeConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepTriggerConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWrappedNativeTokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"hasDedupKey\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkAvailableForPayment\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"migrateUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"pauseUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedUpkeeps\",\"type\":\"bytes\"}],\"name\":\"receiveUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"billingToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"removeBillingOverrides\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"newPrivilegeConfig\",\"type\":\"bytes\"}],\"name\":\"setAdminPrivilegeConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"}],\"internalType\":\"structAutomationRegistryBase2_3.BillingOverrides\",\"name\":\"billingOverrides\",\"type\":\"tuple\"}],\"name\":\"setBillingOverrides\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"onchainConfigBytes\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"financeAdmin\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackNativePrice\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"chainModule\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.OnchainConfig\",\"name\":\"onchainConfig\",\"type\":\"tuple\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"address[]\",\"name\":\"billingTokens\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"address\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig[]\",\"name\":\"billingConfigs\",\"type\":\"tuple[]\"}],\"name\":\"setConfigTypeSafe\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"setPayees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"peer\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"permission\",\"type\":\"uint8\"}],\"name\":\"setPeerRegistryMigrationPermission\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"setUpkeepCheckData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"setUpkeepGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"config\",\"type\":\"bytes\"}],\"name\":\"setUpkeepOffchainConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"newPrivilegeConfig\",\"type\":\"bytes\"}],\"name\":\"setUpkeepPrivilegeConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"setUpkeepTriggerConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"settleNOPsOffchain\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"simulatePerformUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"supportsBillingToken\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"transferPayeeship\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"transferUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"rawReport\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"unpauseUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawERC20Fees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLink\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawPayment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", } var IAutomationRegistryMaster23ABI = IAutomationRegistryMaster23MetaData.ABI @@ -458,6 +488,28 @@ func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) Ge return _IAutomationRegistryMaster23.Contract.GetBalance(&_IAutomationRegistryMaster23.CallOpts, id) } +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) GetBillingToken(opts *bind.CallOpts, upkeepID *big.Int) (common.Address, error) { + var out []interface{} + err := _IAutomationRegistryMaster23.contract.Call(opts, &out, "getBillingToken", upkeepID) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) GetBillingToken(upkeepID *big.Int) (common.Address, error) { + return _IAutomationRegistryMaster23.Contract.GetBillingToken(&_IAutomationRegistryMaster23.CallOpts, upkeepID) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) GetBillingToken(upkeepID *big.Int) (common.Address, error) { + return _IAutomationRegistryMaster23.Contract.GetBillingToken(&_IAutomationRegistryMaster23.CallOpts, upkeepID) +} + func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) GetBillingTokenConfig(opts *bind.CallOpts, token common.Address) (AutomationRegistryBase23BillingConfig, error) { var out []interface{} err := _IAutomationRegistryMaster23.contract.Call(opts, &out, "getBillingTokenConfig", token) @@ -568,6 +620,28 @@ func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) Ge return _IAutomationRegistryMaster23.Contract.GetConditionalGasOverhead(&_IAutomationRegistryMaster23.CallOpts) } +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) GetConfig(opts *bind.CallOpts) (AutomationRegistryBase23OnchainConfig, error) { + var out []interface{} + err := _IAutomationRegistryMaster23.contract.Call(opts, &out, "getConfig") + + if err != nil { + return *new(AutomationRegistryBase23OnchainConfig), err + } + + out0 := *abi.ConvertType(out[0], new(AutomationRegistryBase23OnchainConfig)).(*AutomationRegistryBase23OnchainConfig) + + return out0, err + +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) GetConfig() (AutomationRegistryBase23OnchainConfig, error) { + return _IAutomationRegistryMaster23.Contract.GetConfig(&_IAutomationRegistryMaster23.CallOpts) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) GetConfig() (AutomationRegistryBase23OnchainConfig, error) { + return _IAutomationRegistryMaster23.Contract.GetConfig(&_IAutomationRegistryMaster23.CallOpts) +} + func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) GetFallbackNativePrice(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _IAutomationRegistryMaster23.contract.Call(opts, &out, "getFallbackNativePrice") @@ -634,6 +708,28 @@ func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) Ge return _IAutomationRegistryMaster23.Contract.GetForwarder(&_IAutomationRegistryMaster23.CallOpts, upkeepID) } +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) GetHotVars(opts *bind.CallOpts) (AutomationRegistryBase23HotVars, error) { + var out []interface{} + err := _IAutomationRegistryMaster23.contract.Call(opts, &out, "getHotVars") + + if err != nil { + return *new(AutomationRegistryBase23HotVars), err + } + + out0 := *abi.ConvertType(out[0], new(AutomationRegistryBase23HotVars)).(*AutomationRegistryBase23HotVars) + + return out0, err + +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) GetHotVars() (AutomationRegistryBase23HotVars, error) { + return _IAutomationRegistryMaster23.Contract.GetHotVars(&_IAutomationRegistryMaster23.CallOpts) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) GetHotVars() (AutomationRegistryBase23HotVars, error) { + return _IAutomationRegistryMaster23.Contract.GetHotVars(&_IAutomationRegistryMaster23.CallOpts) +} + func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) GetLinkAddress(opts *bind.CallOpts) (common.Address, error) { var out []interface{} err := _IAutomationRegistryMaster23.contract.Call(opts, &out, "getLinkAddress") @@ -700,9 +796,9 @@ func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) Ge return _IAutomationRegistryMaster23.Contract.GetLogGasOverhead(&_IAutomationRegistryMaster23.CallOpts) } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) GetMaxPaymentForGas(opts *bind.CallOpts, triggerType uint8, gasLimit uint32) (*big.Int, error) { +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) GetMaxPaymentForGas(opts *bind.CallOpts, id *big.Int, triggerType uint8, gasLimit uint32, billingToken common.Address) (*big.Int, error) { var out []interface{} - err := _IAutomationRegistryMaster23.contract.Call(opts, &out, "getMaxPaymentForGas", triggerType, gasLimit) + err := _IAutomationRegistryMaster23.contract.Call(opts, &out, "getMaxPaymentForGas", id, triggerType, gasLimit, billingToken) if err != nil { return *new(*big.Int), err @@ -714,12 +810,12 @@ func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) GetMaxPay } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) GetMaxPaymentForGas(triggerType uint8, gasLimit uint32) (*big.Int, error) { - return _IAutomationRegistryMaster23.Contract.GetMaxPaymentForGas(&_IAutomationRegistryMaster23.CallOpts, triggerType, gasLimit) +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) GetMaxPaymentForGas(id *big.Int, triggerType uint8, gasLimit uint32, billingToken common.Address) (*big.Int, error) { + return _IAutomationRegistryMaster23.Contract.GetMaxPaymentForGas(&_IAutomationRegistryMaster23.CallOpts, id, triggerType, gasLimit, billingToken) } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) GetMaxPaymentForGas(triggerType uint8, gasLimit uint32) (*big.Int, error) { - return _IAutomationRegistryMaster23.Contract.GetMaxPaymentForGas(&_IAutomationRegistryMaster23.CallOpts, triggerType, gasLimit) +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) GetMaxPaymentForGas(id *big.Int, triggerType uint8, gasLimit uint32, billingToken common.Address) (*big.Int, error) { + return _IAutomationRegistryMaster23.Contract.GetMaxPaymentForGas(&_IAutomationRegistryMaster23.CallOpts, id, triggerType, gasLimit, billingToken) } func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) GetMinBalance(opts *bind.CallOpts, id *big.Int) (*big.Int, error) { @@ -788,6 +884,50 @@ func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) Ge return _IAutomationRegistryMaster23.Contract.GetNativeUSDFeedAddress(&_IAutomationRegistryMaster23.CallOpts) } +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) GetNumUpkeeps(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _IAutomationRegistryMaster23.contract.Call(opts, &out, "getNumUpkeeps") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) GetNumUpkeeps() (*big.Int, error) { + return _IAutomationRegistryMaster23.Contract.GetNumUpkeeps(&_IAutomationRegistryMaster23.CallOpts) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) GetNumUpkeeps() (*big.Int, error) { + return _IAutomationRegistryMaster23.Contract.GetNumUpkeeps(&_IAutomationRegistryMaster23.CallOpts) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) GetPayoutMode(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _IAutomationRegistryMaster23.contract.Call(opts, &out, "getPayoutMode") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) GetPayoutMode() (uint8, error) { + return _IAutomationRegistryMaster23.Contract.GetPayoutMode(&_IAutomationRegistryMaster23.CallOpts) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) GetPayoutMode() (uint8, error) { + return _IAutomationRegistryMaster23.Contract.GetPayoutMode(&_IAutomationRegistryMaster23.CallOpts) +} + func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) GetPeerRegistryMigrationPermission(opts *bind.CallOpts, peer common.Address) (uint8, error) { var out []interface{} err := _IAutomationRegistryMaster23.contract.Call(opts, &out, "getPeerRegistryMigrationPermission", peer) @@ -876,6 +1016,28 @@ func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) Ge return _IAutomationRegistryMaster23.Contract.GetReorgProtectionEnabled(&_IAutomationRegistryMaster23.CallOpts) } +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) GetReserveAmount(opts *bind.CallOpts, billingToken common.Address) (*big.Int, error) { + var out []interface{} + err := _IAutomationRegistryMaster23.contract.Call(opts, &out, "getReserveAmount", billingToken) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) GetReserveAmount(billingToken common.Address) (*big.Int, error) { + return _IAutomationRegistryMaster23.Contract.GetReserveAmount(&_IAutomationRegistryMaster23.CallOpts, billingToken) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) GetReserveAmount(billingToken common.Address) (*big.Int, error) { + return _IAutomationRegistryMaster23.Contract.GetReserveAmount(&_IAutomationRegistryMaster23.CallOpts, billingToken) +} + func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) GetSignerInfo(opts *bind.CallOpts, query common.Address) (GetSignerInfo, error) { @@ -917,8 +1079,8 @@ func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) GetState( return *outstruct, err } - outstruct.State = *abi.ConvertType(out[0], new(AutomationRegistryBase23State)).(*AutomationRegistryBase23State) - outstruct.Config = *abi.ConvertType(out[1], new(AutomationRegistryBase23OnchainConfigLegacy)).(*AutomationRegistryBase23OnchainConfigLegacy) + outstruct.State = *abi.ConvertType(out[0], new(IAutomationV21PlusCommonStateLegacy)).(*IAutomationV21PlusCommonStateLegacy) + outstruct.Config = *abi.ConvertType(out[1], new(IAutomationV21PlusCommonOnchainConfigLegacy)).(*IAutomationV21PlusCommonOnchainConfigLegacy) outstruct.Signers = *abi.ConvertType(out[2], new([]common.Address)).(*[]common.Address) outstruct.Transmitters = *abi.ConvertType(out[3], new([]common.Address)).(*[]common.Address) outstruct.F = *abi.ConvertType(out[4], new(uint8)).(*uint8) @@ -939,6 +1101,28 @@ func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) Ge return _IAutomationRegistryMaster23.Contract.GetState(&_IAutomationRegistryMaster23.CallOpts) } +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) GetStorage(opts *bind.CallOpts) (AutomationRegistryBase23Storage, error) { + var out []interface{} + err := _IAutomationRegistryMaster23.contract.Call(opts, &out, "getStorage") + + if err != nil { + return *new(AutomationRegistryBase23Storage), err + } + + out0 := *abi.ConvertType(out[0], new(AutomationRegistryBase23Storage)).(*AutomationRegistryBase23Storage) + + return out0, err + +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) GetStorage() (AutomationRegistryBase23Storage, error) { + return _IAutomationRegistryMaster23.Contract.GetStorage(&_IAutomationRegistryMaster23.CallOpts) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) GetStorage() (AutomationRegistryBase23Storage, error) { + return _IAutomationRegistryMaster23.Contract.GetStorage(&_IAutomationRegistryMaster23.CallOpts) +} + func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) GetTransmitCalldataFixedBytesOverhead(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _IAutomationRegistryMaster23.contract.Call(opts, &out, "getTransmitCalldataFixedBytesOverhead") @@ -1038,25 +1222,25 @@ func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) Ge return _IAutomationRegistryMaster23.Contract.GetTriggerType(&_IAutomationRegistryMaster23.CallOpts, upkeepId) } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) GetUpkeep(opts *bind.CallOpts, id *big.Int) (AutomationRegistryBase23UpkeepInfo, error) { +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) GetUpkeep(opts *bind.CallOpts, id *big.Int) (IAutomationV21PlusCommonUpkeepInfoLegacy, error) { var out []interface{} err := _IAutomationRegistryMaster23.contract.Call(opts, &out, "getUpkeep", id) if err != nil { - return *new(AutomationRegistryBase23UpkeepInfo), err + return *new(IAutomationV21PlusCommonUpkeepInfoLegacy), err } - out0 := *abi.ConvertType(out[0], new(AutomationRegistryBase23UpkeepInfo)).(*AutomationRegistryBase23UpkeepInfo) + out0 := *abi.ConvertType(out[0], new(IAutomationV21PlusCommonUpkeepInfoLegacy)).(*IAutomationV21PlusCommonUpkeepInfoLegacy) return out0, err } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) GetUpkeep(id *big.Int) (AutomationRegistryBase23UpkeepInfo, error) { +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) GetUpkeep(id *big.Int) (IAutomationV21PlusCommonUpkeepInfoLegacy, error) { return _IAutomationRegistryMaster23.Contract.GetUpkeep(&_IAutomationRegistryMaster23.CallOpts, id) } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) GetUpkeep(id *big.Int) (AutomationRegistryBase23UpkeepInfo, error) { +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) GetUpkeep(id *big.Int) (IAutomationV21PlusCommonUpkeepInfoLegacy, error) { return _IAutomationRegistryMaster23.Contract.GetUpkeep(&_IAutomationRegistryMaster23.CallOpts, id) } @@ -1104,6 +1288,28 @@ func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) Ge return _IAutomationRegistryMaster23.Contract.GetUpkeepTriggerConfig(&_IAutomationRegistryMaster23.CallOpts, upkeepId) } +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) GetWrappedNativeTokenAddress(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _IAutomationRegistryMaster23.contract.Call(opts, &out, "getWrappedNativeTokenAddress") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) GetWrappedNativeTokenAddress() (common.Address, error) { + return _IAutomationRegistryMaster23.Contract.GetWrappedNativeTokenAddress(&_IAutomationRegistryMaster23.CallOpts) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) GetWrappedNativeTokenAddress() (common.Address, error) { + return _IAutomationRegistryMaster23.Contract.GetWrappedNativeTokenAddress(&_IAutomationRegistryMaster23.CallOpts) +} + func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) HasDedupKey(opts *bind.CallOpts, dedupKey [32]byte) (bool, error) { var out []interface{} err := _IAutomationRegistryMaster23.contract.Call(opts, &out, "hasDedupKey", dedupKey) @@ -1262,48 +1468,48 @@ func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) Si return _IAutomationRegistryMaster23.Contract.SimulatePerformUpkeep(&_IAutomationRegistryMaster23.CallOpts, id, performData) } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) TypeAndVersion(opts *bind.CallOpts) (string, error) { +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) SupportsBillingToken(opts *bind.CallOpts, token common.Address) (bool, error) { var out []interface{} - err := _IAutomationRegistryMaster23.contract.Call(opts, &out, "typeAndVersion") + err := _IAutomationRegistryMaster23.contract.Call(opts, &out, "supportsBillingToken", token) if err != nil { - return *new(string), err + return *new(bool), err } - out0 := *abi.ConvertType(out[0], new(string)).(*string) + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) return out0, err } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) TypeAndVersion() (string, error) { - return _IAutomationRegistryMaster23.Contract.TypeAndVersion(&_IAutomationRegistryMaster23.CallOpts) +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) SupportsBillingToken(token common.Address) (bool, error) { + return _IAutomationRegistryMaster23.Contract.SupportsBillingToken(&_IAutomationRegistryMaster23.CallOpts, token) } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) TypeAndVersion() (string, error) { - return _IAutomationRegistryMaster23.Contract.TypeAndVersion(&_IAutomationRegistryMaster23.CallOpts) +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) SupportsBillingToken(token common.Address) (bool, error) { + return _IAutomationRegistryMaster23.Contract.SupportsBillingToken(&_IAutomationRegistryMaster23.CallOpts, token) } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) UpkeepTranscoderVersion(opts *bind.CallOpts) (uint8, error) { +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) TypeAndVersion(opts *bind.CallOpts) (string, error) { var out []interface{} - err := _IAutomationRegistryMaster23.contract.Call(opts, &out, "upkeepTranscoderVersion") + err := _IAutomationRegistryMaster23.contract.Call(opts, &out, "typeAndVersion") if err != nil { - return *new(uint8), err + return *new(string), err } - out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + out0 := *abi.ConvertType(out[0], new(string)).(*string) return out0, err } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) UpkeepTranscoderVersion() (uint8, error) { - return _IAutomationRegistryMaster23.Contract.UpkeepTranscoderVersion(&_IAutomationRegistryMaster23.CallOpts) +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) TypeAndVersion() (string, error) { + return _IAutomationRegistryMaster23.Contract.TypeAndVersion(&_IAutomationRegistryMaster23.CallOpts) } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) UpkeepTranscoderVersion() (uint8, error) { - return _IAutomationRegistryMaster23.Contract.UpkeepTranscoderVersion(&_IAutomationRegistryMaster23.CallOpts) +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23CallerSession) TypeAndVersion() (string, error) { + return _IAutomationRegistryMaster23.Contract.TypeAndVersion(&_IAutomationRegistryMaster23.CallOpts) } func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Caller) UpkeepVersion(opts *bind.CallOpts) (uint8, error) { @@ -1388,6 +1594,18 @@ func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23TransactorSession return _IAutomationRegistryMaster23.Contract.CancelUpkeep(&_IAutomationRegistryMaster23.TransactOpts, id) } +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Transactor) DisableOffchainPayments(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.contract.Transact(opts, "disableOffchainPayments") +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) DisableOffchainPayments() (*types.Transaction, error) { + return _IAutomationRegistryMaster23.Contract.DisableOffchainPayments(&_IAutomationRegistryMaster23.TransactOpts) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23TransactorSession) DisableOffchainPayments() (*types.Transaction, error) { + return _IAutomationRegistryMaster23.Contract.DisableOffchainPayments(&_IAutomationRegistryMaster23.TransactOpts) +} + func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Transactor) ExecuteCallback(opts *bind.TransactOpts, id *big.Int, payload []byte) (*types.Transaction, error) { return _IAutomationRegistryMaster23.contract.Transact(opts, "executeCallback", id, payload) } @@ -1460,28 +1678,28 @@ func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23TransactorSession return _IAutomationRegistryMaster23.Contract.ReceiveUpkeeps(&_IAutomationRegistryMaster23.TransactOpts, encodedUpkeeps) } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Transactor) RegisterUpkeep(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { - return _IAutomationRegistryMaster23.contract.Transact(opts, "registerUpkeep", target, gasLimit, admin, triggerType, checkData, triggerConfig, offchainConfig) +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Transactor) RegisterUpkeep(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, billingToken common.Address, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.contract.Transact(opts, "registerUpkeep", target, gasLimit, admin, triggerType, billingToken, checkData, triggerConfig, offchainConfig) } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) RegisterUpkeep(target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { - return _IAutomationRegistryMaster23.Contract.RegisterUpkeep(&_IAutomationRegistryMaster23.TransactOpts, target, gasLimit, admin, triggerType, checkData, triggerConfig, offchainConfig) +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) RegisterUpkeep(target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, billingToken common.Address, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.Contract.RegisterUpkeep(&_IAutomationRegistryMaster23.TransactOpts, target, gasLimit, admin, triggerType, billingToken, checkData, triggerConfig, offchainConfig) } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23TransactorSession) RegisterUpkeep(target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { - return _IAutomationRegistryMaster23.Contract.RegisterUpkeep(&_IAutomationRegistryMaster23.TransactOpts, target, gasLimit, admin, triggerType, checkData, triggerConfig, offchainConfig) +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23TransactorSession) RegisterUpkeep(target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, billingToken common.Address, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.Contract.RegisterUpkeep(&_IAutomationRegistryMaster23.TransactOpts, target, gasLimit, admin, triggerType, billingToken, checkData, triggerConfig, offchainConfig) } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Transactor) RegisterUpkeep0(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) { - return _IAutomationRegistryMaster23.contract.Transact(opts, "registerUpkeep0", target, gasLimit, admin, checkData, offchainConfig) +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Transactor) RemoveBillingOverrides(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.contract.Transact(opts, "removeBillingOverrides", id) } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) RegisterUpkeep0(target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) { - return _IAutomationRegistryMaster23.Contract.RegisterUpkeep0(&_IAutomationRegistryMaster23.TransactOpts, target, gasLimit, admin, checkData, offchainConfig) +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) RemoveBillingOverrides(id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.Contract.RemoveBillingOverrides(&_IAutomationRegistryMaster23.TransactOpts, id) } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23TransactorSession) RegisterUpkeep0(target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) { - return _IAutomationRegistryMaster23.Contract.RegisterUpkeep0(&_IAutomationRegistryMaster23.TransactOpts, target, gasLimit, admin, checkData, offchainConfig) +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23TransactorSession) RemoveBillingOverrides(id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.Contract.RemoveBillingOverrides(&_IAutomationRegistryMaster23.TransactOpts, id) } func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Transactor) SetAdminPrivilegeConfig(opts *bind.TransactOpts, admin common.Address, newPrivilegeConfig []byte) (*types.Transaction, error) { @@ -1496,6 +1714,18 @@ func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23TransactorSession return _IAutomationRegistryMaster23.Contract.SetAdminPrivilegeConfig(&_IAutomationRegistryMaster23.TransactOpts, admin, newPrivilegeConfig) } +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Transactor) SetBillingOverrides(opts *bind.TransactOpts, id *big.Int, billingOverrides AutomationRegistryBase23BillingOverrides) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.contract.Transact(opts, "setBillingOverrides", id, billingOverrides) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) SetBillingOverrides(id *big.Int, billingOverrides AutomationRegistryBase23BillingOverrides) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.Contract.SetBillingOverrides(&_IAutomationRegistryMaster23.TransactOpts, id, billingOverrides) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23TransactorSession) SetBillingOverrides(id *big.Int, billingOverrides AutomationRegistryBase23BillingOverrides) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.Contract.SetBillingOverrides(&_IAutomationRegistryMaster23.TransactOpts, id, billingOverrides) +} + func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Transactor) SetConfig(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfigBytes []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { return _IAutomationRegistryMaster23.contract.Transact(opts, "setConfig", signers, transmitters, f, onchainConfigBytes, offchainConfigVersion, offchainConfig) } @@ -1604,6 +1834,18 @@ func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23TransactorSession return _IAutomationRegistryMaster23.Contract.SetUpkeepTriggerConfig(&_IAutomationRegistryMaster23.TransactOpts, id, triggerConfig) } +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Transactor) SettleNOPsOffchain(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.contract.Transact(opts, "settleNOPsOffchain") +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) SettleNOPsOffchain() (*types.Transaction, error) { + return _IAutomationRegistryMaster23.Contract.SettleNOPsOffchain(&_IAutomationRegistryMaster23.TransactOpts) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23TransactorSession) SettleNOPsOffchain() (*types.Transaction, error) { + return _IAutomationRegistryMaster23.Contract.SettleNOPsOffchain(&_IAutomationRegistryMaster23.TransactOpts) +} + func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Transactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { return _IAutomationRegistryMaster23.contract.Transact(opts, "transferOwnership", to) } @@ -1676,68 +1918,324 @@ func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23TransactorSession return _IAutomationRegistryMaster23.Contract.UnpauseUpkeep(&_IAutomationRegistryMaster23.TransactOpts, id) } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Transactor) WithdrawERC20Fees(opts *bind.TransactOpts, assetAddress common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { - return _IAutomationRegistryMaster23.contract.Transact(opts, "withdrawERC20Fees", assetAddress, to, amount) +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Transactor) WithdrawERC20Fees(opts *bind.TransactOpts, asset common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.contract.Transact(opts, "withdrawERC20Fees", asset, to, amount) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) WithdrawERC20Fees(asset common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.Contract.WithdrawERC20Fees(&_IAutomationRegistryMaster23.TransactOpts, asset, to, amount) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23TransactorSession) WithdrawERC20Fees(asset common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.Contract.WithdrawERC20Fees(&_IAutomationRegistryMaster23.TransactOpts, asset, to, amount) } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) WithdrawERC20Fees(assetAddress common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { - return _IAutomationRegistryMaster23.Contract.WithdrawERC20Fees(&_IAutomationRegistryMaster23.TransactOpts, assetAddress, to, amount) +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Transactor) WithdrawFunds(opts *bind.TransactOpts, id *big.Int, to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.contract.Transact(opts, "withdrawFunds", id, to) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) WithdrawFunds(id *big.Int, to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.Contract.WithdrawFunds(&_IAutomationRegistryMaster23.TransactOpts, id, to) } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23TransactorSession) WithdrawERC20Fees(assetAddress common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { - return _IAutomationRegistryMaster23.Contract.WithdrawERC20Fees(&_IAutomationRegistryMaster23.TransactOpts, assetAddress, to, amount) +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23TransactorSession) WithdrawFunds(id *big.Int, to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.Contract.WithdrawFunds(&_IAutomationRegistryMaster23.TransactOpts, id, to) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Transactor) WithdrawLink(opts *bind.TransactOpts, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.contract.Transact(opts, "withdrawLink", to, amount) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) WithdrawLink(to common.Address, amount *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.Contract.WithdrawLink(&_IAutomationRegistryMaster23.TransactOpts, to, amount) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23TransactorSession) WithdrawLink(to common.Address, amount *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.Contract.WithdrawLink(&_IAutomationRegistryMaster23.TransactOpts, to, amount) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Transactor) WithdrawPayment(opts *bind.TransactOpts, from common.Address, to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.contract.Transact(opts, "withdrawPayment", from, to) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) WithdrawPayment(from common.Address, to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.Contract.WithdrawPayment(&_IAutomationRegistryMaster23.TransactOpts, from, to) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23TransactorSession) WithdrawPayment(from common.Address, to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.Contract.WithdrawPayment(&_IAutomationRegistryMaster23.TransactOpts, from, to) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Transactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.contract.RawTransact(opts, calldata) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) Fallback(calldata []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.Contract.Fallback(&_IAutomationRegistryMaster23.TransactOpts, calldata) +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23TransactorSession) Fallback(calldata []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster23.Contract.Fallback(&_IAutomationRegistryMaster23.TransactOpts, calldata) +} + +type IAutomationRegistryMaster23AdminPrivilegeConfigSetIterator struct { + Event *IAutomationRegistryMaster23AdminPrivilegeConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMaster23AdminPrivilegeConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMaster23AdminPrivilegeConfigSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMaster23AdminPrivilegeConfigSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *IAutomationRegistryMaster23AdminPrivilegeConfigSetIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMaster23AdminPrivilegeConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMaster23AdminPrivilegeConfigSet struct { + Admin common.Address + PrivilegeConfig []byte + Raw types.Log +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Filterer) FilterAdminPrivilegeConfigSet(opts *bind.FilterOpts, admin []common.Address) (*IAutomationRegistryMaster23AdminPrivilegeConfigSetIterator, error) { + + var adminRule []interface{} + for _, adminItem := range admin { + adminRule = append(adminRule, adminItem) + } + + logs, sub, err := _IAutomationRegistryMaster23.contract.FilterLogs(opts, "AdminPrivilegeConfigSet", adminRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMaster23AdminPrivilegeConfigSetIterator{contract: _IAutomationRegistryMaster23.contract, event: "AdminPrivilegeConfigSet", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Filterer) WatchAdminPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMaster23AdminPrivilegeConfigSet, admin []common.Address) (event.Subscription, error) { + + var adminRule []interface{} + for _, adminItem := range admin { + adminRule = append(adminRule, adminItem) + } + + logs, sub, err := _IAutomationRegistryMaster23.contract.WatchLogs(opts, "AdminPrivilegeConfigSet", adminRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMaster23AdminPrivilegeConfigSet) + if err := _IAutomationRegistryMaster23.contract.UnpackLog(event, "AdminPrivilegeConfigSet", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Filterer) ParseAdminPrivilegeConfigSet(log types.Log) (*IAutomationRegistryMaster23AdminPrivilegeConfigSet, error) { + event := new(IAutomationRegistryMaster23AdminPrivilegeConfigSet) + if err := _IAutomationRegistryMaster23.contract.UnpackLog(event, "AdminPrivilegeConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMaster23BillingConfigOverriddenIterator struct { + Event *IAutomationRegistryMaster23BillingConfigOverridden + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMaster23BillingConfigOverriddenIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMaster23BillingConfigOverridden) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMaster23BillingConfigOverridden) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Transactor) WithdrawFunds(opts *bind.TransactOpts, id *big.Int, to common.Address) (*types.Transaction, error) { - return _IAutomationRegistryMaster23.contract.Transact(opts, "withdrawFunds", id, to) +func (it *IAutomationRegistryMaster23BillingConfigOverriddenIterator) Error() error { + return it.fail } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) WithdrawFunds(id *big.Int, to common.Address) (*types.Transaction, error) { - return _IAutomationRegistryMaster23.Contract.WithdrawFunds(&_IAutomationRegistryMaster23.TransactOpts, id, to) +func (it *IAutomationRegistryMaster23BillingConfigOverriddenIterator) Close() error { + it.sub.Unsubscribe() + return nil } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23TransactorSession) WithdrawFunds(id *big.Int, to common.Address) (*types.Transaction, error) { - return _IAutomationRegistryMaster23.Contract.WithdrawFunds(&_IAutomationRegistryMaster23.TransactOpts, id, to) +type IAutomationRegistryMaster23BillingConfigOverridden struct { + Id *big.Int + Overrides AutomationRegistryBase23BillingOverrides + Raw types.Log } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Transactor) WithdrawLinkFees(opts *bind.TransactOpts, to common.Address, amount *big.Int) (*types.Transaction, error) { - return _IAutomationRegistryMaster23.contract.Transact(opts, "withdrawLinkFees", to, amount) -} +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Filterer) FilterBillingConfigOverridden(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMaster23BillingConfigOverriddenIterator, error) { -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) WithdrawLinkFees(to common.Address, amount *big.Int) (*types.Transaction, error) { - return _IAutomationRegistryMaster23.Contract.WithdrawLinkFees(&_IAutomationRegistryMaster23.TransactOpts, to, amount) -} + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23TransactorSession) WithdrawLinkFees(to common.Address, amount *big.Int) (*types.Transaction, error) { - return _IAutomationRegistryMaster23.Contract.WithdrawLinkFees(&_IAutomationRegistryMaster23.TransactOpts, to, amount) + logs, sub, err := _IAutomationRegistryMaster23.contract.FilterLogs(opts, "BillingConfigOverridden", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMaster23BillingConfigOverriddenIterator{contract: _IAutomationRegistryMaster23.contract, event: "BillingConfigOverridden", logs: logs, sub: sub}, nil } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Transactor) WithdrawPayment(opts *bind.TransactOpts, from common.Address, to common.Address) (*types.Transaction, error) { - return _IAutomationRegistryMaster23.contract.Transact(opts, "withdrawPayment", from, to) -} +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Filterer) WatchBillingConfigOverridden(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMaster23BillingConfigOverridden, id []*big.Int) (event.Subscription, error) { -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) WithdrawPayment(from common.Address, to common.Address) (*types.Transaction, error) { - return _IAutomationRegistryMaster23.Contract.WithdrawPayment(&_IAutomationRegistryMaster23.TransactOpts, from, to) -} + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23TransactorSession) WithdrawPayment(from common.Address, to common.Address) (*types.Transaction, error) { - return _IAutomationRegistryMaster23.Contract.WithdrawPayment(&_IAutomationRegistryMaster23.TransactOpts, from, to) -} + logs, sub, err := _IAutomationRegistryMaster23.contract.WatchLogs(opts, "BillingConfigOverridden", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Transactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) { - return _IAutomationRegistryMaster23.contract.RawTransact(opts, calldata) -} + event := new(IAutomationRegistryMaster23BillingConfigOverridden) + if err := _IAutomationRegistryMaster23.contract.UnpackLog(event, "BillingConfigOverridden", log); err != nil { + return err + } + event.Raw = log -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Session) Fallback(calldata []byte) (*types.Transaction, error) { - return _IAutomationRegistryMaster23.Contract.Fallback(&_IAutomationRegistryMaster23.TransactOpts, calldata) + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23TransactorSession) Fallback(calldata []byte) (*types.Transaction, error) { - return _IAutomationRegistryMaster23.Contract.Fallback(&_IAutomationRegistryMaster23.TransactOpts, calldata) +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Filterer) ParseBillingConfigOverridden(log types.Log) (*IAutomationRegistryMaster23BillingConfigOverridden, error) { + event := new(IAutomationRegistryMaster23BillingConfigOverridden) + if err := _IAutomationRegistryMaster23.contract.UnpackLog(event, "BillingConfigOverridden", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil } -type IAutomationRegistryMaster23AdminPrivilegeConfigSetIterator struct { - Event *IAutomationRegistryMaster23AdminPrivilegeConfigSet +type IAutomationRegistryMaster23BillingConfigOverrideRemovedIterator struct { + Event *IAutomationRegistryMaster23BillingConfigOverrideRemoved contract *bind.BoundContract event string @@ -1748,7 +2246,7 @@ type IAutomationRegistryMaster23AdminPrivilegeConfigSetIterator struct { fail error } -func (it *IAutomationRegistryMaster23AdminPrivilegeConfigSetIterator) Next() bool { +func (it *IAutomationRegistryMaster23BillingConfigOverrideRemovedIterator) Next() bool { if it.fail != nil { return false @@ -1757,7 +2255,7 @@ func (it *IAutomationRegistryMaster23AdminPrivilegeConfigSetIterator) Next() boo if it.done { select { case log := <-it.logs: - it.Event = new(IAutomationRegistryMaster23AdminPrivilegeConfigSet) + it.Event = new(IAutomationRegistryMaster23BillingConfigOverrideRemoved) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -1772,7 +2270,7 @@ func (it *IAutomationRegistryMaster23AdminPrivilegeConfigSetIterator) Next() boo select { case log := <-it.logs: - it.Event = new(IAutomationRegistryMaster23AdminPrivilegeConfigSet) + it.Event = new(IAutomationRegistryMaster23BillingConfigOverrideRemoved) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -1787,43 +2285,42 @@ func (it *IAutomationRegistryMaster23AdminPrivilegeConfigSetIterator) Next() boo } } -func (it *IAutomationRegistryMaster23AdminPrivilegeConfigSetIterator) Error() error { +func (it *IAutomationRegistryMaster23BillingConfigOverrideRemovedIterator) Error() error { return it.fail } -func (it *IAutomationRegistryMaster23AdminPrivilegeConfigSetIterator) Close() error { +func (it *IAutomationRegistryMaster23BillingConfigOverrideRemovedIterator) Close() error { it.sub.Unsubscribe() return nil } -type IAutomationRegistryMaster23AdminPrivilegeConfigSet struct { - Admin common.Address - PrivilegeConfig []byte - Raw types.Log +type IAutomationRegistryMaster23BillingConfigOverrideRemoved struct { + Id *big.Int + Raw types.Log } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Filterer) FilterAdminPrivilegeConfigSet(opts *bind.FilterOpts, admin []common.Address) (*IAutomationRegistryMaster23AdminPrivilegeConfigSetIterator, error) { +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Filterer) FilterBillingConfigOverrideRemoved(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMaster23BillingConfigOverrideRemovedIterator, error) { - var adminRule []interface{} - for _, adminItem := range admin { - adminRule = append(adminRule, adminItem) + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) } - logs, sub, err := _IAutomationRegistryMaster23.contract.FilterLogs(opts, "AdminPrivilegeConfigSet", adminRule) + logs, sub, err := _IAutomationRegistryMaster23.contract.FilterLogs(opts, "BillingConfigOverrideRemoved", idRule) if err != nil { return nil, err } - return &IAutomationRegistryMaster23AdminPrivilegeConfigSetIterator{contract: _IAutomationRegistryMaster23.contract, event: "AdminPrivilegeConfigSet", logs: logs, sub: sub}, nil + return &IAutomationRegistryMaster23BillingConfigOverrideRemovedIterator{contract: _IAutomationRegistryMaster23.contract, event: "BillingConfigOverrideRemoved", logs: logs, sub: sub}, nil } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Filterer) WatchAdminPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMaster23AdminPrivilegeConfigSet, admin []common.Address) (event.Subscription, error) { +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Filterer) WatchBillingConfigOverrideRemoved(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMaster23BillingConfigOverrideRemoved, id []*big.Int) (event.Subscription, error) { - var adminRule []interface{} - for _, adminItem := range admin { - adminRule = append(adminRule, adminItem) + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) } - logs, sub, err := _IAutomationRegistryMaster23.contract.WatchLogs(opts, "AdminPrivilegeConfigSet", adminRule) + logs, sub, err := _IAutomationRegistryMaster23.contract.WatchLogs(opts, "BillingConfigOverrideRemoved", idRule) if err != nil { return nil, err } @@ -1833,8 +2330,8 @@ func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Filterer) WatchAd select { case log := <-logs: - event := new(IAutomationRegistryMaster23AdminPrivilegeConfigSet) - if err := _IAutomationRegistryMaster23.contract.UnpackLog(event, "AdminPrivilegeConfigSet", log); err != nil { + event := new(IAutomationRegistryMaster23BillingConfigOverrideRemoved) + if err := _IAutomationRegistryMaster23.contract.UnpackLog(event, "BillingConfigOverrideRemoved", log); err != nil { return err } event.Raw = log @@ -1855,9 +2352,9 @@ func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Filterer) WatchAd }), nil } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Filterer) ParseAdminPrivilegeConfigSet(log types.Log) (*IAutomationRegistryMaster23AdminPrivilegeConfigSet, error) { - event := new(IAutomationRegistryMaster23AdminPrivilegeConfigSet) - if err := _IAutomationRegistryMaster23.contract.UnpackLog(event, "AdminPrivilegeConfigSet", log); err != nil { +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Filterer) ParseBillingConfigOverrideRemoved(log types.Log) (*IAutomationRegistryMaster23BillingConfigOverrideRemoved, error) { + event := new(IAutomationRegistryMaster23BillingConfigOverrideRemoved) + if err := _IAutomationRegistryMaster23.contract.UnpackLog(event, "BillingConfigOverrideRemoved", log); err != nil { return nil, err } event.Raw = log @@ -2550,42 +3047,42 @@ func (it *IAutomationRegistryMaster23FeesWithdrawnIterator) Close() error { } type IAutomationRegistryMaster23FeesWithdrawn struct { - Recipient common.Address AssetAddress common.Address + Recipient common.Address Amount *big.Int Raw types.Log } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Filterer) FilterFeesWithdrawn(opts *bind.FilterOpts, recipient []common.Address, assetAddress []common.Address) (*IAutomationRegistryMaster23FeesWithdrawnIterator, error) { +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Filterer) FilterFeesWithdrawn(opts *bind.FilterOpts, assetAddress []common.Address, recipient []common.Address) (*IAutomationRegistryMaster23FeesWithdrawnIterator, error) { - var recipientRule []interface{} - for _, recipientItem := range recipient { - recipientRule = append(recipientRule, recipientItem) - } var assetAddressRule []interface{} for _, assetAddressItem := range assetAddress { assetAddressRule = append(assetAddressRule, assetAddressItem) } + var recipientRule []interface{} + for _, recipientItem := range recipient { + recipientRule = append(recipientRule, recipientItem) + } - logs, sub, err := _IAutomationRegistryMaster23.contract.FilterLogs(opts, "FeesWithdrawn", recipientRule, assetAddressRule) + logs, sub, err := _IAutomationRegistryMaster23.contract.FilterLogs(opts, "FeesWithdrawn", assetAddressRule, recipientRule) if err != nil { return nil, err } return &IAutomationRegistryMaster23FeesWithdrawnIterator{contract: _IAutomationRegistryMaster23.contract, event: "FeesWithdrawn", logs: logs, sub: sub}, nil } -func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Filterer) WatchFeesWithdrawn(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMaster23FeesWithdrawn, recipient []common.Address, assetAddress []common.Address) (event.Subscription, error) { +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Filterer) WatchFeesWithdrawn(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMaster23FeesWithdrawn, assetAddress []common.Address, recipient []common.Address) (event.Subscription, error) { - var recipientRule []interface{} - for _, recipientItem := range recipient { - recipientRule = append(recipientRule, recipientItem) - } var assetAddressRule []interface{} for _, assetAddressItem := range assetAddress { assetAddressRule = append(assetAddressRule, assetAddressItem) } + var recipientRule []interface{} + for _, recipientItem := range recipient { + recipientRule = append(recipientRule, recipientItem) + } - logs, sub, err := _IAutomationRegistryMaster23.contract.WatchLogs(opts, "FeesWithdrawn", recipientRule, assetAddressRule) + logs, sub, err := _IAutomationRegistryMaster23.contract.WatchLogs(opts, "FeesWithdrawn", assetAddressRule, recipientRule) if err != nil { return nil, err } @@ -3020,6 +3517,124 @@ func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Filterer) ParseIn return event, nil } +type IAutomationRegistryMaster23NOPsSettledOffchainIterator struct { + Event *IAutomationRegistryMaster23NOPsSettledOffchain + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMaster23NOPsSettledOffchainIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMaster23NOPsSettledOffchain) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMaster23NOPsSettledOffchain) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *IAutomationRegistryMaster23NOPsSettledOffchainIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMaster23NOPsSettledOffchainIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMaster23NOPsSettledOffchain struct { + Payees []common.Address + Payments []*big.Int + Raw types.Log +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Filterer) FilterNOPsSettledOffchain(opts *bind.FilterOpts) (*IAutomationRegistryMaster23NOPsSettledOffchainIterator, error) { + + logs, sub, err := _IAutomationRegistryMaster23.contract.FilterLogs(opts, "NOPsSettledOffchain") + if err != nil { + return nil, err + } + return &IAutomationRegistryMaster23NOPsSettledOffchainIterator{contract: _IAutomationRegistryMaster23.contract, event: "NOPsSettledOffchain", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Filterer) WatchNOPsSettledOffchain(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMaster23NOPsSettledOffchain) (event.Subscription, error) { + + logs, sub, err := _IAutomationRegistryMaster23.contract.WatchLogs(opts, "NOPsSettledOffchain") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMaster23NOPsSettledOffchain) + if err := _IAutomationRegistryMaster23.contract.UnpackLog(event, "NOPsSettledOffchain", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23Filterer) ParseNOPsSettledOffchain(log types.Log) (*IAutomationRegistryMaster23NOPsSettledOffchain, error) { + event := new(IAutomationRegistryMaster23NOPsSettledOffchain) + if err := _IAutomationRegistryMaster23.contract.UnpackLog(event, "NOPsSettledOffchain", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + type IAutomationRegistryMaster23OwnershipTransferRequestedIterator struct { Event *IAutomationRegistryMaster23OwnershipTransferRequested @@ -6330,8 +6945,8 @@ type GetSignerInfo struct { Index uint8 } type GetState struct { - State AutomationRegistryBase23State - Config AutomationRegistryBase23OnchainConfigLegacy + State IAutomationV21PlusCommonStateLegacy + Config IAutomationV21PlusCommonOnchainConfigLegacy Signers []common.Address Transmitters []common.Address F uint8 @@ -6362,6 +6977,10 @@ func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23) ParseLog(log ty switch log.Topics[0] { case _IAutomationRegistryMaster23.abi.Events["AdminPrivilegeConfigSet"].ID: return _IAutomationRegistryMaster23.ParseAdminPrivilegeConfigSet(log) + case _IAutomationRegistryMaster23.abi.Events["BillingConfigOverridden"].ID: + return _IAutomationRegistryMaster23.ParseBillingConfigOverridden(log) + case _IAutomationRegistryMaster23.abi.Events["BillingConfigOverrideRemoved"].ID: + return _IAutomationRegistryMaster23.ParseBillingConfigOverrideRemoved(log) case _IAutomationRegistryMaster23.abi.Events["BillingConfigSet"].ID: return _IAutomationRegistryMaster23.ParseBillingConfigSet(log) case _IAutomationRegistryMaster23.abi.Events["CancelledUpkeepReport"].ID: @@ -6380,6 +6999,8 @@ func (_IAutomationRegistryMaster23 *IAutomationRegistryMaster23) ParseLog(log ty return _IAutomationRegistryMaster23.ParseFundsWithdrawn(log) case _IAutomationRegistryMaster23.abi.Events["InsufficientFundsUpkeepReport"].ID: return _IAutomationRegistryMaster23.ParseInsufficientFundsUpkeepReport(log) + case _IAutomationRegistryMaster23.abi.Events["NOPsSettledOffchain"].ID: + return _IAutomationRegistryMaster23.ParseNOPsSettledOffchain(log) case _IAutomationRegistryMaster23.abi.Events["OwnershipTransferRequested"].ID: return _IAutomationRegistryMaster23.ParseOwnershipTransferRequested(log) case _IAutomationRegistryMaster23.abi.Events["OwnershipTransferred"].ID: @@ -6440,8 +7061,16 @@ func (IAutomationRegistryMaster23AdminPrivilegeConfigSet) Topic() common.Hash { return common.HexToHash("0x7c44b4eb59ee7873514e7e43e7718c269d872965938b288aa143befca62f99d2") } +func (IAutomationRegistryMaster23BillingConfigOverridden) Topic() common.Hash { + return common.HexToHash("0xd8a6d79d170a55968079d3a89b960d86b4442aef6aac1d01e644c32b9e38b340") +} + +func (IAutomationRegistryMaster23BillingConfigOverrideRemoved) Topic() common.Hash { + return common.HexToHash("0x97d0ef3f46a56168af653f547bdb6f77ec2b1d7d9bc6ba0193c2b340ec68064a") +} + func (IAutomationRegistryMaster23BillingConfigSet) Topic() common.Hash { - return common.HexToHash("0x5ff767a3a5dbf1ef088ebf56e221e9cea40ad357c31ba060c2f31244cefab7c1") + return common.HexToHash("0x720a5849025dc4fd0061aed1bb30efd713cde64ce7f8d807953ecca27c8f143c") } func (IAutomationRegistryMaster23CancelledUpkeepReport) Topic() common.Hash { @@ -6476,6 +7105,10 @@ func (IAutomationRegistryMaster23InsufficientFundsUpkeepReport) Topic() common.H return common.HexToHash("0x377c8b0c126ae5248d27aca1c76fac4608aff85673ee3caf09747e1044549e02") } +func (IAutomationRegistryMaster23NOPsSettledOffchain) Topic() common.Hash { + return common.HexToHash("0x5af23b715253628d12b660b27a4f3fc626562ea8a55040aa99ab3dc178989fad") +} + func (IAutomationRegistryMaster23OwnershipTransferRequested) Topic() common.Hash { return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") } @@ -6605,6 +7238,8 @@ type IAutomationRegistryMaster23Interface interface { GetBalance(opts *bind.CallOpts, id *big.Int) (*big.Int, error) + GetBillingToken(opts *bind.CallOpts, upkeepID *big.Int) (common.Address, error) + GetBillingTokenConfig(opts *bind.CallOpts, token common.Address) (AutomationRegistryBase23BillingConfig, error) GetBillingTokens(opts *bind.CallOpts) ([]common.Address, error) @@ -6615,19 +7250,23 @@ type IAutomationRegistryMaster23Interface interface { GetConditionalGasOverhead(opts *bind.CallOpts) (*big.Int, error) + GetConfig(opts *bind.CallOpts) (AutomationRegistryBase23OnchainConfig, error) + GetFallbackNativePrice(opts *bind.CallOpts) (*big.Int, error) GetFastGasFeedAddress(opts *bind.CallOpts) (common.Address, error) GetForwarder(opts *bind.CallOpts, upkeepID *big.Int) (common.Address, error) + GetHotVars(opts *bind.CallOpts) (AutomationRegistryBase23HotVars, error) + GetLinkAddress(opts *bind.CallOpts) (common.Address, error) GetLinkUSDFeedAddress(opts *bind.CallOpts) (common.Address, error) GetLogGasOverhead(opts *bind.CallOpts) (*big.Int, error) - GetMaxPaymentForGas(opts *bind.CallOpts, triggerType uint8, gasLimit uint32) (*big.Int, error) + GetMaxPaymentForGas(opts *bind.CallOpts, id *big.Int, triggerType uint8, gasLimit uint32, billingToken common.Address) (*big.Int, error) GetMinBalance(opts *bind.CallOpts, id *big.Int) (*big.Int, error) @@ -6635,6 +7274,10 @@ type IAutomationRegistryMaster23Interface interface { GetNativeUSDFeedAddress(opts *bind.CallOpts) (common.Address, error) + GetNumUpkeeps(opts *bind.CallOpts) (*big.Int, error) + + GetPayoutMode(opts *bind.CallOpts) (uint8, error) + GetPeerRegistryMigrationPermission(opts *bind.CallOpts, peer common.Address) (uint8, error) GetPerPerformByteGasOverhead(opts *bind.CallOpts) (*big.Int, error) @@ -6643,6 +7286,8 @@ type IAutomationRegistryMaster23Interface interface { GetReorgProtectionEnabled(opts *bind.CallOpts) (bool, error) + GetReserveAmount(opts *bind.CallOpts, billingToken common.Address) (*big.Int, error) + GetSignerInfo(opts *bind.CallOpts, query common.Address) (GetSignerInfo, error) @@ -6651,6 +7296,8 @@ type IAutomationRegistryMaster23Interface interface { error) + GetStorage(opts *bind.CallOpts) (AutomationRegistryBase23Storage, error) + GetTransmitCalldataFixedBytesOverhead(opts *bind.CallOpts) (*big.Int, error) GetTransmitCalldataPerSignerBytesOverhead(opts *bind.CallOpts) (*big.Int, error) @@ -6661,12 +7308,14 @@ type IAutomationRegistryMaster23Interface interface { GetTriggerType(opts *bind.CallOpts, upkeepId *big.Int) (uint8, error) - GetUpkeep(opts *bind.CallOpts, id *big.Int) (AutomationRegistryBase23UpkeepInfo, error) + GetUpkeep(opts *bind.CallOpts, id *big.Int) (IAutomationV21PlusCommonUpkeepInfoLegacy, error) GetUpkeepPrivilegeConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) GetUpkeepTriggerConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) + GetWrappedNativeTokenAddress(opts *bind.CallOpts) (common.Address, error) + HasDedupKey(opts *bind.CallOpts, dedupKey [32]byte) (bool, error) LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails, @@ -6685,9 +7334,9 @@ type IAutomationRegistryMaster23Interface interface { error) - TypeAndVersion(opts *bind.CallOpts) (string, error) + SupportsBillingToken(opts *bind.CallOpts, token common.Address) (bool, error) - UpkeepTranscoderVersion(opts *bind.CallOpts) (uint8, error) + TypeAndVersion(opts *bind.CallOpts) (string, error) UpkeepVersion(opts *bind.CallOpts) (uint8, error) @@ -6701,6 +7350,8 @@ type IAutomationRegistryMaster23Interface interface { CancelUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) + DisableOffchainPayments(opts *bind.TransactOpts) (*types.Transaction, error) + ExecuteCallback(opts *bind.TransactOpts, id *big.Int, payload []byte) (*types.Transaction, error) MigrateUpkeeps(opts *bind.TransactOpts, ids []*big.Int, destination common.Address) (*types.Transaction, error) @@ -6713,12 +7364,14 @@ type IAutomationRegistryMaster23Interface interface { ReceiveUpkeeps(opts *bind.TransactOpts, encodedUpkeeps []byte) (*types.Transaction, error) - RegisterUpkeep(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) + RegisterUpkeep(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, billingToken common.Address, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) - RegisterUpkeep0(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) + RemoveBillingOverrides(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) SetAdminPrivilegeConfig(opts *bind.TransactOpts, admin common.Address, newPrivilegeConfig []byte) (*types.Transaction, error) + SetBillingOverrides(opts *bind.TransactOpts, id *big.Int, billingOverrides AutomationRegistryBase23BillingOverrides) (*types.Transaction, error) + SetConfig(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfigBytes []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) SetConfigTypeSafe(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig AutomationRegistryBase23OnchainConfig, offchainConfigVersion uint64, offchainConfig []byte, billingTokens []common.Address, billingConfigs []AutomationRegistryBase23BillingConfig) (*types.Transaction, error) @@ -6737,6 +7390,8 @@ type IAutomationRegistryMaster23Interface interface { SetUpkeepTriggerConfig(opts *bind.TransactOpts, id *big.Int, triggerConfig []byte) (*types.Transaction, error) + SettleNOPsOffchain(opts *bind.TransactOpts) (*types.Transaction, error) + TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) TransferPayeeship(opts *bind.TransactOpts, transmitter common.Address, proposed common.Address) (*types.Transaction, error) @@ -6749,11 +7404,11 @@ type IAutomationRegistryMaster23Interface interface { UnpauseUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) - WithdrawERC20Fees(opts *bind.TransactOpts, assetAddress common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) + WithdrawERC20Fees(opts *bind.TransactOpts, asset common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) WithdrawFunds(opts *bind.TransactOpts, id *big.Int, to common.Address) (*types.Transaction, error) - WithdrawLinkFees(opts *bind.TransactOpts, to common.Address, amount *big.Int) (*types.Transaction, error) + WithdrawLink(opts *bind.TransactOpts, to common.Address, amount *big.Int) (*types.Transaction, error) WithdrawPayment(opts *bind.TransactOpts, from common.Address, to common.Address) (*types.Transaction, error) @@ -6765,6 +7420,18 @@ type IAutomationRegistryMaster23Interface interface { ParseAdminPrivilegeConfigSet(log types.Log) (*IAutomationRegistryMaster23AdminPrivilegeConfigSet, error) + FilterBillingConfigOverridden(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMaster23BillingConfigOverriddenIterator, error) + + WatchBillingConfigOverridden(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMaster23BillingConfigOverridden, id []*big.Int) (event.Subscription, error) + + ParseBillingConfigOverridden(log types.Log) (*IAutomationRegistryMaster23BillingConfigOverridden, error) + + FilterBillingConfigOverrideRemoved(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMaster23BillingConfigOverrideRemovedIterator, error) + + WatchBillingConfigOverrideRemoved(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMaster23BillingConfigOverrideRemoved, id []*big.Int) (event.Subscription, error) + + ParseBillingConfigOverrideRemoved(log types.Log) (*IAutomationRegistryMaster23BillingConfigOverrideRemoved, error) + FilterBillingConfigSet(opts *bind.FilterOpts, token []common.Address) (*IAutomationRegistryMaster23BillingConfigSetIterator, error) WatchBillingConfigSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMaster23BillingConfigSet, token []common.Address) (event.Subscription, error) @@ -6795,9 +7462,9 @@ type IAutomationRegistryMaster23Interface interface { ParseDedupKeyAdded(log types.Log) (*IAutomationRegistryMaster23DedupKeyAdded, error) - FilterFeesWithdrawn(opts *bind.FilterOpts, recipient []common.Address, assetAddress []common.Address) (*IAutomationRegistryMaster23FeesWithdrawnIterator, error) + FilterFeesWithdrawn(opts *bind.FilterOpts, assetAddress []common.Address, recipient []common.Address) (*IAutomationRegistryMaster23FeesWithdrawnIterator, error) - WatchFeesWithdrawn(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMaster23FeesWithdrawn, recipient []common.Address, assetAddress []common.Address) (event.Subscription, error) + WatchFeesWithdrawn(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMaster23FeesWithdrawn, assetAddress []common.Address, recipient []common.Address) (event.Subscription, error) ParseFeesWithdrawn(log types.Log) (*IAutomationRegistryMaster23FeesWithdrawn, error) @@ -6819,6 +7486,12 @@ type IAutomationRegistryMaster23Interface interface { ParseInsufficientFundsUpkeepReport(log types.Log) (*IAutomationRegistryMaster23InsufficientFundsUpkeepReport, error) + FilterNOPsSettledOffchain(opts *bind.FilterOpts) (*IAutomationRegistryMaster23NOPsSettledOffchainIterator, error) + + WatchNOPsSettledOffchain(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMaster23NOPsSettledOffchain) (event.Subscription, error) + + ParseNOPsSettledOffchain(log types.Log) (*IAutomationRegistryMaster23NOPsSettledOffchain, error) + FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*IAutomationRegistryMaster23OwnershipTransferRequestedIterator, error) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMaster23OwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) diff --git a/core/gethwrappers/generated/keeper_registry_logic_a_wrapper_2_1/keeper_registry_logic_a_wrapper_2_1.go b/core/gethwrappers/generated/keeper_registry_logic_a_wrapper_2_1/keeper_registry_logic_a_wrapper_2_1.go index 69d9adbc686..028c2a1488e 100644 --- a/core/gethwrappers/generated/keeper_registry_logic_a_wrapper_2_1/keeper_registry_logic_a_wrapper_2_1.go +++ b/core/gethwrappers/generated/keeper_registry_logic_a_wrapper_2_1/keeper_registry_logic_a_wrapper_2_1.go @@ -31,8 +31,8 @@ var ( ) var KeeperRegistryLogicAMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"contractKeeperRegistryLogicB2_1\",\"name\":\"logicB\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientFunds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxCheckDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxPerformDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentGreaterThanAllLINK\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"OwnerFundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"cancelUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumKeeperRegistryBase2_1.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumKeeperRegistryBase2_1.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkNative\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumKeeperRegistryBase2_1.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkNative\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"executeCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumKeeperRegistryBase2_1.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"migrateUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedUpkeeps\",\"type\":\"bytes\"}],\"name\":\"receiveUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"enumKeeperRegistryBase2_1.Trigger\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"setUpkeepTriggerConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x6101406040523480156200001257600080fd5b50604051620061d1380380620061d18339810160408190526200003591620003df565b80816001600160a01b0316634b4fd03b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b919062000406565b826001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001009190620003df565b836001600160a01b031663b10b673c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001659190620003df565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca9190620003df565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f9190620003df565b3380600081620002865760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620002b957620002b9816200031b565b505050846002811115620002d157620002d162000429565b60e0816002811115620002e857620002e862000429565b9052506001600160a01b0393841660805291831660a052821660c0528116610100529190911661012052506200043f9050565b336001600160a01b03821603620003755760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200027d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b0381168114620003dc57600080fd5b50565b600060208284031215620003f257600080fd5b8151620003ff81620003c6565b9392505050565b6000602082840312156200041957600080fd5b815160038110620003ff57600080fd5b634e487b7160e01b600052602160045260246000fd5b60805160a05160c05160e0516101005161012051615d18620004b96000396000818161010e01526101a90152600081816103e10152611fa10152600081816135370152818161376d015281816139b50152613b5d015260006130e1015260006131c5015260008181611de301526123af0152615d186000f3fe60806040523480156200001157600080fd5b50600436106200010c5760003560e01c806385c1b0ba11620000a5578063c8048022116200006f578063c804802214620002b7578063ce7dc5b414620002ce578063f2fde38b14620002e5578063f7d334ba14620002fc576200010c565b806385c1b0ba14620002535780638da5cb5b146200026a5780638e86139b1462000289578063948108f714620002a0576200010c565b80634ee88d3511620000e75780634ee88d3514620001ef5780636ded9eae146200020657806371791aa0146200021d57806379ba50971462000249576200010c565b806328f32f38146200015457806329c5efad146200017e578063349e8cca14620001a7575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e8080156200014d573d6000f35b3d6000fd5b005b6200016b62000165366004620041ea565b62000313565b6040519081526020015b60405180910390f35b620001956200018f366004620042d0565b6200068c565b604051620001759493929190620043f8565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200162000175565b620001526200020036600462004435565b62000930565b6200016b6200021736600462004485565b62000998565b620002346200022e366004620042d0565b620009fe565b60405162000175979695949392919062004538565b62000152620010f0565b62000152620002643660046200458a565b620011f3565b60005473ffffffffffffffffffffffffffffffffffffffff16620001c9565b620001526200029a36600462004617565b62001e64565b62000152620002b13660046200467a565b620021ec565b62000152620002c8366004620046a9565b6200247f565b62000195620002df3660046200477f565b62002846565b62000152620002f6366004620047f6565b62002916565b620002346200030d366004620046a9565b6200292e565b6000805473ffffffffffffffffffffffffffffffffffffffff163314801590620003475750620003456009336200296c565b155b156200037f576040517fd48b678b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff89163b620003ce576040517f09ee12d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b620003d986620029a0565b9050600089307f00000000000000000000000000000000000000000000000000000000000000006040516200040e9062003f7b565b73ffffffffffffffffffffffffffffffffffffffff938416815291831660208301529091166040820152606001604051809103906000f08015801562000458573d6000803e3d6000fd5b5090506200051f826040518060e001604052806000151581526020018c63ffffffff16815260200163ffffffff801681526020018473ffffffffffffffffffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff168152602001600063ffffffff168152508a89898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508b92508a915062002b449050565b6014805474010000000000000000000000000000000000000000900463ffffffff1690806200054e8362004845565b91906101000a81548163ffffffff021916908363ffffffff16021790555050817fbae366358c023f887e791d7a62f2e4316f1026bd77f6fb49501a917b3bc5d0128a8a604051620005c792919063ffffffff92909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a2817fcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d878760405162000603929190620048b4565b60405180910390a2817f2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d5664856040516200063d9190620048ca565b60405180910390a2817f3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf485084604051620006779190620048ca565b60405180910390a25098975050505050505050565b600060606000806200069d62002f1f565b600086815260046020908152604091829020825160e081018452815460ff811615158252610100810463ffffffff90811694830194909452650100000000008104841694820194909452690100000000000000000090930473ffffffffffffffffffffffffffffffffffffffff166060840152600101546bffffffffffffffffffffffff80821660808501526c0100000000000000000000000082041660a0840152780100000000000000000000000000000000000000000000000090041660c08201525a9150600080826060015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620007b7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620007dd9190620048ec565b73ffffffffffffffffffffffffffffffffffffffff166013600101600c9054906101000a900463ffffffff1663ffffffff16896040516200081f91906200490c565b60006040518083038160008787f1925050503d80600081146200085f576040519150601f19603f3d011682016040523d82523d6000602084013e62000864565b606091505b50915091505a6200087690856200492a565b935081620008a157600060405180602001604052806000815250600796509650965050505062000927565b80806020019051810190620008b791906200499b565b909750955086620008e557600060405180602001604052806000815250600496509650965050505062000927565b601554865164010000000090910463ffffffff1610156200092357600060405180602001604052806000815250600596509650965050505062000927565b5050505b92959194509250565b6200093b8362002f5a565b6000838152601a602052604090206200095682848362004a90565b50827f2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d566483836040516200098b929190620048b4565b60405180910390a2505050565b6000620009f288888860008989604051806020016040528060008152508a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506200031392505050565b98975050505050505050565b60006060600080600080600062000a1462002f1f565b600062000a218a62003010565b905060006012604051806101200160405290816000820160009054906101000a900460ff1660ff1660ff1681526020016000820160019054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160059054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160099054906101000a900462ffffff1662ffffff1662ffffff16815260200160008201600c9054906101000a900461ffff1661ffff1661ffff16815260200160008201600e9054906101000a900460ff1615151515815260200160008201600f9054906101000a900460ff161515151581526020016000820160109054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160008201601c9054906101000a900463ffffffff1663ffffffff1663ffffffff168152505090506000600460008d81526020019081526020016000206040518060e00160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160059054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160099054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160018201600c9054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff1681526020016001820160189054906101000a900463ffffffff1663ffffffff1663ffffffff168152505090508160a001511562000d45576000604051806020016040528060008152506009600084602001516000808263ffffffff1692509950995099509950995099509950505050620010e4565b604081015163ffffffff9081161462000d96576000604051806020016040528060008152506001600084602001516000808263ffffffff1692509950995099509950995099509950505050620010e4565b80511562000ddc576000604051806020016040528060008152506002600084602001516000808263ffffffff1692509950995099509950995099509950505050620010e4565b62000de782620030be565b602083015160155492975090955060009162000e19918591879190640100000000900463ffffffff168a8a87620032b0565b9050806bffffffffffffffffffffffff168260a001516bffffffffffffffffffffffff16101562000e83576000604051806020016040528060008152506006600085602001516000808263ffffffff1692509a509a509a509a509a509a509a5050505050620010e4565b600062000e928e868f62003301565b90505a9850600080846060015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000eea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000f109190620048ec565b73ffffffffffffffffffffffffffffffffffffffff166013600101600c9054906101000a900463ffffffff1663ffffffff168460405162000f5291906200490c565b60006040518083038160008787f1925050503d806000811462000f92576040519150601f19603f3d011682016040523d82523d6000602084013e62000f97565b606091505b50915091505a62000fa9908c6200492a565b9a5081620010295760155481516801000000000000000090910463ffffffff1610156200100657505060408051602080820190925260008082529490910151939c509a50600899505063ffffffff9091169550620010e492505050565b602090940151939b5060039a505063ffffffff9092169650620010e49350505050565b808060200190518101906200103f91906200499b565b909e509c508d6200108057505060408051602080820190925260008082529490910151939c509a50600499505063ffffffff9091169550620010e492505050565b6015548d5164010000000090910463ffffffff161015620010d157505060408051602080820190925260008082529490910151939c509a50600599505063ffffffff9091169550620010e492505050565b505050506020015163ffffffff16945050505b92959891949750929550565b60015473ffffffffffffffffffffffffffffffffffffffff16331462001177576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600173ffffffffffffffffffffffffffffffffffffffff821660009081526019602052604090205460ff1660038111156200123257620012326200438d565b141580156200127e5750600373ffffffffffffffffffffffffffffffffffffffff821660009081526019602052604090205460ff1660038111156200127b576200127b6200438d565b14155b15620012b6576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6013546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1662001316576040517fd12d7d8d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082900362001352576040517f2c2fc94100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081018290526000808567ffffffffffffffff811115620013a957620013a962004071565b604051908082528060200260200182016040528015620013d3578160200160208202803683370190505b50905060008667ffffffffffffffff811115620013f457620013f462004071565b6040519080825280602002602001820160405280156200147b57816020015b6040805160e08101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181620014135790505b50905060008767ffffffffffffffff8111156200149c576200149c62004071565b604051908082528060200260200182016040528015620014d157816020015b6060815260200190600190039081620014bb5790505b50905060008867ffffffffffffffff811115620014f257620014f262004071565b6040519080825280602002602001820160405280156200152757816020015b6060815260200190600190039081620015115790505b50905060008967ffffffffffffffff81111562001548576200154862004071565b6040519080825280602002602001820160405280156200157d57816020015b6060815260200190600190039081620015675790505b50905060005b8a81101562001b61578b8b82818110620015a157620015a162004bb8565b60209081029290920135600081815260048452604090819020815160e081018352815460ff811615158252610100810463ffffffff90811697830197909752650100000000008104871693820193909352690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff166060830152600101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490931660c08401529a509098506200168090508962002f5a565b60608801516040517f1a5da6c800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8c8116600483015290911690631a5da6c890602401600060405180830381600087803b158015620016f057600080fd5b505af115801562001705573d6000803e3d6000fd5b50505050878582815181106200171f576200171f62004bb8565b6020026020010181905250600560008a815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1686828151811062001773576200177362004bb8565b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910182015260008a81526007909152604090208054620017b290620049e8565b80601f0160208091040260200160405190810160405280929190818152602001828054620017e090620049e8565b8015620018315780601f10620018055761010080835404028352916020019162001831565b820191906000526020600020905b8154815290600101906020018083116200181357829003601f168201915b50505050508482815181106200184b576200184b62004bb8565b6020026020010181905250601a60008a815260200190815260200160002080546200187690620049e8565b80601f0160208091040260200160405190810160405280929190818152602001828054620018a490620049e8565b8015620018f55780601f10620018c957610100808354040283529160200191620018f5565b820191906000526020600020905b815481529060010190602001808311620018d757829003601f168201915b50505050508382815181106200190f576200190f62004bb8565b6020026020010181905250601b60008a815260200190815260200160002080546200193a90620049e8565b80601f01602080910402602001604051908101604052809291908181526020018280546200196890620049e8565b8015620019b95780601f106200198d57610100808354040283529160200191620019b9565b820191906000526020600020905b8154815290600101906020018083116200199b57829003601f168201915b5050505050828281518110620019d357620019d362004bb8565b60200260200101819052508760a001516bffffffffffffffffffffffff1687620019fe919062004be7565b60008a815260046020908152604080832080547fffffff000000000000000000000000000000000000000000000000000000000016815560010180547fffffffff000000000000000000000000000000000000000000000000000000001690556007909152812091985062001a74919062003f89565b6000898152601a6020526040812062001a8d9162003f89565b6000898152601b6020526040812062001aa69162003f89565b600089815260066020526040902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905562001ae760028a62003523565b5060a0880151604080516bffffffffffffffffffffffff909216825273ffffffffffffffffffffffffffffffffffffffff8c1660208301528a917fb38647142fbb1ea4c000fc4569b37a4e9a9f6313317b84ee3e5326c1a6cd06ff910160405180910390a28062001b588162004bfd565b91505062001583565b508560185462001b7291906200492a565b60185560008b8b868167ffffffffffffffff81111562001b965762001b9662004071565b60405190808252806020026020018201604052801562001bc0578160200160208202803683370190505b508988888860405160200162001bde98979695949392919062004da3565b60405160208183030381529060405290508973ffffffffffffffffffffffffffffffffffffffff16638e86139b6013600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c71249ab60038e73ffffffffffffffffffffffffffffffffffffffff1663aab9edd66040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001c9a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001cc0919062004e73565b866040518463ffffffff1660e01b815260040162001ce19392919062004e98565b600060405180830381865afa15801562001cff573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405262001d47919081019062004ebf565b6040518263ffffffff1660e01b815260040162001d659190620048ca565b600060405180830381600087803b15801562001d8057600080fd5b505af115801562001d95573d6000803e3d6000fd5b50506040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8d81166004830152602482018b90527f000000000000000000000000000000000000000000000000000000000000000016925063a9059cbb91506044016020604051808303816000875af115801562001e2f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001e55919062004ef8565b50505050505050505050505050565b60023360009081526019602052604090205460ff16600381111562001e8d5762001e8d6200438d565b1415801562001ec3575060033360009081526019602052604090205460ff16600381111562001ec05762001ec06200438d565b14155b1562001efb576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080808080808062001f11888a018a620050f0565b965096509650965096509650965060005b8751811015620021e057600073ffffffffffffffffffffffffffffffffffffffff1687828151811062001f595762001f5962004bb8565b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff16036200206d5785818151811062001f965762001f9662004bb8565b6020026020010151307f000000000000000000000000000000000000000000000000000000000000000060405162001fce9062003f7b565b73ffffffffffffffffffffffffffffffffffffffff938416815291831660208301529091166040820152606001604051809103906000f08015801562002018573d6000803e3d6000fd5b508782815181106200202e576200202e62004bb8565b60200260200101516060019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250505b6200212588828151811062002086576200208662004bb8565b6020026020010151888381518110620020a357620020a362004bb8565b6020026020010151878481518110620020c057620020c062004bb8565b6020026020010151878581518110620020dd57620020dd62004bb8565b6020026020010151878681518110620020fa57620020fa62004bb8565b602002602001015187878151811062002117576200211762004bb8565b602002602001015162002b44565b8781815181106200213a576200213a62004bb8565b60200260200101517f74931a144e43a50694897f241d973aecb5024c0e910f9bb80a163ea3c1cf5a7188838151811062002178576200217862004bb8565b602002602001015160a0015133604051620021c39291906bffffffffffffffffffffffff92909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a280620021d78162004bfd565b91505062001f22565b50505050505050505050565b600082815260046020908152604091829020825160e081018452815460ff81161515825263ffffffff6101008204811694830194909452650100000000008104841694820185905273ffffffffffffffffffffffffffffffffffffffff69010000000000000000009091041660608201526001909101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a083015278010000000000000000000000000000000000000000000000009004821660c08201529114620022ea576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818160a00151620022fc919062005221565b600084815260046020526040902060010180547fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff166c010000000000000000000000006bffffffffffffffffffffffff93841602179055601854620023649184169062004be7565b6018556040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526bffffffffffffffffffffffff831660448201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906323b872dd906064016020604051808303816000875af11580156200240e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002434919062004ef8565b506040516bffffffffffffffffffffffff83168152339084907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a3505050565b6000818152600460209081526040808320815160e081018352815460ff81161515825263ffffffff6101008204811695830195909552650100000000008104851693820184905273ffffffffffffffffffffffffffffffffffffffff69010000000000000000009091041660608201526001909101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a083015278010000000000000000000000000000000000000000000000009004831660c082015292911415906200256860005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16149050818015620025c35750808015620025c15750620025b462003531565b836040015163ffffffff16115b155b15620025fb576040517ffbc0357800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b801580156200262e575060008481526005602052604090205473ffffffffffffffffffffffffffffffffffffffff163314155b1562002666576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006200267262003531565b9050816200268a576200268760328262004be7565b90505b6000858152600460205260409020805463ffffffff80841665010000000000027fffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffff90921691909117909155620026e69060029087906200352316565b5060135460808501516bffffffffffffffffffffffff91821691600091168211156200274f5760808601516200271d908362005249565b90508560a001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff1611156200274f575060a08501515b808660a0015162002761919062005249565b600088815260046020526040902060010180547fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff166c010000000000000000000000006bffffffffffffffffffffffff93841602179055601454620027c99183911662005221565b601480547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff9290921691909117905560405167ffffffffffffffff84169088907f91cb3bb75cfbd718bbfccc56b7f53d92d7048ef4ca39a3b7b7c6d4af1f79118190600090a350505050505050565b600060606000806200285762002f1f565b6000634b56a42e60e01b888888604051602401620028789392919062005271565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290506200290389826200068c565b929c919b50995090975095505050505050565b62002920620035ed565b6200292b8162003670565b50565b600060606000806000806000620029558860405180602001604052806000815250620009fe565b959e949d50929b5090995097509550909350915050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260018301602052604081205415155b90505b92915050565b6000806000620029c76001620029b562003531565b620029c191906200492a565b62003767565b601454604080516020810193909352309083015274010000000000000000000000000000000000000000900463ffffffff166060820152608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201209083015201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060045b600f81101562002ad3578282828151811062002a8f5762002a8f62004bb8565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508062002aca8162004bfd565b91505062002a6f565b5083600181111562002ae95762002ae96200438d565b60f81b81600f8151811062002b025762002b0262004bb8565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535062002b3c81620052a5565b949350505050565b6012546e010000000000000000000000000000900460ff161562002b94576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601554835163ffffffff909116101562002bda576040517fae7235df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108fc856020015163ffffffff16108062002c185750601454602086015163ffffffff70010000000000000000000000000000000090920482169116115b1562002c50576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000868152600460205260409020546901000000000000000000900473ffffffffffffffffffffffffffffffffffffffff161562002cba576040517f6e3b930b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000868152600460209081526040808320885181548a8501518b85015160608d01517fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000009093169315157fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff169390931761010063ffffffff92831602177fffffff000000000000000000000000000000000000000000000000ffffffffff1665010000000000938216939093027fffffff0000000000000000000000000000000000000000ffffffffffffffffff1692909217690100000000000000000073ffffffffffffffffffffffffffffffffffffffff9283160217835560808b01516001909301805460a08d015160c08e01516bffffffffffffffffffffffff9687167fffffffffffffffff000000000000000000000000000000000000000000000000909316929092176c010000000000000000000000009690911695909502949094177fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff1678010000000000000000000000000000000000000000000000009490931693909302919091179091556005835281842080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169189169190911790556007909152902062002ead8482620052e8565b508460a001516bffffffffffffffffffffffff1660185462002ed0919062004be7565b6018556000868152601a6020526040902062002eed8382620052e8565b506000868152601b6020526040902062002f088282620052e8565b5062002f16600287620038cf565b50505050505050565b321562002f58576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60008181526005602052604090205473ffffffffffffffffffffffffffffffffffffffff16331462002fb8576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526004602052604090205465010000000000900463ffffffff908116146200292b576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818160045b600f811015620030a5577fff00000000000000000000000000000000000000000000000000000000000000821683826020811062003059576200305962004bb8565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916146200309057506000949350505050565b806200309c8162004bfd565b91505062003017565b5081600f1a600181111562002b3c5762002b3c6200438d565b6000806000836060015162ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156200314b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200317191906200542a565b50945090925050506000811315806200318957508142105b80620031ae5750828015620031ae5750620031a582426200492a565b8463ffffffff16105b15620031bf576016549550620031c3565b8095505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156200322f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200325591906200542a565b50945090925050506000811315806200326d57508142105b806200329257508280156200329257506200328982426200492a565b8463ffffffff16105b15620032a3576017549450620032a7565b8094505b50505050915091565b600080620032c488878b60000151620038dd565b9050600080620032e18b8a63ffffffff16858a8a60018b6200397c565b9092509050620032f2818362005221565b9b9a5050505050505050505050565b606060008360018111156200331a576200331a6200438d565b03620033e7576000848152600760205260409081902090517f6e04ff0d0000000000000000000000000000000000000000000000000000000091620033629160240162005522565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290506200351c565b6001836001811115620033fe57620033fe6200438d565b03620034ea576000828060200190518101906200341c919062005599565b6000868152600760205260409081902090519192507f40691db4000000000000000000000000000000000000000000000000000000009162003463918491602401620056ad565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915291506200351c9050565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9392505050565b600062002997838362003e1e565b600060017f000000000000000000000000000000000000000000000000000000000000000060028111156200356a576200356a6200438d565b03620035e857606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620035bd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620035e3919062005775565b905090565b504390565b60005473ffffffffffffffffffffffffffffffffffffffff16331462002f58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016200116e565b3373ffffffffffffffffffffffffffffffffffffffff821603620036f1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200116e565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060017f00000000000000000000000000000000000000000000000000000000000000006002811115620037a057620037a06200438d565b03620038c5576000606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620037f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200381b919062005775565b905080831015806200383957506101006200383784836200492a565b115b15620038485750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815260048101849052606490632b407a8290602401602060405180830381865afa1580156200389f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200351c919062005775565b504090565b919050565b600062002997838362003f29565b60008080856001811115620038f657620038f66200438d565b0362003907575062015f906200392a565b60018560018111156200391e576200391e6200438d565b03620034ea57506201adb05b6200393d63ffffffff851660146200578f565b6200394a846001620057cf565b6200395b9060ff16611d4c6200578f565b62003967908362004be7565b62003973919062004be7565b95945050505050565b6000806000896080015161ffff16876200399791906200578f565b9050838015620039a65750803a105b15620039af57503a5b600060027f00000000000000000000000000000000000000000000000000000000000000006002811115620039e857620039e86200438d565b0362003b5957604080516000815260208101909152851562003a4c5760003660405180608001604052806048815260200162005cc46048913960405160200162003a3593929190620057eb565b604051602081830303815290604052905062003aba565b60155462003a6a90640100000000900463ffffffff16600462005814565b63ffffffff1667ffffffffffffffff81111562003a8b5762003a8b62004071565b6040519080825280601f01601f19166020018201604052801562003ab6576020820181803683370190505b5090505b6040517f49948e0e00000000000000000000000000000000000000000000000000000000815273420000000000000000000000000000000000000f906349948e0e9062003b0c908490600401620048ca565b602060405180830381865afa15801562003b2a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003b50919062005775565b91505062003cc3565b60017f0000000000000000000000000000000000000000000000000000000000000000600281111562003b905762003b906200438d565b0362003cc357841562003c1857606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562003bea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003c10919062005775565b905062003cc3565b6000606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c060405180830381865afa15801562003c67573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003c8d919062005843565b505060155492945062003cb293505050640100000000900463ffffffff16826200578f565b62003cbf9060106200578f565b9150505b8462003ce257808b6080015161ffff1662003cdf91906200578f565b90505b62003cf261ffff8716826200588e565b90506000878262003d048c8e62004be7565b62003d1090866200578f565b62003d1c919062004be7565b62003d3090670de0b6b3a76400006200578f565b62003d3c91906200588e565b905060008c6040015163ffffffff1664e8d4a5100062003d5d91906200578f565b898e6020015163ffffffff16858f8862003d7891906200578f565b62003d84919062004be7565b62003d9490633b9aca006200578f565b62003da091906200578f565b62003dac91906200588e565b62003db8919062004be7565b90506b033b2e3c9fd0803ce800000062003dd3828462004be7565b111562003e0c576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b909c909b509950505050505050505050565b6000818152600183016020526040812054801562003f1757600062003e456001836200492a565b855490915060009062003e5b906001906200492a565b905081811462003ec757600086600001828154811062003e7f5762003e7f62004bb8565b906000526020600020015490508087600001848154811062003ea55762003ea562004bb8565b6000918252602080832090910192909255918252600188019052604090208390555b855486908062003edb5762003edb620058ca565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506200299a565b60009150506200299a565b5092915050565b600081815260018301602052604081205462003f72575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200299a565b5060006200299a565b6103ca80620058fa83390190565b50805462003f9790620049e8565b6000825580601f1062003fa8575050565b601f0160209004906000526020600020908101906200292b91905b8082111562003fd9576000815560010162003fc3565b5090565b73ffffffffffffffffffffffffffffffffffffffff811681146200292b57600080fd5b803563ffffffff81168114620038ca57600080fd5b803560028110620038ca57600080fd5b60008083601f8401126200403857600080fd5b50813567ffffffffffffffff8111156200405157600080fd5b6020830191508360208285010111156200406a57600080fd5b9250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160e0810167ffffffffffffffff81118282101715620040c657620040c662004071565b60405290565b604051610100810167ffffffffffffffff81118282101715620040c657620040c662004071565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156200413d576200413d62004071565b604052919050565b600067ffffffffffffffff82111562004162576200416262004071565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112620041a057600080fd5b8135620041b7620041b18262004145565b620040f3565b818152846020838601011115620041cd57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060008060e0898b0312156200420757600080fd5b8835620042148162003fdd565b97506200422460208a0162004000565b96506040890135620042368162003fdd565b95506200424660608a0162004015565b9450608089013567ffffffffffffffff808211156200426457600080fd5b620042728c838d0162004025565b909650945060a08b01359150808211156200428c57600080fd5b6200429a8c838d016200418e565b935060c08b0135915080821115620042b157600080fd5b50620042c08b828c016200418e565b9150509295985092959890939650565b60008060408385031215620042e457600080fd5b82359150602083013567ffffffffffffffff8111156200430357600080fd5b62004311858286016200418e565b9150509250929050565b60005b83811015620043385781810151838201526020016200431e565b50506000910152565b600081518084526200435b8160208601602086016200431b565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600a8110620043f4577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b841515815260806020820152600062004415608083018662004341565b9050620044266040830185620043bc565b82606083015295945050505050565b6000806000604084860312156200444b57600080fd5b83359250602084013567ffffffffffffffff8111156200446a57600080fd5b620044788682870162004025565b9497909650939450505050565b600080600080600080600060a0888a031215620044a157600080fd5b8735620044ae8162003fdd565b9650620044be6020890162004000565b95506040880135620044d08162003fdd565b9450606088013567ffffffffffffffff80821115620044ee57600080fd5b620044fc8b838c0162004025565b909650945060808a01359150808211156200451657600080fd5b50620045258a828b0162004025565b989b979a50959850939692959293505050565b871515815260e0602082015260006200455560e083018962004341565b9050620045666040830188620043bc565b8560608301528460808301528360a08301528260c083015298975050505050505050565b600080600060408486031215620045a057600080fd5b833567ffffffffffffffff80821115620045b957600080fd5b818601915086601f830112620045ce57600080fd5b813581811115620045de57600080fd5b8760208260051b8501011115620045f457600080fd5b602092830195509350508401356200460c8162003fdd565b809150509250925092565b600080602083850312156200462b57600080fd5b823567ffffffffffffffff8111156200464357600080fd5b620046518582860162004025565b90969095509350505050565b80356bffffffffffffffffffffffff81168114620038ca57600080fd5b600080604083850312156200468e57600080fd5b82359150620046a0602084016200465d565b90509250929050565b600060208284031215620046bc57600080fd5b5035919050565b600067ffffffffffffffff821115620046e057620046e062004071565b5060051b60200190565b600082601f830112620046fc57600080fd5b813560206200470f620041b183620046c3565b82815260059290921b840181019181810190868411156200472f57600080fd5b8286015b848110156200477457803567ffffffffffffffff811115620047555760008081fd5b620047658986838b01016200418e565b84525091830191830162004733565b509695505050505050565b600080600080606085870312156200479657600080fd5b84359350602085013567ffffffffffffffff80821115620047b657600080fd5b620047c488838901620046ea565b94506040870135915080821115620047db57600080fd5b50620047ea8782880162004025565b95989497509550505050565b6000602082840312156200480957600080fd5b81356200351c8162003fdd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff80831681810362004861576200486162004816565b6001019392505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60208152600062002b3c6020830184866200486b565b60208152600062002997602083018462004341565b8051620038ca8162003fdd565b600060208284031215620048ff57600080fd5b81516200351c8162003fdd565b60008251620049208184602087016200431b565b9190910192915050565b818103818111156200299a576200299a62004816565b80151581146200292b57600080fd5b600082601f8301126200496157600080fd5b815162004972620041b18262004145565b8181528460208386010111156200498857600080fd5b62002b3c8260208301602087016200431b565b60008060408385031215620049af57600080fd5b8251620049bc8162004940565b602084015190925067ffffffffffffffff811115620049da57600080fd5b62004311858286016200494f565b600181811c90821680620049fd57607f821691505b60208210810362004a37577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f82111562004a8b57600081815260208120601f850160051c8101602086101562004a665750805b601f850160051c820191505b8181101562004a875782815560010162004a72565b5050505b505050565b67ffffffffffffffff83111562004aab5762004aab62004071565b62004ac38362004abc8354620049e8565b8362004a3d565b6000601f84116001811462004b18576000851562004ae15750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b17835562004bb1565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b8281101562004b69578685013582556020948501946001909201910162004b47565b508682101562004ba5577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b808201808211156200299a576200299a62004816565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820362004c315762004c3162004816565b5060010190565b600081518084526020808501945080840160005b8381101562004cf75781518051151588528381015163ffffffff908116858a01526040808301519091169089015260608082015173ffffffffffffffffffffffffffffffffffffffff16908901526080808201516bffffffffffffffffffffffff169089015260a08082015162004cd2828b01826bffffffffffffffffffffffff169052565b505060c09081015163ffffffff169088015260e0909601959082019060010162004c4c565b509495945050505050565b600081518084526020808501945080840160005b8381101562004cf757815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010162004d16565b600081518084526020808501808196508360051b8101915082860160005b8581101562004d9657828403895262004d8384835162004341565b9885019893509084019060010162004d68565b5091979650505050505050565b60e081528760e082015260006101007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a111562004de057600080fd5b8960051b808c8386013783018381038201602085015262004e048282018b62004c38565b915050828103604084015262004e1b818962004d02565b9050828103606084015262004e31818862004d02565b9050828103608084015262004e47818762004d4a565b905082810360a084015262004e5d818662004d4a565b905082810360c0840152620032f2818562004d4a565b60006020828403121562004e8657600080fd5b815160ff811681146200351c57600080fd5b60ff8416815260ff8316602082015260606040820152600062003973606083018462004341565b60006020828403121562004ed257600080fd5b815167ffffffffffffffff81111562004eea57600080fd5b62002b3c848285016200494f565b60006020828403121562004f0b57600080fd5b81516200351c8162004940565b600082601f83011262004f2a57600080fd5b8135602062004f3d620041b183620046c3565b82815260059290921b8401810191818101908684111562004f5d57600080fd5b8286015b8481101562004774578035835291830191830162004f61565b600082601f83011262004f8c57600080fd5b8135602062004f9f620041b183620046c3565b82815260e0928302850182019282820191908785111562004fbf57600080fd5b8387015b85811015620050765781818a03121562004fdd5760008081fd5b62004fe7620040a0565b813562004ff48162004940565b81526200500382870162004000565b8682015260406200501681840162004000565b908201526060828101356200502b8162003fdd565b9082015260806200503e8382016200465d565b9082015260a0620050518382016200465d565b9082015260c06200506483820162004000565b90820152845292840192810162004fc3565b5090979650505050505050565b600082601f8301126200509557600080fd5b81356020620050a8620041b183620046c3565b82815260059290921b84018101918181019086841115620050c857600080fd5b8286015b8481101562004774578035620050e28162003fdd565b8352918301918301620050cc565b600080600080600080600060e0888a0312156200510c57600080fd5b873567ffffffffffffffff808211156200512557600080fd5b620051338b838c0162004f18565b985060208a01359150808211156200514a57600080fd5b620051588b838c0162004f7a565b975060408a01359150808211156200516f57600080fd5b6200517d8b838c0162005083565b965060608a01359150808211156200519457600080fd5b620051a28b838c0162005083565b955060808a0135915080821115620051b957600080fd5b620051c78b838c01620046ea565b945060a08a0135915080821115620051de57600080fd5b620051ec8b838c01620046ea565b935060c08a01359150808211156200520357600080fd5b50620052128a828b01620046ea565b91505092959891949750929550565b6bffffffffffffffffffffffff81811683821601908082111562003f225762003f2262004816565b6bffffffffffffffffffffffff82811682821603908082111562003f225762003f2262004816565b60408152600062005286604083018662004d4a565b82810360208401526200529b8185876200486b565b9695505050505050565b8051602080830151919081101562004a37577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b815167ffffffffffffffff81111562005305576200530562004071565b6200531d81620053168454620049e8565b8462004a3d565b602080601f8311600181146200537357600084156200533c5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b17855562004a87565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015620053c257888601518255948401946001909101908401620053a1565b5085821015620053ff57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b805169ffffffffffffffffffff81168114620038ca57600080fd5b600080600080600060a086880312156200544357600080fd5b6200544e866200540f565b945060208601519350604086015192506060860151915062005473608087016200540f565b90509295509295909350565b600081546200548e81620049e8565b808552602060018381168015620054ae5760018114620054e75762005517565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b890101955062005517565b866000528260002060005b858110156200550f5781548a8201860152908301908401620054f2565b890184019650505b505050505092915050565b6020815260006200299760208301846200547f565b600082601f8301126200554957600080fd5b815160206200555c620041b183620046c3565b82815260059290921b840181019181810190868411156200557c57600080fd5b8286015b8481101562004774578051835291830191830162005580565b600060208284031215620055ac57600080fd5b815167ffffffffffffffff80821115620055c557600080fd5b908301906101008286031215620055db57600080fd5b620055e5620040cc565b82518152602083015160208201526040830151604082015260608301516060820152608083015160808201526200561f60a08401620048df565b60a082015260c0830151828111156200563757600080fd5b620056458782860162005537565b60c08301525060e0830151828111156200565e57600080fd5b6200566c878286016200494f565b60e08301525095945050505050565b600081518084526020808501945080840160005b8381101562004cf7578151875295820195908201906001016200568f565b60408152825160408201526020830151606082015260408301516080820152606083015160a0820152608083015160c082015273ffffffffffffffffffffffffffffffffffffffff60a08401511660e0820152600060c0840151610100808185015250620057206101408401826200567b565b905060e08501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0848303016101208501526200575e828262004341565b91505082810360208401526200397381856200547f565b6000602082840312156200578857600080fd5b5051919050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615620057ca57620057ca62004816565b500290565b60ff81811683821601908111156200299a576200299a62004816565b8284823760008382016000815283516200580a8183602088016200431b565b0195945050505050565b600063ffffffff808316818516818304811182151516156200583a576200583a62004816565b02949350505050565b60008060008060008060c087890312156200585d57600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b600082620058c5577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe60c060405234801561001057600080fd5b506040516103ca3803806103ca83398101604081905261002f91610076565b600080546001600160a01b0319166001600160a01b039384161790559181166080521660a0526100b9565b80516001600160a01b038116811461007157600080fd5b919050565b60008060006060848603121561008b57600080fd5b6100948461005a565b92506100a26020850161005a565b91506100b06040850161005a565b90509250925092565b60805160a0516102e76100e36000396000603801526000818160c4015261011701526102e76000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806379188d161461007b578063f00e6a2a146100aa575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e808015610076573d6000f35b3d6000fd5b61008e6100893660046101c1565b6100ee565b6040805192151583526020830191909152015b60405180910390f35b60405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001681526020016100a1565b60008054819073ffffffffffffffffffffffffffffffffffffffff16331461011557600080fd5b7f00000000000000000000000000000000000000000000000000000000000000005a91505a61138881101561014957600080fd5b61138881039050856040820482031161016157600080fd5b50803b61016d57600080fd5b6000808551602087016000858af192505a610188908361029a565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080604083850312156101d457600080fd5b82359150602083013567ffffffffffffffff808211156101f357600080fd5b818501915085601f83011261020757600080fd5b81358181111561021957610219610192565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561025f5761025f610192565b8160405282815288602084870101111561027857600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b818103818111156102d4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea164736f6c6343000810000a307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000810000a", + ABI: "[{\"inputs\":[{\"internalType\":\"contractKeeperRegistryLogicB2_1\",\"name\":\"logicB\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientFunds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxCheckDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxPerformDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentGreaterThanAllLINK\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"OwnerFundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"cancelUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumKeeperRegistryBase2_1.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumKeeperRegistryBase2_1.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkNative\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumKeeperRegistryBase2_1.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkNative\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"executeCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"enumKeeperRegistryBase2_1.UpkeepFailureReason\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"migrateUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedUpkeeps\",\"type\":\"bytes\"}],\"name\":\"receiveUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"enumKeeperRegistryBase2_1.Trigger\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"setUpkeepTriggerConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x6101406040523480156200001257600080fd5b5060405162006295380380620062958339810160408190526200003591620003df565b80816001600160a01b0316634b4fd03b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b919062000406565b826001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001009190620003df565b836001600160a01b031663b10b673c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001659190620003df565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca9190620003df565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f9190620003df565b3380600081620002865760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620002b957620002b9816200031b565b505050846002811115620002d157620002d162000429565b60e0816002811115620002e857620002e862000429565b9052506001600160a01b0393841660805291831660a052821660c0528116610100529190911661012052506200043f9050565b336001600160a01b03821603620003755760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200027d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b0381168114620003dc57600080fd5b50565b600060208284031215620003f257600080fd5b8151620003ff81620003c6565b9392505050565b6000602082840312156200041957600080fd5b815160038110620003ff57600080fd5b634e487b7160e01b600052602160045260246000fd5b60805160a05160c05160e0516101005161012051615ddc620004b96000396000818161010001526101c50152600081816104a501526120650152600081816135fb0152818161383101528181613a790152613c21015260006131a501526000613289015260008181611ea701526124730152615ddc6000f3fe608060405260043610620000fe5760003560e01c806385c1b0ba1162000097578063c80480221162000061578063c80480221462000343578063ce7dc5b41462000368578063f2fde38b146200038d578063f7d334ba14620003b257620000fe565b806385c1b0ba14620002a75780638da5cb5b14620002cc5780638e86139b14620002f9578063948108f7146200031e57620000fe565b80634ee88d3511620000d95780634ee88d35146200020b5780636ded9eae146200023057806371791aa0146200025557806379ba5097146200028f57620000fe565b806328f32f38146200014657806329c5efad146200017e578063349e8cca14620001b5575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e8080156200013f573d6000f35b3d6000fd5b005b3480156200015357600080fd5b506200016b62000165366004620042ae565b620003d7565b6040519081526020015b60405180910390f35b3480156200018b57600080fd5b50620001a36200019d36600462004394565b62000750565b604051620001759493929190620044bc565b348015620001c257600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200162000175565b3480156200021857600080fd5b50620001446200022a366004620044f9565b620009f4565b3480156200023d57600080fd5b506200016b6200024f36600462004549565b62000a5c565b3480156200026257600080fd5b506200027a6200027436600462004394565b62000ac2565b604051620001759796959493929190620045fc565b3480156200029c57600080fd5b5062000144620011b4565b348015620002b457600080fd5b5062000144620002c63660046200464e565b620012b7565b348015620002d957600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16620001e5565b3480156200030657600080fd5b506200014462000318366004620046db565b62001f28565b3480156200032b57600080fd5b50620001446200033d3660046200473e565b620022b0565b3480156200035057600080fd5b5062000144620003623660046200476d565b62002543565b3480156200037557600080fd5b50620001a36200038736600462004843565b6200290a565b3480156200039a57600080fd5b5062000144620003ac366004620048ba565b620029da565b348015620003bf57600080fd5b506200027a620003d13660046200476d565b620029f2565b6000805473ffffffffffffffffffffffffffffffffffffffff1633148015906200040b57506200040960093362002a30565b155b1562000443576040517fd48b678b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff89163b62000492576040517f09ee12d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6200049d8662002a64565b9050600089307f0000000000000000000000000000000000000000000000000000000000000000604051620004d2906200403f565b73ffffffffffffffffffffffffffffffffffffffff938416815291831660208301529091166040820152606001604051809103906000f0801580156200051c573d6000803e3d6000fd5b509050620005e3826040518060e001604052806000151581526020018c63ffffffff16815260200163ffffffff801681526020018473ffffffffffffffffffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff168152602001600063ffffffff168152508a89898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508b92508a915062002c089050565b6014805474010000000000000000000000000000000000000000900463ffffffff169080620006128362004909565b91906101000a81548163ffffffff021916908363ffffffff16021790555050817fbae366358c023f887e791d7a62f2e4316f1026bd77f6fb49501a917b3bc5d0128a8a6040516200068b92919063ffffffff92909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a2817fcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d8787604051620006c792919062004978565b60405180910390a2817f2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d5664856040516200070191906200498e565b60405180910390a2817f3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf4850846040516200073b91906200498e565b60405180910390a25098975050505050505050565b600060606000806200076162002fe3565b600086815260046020908152604091829020825160e081018452815460ff811615158252610100810463ffffffff90811694830194909452650100000000008104841694820194909452690100000000000000000090930473ffffffffffffffffffffffffffffffffffffffff166060840152600101546bffffffffffffffffffffffff80821660808501526c0100000000000000000000000082041660a0840152780100000000000000000000000000000000000000000000000090041660c08201525a9150600080826060015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200087b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620008a19190620049b0565b73ffffffffffffffffffffffffffffffffffffffff166013600101600c9054906101000a900463ffffffff1663ffffffff1689604051620008e39190620049d0565b60006040518083038160008787f1925050503d806000811462000923576040519150601f19603f3d011682016040523d82523d6000602084013e62000928565b606091505b50915091505a6200093a9085620049ee565b93508162000965576000604051806020016040528060008152506007965096509650505050620009eb565b808060200190518101906200097b919062004a5f565b909750955086620009a9576000604051806020016040528060008152506004965096509650505050620009eb565b601554865164010000000090910463ffffffff161015620009e7576000604051806020016040528060008152506005965096509650505050620009eb565b5050505b92959194509250565b620009ff836200301e565b6000838152601a6020526040902062000a1a82848362004b54565b50827f2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d5664838360405162000a4f92919062004978565b60405180910390a2505050565b600062000ab688888860008989604051806020016040528060008152508a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250620003d792505050565b98975050505050505050565b60006060600080600080600062000ad862002fe3565b600062000ae58a620030d4565b905060006012604051806101200160405290816000820160009054906101000a900460ff1660ff1660ff1681526020016000820160019054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160059054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160099054906101000a900462ffffff1662ffffff1662ffffff16815260200160008201600c9054906101000a900461ffff1661ffff1661ffff16815260200160008201600e9054906101000a900460ff1615151515815260200160008201600f9054906101000a900460ff161515151581526020016000820160109054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160008201601c9054906101000a900463ffffffff1663ffffffff1663ffffffff168152505090506000600460008d81526020019081526020016000206040518060e00160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160059054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160099054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160018201600c9054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff1681526020016001820160189054906101000a900463ffffffff1663ffffffff1663ffffffff168152505090508160a001511562000e09576000604051806020016040528060008152506009600084602001516000808263ffffffff1692509950995099509950995099509950505050620011a8565b604081015163ffffffff9081161462000e5a576000604051806020016040528060008152506001600084602001516000808263ffffffff1692509950995099509950995099509950505050620011a8565b80511562000ea0576000604051806020016040528060008152506002600084602001516000808263ffffffff1692509950995099509950995099509950505050620011a8565b62000eab8262003182565b602083015160155492975090955060009162000edd918591879190640100000000900463ffffffff168a8a8762003374565b9050806bffffffffffffffffffffffff168260a001516bffffffffffffffffffffffff16101562000f47576000604051806020016040528060008152506006600085602001516000808263ffffffff1692509a509a509a509a509a509a509a5050505050620011a8565b600062000f568e868f620033c5565b90505a9850600080846060015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000fae573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000fd49190620049b0565b73ffffffffffffffffffffffffffffffffffffffff166013600101600c9054906101000a900463ffffffff1663ffffffff1684604051620010169190620049d0565b60006040518083038160008787f1925050503d806000811462001056576040519150601f19603f3d011682016040523d82523d6000602084013e6200105b565b606091505b50915091505a6200106d908c620049ee565b9a5081620010ed5760155481516801000000000000000090910463ffffffff161015620010ca57505060408051602080820190925260008082529490910151939c509a50600899505063ffffffff9091169550620011a892505050565b602090940151939b5060039a505063ffffffff9092169650620011a89350505050565b8080602001905181019062001103919062004a5f565b909e509c508d6200114457505060408051602080820190925260008082529490910151939c509a50600499505063ffffffff9091169550620011a892505050565b6015548d5164010000000090910463ffffffff1610156200119557505060408051602080820190925260008082529490910151939c509a50600599505063ffffffff9091169550620011a892505050565b505050506020015163ffffffff16945050505b92959891949750929550565b60015473ffffffffffffffffffffffffffffffffffffffff1633146200123b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600173ffffffffffffffffffffffffffffffffffffffff821660009081526019602052604090205460ff166003811115620012f657620012f662004451565b14158015620013425750600373ffffffffffffffffffffffffffffffffffffffff821660009081526019602052604090205460ff1660038111156200133f576200133f62004451565b14155b156200137a576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6013546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff16620013da576040517fd12d7d8d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082900362001416576040517f2c2fc94100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081018290526000808567ffffffffffffffff8111156200146d576200146d62004135565b60405190808252806020026020018201604052801562001497578160200160208202803683370190505b50905060008667ffffffffffffffff811115620014b857620014b862004135565b6040519080825280602002602001820160405280156200153f57816020015b6040805160e08101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181620014d75790505b50905060008767ffffffffffffffff81111562001560576200156062004135565b6040519080825280602002602001820160405280156200159557816020015b60608152602001906001900390816200157f5790505b50905060008867ffffffffffffffff811115620015b657620015b662004135565b604051908082528060200260200182016040528015620015eb57816020015b6060815260200190600190039081620015d55790505b50905060008967ffffffffffffffff8111156200160c576200160c62004135565b6040519080825280602002602001820160405280156200164157816020015b60608152602001906001900390816200162b5790505b50905060005b8a81101562001c25578b8b8281811062001665576200166562004c7c565b60209081029290920135600081815260048452604090819020815160e081018352815460ff811615158252610100810463ffffffff90811697830197909752650100000000008104871693820193909352690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff166060830152600101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490931660c08401529a50909850620017449050896200301e565b60608801516040517f1a5da6c800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8c8116600483015290911690631a5da6c890602401600060405180830381600087803b158015620017b457600080fd5b505af1158015620017c9573d6000803e3d6000fd5b5050505087858281518110620017e357620017e362004c7c565b6020026020010181905250600560008a815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1686828151811062001837576200183762004c7c565b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910182015260008a81526007909152604090208054620018769062004aac565b80601f0160208091040260200160405190810160405280929190818152602001828054620018a49062004aac565b8015620018f55780601f10620018c957610100808354040283529160200191620018f5565b820191906000526020600020905b815481529060010190602001808311620018d757829003601f168201915b50505050508482815181106200190f576200190f62004c7c565b6020026020010181905250601a60008a815260200190815260200160002080546200193a9062004aac565b80601f0160208091040260200160405190810160405280929190818152602001828054620019689062004aac565b8015620019b95780601f106200198d57610100808354040283529160200191620019b9565b820191906000526020600020905b8154815290600101906020018083116200199b57829003601f168201915b5050505050838281518110620019d357620019d362004c7c565b6020026020010181905250601b60008a81526020019081526020016000208054620019fe9062004aac565b80601f016020809104026020016040519081016040528092919081815260200182805462001a2c9062004aac565b801562001a7d5780601f1062001a515761010080835404028352916020019162001a7d565b820191906000526020600020905b81548152906001019060200180831162001a5f57829003601f168201915b505050505082828151811062001a975762001a9762004c7c565b60200260200101819052508760a001516bffffffffffffffffffffffff168762001ac2919062004cab565b60008a815260046020908152604080832080547fffffff000000000000000000000000000000000000000000000000000000000016815560010180547fffffffff000000000000000000000000000000000000000000000000000000001690556007909152812091985062001b3891906200404d565b6000898152601a6020526040812062001b51916200404d565b6000898152601b6020526040812062001b6a916200404d565b600089815260066020526040902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905562001bab60028a620035e7565b5060a0880151604080516bffffffffffffffffffffffff909216825273ffffffffffffffffffffffffffffffffffffffff8c1660208301528a917fb38647142fbb1ea4c000fc4569b37a4e9a9f6313317b84ee3e5326c1a6cd06ff910160405180910390a28062001c1c8162004cc1565b91505062001647565b508560185462001c369190620049ee565b60185560008b8b868167ffffffffffffffff81111562001c5a5762001c5a62004135565b60405190808252806020026020018201604052801562001c84578160200160208202803683370190505b508988888860405160200162001ca298979695949392919062004e67565b60405160208183030381529060405290508973ffffffffffffffffffffffffffffffffffffffff16638e86139b6013600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c71249ab60038e73ffffffffffffffffffffffffffffffffffffffff1663aab9edd66040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001d5e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001d84919062004f37565b866040518463ffffffff1660e01b815260040162001da59392919062004f5c565b600060405180830381865afa15801562001dc3573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405262001e0b919081019062004f83565b6040518263ffffffff1660e01b815260040162001e2991906200498e565b600060405180830381600087803b15801562001e4457600080fd5b505af115801562001e59573d6000803e3d6000fd5b50506040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8d81166004830152602482018b90527f000000000000000000000000000000000000000000000000000000000000000016925063a9059cbb91506044016020604051808303816000875af115801562001ef3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001f19919062004fbc565b50505050505050505050505050565b60023360009081526019602052604090205460ff16600381111562001f515762001f5162004451565b1415801562001f87575060033360009081526019602052604090205460ff16600381111562001f845762001f8462004451565b14155b1562001fbf576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080808080808062001fd5888a018a620051b4565b965096509650965096509650965060005b8751811015620022a457600073ffffffffffffffffffffffffffffffffffffffff168782815181106200201d576200201d62004c7c565b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff160362002131578581815181106200205a576200205a62004c7c565b6020026020010151307f000000000000000000000000000000000000000000000000000000000000000060405162002092906200403f565b73ffffffffffffffffffffffffffffffffffffffff938416815291831660208301529091166040820152606001604051809103906000f080158015620020dc573d6000803e3d6000fd5b50878281518110620020f257620020f262004c7c565b60200260200101516060019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250505b620021e98882815181106200214a576200214a62004c7c565b602002602001015188838151811062002167576200216762004c7c565b602002602001015187848151811062002184576200218462004c7c565b6020026020010151878581518110620021a157620021a162004c7c565b6020026020010151878681518110620021be57620021be62004c7c565b6020026020010151878781518110620021db57620021db62004c7c565b602002602001015162002c08565b878181518110620021fe57620021fe62004c7c565b60200260200101517f74931a144e43a50694897f241d973aecb5024c0e910f9bb80a163ea3c1cf5a718883815181106200223c576200223c62004c7c565b602002602001015160a0015133604051620022879291906bffffffffffffffffffffffff92909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a2806200229b8162004cc1565b91505062001fe6565b50505050505050505050565b600082815260046020908152604091829020825160e081018452815460ff81161515825263ffffffff6101008204811694830194909452650100000000008104841694820185905273ffffffffffffffffffffffffffffffffffffffff69010000000000000000009091041660608201526001909101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a083015278010000000000000000000000000000000000000000000000009004821660c08201529114620023ae576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818160a00151620023c09190620052e5565b600084815260046020526040902060010180547fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff166c010000000000000000000000006bffffffffffffffffffffffff93841602179055601854620024289184169062004cab565b6018556040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526bffffffffffffffffffffffff831660448201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906323b872dd906064016020604051808303816000875af1158015620024d2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620024f8919062004fbc565b506040516bffffffffffffffffffffffff83168152339084907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a3505050565b6000818152600460209081526040808320815160e081018352815460ff81161515825263ffffffff6101008204811695830195909552650100000000008104851693820184905273ffffffffffffffffffffffffffffffffffffffff69010000000000000000009091041660608201526001909101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a083015278010000000000000000000000000000000000000000000000009004831660c082015292911415906200262c60005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905081801562002687575080801562002685575062002678620035f5565b836040015163ffffffff16115b155b15620026bf576040517ffbc0357800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80158015620026f2575060008481526005602052604090205473ffffffffffffffffffffffffffffffffffffffff163314155b156200272a576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600062002736620035f5565b9050816200274e576200274b60328262004cab565b90505b6000858152600460205260409020805463ffffffff80841665010000000000027fffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffff90921691909117909155620027aa906002908790620035e716565b5060135460808501516bffffffffffffffffffffffff918216916000911682111562002813576080860151620027e190836200530d565b90508560a001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff16111562002813575060a08501515b808660a001516200282591906200530d565b600088815260046020526040902060010180547fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff166c010000000000000000000000006bffffffffffffffffffffffff938416021790556014546200288d91839116620052e5565b601480547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff9290921691909117905560405167ffffffffffffffff84169088907f91cb3bb75cfbd718bbfccc56b7f53d92d7048ef4ca39a3b7b7c6d4af1f79118190600090a350505050505050565b600060606000806200291b62002fe3565b6000634b56a42e60e01b8888886040516024016200293c9392919062005335565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050620029c7898262000750565b929c919b50995090975095505050505050565b620029e4620036b1565b620029ef8162003734565b50565b60006060600080600080600062002a19886040518060200160405280600081525062000ac2565b959e949d50929b5090995097509550909350915050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260018301602052604081205415155b90505b92915050565b600080600062002a8b600162002a79620035f5565b62002a859190620049ee565b6200382b565b601454604080516020810193909352309083015274010000000000000000000000000000000000000000900463ffffffff166060820152608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201209083015201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060045b600f81101562002b97578282828151811062002b535762002b5362004c7c565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508062002b8e8162004cc1565b91505062002b33565b5083600181111562002bad5762002bad62004451565b60f81b81600f8151811062002bc65762002bc662004c7c565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535062002c008162005369565b949350505050565b6012546e010000000000000000000000000000900460ff161562002c58576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601554835163ffffffff909116101562002c9e576040517fae7235df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108fc856020015163ffffffff16108062002cdc5750601454602086015163ffffffff70010000000000000000000000000000000090920482169116115b1562002d14576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000868152600460205260409020546901000000000000000000900473ffffffffffffffffffffffffffffffffffffffff161562002d7e576040517f6e3b930b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000868152600460209081526040808320885181548a8501518b85015160608d01517fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000009093169315157fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff169390931761010063ffffffff92831602177fffffff000000000000000000000000000000000000000000000000ffffffffff1665010000000000938216939093027fffffff0000000000000000000000000000000000000000ffffffffffffffffff1692909217690100000000000000000073ffffffffffffffffffffffffffffffffffffffff9283160217835560808b01516001909301805460a08d015160c08e01516bffffffffffffffffffffffff9687167fffffffffffffffff000000000000000000000000000000000000000000000000909316929092176c010000000000000000000000009690911695909502949094177fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff1678010000000000000000000000000000000000000000000000009490931693909302919091179091556005835281842080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169189169190911790556007909152902062002f718482620053ac565b508460a001516bffffffffffffffffffffffff1660185462002f94919062004cab565b6018556000868152601a6020526040902062002fb18382620053ac565b506000868152601b6020526040902062002fcc8282620053ac565b5062002fda60028762003993565b50505050505050565b32156200301c576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60008181526005602052604090205473ffffffffffffffffffffffffffffffffffffffff1633146200307c576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526004602052604090205465010000000000900463ffffffff90811614620029ef576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818160045b600f81101562003169577fff0000000000000000000000000000000000000000000000000000000000000082168382602081106200311d576200311d62004c7c565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916146200315457506000949350505050565b80620031608162004cc1565b915050620030db565b5081600f1a600181111562002c005762002c0062004451565b6000806000836060015162ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156200320f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620032359190620054ee565b50945090925050506000811315806200324d57508142105b80620032725750828015620032725750620032698242620049ee565b8463ffffffff16105b156200328357601654955062003287565b8095505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015620032f3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620033199190620054ee565b50945090925050506000811315806200333157508142105b806200335657508280156200335657506200334d8242620049ee565b8463ffffffff16105b15620033675760175494506200336b565b8094505b50505050915091565b6000806200338888878b60000151620039a1565b9050600080620033a58b8a63ffffffff16858a8a60018b62003a40565b9092509050620033b68183620052e5565b9b9a5050505050505050505050565b60606000836001811115620033de57620033de62004451565b03620034ab576000848152600760205260409081902090517f6e04ff0d00000000000000000000000000000000000000000000000000000000916200342691602401620055e6565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050620035e0565b6001836001811115620034c257620034c262004451565b03620035ae57600082806020019051810190620034e091906200565d565b6000868152600760205260409081902090519192507f40691db400000000000000000000000000000000000000000000000000000000916200352791849160240162005771565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529150620035e09050565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9392505050565b600062002a5b838362003ee2565b600060017f000000000000000000000000000000000000000000000000000000000000000060028111156200362e576200362e62004451565b03620036ac57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562003681573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620036a7919062005839565b905090565b504390565b60005473ffffffffffffffffffffffffffffffffffffffff1633146200301c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162001232565b3373ffffffffffffffffffffffffffffffffffffffff821603620037b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162001232565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060017f0000000000000000000000000000000000000000000000000000000000000000600281111562003864576200386462004451565b0362003989576000606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620038b9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620038df919062005839565b90508083101580620038fd5750610100620038fb8483620049ee565b115b156200390c5750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815260048101849052606490632b407a8290602401602060405180830381865afa15801562003963573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620035e0919062005839565b504090565b919050565b600062002a5b838362003fed565b60008080856001811115620039ba57620039ba62004451565b03620039cb575062015f90620039ee565b6001856001811115620039e257620039e262004451565b03620035ae57506201adb05b62003a0163ffffffff8516601462005853565b62003a0e84600162005893565b62003a1f9060ff16611d4c62005853565b62003a2b908362004cab565b62003a37919062004cab565b95945050505050565b6000806000896080015161ffff168762003a5b919062005853565b905083801562003a6a5750803a105b1562003a7357503a5b600060027f0000000000000000000000000000000000000000000000000000000000000000600281111562003aac5762003aac62004451565b0362003c1d57604080516000815260208101909152851562003b105760003660405180608001604052806048815260200162005d886048913960405160200162003af993929190620058af565b604051602081830303815290604052905062003b7e565b60155462003b2e90640100000000900463ffffffff166004620058d8565b63ffffffff1667ffffffffffffffff81111562003b4f5762003b4f62004135565b6040519080825280601f01601f19166020018201604052801562003b7a576020820181803683370190505b5090505b6040517f49948e0e00000000000000000000000000000000000000000000000000000000815273420000000000000000000000000000000000000f906349948e0e9062003bd09084906004016200498e565b602060405180830381865afa15801562003bee573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003c14919062005839565b91505062003d87565b60017f0000000000000000000000000000000000000000000000000000000000000000600281111562003c545762003c5462004451565b0362003d8757841562003cdc57606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562003cae573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003cd4919062005839565b905062003d87565b6000606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c060405180830381865afa15801562003d2b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003d51919062005907565b505060155492945062003d7693505050640100000000900463ffffffff168262005853565b62003d8390601062005853565b9150505b8462003da657808b6080015161ffff1662003da3919062005853565b90505b62003db661ffff87168262005952565b90506000878262003dc88c8e62004cab565b62003dd4908662005853565b62003de0919062004cab565b62003df490670de0b6b3a764000062005853565b62003e00919062005952565b905060008c6040015163ffffffff1664e8d4a5100062003e21919062005853565b898e6020015163ffffffff16858f8862003e3c919062005853565b62003e48919062004cab565b62003e5890633b9aca0062005853565b62003e64919062005853565b62003e70919062005952565b62003e7c919062004cab565b90506b033b2e3c9fd0803ce800000062003e97828462004cab565b111562003ed0576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b909c909b509950505050505050505050565b6000818152600183016020526040812054801562003fdb57600062003f09600183620049ee565b855490915060009062003f1f90600190620049ee565b905081811462003f8b57600086600001828154811062003f435762003f4362004c7c565b906000526020600020015490508087600001848154811062003f695762003f6962004c7c565b6000918252602080832090910192909255918252600188019052604090208390555b855486908062003f9f5762003f9f6200598e565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505062002a5e565b600091505062002a5e565b5092915050565b6000818152600183016020526040812054620040365750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562002a5e565b50600062002a5e565b6103ca80620059be83390190565b5080546200405b9062004aac565b6000825580601f106200406c575050565b601f016020900490600052602060002090810190620029ef91905b808211156200409d576000815560010162004087565b5090565b73ffffffffffffffffffffffffffffffffffffffff81168114620029ef57600080fd5b803563ffffffff811681146200398e57600080fd5b8035600281106200398e57600080fd5b60008083601f840112620040fc57600080fd5b50813567ffffffffffffffff8111156200411557600080fd5b6020830191508360208285010111156200412e57600080fd5b9250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160e0810167ffffffffffffffff811182821017156200418a576200418a62004135565b60405290565b604051610100810167ffffffffffffffff811182821017156200418a576200418a62004135565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171562004201576200420162004135565b604052919050565b600067ffffffffffffffff82111562004226576200422662004135565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f8301126200426457600080fd5b81356200427b620042758262004209565b620041b7565b8181528460208386010111156200429157600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060008060e0898b031215620042cb57600080fd5b8835620042d881620040a1565b9750620042e860208a01620040c4565b96506040890135620042fa81620040a1565b95506200430a60608a01620040d9565b9450608089013567ffffffffffffffff808211156200432857600080fd5b620043368c838d01620040e9565b909650945060a08b01359150808211156200435057600080fd5b6200435e8c838d0162004252565b935060c08b01359150808211156200437557600080fd5b50620043848b828c0162004252565b9150509295985092959890939650565b60008060408385031215620043a857600080fd5b82359150602083013567ffffffffffffffff811115620043c757600080fd5b620043d58582860162004252565b9150509250929050565b60005b83811015620043fc578181015183820152602001620043e2565b50506000910152565b600081518084526200441f816020860160208601620043df565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600a8110620044b8577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b8415158152608060208201526000620044d9608083018662004405565b9050620044ea604083018562004480565b82606083015295945050505050565b6000806000604084860312156200450f57600080fd5b83359250602084013567ffffffffffffffff8111156200452e57600080fd5b6200453c86828701620040e9565b9497909650939450505050565b600080600080600080600060a0888a0312156200456557600080fd5b87356200457281620040a1565b96506200458260208901620040c4565b955060408801356200459481620040a1565b9450606088013567ffffffffffffffff80821115620045b257600080fd5b620045c08b838c01620040e9565b909650945060808a0135915080821115620045da57600080fd5b50620045e98a828b01620040e9565b989b979a50959850939692959293505050565b871515815260e0602082015260006200461960e083018962004405565b90506200462a604083018862004480565b8560608301528460808301528360a08301528260c083015298975050505050505050565b6000806000604084860312156200466457600080fd5b833567ffffffffffffffff808211156200467d57600080fd5b818601915086601f8301126200469257600080fd5b813581811115620046a257600080fd5b8760208260051b8501011115620046b857600080fd5b60209283019550935050840135620046d081620040a1565b809150509250925092565b60008060208385031215620046ef57600080fd5b823567ffffffffffffffff8111156200470757600080fd5b6200471585828601620040e9565b90969095509350505050565b80356bffffffffffffffffffffffff811681146200398e57600080fd5b600080604083850312156200475257600080fd5b82359150620047646020840162004721565b90509250929050565b6000602082840312156200478057600080fd5b5035919050565b600067ffffffffffffffff821115620047a457620047a462004135565b5060051b60200190565b600082601f830112620047c057600080fd5b81356020620047d3620042758362004787565b82815260059290921b84018101918181019086841115620047f357600080fd5b8286015b848110156200483857803567ffffffffffffffff811115620048195760008081fd5b620048298986838b010162004252565b845250918301918301620047f7565b509695505050505050565b600080600080606085870312156200485a57600080fd5b84359350602085013567ffffffffffffffff808211156200487a57600080fd5b6200488888838901620047ae565b945060408701359150808211156200489f57600080fd5b50620048ae87828801620040e9565b95989497509550505050565b600060208284031215620048cd57600080fd5b8135620035e081620040a1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff808316818103620049255762004925620048da565b6001019392505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60208152600062002c006020830184866200492f565b60208152600062002a5b602083018462004405565b80516200398e81620040a1565b600060208284031215620049c357600080fd5b8151620035e081620040a1565b60008251620049e4818460208701620043df565b9190910192915050565b8181038181111562002a5e5762002a5e620048da565b8015158114620029ef57600080fd5b600082601f83011262004a2557600080fd5b815162004a36620042758262004209565b81815284602083860101111562004a4c57600080fd5b62002c00826020830160208701620043df565b6000806040838503121562004a7357600080fd5b825162004a808162004a04565b602084015190925067ffffffffffffffff81111562004a9e57600080fd5b620043d58582860162004a13565b600181811c9082168062004ac157607f821691505b60208210810362004afb577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f82111562004b4f57600081815260208120601f850160051c8101602086101562004b2a5750805b601f850160051c820191505b8181101562004b4b5782815560010162004b36565b5050505b505050565b67ffffffffffffffff83111562004b6f5762004b6f62004135565b62004b878362004b80835462004aac565b8362004b01565b6000601f84116001811462004bdc576000851562004ba55750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b17835562004c75565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b8281101562004c2d578685013582556020948501946001909201910162004c0b565b508682101562004c69577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8082018082111562002a5e5762002a5e620048da565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820362004cf55762004cf5620048da565b5060010190565b600081518084526020808501945080840160005b8381101562004dbb5781518051151588528381015163ffffffff908116858a01526040808301519091169089015260608082015173ffffffffffffffffffffffffffffffffffffffff16908901526080808201516bffffffffffffffffffffffff169089015260a08082015162004d96828b01826bffffffffffffffffffffffff169052565b505060c09081015163ffffffff169088015260e0909601959082019060010162004d10565b509495945050505050565b600081518084526020808501945080840160005b8381101562004dbb57815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010162004dda565b600081518084526020808501808196508360051b8101915082860160005b8581101562004e5a57828403895262004e4784835162004405565b9885019893509084019060010162004e2c565b5091979650505050505050565b60e081528760e082015260006101007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a111562004ea457600080fd5b8960051b808c8386013783018381038201602085015262004ec88282018b62004cfc565b915050828103604084015262004edf818962004dc6565b9050828103606084015262004ef5818862004dc6565b9050828103608084015262004f0b818762004e0e565b905082810360a084015262004f21818662004e0e565b905082810360c0840152620033b6818562004e0e565b60006020828403121562004f4a57600080fd5b815160ff81168114620035e057600080fd5b60ff8416815260ff8316602082015260606040820152600062003a37606083018462004405565b60006020828403121562004f9657600080fd5b815167ffffffffffffffff81111562004fae57600080fd5b62002c008482850162004a13565b60006020828403121562004fcf57600080fd5b8151620035e08162004a04565b600082601f83011262004fee57600080fd5b8135602062005001620042758362004787565b82815260059290921b840181019181810190868411156200502157600080fd5b8286015b8481101562004838578035835291830191830162005025565b600082601f8301126200505057600080fd5b8135602062005063620042758362004787565b82815260e092830285018201928282019190878511156200508357600080fd5b8387015b858110156200513a5781818a031215620050a15760008081fd5b620050ab62004164565b8135620050b88162004a04565b8152620050c7828701620040c4565b868201526040620050da818401620040c4565b90820152606082810135620050ef81620040a1565b9082015260806200510283820162004721565b9082015260a06200511583820162004721565b9082015260c062005128838201620040c4565b90820152845292840192810162005087565b5090979650505050505050565b600082601f8301126200515957600080fd5b813560206200516c620042758362004787565b82815260059290921b840181019181810190868411156200518c57600080fd5b8286015b8481101562004838578035620051a681620040a1565b835291830191830162005190565b600080600080600080600060e0888a031215620051d057600080fd5b873567ffffffffffffffff80821115620051e957600080fd5b620051f78b838c0162004fdc565b985060208a01359150808211156200520e57600080fd5b6200521c8b838c016200503e565b975060408a01359150808211156200523357600080fd5b620052418b838c0162005147565b965060608a01359150808211156200525857600080fd5b620052668b838c0162005147565b955060808a01359150808211156200527d57600080fd5b6200528b8b838c01620047ae565b945060a08a0135915080821115620052a257600080fd5b620052b08b838c01620047ae565b935060c08a0135915080821115620052c757600080fd5b50620052d68a828b01620047ae565b91505092959891949750929550565b6bffffffffffffffffffffffff81811683821601908082111562003fe65762003fe6620048da565b6bffffffffffffffffffffffff82811682821603908082111562003fe65762003fe6620048da565b6040815260006200534a604083018662004e0e565b82810360208401526200535f8185876200492f565b9695505050505050565b8051602080830151919081101562004afb577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b815167ffffffffffffffff811115620053c957620053c962004135565b620053e181620053da845462004aac565b8462004b01565b602080601f831160018114620054375760008415620054005750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b17855562004b4b565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015620054865788860151825594840194600190910190840162005465565b5085821015620054c357878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b805169ffffffffffffffffffff811681146200398e57600080fd5b600080600080600060a086880312156200550757600080fd5b6200551286620054d3565b94506020860151935060408601519250606086015191506200553760808701620054d3565b90509295509295909350565b60008154620055528162004aac565b808552602060018381168015620055725760018114620055ab57620055db565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b8901019550620055db565b866000528260002060005b85811015620055d35781548a8201860152908301908401620055b6565b890184019650505b505050505092915050565b60208152600062002a5b602083018462005543565b600082601f8301126200560d57600080fd5b8151602062005620620042758362004787565b82815260059290921b840181019181810190868411156200564057600080fd5b8286015b8481101562004838578051835291830191830162005644565b6000602082840312156200567057600080fd5b815167ffffffffffffffff808211156200568957600080fd5b9083019061010082860312156200569f57600080fd5b620056a962004190565b8251815260208301516020820152604083015160408201526060830151606082015260808301516080820152620056e360a08401620049a3565b60a082015260c083015182811115620056fb57600080fd5b6200570987828601620055fb565b60c08301525060e0830151828111156200572257600080fd5b620057308782860162004a13565b60e08301525095945050505050565b600081518084526020808501945080840160005b8381101562004dbb5781518752958201959082019060010162005753565b60408152825160408201526020830151606082015260408301516080820152606083015160a0820152608083015160c082015273ffffffffffffffffffffffffffffffffffffffff60a08401511660e0820152600060c0840151610100808185015250620057e46101408401826200573f565b905060e08501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08483030161012085015262005822828262004405565b915050828103602084015262003a37818562005543565b6000602082840312156200584c57600080fd5b5051919050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156200588e576200588e620048da565b500290565b60ff818116838216019081111562002a5e5762002a5e620048da565b828482376000838201600081528351620058ce818360208801620043df565b0195945050505050565b600063ffffffff80831681851681830481118215151615620058fe57620058fe620048da565b02949350505050565b60008060008060008060c087890312156200592157600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b60008262005989577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe60c060405234801561001057600080fd5b506040516103ca3803806103ca83398101604081905261002f91610076565b600080546001600160a01b0319166001600160a01b039384161790559181166080521660a0526100b9565b80516001600160a01b038116811461007157600080fd5b919050565b60008060006060848603121561008b57600080fd5b6100948461005a565b92506100a26020850161005a565b91506100b06040850161005a565b90509250925092565b60805160a0516102e76100e36000396000603801526000818160c4015261011701526102e76000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806379188d161461007b578063f00e6a2a146100aa575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e808015610076573d6000f35b3d6000fd5b61008e6100893660046101c1565b6100ee565b6040805192151583526020830191909152015b60405180910390f35b60405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001681526020016100a1565b60008054819073ffffffffffffffffffffffffffffffffffffffff16331461011557600080fd5b7f00000000000000000000000000000000000000000000000000000000000000005a91505a61138881101561014957600080fd5b61138881039050856040820482031161016157600080fd5b50803b61016d57600080fd5b6000808551602087016000858af192505a610188908361029a565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080604083850312156101d457600080fd5b82359150602083013567ffffffffffffffff808211156101f357600080fd5b818501915085601f83011261020757600080fd5b81358181111561021957610219610192565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561025f5761025f610192565b8160405282815288602084870101111561027857600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b818103818111156102d4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea164736f6c6343000810000a307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000810000a", } var KeeperRegistryLogicAABI = KeeperRegistryLogicAMetaData.ABI diff --git a/core/gethwrappers/generated/keeper_registry_wrapper_2_1/keeper_registry_wrapper_2_1.go b/core/gethwrappers/generated/keeper_registry_wrapper_2_1/keeper_registry_wrapper_2_1.go index 54f69961fec..1d7be8a9e6a 100644 --- a/core/gethwrappers/generated/keeper_registry_wrapper_2_1/keeper_registry_wrapper_2_1.go +++ b/core/gethwrappers/generated/keeper_registry_wrapper_2_1/keeper_registry_wrapper_2_1.go @@ -49,8 +49,8 @@ type IAutomationV21PlusCommonOnchainConfigLegacy struct { } var KeeperRegistryMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"contractKeeperRegistryLogicB2_1\",\"name\":\"logicA\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientFunds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxCheckDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxPerformDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentGreaterThanAllLINK\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"OwnerFundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"onchainConfigBytes\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"}],\"internalType\":\"structIAutomationV21PlusCommon.OnchainConfigLegacy\",\"name\":\"onchainConfig\",\"type\":\"tuple\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfigTypeSafe\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"simulatePerformUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"rawReport\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x6101406040523480156200001257600080fd5b50604051620054d0380380620054d08339810160408190526200003591620003df565b80816001600160a01b0316634b4fd03b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b919062000406565b826001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001009190620003df565b836001600160a01b031663b10b673c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001659190620003df565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca9190620003df565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f9190620003df565b3380600081620002865760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620002b957620002b9816200031b565b505050846002811115620002d157620002d162000429565b60e0816002811115620002e857620002e862000429565b9052506001600160a01b0393841660805291831660a052821660c0528116610100529190911661012052506200043f9050565b336001600160a01b03821603620003755760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200027d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b0381168114620003dc57600080fd5b50565b600060208284031215620003f257600080fd5b8151620003ff81620003c6565b9392505050565b6000602082840312156200041957600080fd5b815160038110620003ff57600080fd5b634e487b7160e01b600052602160045260246000fd5b60805160a05160c05160e051610100516101205161502f620004a16000396000818160d6015261016f01526000505060008181612eb701528181613220015281816133b30152613a4901526000505060005050600061043b015261502f6000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c8063aed2e92911610081578063e29b753c1161005b578063e29b753c146102e8578063e3d0e712146102fb578063f2fde38b1461030e576100d4565b8063aed2e92914610262578063afcb95d71461028c578063b1dc65a4146102d5576100d4565b806381ff7048116100b257806381ff7048146101bc5780638da5cb5b14610231578063a4c0ed361461024f576100d4565b8063181f5a771461011b578063349e8cca1461016d57806379ba5097146101b4575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e808015610114573d6000f35b3d6000fd5b005b6101576040518060400160405280601481526020017f4b6565706572526567697374727920322e312e3000000000000000000000000081525081565b6040516101649190613cc8565b60405180910390f35b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610164565b610119610321565b61020e60145460115463ffffffff780100000000000000000000000000000000000000000000000083048116937c01000000000000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610164565b60005473ffffffffffffffffffffffffffffffffffffffff1661018f565b61011961025d366004613d51565b610423565b610275610270366004613dad565b61063f565b604080519215158352602083019190915201610164565b601154601254604080516000815260208101939093527c010000000000000000000000000000000000000000000000000000000090910463ffffffff1690820152606001610164565b6101196102e3366004613e3e565b6107a7565b6101196102f63660046142b9565b6112ea565b610119610309366004614386565b6121e6565b61011961031c366004614415565b61220f565b60015473ffffffffffffffffffffffffffffffffffffffff1633146103a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610492576040517fc8bad78d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602081146104cc576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006104da82840184614432565b60008181526004602052604090205490915065010000000000900463ffffffff90811614610534576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526004602052604090206001015461056f9085906c0100000000000000000000000090046bffffffffffffffffffffffff1661447a565b600082815260046020526040902060010180546bffffffffffffffffffffffff929092166c01000000000000000000000000027fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff9092169190911790556018546105da90859061449f565b6018556040516bffffffffffffffffffffffff8516815273ffffffffffffffffffffffffffffffffffffffff86169082907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a35050505050565b60008061064a612223565b6012546e010000000000000000000000000000900460ff1615610699576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600085815260046020908152604091829020825160e081018452815460ff811615158252610100810463ffffffff908116838601819052650100000000008304821684880152690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff16606084018190526001909401546bffffffffffffffffffffffff80821660808601526c0100000000000000000000000082041660a0850152780100000000000000000000000000000000000000000000000090041660c08301528451601f8901859004850281018501909552878552909361079893899089908190840183828082843760009201919091525061225d92505050565b9093509150505b935093915050565b60005a604080516101208101825260125460ff808216835261010080830463ffffffff90811660208601526501000000000084048116958501959095526901000000000000000000830462ffffff1660608501526c01000000000000000000000000830461ffff1660808501526e0100000000000000000000000000008304821615801560a08601526f010000000000000000000000000000008404909216151560c085015270010000000000000000000000000000000083046bffffffffffffffffffffffff1660e08501527c0100000000000000000000000000000000000000000000000000000000909204909316908201529192506108d5576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600b602052604090205460ff1661091e576040517f1099ed7500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6011548a351461095a576040517fdfdcf8e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516109679060016144e1565b60ff16861415806109785750858414155b156109af576040517f0244f71a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109bf8a8a8a8a8a8a8a8a612468565b60006109cb8a8a6126d1565b9050600081604001515167ffffffffffffffff8111156109ed576109ed613ef5565b604051908082528060200260200182016040528015610ab157816020015b604080516101e0810182526000610100820181815261012083018290526101408301829052610160830182905261018083018290526101a083018290526101c0830182905282526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181610a0b5790505b5090506000805b836040015151811015610efa576004600085604001518381518110610adf57610adf6144b2565b6020908102919091018101518252818101929092526040908101600020815160e081018352815460ff811615158252610100810463ffffffff90811695830195909552650100000000008104851693820193909352690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff166060830152600101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490911660c08201528351849083908110610bc457610bc46144b2565b602002602001015160000181905250610bf984604001518281518110610bec57610bec6144b2565b602002602001015161278c565b838281518110610c0b57610c0b6144b2565b6020026020010151608001906001811115610c2857610c286144fa565b90816001811115610c3b57610c3b6144fa565b81525050610caf85848381518110610c5557610c556144b2565b60200260200101516080015186606001518481518110610c7757610c776144b2565b60200260200101518760a001518581518110610c9557610c956144b2565b602002602001015151886000015189602001516001612837565b838281518110610cc157610cc16144b2565b6020026020010151604001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff1681525050610d4d84604001518281518110610d0857610d086144b2565b602002602001015185608001518381518110610d2657610d266144b2565b6020026020010151858481518110610d4057610d406144b2565b6020026020010151612882565b848381518110610d5f57610d5f6144b2565b6020026020010151602001858481518110610d7c57610d7c6144b2565b602002602001015160e0018281525082151515158152505050828181518110610da757610da76144b2565b60200260200101516020015115610dca57610dc3600183614529565b9150610dcf565b610ee8565b610e35838281518110610de457610de46144b2565b6020026020010151600001516060015185606001518381518110610e0a57610e0a6144b2565b60200260200101518660a001518481518110610e2857610e286144b2565b602002602001015161225d565b848381518110610e4757610e476144b2565b6020026020010151606001858481518110610e6457610e646144b2565b602002602001015160a0018281525082151515158152505050828181518110610e8f57610e8f6144b2565b602002602001015160a0015186610ea69190614544565b9550610ee884604001518281518110610ec157610ec16144b2565b6020026020010151848381518110610edb57610edb6144b2565b6020026020010151612a01565b80610ef281614557565b915050610ab8565b508061ffff16600003610f115750505050506112e0565b8351610f1e9060016144e1565b610f2d9060ff1661044c61458f565b616b6c610f3b8d601061458f565b5a610f469089614544565b610f50919061449f565b610f5a919061449f565b610f64919061449f565b9450611b58610f7761ffff8316876145fb565b610f81919061449f565b945060008060008060005b87604001515181101561118257868181518110610fab57610fab6144b2565b60200260200101516020015115611170576110078a888381518110610fd257610fd26144b2565b6020026020010151608001518a60a001518481518110610ff457610ff46144b2565b6020026020010151518c60000151612b13565b878281518110611019576110196144b2565b602002602001015160c00181815250506110758989604001518381518110611043576110436144b2565b602002602001015189848151811061105d5761105d6144b2565b60200260200101518b600001518c602001518b612b33565b9093509150611084828561447a565b9350611090838661447a565b94508681815181106110a4576110a46144b2565b6020026020010151606001511515886040015182815181106110c8576110c86144b2565b60200260200101517fad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b84866110fd919061447a565b8a858151811061110f5761110f6144b2565b602002602001015160a001518b868151811061112d5761112d6144b2565b602002602001015160c001518d60800151878151811061114f5761114f6144b2565b6020026020010151604051611167949392919061460f565b60405180910390a35b8061117a81614557565b915050610f8c565b5050336000908152600b6020526040902080548492506002906111ba9084906201000090046bffffffffffffffffffffffff1661447a565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080601260000160108282829054906101000a90046bffffffffffffffffffffffff16611214919061447a565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555060008f600160038110611257576112576144b2565b602002013560001c9050600060088264ffffffffff16901c905087610100015163ffffffff168163ffffffff1611156112d657601280547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff8416021790555b5050505050505050505b5050505050505050565b6112f2612c26565b601f8651111561132e576040517f25d0209c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8360ff1660000361136b576040517fe77dba5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8451865114158061138a575061138284600361464c565b60ff16865111155b156113c1576040517f1d2d1c5800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601254600e547001000000000000000000000000000000009091046bffffffffffffffffffffffff169060005b816bffffffffffffffffffffffff1681101561145657611443600e828154811061141a5761141a6144b2565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff168484612ca7565b508061144e81614557565b9150506113ee565b5060008060005b836bffffffffffffffffffffffff1681101561155f57600d8181548110611486576114866144b2565b600091825260209091200154600e805473ffffffffffffffffffffffffffffffffffffffff909216945090829081106114c1576114c16144b2565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff8681168452600c8352604080852080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690559116808452600b90925290912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905591508061155781614557565b91505061145d565b5061156c600d6000613b9d565b611578600e6000613b9d565b604080516080810182526000808252602082018190529181018290526060810182905290805b8c518110156119e157600c60008e83815181106115bd576115bd6144b2565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000205460ff1615611628576040517f77cea0fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168d8281518110611652576116526144b2565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16036116a7576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180604001604052806001151581526020018260ff16815250600c60008f84815181106116d8576116d86144b2565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528181019290925260400160002082518154939092015160ff16610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909316929092171790558b518c9082908110611780576117806144b2565b60200260200101519150600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036117f0576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166000908152600b60209081526040918290208251608081018452905460ff80821615801584526101008304909116938301939093526bffffffffffffffffffffffff6201000082048116948301949094526e010000000000000000000000000000900490921660608301529093506118ab576040517f6a7281ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001835260ff80821660208086019182526bffffffffffffffffffffffff808b166060880190815273ffffffffffffffffffffffffffffffffffffffff87166000908152600b909352604092839020885181549551948a0151925184166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff939094166201000002929092167fffffffffffff000000000000000000000000000000000000000000000000ffff94909616610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090951694909417179190911692909217919091179055806119d981614557565b91505061159e565b50508a516119f79150600d9060208d0190613bbb565b508851611a0b90600e9060208c0190613bbb565b506040518061012001604052808960ff168152602001886000015163ffffffff168152602001886020015163ffffffff168152602001886060015162ffffff168152602001886080015161ffff1681526020016012600001600e9054906101000a900460ff16151581526020016012600001600f9054906101000a900460ff1615158152602001856bffffffffffffffffffffffff168152602001600063ffffffff16815250601260008201518160000160006101000a81548160ff021916908360ff16021790555060208201518160000160016101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160056101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160096101000a81548162ffffff021916908362ffffff160217905550608082015181600001600c6101000a81548161ffff021916908361ffff16021790555060a082015181600001600e6101000a81548160ff02191690831515021790555060c082015181600001600f6101000a81548160ff02191690831515021790555060e08201518160000160106101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555061010082015181600001601c6101000a81548163ffffffff021916908363ffffffff1602179055509050506040518061018001604052808860a001516bffffffffffffffffffffffff16815260200188610180015173ffffffffffffffffffffffffffffffffffffffff168152602001601360010160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff168152602001886040015163ffffffff1681526020018860c0015163ffffffff168152602001601360010160149054906101000a900463ffffffff1663ffffffff168152602001601360010160189054906101000a900463ffffffff1663ffffffff1681526020016013600101601c9054906101000a900463ffffffff1663ffffffff1681526020018860e0015163ffffffff16815260200188610100015163ffffffff16815260200188610120015163ffffffff168152602001886101c0015173ffffffffffffffffffffffffffffffffffffffff16815250601360008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160010160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550606082015181600101600c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160106101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160010160146101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555060e082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160020160006101000a81548163ffffffff021916908363ffffffff1602179055506101208201518160020160046101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160086101000a81548163ffffffff021916908363ffffffff16021790555061016082015181600201600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555090505086610140015160168190555086610160015160178190555060006013600101601c9054906101000a900463ffffffff169050611fcd612eb1565b601480547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff93841602178082556001926018916120489185917801000000000000000000000000000000000000000000000000900416614675565b92506101000a81548163ffffffff021916908363ffffffff16021790555060008860405160200161207991906146e3565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526014549091506120e290469030907801000000000000000000000000000000000000000000000000900463ffffffff168f8f8f878f8f612f66565b60115560005b6120f26009613010565b8110156121225761210f61210760098361301a565b600990613026565b508061211a81614557565b9150506120e8565b5060005b896101a0015151811015612179576121668a6101a00151828151811061214e5761214e6144b2565b6020026020010151600961304890919063ffffffff16565b508061217181614557565b915050612126565b507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0582601154601360010160189054906101000a900463ffffffff168f8f8f878f8f6040516121d099989796959493929190614847565b60405180910390a1505050505050505050505050565b612207868686868060200190518101906122009190614978565b86866112ea565b505050505050565b612217612c26565b6122208161306a565b50565b321561225b576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60125460009081906f01000000000000000000000000000000900460ff16156122b2576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601280547fffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffff166f010000000000000000000000000000001790556040517f4585e33b000000000000000000000000000000000000000000000000000000009061231f908590602401613cc8565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d16906123f29087908790600401614ad2565b60408051808303816000875af1158015612410573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124349190614aeb565b601280547fffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffff16905590969095509350505050565b6000878760405161247a929190614b1e565b604051908190038120612491918b90602001614b2e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201208383019092526000808452908301819052909250906000805b88811015612668576001858783602081106124fd576124fd6144b2565b61250a91901a601b6144e1565b8c8c8581811061251c5761251c6144b2565b905060200201358b8b86818110612535576125356144b2565b9050602002013560405160008152602001604052604051612572949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015612594573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff81166000908152600c602090815290849020838501909452925460ff8082161515808552610100909204169383019390935290955093509050612642576040517f0f4c073700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015160080260ff166001901b84019350808061266090614557565b9150506124e0565b50827e010101010101010101010101010101010101010101010101010101010101018416146126c3576040517fc103be2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050505050565b61270a6040518060c001604052806000815260200160008152602001606081526020016060815260200160608152602001606081525090565b600061271883850185614c1f565b604081015151606082015151919250908114158061273b57508082608001515114155b8061274b5750808260a001515114155b15612782576040517fb55ac75400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090505b92915050565b6000818160045b600f811015612819577fff0000000000000000000000000000000000000000000000000000000000000082168382602081106127d1576127d16144b2565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461280757506000949350505050565b8061281181614557565b915050612793565b5081600f1a600181111561282f5761282f6144fa565b949350505050565b60008061284988878b6000015161315f565b90506000806128648b8a63ffffffff16858a8a60018b6131eb565b9092509050612873818361447a565b9b9a5050505050505050505050565b60008080808460800151600181111561289d5761289d6144fa565b036128c1576128ad868686613644565b6128bc5760009250905061079f565b612938565b6001846080015160018111156128d9576128d96144fa565b036129065760006128eb878787613738565b9250905080612900575060009250905061079f565b50612938565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612940612eb1565b84516040015163ffffffff161161299457857fc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd5636866040516129819190613cc8565b60405180910390a260009250905061079f565b83604001516bffffffffffffffffffffffff16846000015160a001516bffffffffffffffffffffffff1610156129f457857f377c8b0c126ae5248d27aca1c76fac4608aff85673ee3caf09747e1044549e02866040516129819190613cc8565b6001969095509350505050565b600081608001516001811115612a1957612a196144fa565b03612a8b57612a26612eb1565b6000838152600460205260409020600101805463ffffffff929092167801000000000000000000000000000000000000000000000000027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff9092169190911790555050565b600181608001516001811115612aa357612aa36144fa565b03612b0f5760e08101805160009081526008602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055915191517fa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f29190a25b5050565b6000612b2084848461315f565b90508085101561282f5750929392505050565b600080612b4e888760a001518860c0015188888860016131eb565b90925090506000612b5f828461447a565b600089815260046020526040902060010180549192508291600c90612ba39084906c0100000000000000000000000090046bffffffffffffffffffffffff16614d0c565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008a815260046020526040812060010180548594509092612bec9185911661447a565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555050965096945050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461225b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161039e565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e0100000000000000000000000000009004909116606082015290612ea3576000816060015185612d3f9190614d0c565b90506000612d4d8583614d31565b90508083604001818151612d61919061447a565b6bffffffffffffffffffffffff16905250612d7c8582614d5c565b83606001818151612d8d919061447a565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b6040015190505b9392505050565b600060017f00000000000000000000000000000000000000000000000000000000000000006002811115612ee757612ee76144fa565b03612f6157606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f5c9190614d90565b905090565b504390565b6000808a8a8a8a8a8a8a8a8a604051602001612f8a99989796959493929190614da9565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179b9a5050505050505050505050565b6000612786825490565b6000612eaa83836138d0565b6000612eaa8373ffffffffffffffffffffffffffffffffffffffff84166138fa565b6000612eaa8373ffffffffffffffffffffffffffffffffffffffff84166139f4565b3373ffffffffffffffffffffffffffffffffffffffff8216036130e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161039e565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008080856001811115613175576131756144fa565b03613184575062015f906131a3565b6001856001811115613198576131986144fa565b0361290657506201adb05b6131b463ffffffff8516601461458f565b6131bf8460016144e1565b6131ce9060ff16611d4c61458f565b6131d8908361449f565b6131e2919061449f565b95945050505050565b6000806000896080015161ffff1687613204919061458f565b90508380156132125750803a105b1561321a57503a5b600060027f00000000000000000000000000000000000000000000000000000000000000006002811115613250576132506144fa565b036133af5760408051600081526020810190915285156132ae57600036604051806080016040528060488152602001614fdb6048913960405160200161329893929190614e3e565b6040516020818303038152906040529050613316565b6015546132ca90640100000000900463ffffffff166004614e65565b63ffffffff1667ffffffffffffffff8111156132e8576132e8613ef5565b6040519080825280601f01601f191660200182016040528015613312576020820181803683370190505b5090505b6040517f49948e0e00000000000000000000000000000000000000000000000000000000815273420000000000000000000000000000000000000f906349948e0e90613366908490600401613cc8565b602060405180830381865afa158015613383573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133a79190614d90565b915050613509565b60017f000000000000000000000000000000000000000000000000000000000000000060028111156133e3576133e36144fa565b0361350957841561346557606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561343a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061345e9190614d90565b9050613509565b6000606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c060405180830381865afa1580156134b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134d79190614e88565b50506015549294506134fa93505050640100000000900463ffffffff168261458f565b61350590601061458f565b9150505b8461352557808b6080015161ffff16613522919061458f565b90505b61353361ffff8716826145fb565b9050600087826135438c8e61449f565b61354d908661458f565b613557919061449f565b61356990670de0b6b3a764000061458f565b61357391906145fb565b905060008c6040015163ffffffff1664e8d4a51000613592919061458f565b898e6020015163ffffffff16858f886135ab919061458f565b6135b5919061449f565b6135c390633b9aca0061458f565b6135cd919061458f565b6135d791906145fb565b6135e1919061449f565b90506b033b2e3c9fd0803ce80000006135fa828461449f565b1115613632576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b909c909b509950505050505050505050565b6000808380602001905181019061365b9190614ed2565b835160c00151815191925063ffffffff908116911610156136b857847f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8856040516136a69190613cc8565b60405180910390a26000915050612eaa565b6020810151158015906136df5750602081015181516136dc9063ffffffff16613a43565b14155b806136f857506136ed612eb1565b815163ffffffff1610155b1561372d57847f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301856040516136a69190613cc8565b506001949350505050565b6000806000848060200190518101906137519190614f2a565b90506000868260000151836020015184604001516040516020016137b394939291909384526020840192909252604083015260e01b7fffffffff0000000000000000000000000000000000000000000000000000000016606082015260640190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012060808301519091501580159061381557508160800151613812836060015163ffffffff16613a43565b14155b806138315750613823612eb1565b826060015163ffffffff1610155b1561387b57867f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301876040516138669190613cc8565b60405180910390a260009350915061079f9050565b60008181526008602052604090205460ff16156138c257867f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8876040516138669190613cc8565b600197909650945050505050565b60008260000182815481106138e7576138e76144b2565b9060005260206000200154905092915050565b600081815260018301602052604081205480156139e357600061391e600183614544565b855490915060009061393290600190614544565b9050818114613997576000866000018281548110613952576139526144b2565b9060005260206000200154905080876000018481548110613975576139756144b2565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806139a8576139a8614fab565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612786565b6000915050612786565b5092915050565b6000818152600183016020526040812054613a3b57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155612786565b506000612786565b600060017f00000000000000000000000000000000000000000000000000000000000000006002811115613a7957613a796144fa565b03613b93576000606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613acc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613af09190614d90565b90508083101580613b0b5750610100613b098483614544565b115b15613b195750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815260048101849052606490632b407a8290602401602060405180830381865afa158015613b6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612eaa9190614d90565b504090565b919050565b50805460008255906000526020600020908101906122209190613c45565b828054828255906000526020600020908101928215613c35579160200282015b82811115613c3557825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190613bdb565b50613c41929150613c45565b5090565b5b80821115613c415760008155600101613c46565b60005b83811015613c75578181015183820152602001613c5d565b50506000910152565b60008151808452613c96816020860160208601613c5a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000612eaa6020830184613c7e565b73ffffffffffffffffffffffffffffffffffffffff8116811461222057600080fd5b8035613b9881613cdb565b60008083601f840112613d1a57600080fd5b50813567ffffffffffffffff811115613d3257600080fd5b602083019150836020828501011115613d4a57600080fd5b9250929050565b60008060008060608587031215613d6757600080fd5b8435613d7281613cdb565b935060208501359250604085013567ffffffffffffffff811115613d9557600080fd5b613da187828801613d08565b95989497509550505050565b600080600060408486031215613dc257600080fd5b83359250602084013567ffffffffffffffff811115613de057600080fd5b613dec86828701613d08565b9497909650939450505050565b60008083601f840112613e0b57600080fd5b50813567ffffffffffffffff811115613e2357600080fd5b6020830191508360208260051b8501011115613d4a57600080fd5b60008060008060008060008060e0898b031215613e5a57600080fd5b606089018a811115613e6b57600080fd5b8998503567ffffffffffffffff80821115613e8557600080fd5b613e918c838d01613d08565b909950975060808b0135915080821115613eaa57600080fd5b613eb68c838d01613df9565b909750955060a08b0135915080821115613ecf57600080fd5b50613edc8b828c01613df9565b999c989b50969995989497949560c00135949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516101e0810167ffffffffffffffff81118282101715613f4857613f48613ef5565b60405290565b60405160c0810167ffffffffffffffff81118282101715613f4857613f48613ef5565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613fb857613fb8613ef5565b604052919050565b600067ffffffffffffffff821115613fda57613fda613ef5565b5060051b60200190565b600082601f830112613ff557600080fd5b8135602061400a61400583613fc0565b613f71565b82815260059290921b8401810191818101908684111561402957600080fd5b8286015b8481101561404d57803561404081613cdb565b835291830191830161402d565b509695505050505050565b803560ff81168114613b9857600080fd5b63ffffffff8116811461222057600080fd5b8035613b9881614069565b62ffffff8116811461222057600080fd5b8035613b9881614086565b61ffff8116811461222057600080fd5b8035613b98816140a2565b6bffffffffffffffffffffffff8116811461222057600080fd5b8035613b98816140bd565b60006101e082840312156140f557600080fd5b6140fd613f24565b90506141088261407b565b81526141166020830161407b565b60208201526141276040830161407b565b604082015261413860608301614097565b6060820152614149608083016140b2565b608082015261415a60a083016140d7565b60a082015261416b60c0830161407b565b60c082015261417c60e0830161407b565b60e082015261010061418f81840161407b565b908201526101206141a183820161407b565b90820152610140828101359082015261016080830135908201526101806141c9818401613cfd565b908201526101a08281013567ffffffffffffffff8111156141e957600080fd5b6141f585828601613fe4565b8284015250506101c0614209818401613cfd565b9082015292915050565b803567ffffffffffffffff81168114613b9857600080fd5b600082601f83011261423c57600080fd5b813567ffffffffffffffff81111561425657614256613ef5565b61428760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613f71565b81815284602083860101111561429c57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c087890312156142d257600080fd5b863567ffffffffffffffff808211156142ea57600080fd5b6142f68a838b01613fe4565b9750602089013591508082111561430c57600080fd5b6143188a838b01613fe4565b965061432660408a01614058565b9550606089013591508082111561433c57600080fd5b6143488a838b016140e2565b945061435660808a01614213565b935060a089013591508082111561436c57600080fd5b5061437989828a0161422b565b9150509295509295509295565b60008060008060008060c0878903121561439f57600080fd5b863567ffffffffffffffff808211156143b757600080fd5b6143c38a838b01613fe4565b975060208901359150808211156143d957600080fd5b6143e58a838b01613fe4565b96506143f360408a01614058565b9550606089013591508082111561440957600080fd5b6143488a838b0161422b565b60006020828403121561442757600080fd5b8135612eaa81613cdb565b60006020828403121561444457600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff8181168382160190808211156139ed576139ed61444b565b808201808211156127865761278661444b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60ff81811683821601908111156127865761278661444b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b61ffff8181168382160190808211156139ed576139ed61444b565b818103818111156127865761278661444b565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036145885761458861444b565b5060010190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156145c7576145c761444b565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261460a5761460a6145cc565b500490565b6bffffffffffffffffffffffff851681528360208201528260408201526080606082015260006146426080830184613c7e565b9695505050505050565b600060ff821660ff84168160ff048111821515161561466d5761466d61444b565b029392505050565b63ffffffff8181168382160190808211156139ed576139ed61444b565b600081518084526020808501945080840160005b838110156146d857815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016146a6565b509495945050505050565b602081526146fa60208201835163ffffffff169052565b60006020830151614713604084018263ffffffff169052565b50604083015163ffffffff8116606084015250606083015162ffffff8116608084015250608083015161ffff811660a08401525060a08301516bffffffffffffffffffffffff811660c08401525060c083015163ffffffff811660e08401525060e083015161010061478c8185018363ffffffff169052565b84015190506101206147a58482018363ffffffff169052565b84015190506101406147be8482018363ffffffff169052565b840151610160848101919091528401516101808085019190915284015190506101a06148018185018373ffffffffffffffffffffffffffffffffffffffff169052565b808501519150506101e06101c08181860152614821610200860184614692565b95015173ffffffffffffffffffffffffffffffffffffffff169301929092525090919050565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526148778184018a614692565b9050828103608084015261488b8189614692565b905060ff871660a084015282810360c08401526148a88187613c7e565b905067ffffffffffffffff851660e08401528281036101008401526148cd8185613c7e565b9c9b505050505050505050505050565b8051613b9881614069565b8051613b9881614086565b8051613b98816140a2565b8051613b98816140bd565b8051613b9881613cdb565b600082601f83011261492557600080fd5b8151602061493561400583613fc0565b82815260059290921b8401810191818101908684111561495457600080fd5b8286015b8481101561404d57805161496b81613cdb565b8352918301918301614958565b60006020828403121561498a57600080fd5b815167ffffffffffffffff808211156149a257600080fd5b908301906101e082860312156149b757600080fd5b6149bf613f24565b6149c8836148dd565b81526149d6602084016148dd565b60208201526149e7604084016148dd565b60408201526149f8606084016148e8565b6060820152614a09608084016148f3565b6080820152614a1a60a084016148fe565b60a0820152614a2b60c084016148dd565b60c0820152614a3c60e084016148dd565b60e0820152610100614a4f8185016148dd565b90820152610120614a618482016148dd565b9082015261014083810151908201526101608084015190820152610180614a89818501614909565b908201526101a08381015183811115614aa157600080fd5b614aad88828701614914565b8284015250506101c09150614ac3828401614909565b91810191909152949350505050565b82815260406020820152600061282f6040830184613c7e565b60008060408385031215614afe57600080fd5b82518015158114614b0e57600080fd5b6020939093015192949293505050565b8183823760009101908152919050565b8281526080810160608360208401379392505050565b600082601f830112614b5557600080fd5b81356020614b6561400583613fc0565b82815260059290921b84018101918181019086841115614b8457600080fd5b8286015b8481101561404d5780358352918301918301614b88565b600082601f830112614bb057600080fd5b81356020614bc061400583613fc0565b82815260059290921b84018101918181019086841115614bdf57600080fd5b8286015b8481101561404d57803567ffffffffffffffff811115614c035760008081fd5b614c118986838b010161422b565b845250918301918301614be3565b600060208284031215614c3157600080fd5b813567ffffffffffffffff80821115614c4957600080fd5b9083019060c08286031215614c5d57600080fd5b614c65613f4e565b8235815260208301356020820152604083013582811115614c8557600080fd5b614c9187828601614b44565b604083015250606083013582811115614ca957600080fd5b614cb587828601614b44565b606083015250608083013582811115614ccd57600080fd5b614cd987828601614b9f565b60808301525060a083013582811115614cf157600080fd5b614cfd87828601614b9f565b60a08301525095945050505050565b6bffffffffffffffffffffffff8281168282160390808211156139ed576139ed61444b565b60006bffffffffffffffffffffffff80841680614d5057614d506145cc565b92169190910492915050565b60006bffffffffffffffffffffffff80831681851681830481118215151615614d8757614d8761444b565b02949350505050565b600060208284031215614da257600080fd5b5051919050565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152614df08285018b614692565b91508382036080850152614e04828a614692565b915060ff881660a085015283820360c0850152614e218288613c7e565b90861660e085015283810361010085015290506148cd8185613c7e565b828482376000838201600081528351614e5b818360208801613c5a565b0195945050505050565b600063ffffffff80831681851681830481118215151615614d8757614d8761444b565b60008060008060008060c08789031215614ea157600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b600060408284031215614ee457600080fd5b6040516040810181811067ffffffffffffffff82111715614f0757614f07613ef5565b6040528251614f1581614069565b81526020928301519281019290925250919050565b600060a08284031215614f3c57600080fd5b60405160a0810181811067ffffffffffffffff82111715614f5f57614f5f613ef5565b806040525082518152602083015160208201526040830151614f8081614069565b60408201526060830151614f9381614069565b60608201526080928301519281019290925250919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000810000a", + ABI: "[{\"inputs\":[{\"internalType\":\"contractKeeperRegistryLogicB2_1\",\"name\":\"logicA\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientFunds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxCheckDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxPerformDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentGreaterThanAllLINK\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"OwnerFundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"onchainConfigBytes\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"}],\"internalType\":\"structIAutomationV21PlusCommon.OnchainConfigLegacy\",\"name\":\"onchainConfig\",\"type\":\"tuple\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfigTypeSafe\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"simulatePerformUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"rawReport\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x6101406040523480156200001257600080fd5b506040516200555f3803806200555f8339810160408190526200003591620003df565b80816001600160a01b0316634b4fd03b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b919062000406565b826001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001009190620003df565b836001600160a01b031663b10b673c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001659190620003df565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca9190620003df565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f9190620003df565b3380600081620002865760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620002b957620002b9816200031b565b505050846002811115620002d157620002d162000429565b60e0816002811115620002e857620002e862000429565b9052506001600160a01b0393841660805291831660a052821660c0528116610100529190911661012052506200043f9050565b336001600160a01b03821603620003755760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200027d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b0381168114620003dc57600080fd5b50565b600060208284031215620003f257600080fd5b8151620003ff81620003c6565b9392505050565b6000602082840312156200041957600080fd5b815160038110620003ff57600080fd5b634e487b7160e01b600052602160045260246000fd5b60805160a05160c05160e05161010051610120516150be620004a16000396000818160c9015261017c01526000505060008181612f46015281816132af015281816134420152613ad80152600050506000505060006104ca01526150be6000f3fe6080604052600436106100c75760003560e01c8063aed2e92911610074578063e29b753c1161004e578063e29b753c14610350578063e3d0e71214610370578063f2fde38b14610390576100c7565b8063aed2e929146102a3578063afcb95d7146102da578063b1dc65a414610330576100c7565b806381ff7048116100a557806381ff7048146101d65780638da5cb5b14610258578063a4c0ed3614610283576100c7565b8063181f5a771461010e578063349e8cca1461016d57806379ba5097146101c1575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e808015610107573d6000f35b3d6000fd5b005b34801561011a57600080fd5b506101576040518060400160405280601481526020017f4b6565706572526567697374727920322e312e3000000000000000000000000081525081565b6040516101649190613d57565b60405180910390f35b34801561017957600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610164565b3480156101cd57600080fd5b5061010c6103b0565b3480156101e257600080fd5b5061023560145460115463ffffffff780100000000000000000000000000000000000000000000000083048116937c01000000000000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610164565b34801561026457600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff1661019c565b34801561028f57600080fd5b5061010c61029e366004613de0565b6104b2565b3480156102af57600080fd5b506102c36102be366004613e3c565b6106ce565b604080519215158352602083019190915201610164565b3480156102e657600080fd5b50601154601254604080516000815260208101939093527c010000000000000000000000000000000000000000000000000000000090910463ffffffff1690820152606001610164565b34801561033c57600080fd5b5061010c61034b366004613ecd565b610836565b34801561035c57600080fd5b5061010c61036b366004614348565b611379565b34801561037c57600080fd5b5061010c61038b366004614415565b612275565b34801561039c57600080fd5b5061010c6103ab3660046144a4565b61229e565b60015473ffffffffffffffffffffffffffffffffffffffff163314610436576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610521576040517fc8bad78d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020811461055b576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610569828401846144c1565b60008181526004602052604090205490915065010000000000900463ffffffff908116146105c3576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600460205260409020600101546105fe9085906c0100000000000000000000000090046bffffffffffffffffffffffff16614509565b600082815260046020526040902060010180546bffffffffffffffffffffffff929092166c01000000000000000000000000027fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff90921691909117905560185461066990859061452e565b6018556040516bffffffffffffffffffffffff8516815273ffffffffffffffffffffffffffffffffffffffff86169082907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a35050505050565b6000806106d96122b2565b6012546e010000000000000000000000000000900460ff1615610728576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600085815260046020908152604091829020825160e081018452815460ff811615158252610100810463ffffffff908116838601819052650100000000008304821684880152690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff16606084018190526001909401546bffffffffffffffffffffffff80821660808601526c0100000000000000000000000082041660a0850152780100000000000000000000000000000000000000000000000090041660c08301528451601f890185900485028101850190955287855290936108279389908990819084018382808284376000920191909152506122ec92505050565b9093509150505b935093915050565b60005a604080516101208101825260125460ff808216835261010080830463ffffffff90811660208601526501000000000084048116958501959095526901000000000000000000830462ffffff1660608501526c01000000000000000000000000830461ffff1660808501526e0100000000000000000000000000008304821615801560a08601526f010000000000000000000000000000008404909216151560c085015270010000000000000000000000000000000083046bffffffffffffffffffffffff1660e08501527c010000000000000000000000000000000000000000000000000000000090920490931690820152919250610964576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600b602052604090205460ff166109ad576040517f1099ed7500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6011548a35146109e9576040517fdfdcf8e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516109f6906001614570565b60ff1686141580610a075750858414155b15610a3e576040517f0244f71a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a4e8a8a8a8a8a8a8a8a6124f7565b6000610a5a8a8a612760565b9050600081604001515167ffffffffffffffff811115610a7c57610a7c613f84565b604051908082528060200260200182016040528015610b4057816020015b604080516101e0810182526000610100820181815261012083018290526101408301829052610160830182905261018083018290526101a083018290526101c0830182905282526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181610a9a5790505b5090506000805b836040015151811015610f89576004600085604001518381518110610b6e57610b6e614541565b6020908102919091018101518252818101929092526040908101600020815160e081018352815460ff811615158252610100810463ffffffff90811695830195909552650100000000008104851693820193909352690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff166060830152600101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490911660c08201528351849083908110610c5357610c53614541565b602002602001015160000181905250610c8884604001518281518110610c7b57610c7b614541565b602002602001015161281b565b838281518110610c9a57610c9a614541565b6020026020010151608001906001811115610cb757610cb7614589565b90816001811115610cca57610cca614589565b81525050610d3e85848381518110610ce457610ce4614541565b60200260200101516080015186606001518481518110610d0657610d06614541565b60200260200101518760a001518581518110610d2457610d24614541565b6020026020010151518860000151896020015160016128c6565b838281518110610d5057610d50614541565b6020026020010151604001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff1681525050610ddc84604001518281518110610d9757610d97614541565b602002602001015185608001518381518110610db557610db5614541565b6020026020010151858481518110610dcf57610dcf614541565b6020026020010151612911565b848381518110610dee57610dee614541565b6020026020010151602001858481518110610e0b57610e0b614541565b602002602001015160e0018281525082151515158152505050828181518110610e3657610e36614541565b60200260200101516020015115610e5957610e526001836145b8565b9150610e5e565b610f77565b610ec4838281518110610e7357610e73614541565b6020026020010151600001516060015185606001518381518110610e9957610e99614541565b60200260200101518660a001518481518110610eb757610eb7614541565b60200260200101516122ec565b848381518110610ed657610ed6614541565b6020026020010151606001858481518110610ef357610ef3614541565b602002602001015160a0018281525082151515158152505050828181518110610f1e57610f1e614541565b602002602001015160a0015186610f3591906145d3565b9550610f7784604001518281518110610f5057610f50614541565b6020026020010151848381518110610f6a57610f6a614541565b6020026020010151612a90565b80610f81816145e6565b915050610b47565b508061ffff16600003610fa057505050505061136f565b8351610fad906001614570565b610fbc9060ff1661044c61461e565b616b6c610fca8d601061461e565b5a610fd590896145d3565b610fdf919061452e565b610fe9919061452e565b610ff3919061452e565b9450611b5861100661ffff83168761468a565b611010919061452e565b945060008060008060005b8760400151518110156112115786818151811061103a5761103a614541565b602002602001015160200151156111ff576110968a88838151811061106157611061614541565b6020026020010151608001518a60a00151848151811061108357611083614541565b6020026020010151518c60000151612ba2565b8782815181106110a8576110a8614541565b602002602001015160c001818152505061110489896040015183815181106110d2576110d2614541565b60200260200101518984815181106110ec576110ec614541565b60200260200101518b600001518c602001518b612bc2565b90935091506111138285614509565b935061111f8386614509565b945086818151811061113357611133614541565b60200260200101516060015115158860400151828151811061115757611157614541565b60200260200101517fad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b848661118c9190614509565b8a858151811061119e5761119e614541565b602002602001015160a001518b86815181106111bc576111bc614541565b602002602001015160c001518d6080015187815181106111de576111de614541565b60200260200101516040516111f6949392919061469e565b60405180910390a35b80611209816145e6565b91505061101b565b5050336000908152600b6020526040902080548492506002906112499084906201000090046bffffffffffffffffffffffff16614509565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080601260000160108282829054906101000a90046bffffffffffffffffffffffff166112a39190614509565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555060008f6001600381106112e6576112e6614541565b602002013560001c9050600060088264ffffffffff16901c905087610100015163ffffffff168163ffffffff16111561136557601280547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff8416021790555b5050505050505050505b5050505050505050565b611381612cb5565b601f865111156113bd576040517f25d0209c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8360ff166000036113fa576040517fe77dba5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8451865114158061141957506114118460036146db565b60ff16865111155b15611450576040517f1d2d1c5800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601254600e547001000000000000000000000000000000009091046bffffffffffffffffffffffff169060005b816bffffffffffffffffffffffff168110156114e5576114d2600e82815481106114a9576114a9614541565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff168484612d36565b50806114dd816145e6565b91505061147d565b5060008060005b836bffffffffffffffffffffffff168110156115ee57600d818154811061151557611515614541565b600091825260209091200154600e805473ffffffffffffffffffffffffffffffffffffffff9092169450908290811061155057611550614541565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff8681168452600c8352604080852080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690559116808452600b90925290912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690559150806115e6816145e6565b9150506114ec565b506115fb600d6000613c2c565b611607600e6000613c2c565b604080516080810182526000808252602082018190529181018290526060810182905290805b8c51811015611a7057600c60008e838151811061164c5761164c614541565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000205460ff16156116b7576040517f77cea0fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168d82815181106116e1576116e1614541565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611736576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180604001604052806001151581526020018260ff16815250600c60008f848151811061176757611767614541565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528181019290925260400160002082518154939092015160ff16610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909316929092171790558b518c908290811061180f5761180f614541565b60200260200101519150600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361187f576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166000908152600b60209081526040918290208251608081018452905460ff80821615801584526101008304909116938301939093526bffffffffffffffffffffffff6201000082048116948301949094526e0100000000000000000000000000009004909216606083015290935061193a576040517f6a7281ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001835260ff80821660208086019182526bffffffffffffffffffffffff808b166060880190815273ffffffffffffffffffffffffffffffffffffffff87166000908152600b909352604092839020885181549551948a0151925184166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff939094166201000002929092167fffffffffffff000000000000000000000000000000000000000000000000ffff94909616610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009095169490941717919091169290921791909117905580611a68816145e6565b91505061162d565b50508a51611a869150600d9060208d0190613c4a565b508851611a9a90600e9060208c0190613c4a565b506040518061012001604052808960ff168152602001886000015163ffffffff168152602001886020015163ffffffff168152602001886060015162ffffff168152602001886080015161ffff1681526020016012600001600e9054906101000a900460ff16151581526020016012600001600f9054906101000a900460ff1615158152602001856bffffffffffffffffffffffff168152602001600063ffffffff16815250601260008201518160000160006101000a81548160ff021916908360ff16021790555060208201518160000160016101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160056101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160096101000a81548162ffffff021916908362ffffff160217905550608082015181600001600c6101000a81548161ffff021916908361ffff16021790555060a082015181600001600e6101000a81548160ff02191690831515021790555060c082015181600001600f6101000a81548160ff02191690831515021790555060e08201518160000160106101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555061010082015181600001601c6101000a81548163ffffffff021916908363ffffffff1602179055509050506040518061018001604052808860a001516bffffffffffffffffffffffff16815260200188610180015173ffffffffffffffffffffffffffffffffffffffff168152602001601360010160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff168152602001886040015163ffffffff1681526020018860c0015163ffffffff168152602001601360010160149054906101000a900463ffffffff1663ffffffff168152602001601360010160189054906101000a900463ffffffff1663ffffffff1681526020016013600101601c9054906101000a900463ffffffff1663ffffffff1681526020018860e0015163ffffffff16815260200188610100015163ffffffff16815260200188610120015163ffffffff168152602001886101c0015173ffffffffffffffffffffffffffffffffffffffff16815250601360008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160010160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550606082015181600101600c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160106101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160010160146101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555060e082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160020160006101000a81548163ffffffff021916908363ffffffff1602179055506101208201518160020160046101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160086101000a81548163ffffffff021916908363ffffffff16021790555061016082015181600201600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555090505086610140015160168190555086610160015160178190555060006013600101601c9054906101000a900463ffffffff16905061205c612f40565b601480547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff93841602178082556001926018916120d79185917801000000000000000000000000000000000000000000000000900416614704565b92506101000a81548163ffffffff021916908363ffffffff1602179055506000886040516020016121089190614772565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905260145490915061217190469030907801000000000000000000000000000000000000000000000000900463ffffffff168f8f8f878f8f612ff5565b60115560005b612181600961309f565b8110156121b15761219e6121966009836130a9565b6009906130b5565b50806121a9816145e6565b915050612177565b5060005b896101a0015151811015612208576121f58a6101a0015182815181106121dd576121dd614541565b602002602001015160096130d790919063ffffffff16565b5080612200816145e6565b9150506121b5565b507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0582601154601360010160189054906101000a900463ffffffff168f8f8f878f8f60405161225f999897969594939291906148d6565b60405180910390a1505050505050505050505050565b6122968686868680602001905181019061228f9190614a07565b8686611379565b505050505050565b6122a6612cb5565b6122af816130f9565b50565b32156122ea576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60125460009081906f01000000000000000000000000000000900460ff1615612341576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601280547fffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffff166f010000000000000000000000000000001790556040517f4585e33b00000000000000000000000000000000000000000000000000000000906123ae908590602401613d57565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d16906124819087908790600401614b61565b60408051808303816000875af115801561249f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124c39190614b7a565b601280547fffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffff16905590969095509350505050565b60008787604051612509929190614bad565b604051908190038120612520918b90602001614bbd565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201208383019092526000808452908301819052909250906000805b888110156126f75760018587836020811061258c5761258c614541565b61259991901a601b614570565b8c8c858181106125ab576125ab614541565b905060200201358b8b868181106125c4576125c4614541565b9050602002013560405160008152602001604052604051612601949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015612623573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff81166000908152600c602090815290849020838501909452925460ff80821615158085526101009092041693830193909352909550935090506126d1576040517f0f4c073700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015160080260ff166001901b8401935080806126ef906145e6565b91505061256f565b50827e01010101010101010101010101010101010101010101010101010101010101841614612752576040517fc103be2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050505050565b6127996040518060c001604052806000815260200160008152602001606081526020016060815260200160608152602001606081525090565b60006127a783850185614cae565b60408101515160608201515191925090811415806127ca57508082608001515114155b806127da5750808260a001515114155b15612811576040517fb55ac75400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090505b92915050565b6000818160045b600f8110156128a8577fff00000000000000000000000000000000000000000000000000000000000000821683826020811061286057612860614541565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461289657506000949350505050565b806128a0816145e6565b915050612822565b5081600f1a60018111156128be576128be614589565b949350505050565b6000806128d888878b600001516131ee565b90506000806128f38b8a63ffffffff16858a8a60018b61327a565b90925090506129028183614509565b9b9a5050505050505050505050565b60008080808460800151600181111561292c5761292c614589565b036129505761293c8686866136d3565b61294b5760009250905061082e565b6129c7565b60018460800151600181111561296857612968614589565b0361299557600061297a8787876137c7565b925090508061298f575060009250905061082e565b506129c7565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6129cf612f40565b84516040015163ffffffff1611612a2357857fc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd563686604051612a109190613d57565b60405180910390a260009250905061082e565b83604001516bffffffffffffffffffffffff16846000015160a001516bffffffffffffffffffffffff161015612a8357857f377c8b0c126ae5248d27aca1c76fac4608aff85673ee3caf09747e1044549e0286604051612a109190613d57565b6001969095509350505050565b600081608001516001811115612aa857612aa8614589565b03612b1a57612ab5612f40565b6000838152600460205260409020600101805463ffffffff929092167801000000000000000000000000000000000000000000000000027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff9092169190911790555050565b600181608001516001811115612b3257612b32614589565b03612b9e5760e08101805160009081526008602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055915191517fa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f29190a25b5050565b6000612baf8484846131ee565b9050808510156128be5750929392505050565b600080612bdd888760a001518860c00151888888600161327a565b90925090506000612bee8284614509565b600089815260046020526040902060010180549192508291600c90612c329084906c0100000000000000000000000090046bffffffffffffffffffffffff16614d9b565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008a815260046020526040812060010180548594509092612c7b91859116614509565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555050965096945050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146122ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161042d565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e0100000000000000000000000000009004909116606082015290612f32576000816060015185612dce9190614d9b565b90506000612ddc8583614dc0565b90508083604001818151612df09190614509565b6bffffffffffffffffffffffff16905250612e0b8582614deb565b83606001818151612e1c9190614509565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b6040015190505b9392505050565b600060017f00000000000000000000000000000000000000000000000000000000000000006002811115612f7657612f76614589565b03612ff057606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612feb9190614e1f565b905090565b504390565b6000808a8a8a8a8a8a8a8a8a60405160200161301999989796959493929190614e38565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179b9a5050505050505050505050565b6000612815825490565b6000612f39838361395f565b6000612f398373ffffffffffffffffffffffffffffffffffffffff8416613989565b6000612f398373ffffffffffffffffffffffffffffffffffffffff8416613a83565b3373ffffffffffffffffffffffffffffffffffffffff821603613178576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161042d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000808085600181111561320457613204614589565b03613213575062015f90613232565b600185600181111561322757613227614589565b0361299557506201adb05b61324363ffffffff8516601461461e565b61324e846001614570565b61325d9060ff16611d4c61461e565b613267908361452e565b613271919061452e565b95945050505050565b6000806000896080015161ffff1687613293919061461e565b90508380156132a15750803a105b156132a957503a5b600060027f000000000000000000000000000000000000000000000000000000000000000060028111156132df576132df614589565b0361343e57604080516000815260208101909152851561333d5760003660405180608001604052806048815260200161506a6048913960405160200161332793929190614ecd565b60405160208183030381529060405290506133a5565b60155461335990640100000000900463ffffffff166004614ef4565b63ffffffff1667ffffffffffffffff81111561337757613377613f84565b6040519080825280601f01601f1916602001820160405280156133a1576020820181803683370190505b5090505b6040517f49948e0e00000000000000000000000000000000000000000000000000000000815273420000000000000000000000000000000000000f906349948e0e906133f5908490600401613d57565b602060405180830381865afa158015613412573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134369190614e1f565b915050613598565b60017f0000000000000000000000000000000000000000000000000000000000000000600281111561347257613472614589565b036135985784156134f457606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156134c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134ed9190614e1f565b9050613598565b6000606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c060405180830381865afa158015613542573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135669190614f17565b505060155492945061358993505050640100000000900463ffffffff168261461e565b61359490601061461e565b9150505b846135b457808b6080015161ffff166135b1919061461e565b90505b6135c261ffff87168261468a565b9050600087826135d28c8e61452e565b6135dc908661461e565b6135e6919061452e565b6135f890670de0b6b3a764000061461e565b613602919061468a565b905060008c6040015163ffffffff1664e8d4a51000613621919061461e565b898e6020015163ffffffff16858f8861363a919061461e565b613644919061452e565b61365290633b9aca0061461e565b61365c919061461e565b613666919061468a565b613670919061452e565b90506b033b2e3c9fd0803ce8000000613689828461452e565b11156136c1576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b909c909b509950505050505050505050565b600080838060200190518101906136ea9190614f61565b835160c00151815191925063ffffffff9081169116101561374757847f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8856040516137359190613d57565b60405180910390a26000915050612f39565b60208101511580159061376e57506020810151815161376b9063ffffffff16613ad2565b14155b80613787575061377c612f40565b815163ffffffff1610155b156137bc57847f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301856040516137359190613d57565b506001949350505050565b6000806000848060200190518101906137e09190614fb9565b905060008682600001518360200151846040015160405160200161384294939291909384526020840192909252604083015260e01b7fffffffff0000000000000000000000000000000000000000000000000000000016606082015260640190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101206080830151909150158015906138a4575081608001516138a1836060015163ffffffff16613ad2565b14155b806138c057506138b2612f40565b826060015163ffffffff1610155b1561390a57867f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301876040516138f59190613d57565b60405180910390a260009350915061082e9050565b60008181526008602052604090205460ff161561395157867f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8876040516138f59190613d57565b600197909650945050505050565b600082600001828154811061397657613976614541565b9060005260206000200154905092915050565b60008181526001830160205260408120548015613a725760006139ad6001836145d3565b85549091506000906139c1906001906145d3565b9050818114613a265760008660000182815481106139e1576139e1614541565b9060005260206000200154905080876000018481548110613a0457613a04614541565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613a3757613a3761503a565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612815565b6000915050612815565b5092915050565b6000818152600183016020526040812054613aca57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155612815565b506000612815565b600060017f00000000000000000000000000000000000000000000000000000000000000006002811115613b0857613b08614589565b03613c22576000606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613b5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b7f9190614e1f565b90508083101580613b9a5750610100613b9884836145d3565b115b15613ba85750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815260048101849052606490632b407a8290602401602060405180830381865afa158015613bfe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f399190614e1f565b504090565b919050565b50805460008255906000526020600020908101906122af9190613cd4565b828054828255906000526020600020908101928215613cc4579160200282015b82811115613cc457825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190613c6a565b50613cd0929150613cd4565b5090565b5b80821115613cd05760008155600101613cd5565b60005b83811015613d04578181015183820152602001613cec565b50506000910152565b60008151808452613d25816020860160208601613ce9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000612f396020830184613d0d565b73ffffffffffffffffffffffffffffffffffffffff811681146122af57600080fd5b8035613c2781613d6a565b60008083601f840112613da957600080fd5b50813567ffffffffffffffff811115613dc157600080fd5b602083019150836020828501011115613dd957600080fd5b9250929050565b60008060008060608587031215613df657600080fd5b8435613e0181613d6a565b935060208501359250604085013567ffffffffffffffff811115613e2457600080fd5b613e3087828801613d97565b95989497509550505050565b600080600060408486031215613e5157600080fd5b83359250602084013567ffffffffffffffff811115613e6f57600080fd5b613e7b86828701613d97565b9497909650939450505050565b60008083601f840112613e9a57600080fd5b50813567ffffffffffffffff811115613eb257600080fd5b6020830191508360208260051b8501011115613dd957600080fd5b60008060008060008060008060e0898b031215613ee957600080fd5b606089018a811115613efa57600080fd5b8998503567ffffffffffffffff80821115613f1457600080fd5b613f208c838d01613d97565b909950975060808b0135915080821115613f3957600080fd5b613f458c838d01613e88565b909750955060a08b0135915080821115613f5e57600080fd5b50613f6b8b828c01613e88565b999c989b50969995989497949560c00135949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516101e0810167ffffffffffffffff81118282101715613fd757613fd7613f84565b60405290565b60405160c0810167ffffffffffffffff81118282101715613fd757613fd7613f84565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561404757614047613f84565b604052919050565b600067ffffffffffffffff82111561406957614069613f84565b5060051b60200190565b600082601f83011261408457600080fd5b813560206140996140948361404f565b614000565b82815260059290921b840181019181810190868411156140b857600080fd5b8286015b848110156140dc5780356140cf81613d6a565b83529183019183016140bc565b509695505050505050565b803560ff81168114613c2757600080fd5b63ffffffff811681146122af57600080fd5b8035613c27816140f8565b62ffffff811681146122af57600080fd5b8035613c2781614115565b61ffff811681146122af57600080fd5b8035613c2781614131565b6bffffffffffffffffffffffff811681146122af57600080fd5b8035613c278161414c565b60006101e0828403121561418457600080fd5b61418c613fb3565b90506141978261410a565b81526141a56020830161410a565b60208201526141b66040830161410a565b60408201526141c760608301614126565b60608201526141d860808301614141565b60808201526141e960a08301614166565b60a08201526141fa60c0830161410a565b60c082015261420b60e0830161410a565b60e082015261010061421e81840161410a565b9082015261012061423083820161410a565b9082015261014082810135908201526101608083013590820152610180614258818401613d8c565b908201526101a08281013567ffffffffffffffff81111561427857600080fd5b61428485828601614073565b8284015250506101c0614298818401613d8c565b9082015292915050565b803567ffffffffffffffff81168114613c2757600080fd5b600082601f8301126142cb57600080fd5b813567ffffffffffffffff8111156142e5576142e5613f84565b61431660207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614000565b81815284602083860101111561432b57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c0878903121561436157600080fd5b863567ffffffffffffffff8082111561437957600080fd5b6143858a838b01614073565b9750602089013591508082111561439b57600080fd5b6143a78a838b01614073565b96506143b560408a016140e7565b955060608901359150808211156143cb57600080fd5b6143d78a838b01614171565b94506143e560808a016142a2565b935060a08901359150808211156143fb57600080fd5b5061440889828a016142ba565b9150509295509295509295565b60008060008060008060c0878903121561442e57600080fd5b863567ffffffffffffffff8082111561444657600080fd5b6144528a838b01614073565b9750602089013591508082111561446857600080fd5b6144748a838b01614073565b965061448260408a016140e7565b9550606089013591508082111561449857600080fd5b6143d78a838b016142ba565b6000602082840312156144b657600080fd5b8135612f3981613d6a565b6000602082840312156144d357600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff818116838216019080821115613a7c57613a7c6144da565b80820180821115612815576128156144da565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60ff8181168382160190811115612815576128156144da565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b61ffff818116838216019080821115613a7c57613a7c6144da565b81810381811115612815576128156144da565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614617576146176144da565b5060010190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614656576146566144da565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826146995761469961465b565b500490565b6bffffffffffffffffffffffff851681528360208201528260408201526080606082015260006146d16080830184613d0d565b9695505050505050565b600060ff821660ff84168160ff04811182151516156146fc576146fc6144da565b029392505050565b63ffffffff818116838216019080821115613a7c57613a7c6144da565b600081518084526020808501945080840160005b8381101561476757815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614735565b509495945050505050565b6020815261478960208201835163ffffffff169052565b600060208301516147a2604084018263ffffffff169052565b50604083015163ffffffff8116606084015250606083015162ffffff8116608084015250608083015161ffff811660a08401525060a08301516bffffffffffffffffffffffff811660c08401525060c083015163ffffffff811660e08401525060e083015161010061481b8185018363ffffffff169052565b84015190506101206148348482018363ffffffff169052565b840151905061014061484d8482018363ffffffff169052565b840151610160848101919091528401516101808085019190915284015190506101a06148908185018373ffffffffffffffffffffffffffffffffffffffff169052565b808501519150506101e06101c081818601526148b0610200860184614721565b95015173ffffffffffffffffffffffffffffffffffffffff169301929092525090919050565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526149068184018a614721565b9050828103608084015261491a8189614721565b905060ff871660a084015282810360c08401526149378187613d0d565b905067ffffffffffffffff851660e084015282810361010084015261495c8185613d0d565b9c9b505050505050505050505050565b8051613c27816140f8565b8051613c2781614115565b8051613c2781614131565b8051613c278161414c565b8051613c2781613d6a565b600082601f8301126149b457600080fd5b815160206149c46140948361404f565b82815260059290921b840181019181810190868411156149e357600080fd5b8286015b848110156140dc5780516149fa81613d6a565b83529183019183016149e7565b600060208284031215614a1957600080fd5b815167ffffffffffffffff80821115614a3157600080fd5b908301906101e08286031215614a4657600080fd5b614a4e613fb3565b614a578361496c565b8152614a656020840161496c565b6020820152614a766040840161496c565b6040820152614a8760608401614977565b6060820152614a9860808401614982565b6080820152614aa960a0840161498d565b60a0820152614aba60c0840161496c565b60c0820152614acb60e0840161496c565b60e0820152610100614ade81850161496c565b90820152610120614af084820161496c565b9082015261014083810151908201526101608084015190820152610180614b18818501614998565b908201526101a08381015183811115614b3057600080fd5b614b3c888287016149a3565b8284015250506101c09150614b52828401614998565b91810191909152949350505050565b8281526040602082015260006128be6040830184613d0d565b60008060408385031215614b8d57600080fd5b82518015158114614b9d57600080fd5b6020939093015192949293505050565b8183823760009101908152919050565b8281526080810160608360208401379392505050565b600082601f830112614be457600080fd5b81356020614bf46140948361404f565b82815260059290921b84018101918181019086841115614c1357600080fd5b8286015b848110156140dc5780358352918301918301614c17565b600082601f830112614c3f57600080fd5b81356020614c4f6140948361404f565b82815260059290921b84018101918181019086841115614c6e57600080fd5b8286015b848110156140dc57803567ffffffffffffffff811115614c925760008081fd5b614ca08986838b01016142ba565b845250918301918301614c72565b600060208284031215614cc057600080fd5b813567ffffffffffffffff80821115614cd857600080fd5b9083019060c08286031215614cec57600080fd5b614cf4613fdd565b8235815260208301356020820152604083013582811115614d1457600080fd5b614d2087828601614bd3565b604083015250606083013582811115614d3857600080fd5b614d4487828601614bd3565b606083015250608083013582811115614d5c57600080fd5b614d6887828601614c2e565b60808301525060a083013582811115614d8057600080fd5b614d8c87828601614c2e565b60a08301525095945050505050565b6bffffffffffffffffffffffff828116828216039080821115613a7c57613a7c6144da565b60006bffffffffffffffffffffffff80841680614ddf57614ddf61465b565b92169190910492915050565b60006bffffffffffffffffffffffff80831681851681830481118215151615614e1657614e166144da565b02949350505050565b600060208284031215614e3157600080fd5b5051919050565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152614e7f8285018b614721565b91508382036080850152614e93828a614721565b915060ff881660a085015283820360c0850152614eb08288613d0d565b90861660e0850152838103610100850152905061495c8185613d0d565b828482376000838201600081528351614eea818360208801613ce9565b0195945050505050565b600063ffffffff80831681851681830481118215151615614e1657614e166144da565b60008060008060008060c08789031215614f3057600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b600060408284031215614f7357600080fd5b6040516040810181811067ffffffffffffffff82111715614f9657614f96613f84565b6040528251614fa4816140f8565b81526020928301519281019290925250919050565b600060a08284031215614fcb57600080fd5b60405160a0810181811067ffffffffffffffff82111715614fee57614fee613f84565b80604052508251815260208301516020820152604083015161500f816140f8565b60408201526060830151615022816140f8565b60608201526080928301519281019290925250919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000810000a", } var KeeperRegistryABI = KeeperRegistryMetaData.ABI diff --git a/core/gethwrappers/generated/operator_factory/operator_factory.go b/core/gethwrappers/generated/operator_factory/operator_factory.go index c14ef439368..dae113afe32 100644 --- a/core/gethwrappers/generated/operator_factory/operator_factory.go +++ b/core/gethwrappers/generated/operator_factory/operator_factory.go @@ -32,7 +32,7 @@ var ( var OperatorFactoryMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"linkAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"forwarder\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AuthorizedForwarderCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"OperatorCreated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"query\",\"type\":\"address\"}],\"name\":\"created\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployNewForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"deployNewForwarderAndTransferOwnership\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployNewOperator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployNewOperatorAndForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x60a060405234801561001057600080fd5b50604051615d59380380615d5983398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b608051615cab6100ae6000396000818161014f015281816101e6015281816102e3015281816103da015281816104be01526105a50152615cab6000f3fe60806040523480156200001157600080fd5b5060043610620000875760003560e01c806357970e93116200006257806357970e931462000149578063d42efd831462000171578063d689d09514620001be578063f4adb6e114620001d557600080fd5b8063181f5a77146200008c57806332f01eae14620000e15780633babafdb1462000119575b600080fd5b620000c96040518060400160405280601581526020017f4f70657261746f72466163746f727920312e302e30000000000000000000000081525081565b604051620000d8919062000717565b60405180910390f35b620000eb620001df565b6040805173ffffffffffffffffffffffffffffffffffffffff938416815292909116602083015201620000d8565b62000123620003c6565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001620000d8565b620001237f000000000000000000000000000000000000000000000000000000000000000081565b620001ad620001823660046200075d565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b6040519015158152602001620000d8565b62000123620001cf3660046200077b565b620004b9565b62000123620005a0565b60008060007f000000000000000000000000000000000000000000000000000000000000000033604051620002149062000695565b73ffffffffffffffffffffffffffffffffffffffff928316815291166020820152604001604051809103906000f08015801562000255573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917fd3bb727b2e716a1f142bc9c63c66fe0ae4c5fbc89234f8aa77d0c864a7b63bab91a4604080516000808252602082019092527f000000000000000000000000000000000000000000000000000000000000000090309084906040516200031590620006a3565b62000324949392919062000805565b604051809103906000f08015801562000341573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033923092917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a490939092509050565b6040805160008082526020820190925281907f000000000000000000000000000000000000000000000000000000000000000090339083906040516200040c90620006a3565b6200041b949392919062000805565b604051809103906000f08015801562000438573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a4919050565b6000807f000000000000000000000000000000000000000000000000000000000000000033868686604051620004ef90620006a3565b620004ff95949392919062000852565b604051809103906000f0801580156200051c573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a4949350505050565b6000807f000000000000000000000000000000000000000000000000000000000000000033604051620005d39062000695565b73ffffffffffffffffffffffffffffffffffffffff928316815291166020820152604001604051809103906000f08015801562000614573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917fd3bb727b2e716a1f142bc9c63c66fe0ae4c5fbc89234f8aa77d0c864a7b63bab91a4919050565b613d3280620008d483390190565b611699806200460683390190565b6000815180845260005b81811015620006d957602081850181015186830182015201620006bb565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006200072c6020830184620006b1565b9392505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146200075857600080fd5b919050565b6000602082840312156200077057600080fd5b6200072c8262000733565b6000806000604084860312156200079157600080fd5b6200079c8462000733565b9250602084013567ffffffffffffffff80821115620007ba57600080fd5b818601915086601f830112620007cf57600080fd5b813581811115620007df57600080fd5b876020828501011115620007f257600080fd5b6020830194508093505050509250925092565b600073ffffffffffffffffffffffffffffffffffffffff8087168352808616602084015280851660408401525060806060830152620008486080830184620006b1565b9695505050505050565b600073ffffffffffffffffffffffffffffffffffffffff8088168352808716602084015280861660408401525060806060830152826080830152828460a0840137600060a0848401015260a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501168301019050969550505050505056fe60a060405260016006553480156200001657600080fd5b5060405162003d3238038062003d328339810160408190526200003991620001ab565b808060006001600160a01b038216620000995760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0384811691909117909155811615620000cc57620000cc81620000e2565b505050506001600160a01b0316608052620001e3565b336001600160a01b038216036200013c5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000090565b600380546001600160a01b0319166001600160a01b03838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b80516001600160a01b0381168114620001a657600080fd5b919050565b60008060408385031215620001bf57600080fd5b620001ca836200018e565b9150620001da602084016200018e565b90509250929050565b608051613aed62000245600039600081816101ec0152818161075e015281816109f301528181610c4f0152818161187c01528181611ae601528181611b8601528181611f21015281816123ba0152818161266d0152612bf50152613aed6000f3fe6080604052600436106101965760003560e01c80636ae0bc76116100e1578063a4c0ed361161008a578063f2fde38b11610064578063f2fde38b146104aa578063f3fef3a3146104ca578063fa00763a146104ea578063fc4a03ed1461053057600080fd5b8063a4c0ed361461044a578063eb007d991461046a578063ee56997b1461048a57600080fd5b806379ba5097116100bb57806379ba5097146103ea5780638da5cb5b146103ff578063902fc3701461042a57600080fd5b80636ae0bc76146103975780636bd59ec0146103b75780636ee4d553146103ca57600080fd5b80633ec5bc1411610143578063501883011161011d578063501883011461033e57806352043783146103615780635ffa62881461037757600080fd5b80633ec5bc14146102ce57806340429946146102ee5780634ab0d1901461030e57600080fd5b8063181f5a7711610174578063181f5a77146102365780632408afaa1461028c5780633c6d41b9146102ae57600080fd5b806301994b991461019b578063033f49f7146101bd578063165d35e1146101dd575b600080fd5b3480156101a757600080fd5b506101bb6101b6366004613068565b610550565b005b3480156101c957600080fd5b506101bb6101d836600461310e565b610753565b3480156101e957600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561024257600080fd5b5061027f6040518060400160405280600e81526020017f4f70657261746f7220312e302e3000000000000000000000000000000000000081525081565b60405161022d9190613187565b34801561029857600080fd5b506102a161096c565b60405161022d91906131d8565b3480156102ba57600080fd5b506101bb6102c9366004613267565b6109db565b3480156102da57600080fd5b506101bb6102e93660046132f4565b610ae3565b3480156102fa57600080fd5b506101bb61030936600461334b565b610c37565b34801561031a57600080fd5b5061032e6103293660046133ee565b610d40565b604051901515815260200161022d565b34801561034a57600080fd5b50610353611036565b60405190815260200161022d565b34801561036d57600080fd5b5061035361012c81565b34801561038357600080fd5b506101bb610392366004613448565b611045565b3480156103a357600080fd5b5061032e6103b23660046134b4565b6110c9565b6101bb6103c5366004613448565b611445565b3480156103d657600080fd5b506101bb6103e5366004613538565b611682565b3480156103f657600080fd5b506101bb611906565b34801561040b57600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff1661020c565b34801561043657600080fd5b5061032e610445366004613575565b611a07565b34801561045657600080fd5b506101bb6104653660046135f4565b611b6e565b34801561047657600080fd5b506101bb610485366004613538565b611cfc565b34801561049657600080fd5b506101bb6104a5366004613068565b611fac565b3480156104b657600080fd5b506101bb6104c53660046136df565b6122ba565b3480156104d657600080fd5b506101bb6104e5366004613703565b6122ce565b3480156104f657600080fd5b5061032e6105053660046136df565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b34801561053c57600080fd5b506101bb61054b366004613448565b612433565b61055861258f565b6105c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064015b60405180910390fd5b60005b8181101561074e576001600560008585858181106105e6576105e661372f565b90506020020160208101906105fb91906136df565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790558282828181106106605761066061372f565b905060200201602081019061067591906136df565b73ffffffffffffffffffffffffffffffffffffffff167f615a0c1cb00a60d4acd77ec67acf2f17f223ef0932d591052fabc33643fe7e8260405160405180910390a28282828181106106c9576106c961372f565b90506020020160208101906106de91906136df565b73ffffffffffffffffffffffffffffffffffffffff166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561072557600080fd5b505af1158015610739573d6000803e3d6000fd5b50505050806107479061378d565b90506105c6565b505050565b61075b6125e4565b827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610811576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff84163b61088f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e747261637400000000000060448201526064016105ba565b60008473ffffffffffffffffffffffffffffffffffffffff1684846040516108b89291906137c5565b6000604051808303816000865af19150503d80600081146108f5576040519150601f19603f3d011682016040523d82523d6000602084013e6108fa565b606091505b5050905080610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f466f727761726465642063616c6c206661696c6564000000000000000000000060448201526064016105ba565b5050505050565b606060018054806020026020016040519081016040528092919081815260200182805480156109d157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116109a6575b5050505050905090565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610a7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610a8b8a8a8c8a8a8a612667565b91509150877fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658b848c8e8c878c8c8c604051610acf9998979695949392919061381e565b60405180910390a250505050505050505050565b610aeb6125e4565b60005b82811015610c3157600060056000868685818110610b0e57610b0e61372f565b9050602002016020810190610b2391906136df565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055838382818110610b8857610b8861372f565b9050602002016020810190610b9d91906136df565b6040517ff2fde38b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152919091169063f2fde38b90602401600060405180830381600087803b158015610c0857600080fd5b505af1158015610c1c573d6000803e3d6000fd5b5050505080610c2a9061378d565b9050610aee565b50505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610cd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610ce78b8b8a8a8a8a612667565b91509150887fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658c848d8f8c878c8c8c604051610d2b9998979695949392919061381e565b60405180910390a25050505050505050505050565b6000610d4a612945565b600087815260046020526040812054889160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003610deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260056020526040902054869060ff1615610e7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b610e8c898989898960016129be565b60405189907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015610f24576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008773ffffffffffffffffffffffffffffffffffffffff16878b87604051602401610f5a929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051610fe391906138a9565b6000604051808303816000865af19150503d8060008114611020576040519150601f19603f3d011682016040523d82523d6000602084013e611025565b606091505b50909b9a5050505050505050505050565b6000611040612bb6565b905090565b61104d61258f565b6110b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b6110bd8484610550565b610c3184848484612433565b60006110d3612945565b600088815260046020526040812054899160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003611174576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260056020526040902054879060ff1615611206576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b8985856020811015611274576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526573706f6e7365206d757374206265203e203332206279746573000000000060448201526064016105ba565b81358381146112df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f466972737420776f7264206d757374206265207265717565737449640000000060448201526064016105ba565b6112ee8e8e8e8e8e60026129be565b6040518e907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015611386576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008c73ffffffffffffffffffffffffffffffffffffffff168c8b8b6040516020016113b4939291906138c5565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526113ec916138a9565b6000604051808303816000865af19150503d8060008114611429576040519150601f19603f3d011682016040523d82523d6000602084013e61142e565b606091505b509098505050505050505050979650505050505050565b821580159061145357508281145b6114b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c6964206172726179206c656e67746828732900000000000000000060448201526064016105ba565b3460005b848110156116195760008484838181106114d9576114d961372f565b90506020020135905080836114ee9190613901565b925060008787848181106115045761150461372f565b905060200201602081019061151991906136df565b73ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114611570576040519150601f19603f3d011682016040523d82523d6000602084013e611575565b606091505b5050905080611606576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016105ba565b5050806116129061378d565b90506114bd565b508015610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f546f6f206d756368204554482073656e7400000000000000000000000000000060448201526064016105ba565b6040805160208082018690527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b16828401527fffffffff00000000000000000000000000000000000000000000000000000000851660548301526058808301859052835180840390910181526078909201909252805191012060009060008681526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116908216146117a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b4282111561180f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000858152600460205260408082208290555186917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018590527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af11580156118da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118fe919061391a565b505050505050565b60035473ffffffffffffffffffffffffffffffffffffffff163314611987576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016105ba565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560038054909116905560405173ffffffffffffffffffffffffffffffffffffffff909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6000611a116125e4565b8380611a1b612bb6565b1015611aa9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517f4000aea000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634000aea090611b2190899089908990899060040161393c565b6020604051808303816000875af1158015611b40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b64919061391a565b9695505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611c0d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b60208101518190611c1e8183612c7f565b84602484015283604484015260003073ffffffffffffffffffffffffffffffffffffffff1684604051611c5191906138a9565b600060405180830381855af49150503d8060008114611c8c576040519150601f19603f3d011682016040523d82523d6000602084013e611c91565b606091505b50509050806118fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e61626c6520746f206372656174652072657175657374000000000000000060448201526064016105ba565b604080513360601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660208083018290526034808401899052845180850390910181526054840185528051908201206074840188905260948401929092527fffffffff00000000000000000000000000000000000000000000000000000000861660a884015260ac8084018690528451808503909101815260cc9093019093528151919092012060009060008381526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614611e4a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b42831115611eb4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000828152600460205260408082208290555183917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018690527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015611f7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa3919061391a565b50505050505050565b611fb461258f565b61201a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b80612081576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e646572000000000060448201526064016105ba565b60015460005b81811015612116576000806000600184815481106120a7576120a761372f565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905561210f8161378d565b9050612087565b5060005b8281101561226c576000808585848181106121375761213761372f565b905060200201602081019061214c91906136df565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff16156121dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e646572730060448201526064016105ba565b60016000808686858181106121f4576121f461372f565b905060200201602081019061220991906136df565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556122658161378d565b905061211a565b5061227960018484612f88565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a08383336040516122ad939291906139c8565b60405180910390a1505050565b6122c26125e4565b6122cb81612dfb565b50565b6122d66125e4565b80806122e0612bb6565b101561236e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015612403573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612427919061391a565b61074e5761074e613a02565b61243b61258f565b6124a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b7f1bb185903e2cb2f1b303523128b60e314dea81df4f8d9b7351cadd344f6e772784848484336040516124d8959493929190613a31565b60405180910390a160005b83811015610965578484828181106124fd576124fd61372f565b905060200201602081019061251291906136df565b73ffffffffffffffffffffffffffffffffffffffff1663ee56997b84846040518363ffffffff1660e01b815260040161254c929190613a81565b600060405180830381600087803b15801561256657600080fd5b505af115801561257a573d6000803e3d6000fd5b50505050806125889061378d565b90506124e3565b3360009081526020819052604081205460ff16806110405750336125c860025473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b60025473ffffffffffffffffffffffffffffffffffffffff163314612665576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016105ba565b565b600080857f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612720576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b6040517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608b901b16602082015260348101869052605401604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291815281516020928301206000818152600490935291205490935060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00161561282b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4d75737420757365206120756e6971756520494400000000000000000000000060448201526064016105ba565b61283761012c42613a9d565b6040805160208082018c90527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608c901b16828401527fffffffff000000000000000000000000000000000000000000000000000000008a1660548301526058808301859052835180840390910181526078909201909252805191012090925060405180604001604052808260ff191681526020016128d687612ef1565b60ff9081169091526000868152600460209081526040909120835193909101519091167f01000000000000000000000000000000000000000000000000000000000000000260089290921c919091179055600654612935908a90613a9d565b6006555050965096945050505050565b3360009081526020819052604090205460ff16612665576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e646572000000000000000000000060448201526064016105ba565b6040805160208082018890527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606088901b16828401527fffffffff00000000000000000000000000000000000000000000000000000000861660548301526058808301869052835180840390910181526078909201909252805191012060009060008881526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614612ae2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b612aeb82612ef1565b60008881526004602052604090205460ff9182167f01000000000000000000000000000000000000000000000000000000000000009091049091161115612b8e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f446174612076657273696f6e73206d757374206d61746368000000000000000060448201526064016105ba565b85600654612b9c9190613901565b600655505050600093845250506004602052506040812055565b60006001600654612bc79190613901565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612c51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c759190613ab0565b6110409190613901565b612c8b60026020613ac9565b612c96906004613a9d565b81511015612d00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c69642072657175657374206c656e6774680000000000000000000060448201526064016105ba565b7fffffffff0000000000000000000000000000000000000000000000000000000082167f3c6d41b9000000000000000000000000000000000000000000000000000000001480612d9157507fffffffff0000000000000000000000000000000000000000000000000000000082167f4042994600000000000000000000000000000000000000000000000000000000145b612df7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4d757374207573652077686974656c69737465642066756e6374696f6e73000060448201526064016105ba565b5050565b3373ffffffffffffffffffffffffffffffffffffffff821603612e7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016105ba565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b600060ff821115612f84576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203860448201527f206269747300000000000000000000000000000000000000000000000000000060648201526084016105ba565b5090565b828054828255906000526020600020908101928215613000579160200282015b828111156130005781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190612fa8565b50612f849291505b80821115612f845760008155600101613008565b60008083601f84011261302e57600080fd5b50813567ffffffffffffffff81111561304657600080fd5b6020830191508360208260051b850101111561306157600080fd5b9250929050565b6000806020838503121561307b57600080fd5b823567ffffffffffffffff81111561309257600080fd5b61309e8582860161301c565b90969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff811681146122cb57600080fd5b60008083601f8401126130de57600080fd5b50813567ffffffffffffffff8111156130f657600080fd5b60208301915083602082850101111561306157600080fd5b60008060006040848603121561312357600080fd5b833561312e816130aa565b9250602084013567ffffffffffffffff81111561314a57600080fd5b613156868287016130cc565b9497909650939450505050565b60005b8381101561317e578181015183820152602001613166565b50506000910152565b60208152600082518060208401526131a6816040850160208701613163565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6020808252825182820181905260009190848201906040850190845b8181101561322657835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016131f4565b50909695505050505050565b80357fffffffff000000000000000000000000000000000000000000000000000000008116811461326257600080fd5b919050565b60008060008060008060008060e0898b03121561328357600080fd5b883561328e816130aa565b975060208901359650604089013595506132aa60608a01613232565b94506080890135935060a0890135925060c089013567ffffffffffffffff8111156132d457600080fd5b6132e08b828c016130cc565b999c989b5096995094979396929594505050565b60008060006040848603121561330957600080fd5b833567ffffffffffffffff81111561332057600080fd5b61332c8682870161301c565b9094509250506020840135613340816130aa565b809150509250925092565b60008060008060008060008060006101008a8c03121561336a57600080fd5b8935613375816130aa565b985060208a0135975060408a0135965060608a0135613393816130aa565b95506133a160808b01613232565b945060a08a0135935060c08a0135925060e08a013567ffffffffffffffff8111156133cb57600080fd5b6133d78c828d016130cc565b915080935050809150509295985092959850929598565b60008060008060008060c0878903121561340757600080fd5b86359550602087013594506040870135613420816130aa565b935061342e60608801613232565b92506080870135915060a087013590509295509295509295565b6000806000806040858703121561345e57600080fd5b843567ffffffffffffffff8082111561347657600080fd5b6134828883890161301c565b9096509450602087013591508082111561349b57600080fd5b506134a88782880161301c565b95989497509550505050565b600080600080600080600060c0888a0312156134cf57600080fd5b873596506020880135955060408801356134e8816130aa565b94506134f660608901613232565b93506080880135925060a088013567ffffffffffffffff81111561351957600080fd5b6135258a828b016130cc565b989b979a50959850939692959293505050565b6000806000806080858703121561354e57600080fd5b843593506020850135925061356560408601613232565b9396929550929360600135925050565b6000806000806060858703121561358b57600080fd5b8435613596816130aa565b935060208501359250604085013567ffffffffffffffff8111156135b957600080fd5b6134a8878288016130cc565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060006060848603121561360957600080fd5b8335613614816130aa565b925060208401359150604084013567ffffffffffffffff8082111561363857600080fd5b818601915086601f83011261364c57600080fd5b81358181111561365e5761365e6135c5565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156136a4576136a46135c5565b816040528281528960208487010111156136bd57600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b6000602082840312156136f157600080fd5b81356136fc816130aa565b9392505050565b6000806040838503121561371657600080fd5b8235613721816130aa565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036137be576137be61375e565b5060010190565b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600061010073ffffffffffffffffffffffffffffffffffffffff808d1684528b60208501528a6040850152808a166060850152507fffffffff00000000000000000000000000000000000000000000000000000000881660808401528660a08401528560c08401528060e084015261389981840185876137d5565b9c9b505050505050505050505050565b600082516138bb818460208701613163565b9190910192915050565b7fffffffff0000000000000000000000000000000000000000000000000000000084168152818360048301376000910160040190815292915050565b818103818111156139145761391461375e565b92915050565b60006020828403121561392c57600080fd5b815180151581146136fc57600080fd5b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201526000611b646060830184866137d5565b8183526000602080850194508260005b858110156139bd578135613995816130aa565b73ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613982565b509495945050505050565b6040815260006139dc604083018587613972565b905073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b606081526000613a45606083018789613972565b8281036020840152613a58818688613972565b91505073ffffffffffffffffffffffffffffffffffffffff831660408301529695505050505050565b602081526000613a95602083018486613972565b949350505050565b808201808211156139145761391461375e565b600060208284031215613ac257600080fd5b5051919050565b80820281158282048414176139145761391461375e56fea164736f6c6343000813000a60a06040523480156200001157600080fd5b50604051620016993803806200169983398101604081905262000034916200029d565b82826001600160a01b038216620000925760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c557620000c58162000199565b50506001600160a01b0384166200012b5760405162461bcd60e51b815260206004820152602360248201527f4c696e6b20746f6b656e2063616e6e6f742062652061207a65726f206164647260448201526265737360e81b606482015260840162000089565b6001600160a01b038085166080528216156200018f57816001600160a01b0316836001600160a01b03167f4e1e878dc28d5f040db5969163ff1acd75c44c3f655da2dde9c70bbd8e56dc7e836040516200018691906200038e565b60405180910390a35b50505050620003c3565b336001600160a01b03821603620001f35760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000089565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200025c57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620002945781810151838201526020016200027a565b50506000910152565b60008060008060808587031215620002b457600080fd5b620002bf8562000244565b9350620002cf6020860162000244565b9250620002df6040860162000244565b60608601519092506001600160401b0380821115620002fd57600080fd5b818701915087601f8301126200031257600080fd5b81518181111562000327576200032762000261565b604051601f8201601f19908116603f0116810190838211818310171562000352576200035262000261565b816040528281528a60208487010111156200036c57600080fd5b6200037f83602083016020880162000277565b979a9699509497505050505050565b6020815260008251806020840152620003af81604085016020870162000277565b601f01601f19169190910160400192915050565b6080516112ac620003ed6000396000818161016d0152818161037501526105d301526112ac6000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c806379ba509711610081578063ee56997b1161005b578063ee56997b14610200578063f2fde38b14610213578063fa00763a1461022657600080fd5b806379ba5097146101c75780638da5cb5b146101cf578063b64fa9e6146101ed57600080fd5b80634d3e2323116100b25780634d3e23231461015557806357970e93146101685780636fadcf72146101b457600080fd5b8063033f49f7146100d9578063181f5a77146100ee5780632408afaa14610140575b600080fd5b6100ec6100e7366004610e72565b61026f565b005b61012a6040518060400160405280601981526020017f417574686f72697a6564466f7277617264657220312e312e300000000000000081525081565b6040516101379190610ef5565b60405180910390f35b610148610287565b6040516101379190610f61565b6100ec610163366004610e72565b6102f6565b61018f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610137565b6100ec6101c2366004610e72565b61036b565b6100ec61042d565b60005473ffffffffffffffffffffffffffffffffffffffff1661018f565b6100ec6101fb366004611007565b61052a565b6100ec61020e366004611073565b6106cb565b6100ec6102213660046110b5565b6109dc565b61025f6102343660046110b5565b73ffffffffffffffffffffffffffffffffffffffff1660009081526002602052604090205460ff1690565b6040519015158152602001610137565b6102776109f0565b610282838383610a73565b505050565b606060038054806020026020016040519081016040528092919081815260200182805480156102ec57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116102c1575b5050505050905090565b6102ff836109dc565b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f4e1e878dc28d5f040db5969163ff1acd75c44c3f655da2dde9c70bbd8e56dc7e848460405161035e9291906110d7565b60405180910390a3505050565b610373610c00565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610277576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f43616e6e6f7420666f727761726420746f204c696e6b20746f6b656e0000000060448201526064015b60405180910390fd5b60015473ffffffffffffffffffffffffffffffffffffffff1633146104ae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610424565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610532610c00565b82811461059b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f417272617973206d7573742068617665207468652073616d65206c656e6774686044820152606401610424565b60005b838110156106c45760008585838181106105ba576105ba611124565b90506020020160208101906105cf91906110b5565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610686576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f43616e6e6f7420666f727761726420746f204c696e6b20746f6b656e000000006044820152606401610424565b6106b38185858581811061069c5761069c611124565b90506020028101906106ae9190611153565b610a73565b506106bd816111b8565b905061059e565b5050505050565b6106d3610c79565b610739576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e646572730000006044820152606401610424565b806107a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e64657200000000006044820152606401610424565b60035460005b8181101561083657600060026000600384815481106107c7576107c7611124565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905561082f816111b8565b90506107a6565b5060005b8281101561098e576002600085858481811061085857610858611124565b905060200201602081019061086d91906110b5565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff16156108fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e64657273006044820152606401610424565b60016002600086868581811061091657610916611124565b905060200201602081019061092b91906110b5565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055610987816111b8565b905061083a565b5061099b60038484610dac565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a08383336040516109cf93929190611217565b60405180910390a1505050565b6109e46109f0565b6109ed81610cb7565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610a71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610424565b565b73ffffffffffffffffffffffffffffffffffffffff83163b610af1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e74726163740000000000006044820152606401610424565b6000808473ffffffffffffffffffffffffffffffffffffffff168484604051610b1b92919061128f565b6000604051808303816000865af19150503d8060008114610b58576040519150601f19603f3d011682016040523d82523d6000602084013e610b5d565b606091505b5091509150816106c4578051600003610bf8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f466f727761726465642063616c6c20726576657274656420776974686f75742060448201527f726561736f6e00000000000000000000000000000000000000000000000000006064820152608401610424565b805181602001fd5b3360009081526002602052604090205460ff16610a71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e64657200000000000000000000006044820152606401610424565b600033610c9b60005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b3373ffffffffffffffffffffffffffffffffffffffff821603610d36576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610424565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610e24579160200282015b82811115610e245781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190610dcc565b50610e30929150610e34565b5090565b5b80821115610e305760008155600101610e35565b803573ffffffffffffffffffffffffffffffffffffffff81168114610e6d57600080fd5b919050565b600080600060408486031215610e8757600080fd5b610e9084610e49565b9250602084013567ffffffffffffffff80821115610ead57600080fd5b818601915086601f830112610ec157600080fd5b813581811115610ed057600080fd5b876020828501011115610ee257600080fd5b6020830194508093505050509250925092565b600060208083528351808285015260005b81811015610f2257858101830151858201604001528201610f06565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b6020808252825182820181905260009190848201906040850190845b81811015610faf57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101610f7d565b50909695505050505050565b60008083601f840112610fcd57600080fd5b50813567ffffffffffffffff811115610fe557600080fd5b6020830191508360208260051b850101111561100057600080fd5b9250929050565b6000806000806040858703121561101d57600080fd5b843567ffffffffffffffff8082111561103557600080fd5b61104188838901610fbb565b9096509450602087013591508082111561105a57600080fd5b5061106787828801610fbb565b95989497509550505050565b6000806020838503121561108657600080fd5b823567ffffffffffffffff81111561109d57600080fd5b6110a985828601610fbb565b90969095509350505050565b6000602082840312156110c757600080fd5b6110d082610e49565b9392505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261118857600080fd5b83018035915067ffffffffffffffff8211156111a357600080fd5b60200191503681900382131561100057600080fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611210577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b6040808252810183905260008460608301825b868110156112655773ffffffffffffffffffffffffffffffffffffffff61125084610e49565b1682526020928301929091019060010161122a565b50809250505073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b818382376000910190815291905056fea164736f6c6343000813000aa164736f6c6343000813000a", + Bin: "0x60a060405234801561001057600080fd5b50604051615b13380380615b1383398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b608051615a656100ae6000396000818161014f015281816101e6015281816102e3015281816103da015281816104be01526105a50152615a656000f3fe60806040523480156200001157600080fd5b5060043610620000875760003560e01c806357970e93116200006257806357970e931462000149578063d42efd831462000171578063d689d09514620001be578063f4adb6e114620001d557600080fd5b8063181f5a77146200008c57806332f01eae14620000e15780633babafdb1462000119575b600080fd5b620000c96040518060400160405280601581526020017f4f70657261746f72466163746f727920312e302e30000000000000000000000081525081565b604051620000d8919062000717565b60405180910390f35b620000eb620001df565b6040805173ffffffffffffffffffffffffffffffffffffffff938416815292909116602083015201620000d8565b62000123620003c6565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001620000d8565b620001237f000000000000000000000000000000000000000000000000000000000000000081565b620001ad620001823660046200075d565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b6040519015158152602001620000d8565b62000123620001cf3660046200077b565b620004b9565b62000123620005a0565b60008060007f000000000000000000000000000000000000000000000000000000000000000033604051620002149062000695565b73ffffffffffffffffffffffffffffffffffffffff928316815291166020820152604001604051809103906000f08015801562000255573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917fd3bb727b2e716a1f142bc9c63c66fe0ae4c5fbc89234f8aa77d0c864a7b63bab91a4604080516000808252602082019092527f000000000000000000000000000000000000000000000000000000000000000090309084906040516200031590620006a3565b62000324949392919062000805565b604051809103906000f08015801562000341573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033923092917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a490939092509050565b6040805160008082526020820190925281907f000000000000000000000000000000000000000000000000000000000000000090339083906040516200040c90620006a3565b6200041b949392919062000805565b604051809103906000f08015801562000438573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a4919050565b6000807f000000000000000000000000000000000000000000000000000000000000000033868686604051620004ef90620006a3565b620004ff95949392919062000852565b604051809103906000f0801580156200051c573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a4949350505050565b6000807f000000000000000000000000000000000000000000000000000000000000000033604051620005d39062000695565b73ffffffffffffffffffffffffffffffffffffffff928316815291166020820152604001604051809103906000f08015801562000614573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917fd3bb727b2e716a1f142bc9c63c66fe0ae4c5fbc89234f8aa77d0c864a7b63bab91a4919050565b613aec80620008d483390190565b61169980620043c083390190565b6000815180845260005b81811015620006d957602081850181015186830182015201620006bb565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006200072c6020830184620006b1565b9392505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146200075857600080fd5b919050565b6000602082840312156200077057600080fd5b6200072c8262000733565b6000806000604084860312156200079157600080fd5b6200079c8462000733565b9250602084013567ffffffffffffffff80821115620007ba57600080fd5b818601915086601f830112620007cf57600080fd5b813581811115620007df57600080fd5b876020828501011115620007f257600080fd5b6020830194508093505050509250925092565b600073ffffffffffffffffffffffffffffffffffffffff8087168352808616602084015280851660408401525060806060830152620008486080830184620006b1565b9695505050505050565b600073ffffffffffffffffffffffffffffffffffffffff8088168352808716602084015280861660408401525060806060830152826080830152828460a0840137600060a0848401015260a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501168301019050969550505050505056fe60a060405260016006553480156200001657600080fd5b5060405162003aec38038062003aec8339810160408190526200003991620001ab565b808060006001600160a01b038216620000995760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0384811691909117909155811615620000cc57620000cc81620000e2565b505050506001600160a01b0316608052620001e3565b336001600160a01b038216036200013c5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000090565b600380546001600160a01b0319166001600160a01b03838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b80516001600160a01b0381168114620001a657600080fd5b919050565b60008060408385031215620001bf57600080fd5b620001ca836200018e565b9150620001da602084016200018e565b90509250929050565b6080516138ae6200023e600039600081816101ec0152818161075e015281816109f301528181610c4f0152818161189301528181611afd01528181611b9d0152818161217b0152818161242e01526129b601526138ae6000f3fe6080604052600436106101965760003560e01c80636ae0bc76116100e1578063a4c0ed361161008a578063f2fde38b11610064578063f2fde38b146104aa578063f3fef3a3146104ca578063fa00763a146104ea578063fc4a03ed1461053057600080fd5b8063a4c0ed361461044a578063eb007d991461046a578063ee56997b1461048a57600080fd5b806379ba5097116100bb57806379ba5097146103ea5780638da5cb5b146103ff578063902fc3701461042a57600080fd5b80636ae0bc76146103975780636bd59ec0146103b75780636ee4d553146103ca57600080fd5b80633ec5bc1411610143578063501883011161011d578063501883011461033e57806352043783146103615780635ffa62881461037757600080fd5b80633ec5bc14146102ce57806340429946146102ee5780634ab0d1901461030e57600080fd5b8063181f5a7711610174578063181f5a77146102365780632408afaa1461028c5780633c6d41b9146102ae57600080fd5b806301994b991461019b578063033f49f7146101bd578063165d35e1146101dd575b600080fd5b3480156101a757600080fd5b506101bb6101b6366004612e29565b610550565b005b3480156101c957600080fd5b506101bb6101d8366004612ecf565b610753565b3480156101e957600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561024257600080fd5b5061027f6040518060400160405280600e81526020017f4f70657261746f7220312e302e3000000000000000000000000000000000000081525081565b60405161022d9190612f48565b34801561029857600080fd5b506102a161096c565b60405161022d9190612f99565b3480156102ba57600080fd5b506101bb6102c9366004613028565b6109db565b3480156102da57600080fd5b506101bb6102e93660046130b5565b610ae3565b3480156102fa57600080fd5b506101bb61030936600461310c565b610c37565b34801561031a57600080fd5b5061032e6103293660046131af565b610d40565b604051901515815260200161022d565b34801561034a57600080fd5b50610353611036565b60405190815260200161022d565b34801561036d57600080fd5b5061035361012c81565b34801561038357600080fd5b506101bb610392366004613209565b611045565b3480156103a357600080fd5b5061032e6103b2366004613275565b6110c9565b6101bb6103c5366004613209565b611445565b3480156103d657600080fd5b506101bb6103e53660046132f9565b611682565b3480156103f657600080fd5b506101bb61191d565b34801561040b57600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff1661020c565b34801561043657600080fd5b5061032e610445366004613336565b611a1e565b34801561045657600080fd5b506101bb6104653660046133b5565b611b85565b34801561047657600080fd5b506101bb6104853660046132f9565b611d13565b34801561049657600080fd5b506101bb6104a5366004612e29565b611d6d565b3480156104b657600080fd5b506101bb6104c53660046134a0565b61207b565b3480156104d657600080fd5b506101bb6104e53660046134c4565b61208f565b3480156104f657600080fd5b5061032e6105053660046134a0565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b34801561053c57600080fd5b506101bb61054b366004613209565b6121f4565b610558612350565b6105c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064015b60405180910390fd5b60005b8181101561074e576001600560008585858181106105e6576105e66134f0565b90506020020160208101906105fb91906134a0565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055828282818110610660576106606134f0565b905060200201602081019061067591906134a0565b73ffffffffffffffffffffffffffffffffffffffff167f615a0c1cb00a60d4acd77ec67acf2f17f223ef0932d591052fabc33643fe7e8260405160405180910390a28282828181106106c9576106c96134f0565b90506020020160208101906106de91906134a0565b73ffffffffffffffffffffffffffffffffffffffff166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561072557600080fd5b505af1158015610739573d6000803e3d6000fd5b50505050806107479061354e565b90506105c6565b505050565b61075b6123a5565b827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610811576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff84163b61088f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e747261637400000000000060448201526064016105ba565b60008473ffffffffffffffffffffffffffffffffffffffff1684846040516108b8929190613586565b6000604051808303816000865af19150503d80600081146108f5576040519150601f19603f3d011682016040523d82523d6000602084013e6108fa565b606091505b5050905080610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f466f727761726465642063616c6c206661696c6564000000000000000000000060448201526064016105ba565b5050505050565b606060018054806020026020016040519081016040528092919081815260200182805480156109d157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116109a6575b5050505050905090565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610a7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610a8b8a8a8c8a8a8a612428565b91509150877fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658b848c8e8c878c8c8c604051610acf999897969594939291906135df565b60405180910390a250505050505050505050565b610aeb6123a5565b60005b82811015610c3157600060056000868685818110610b0e57610b0e6134f0565b9050602002016020810190610b2391906134a0565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055838382818110610b8857610b886134f0565b9050602002016020810190610b9d91906134a0565b6040517ff2fde38b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152919091169063f2fde38b90602401600060405180830381600087803b158015610c0857600080fd5b505af1158015610c1c573d6000803e3d6000fd5b5050505080610c2a9061354e565b9050610aee565b50505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610cd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610ce78b8b8a8a8a8a612428565b91509150887fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658c848d8f8c878c8c8c604051610d2b999897969594939291906135df565b60405180910390a25050505050505050505050565b6000610d4a612706565b600087815260046020526040812054889160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003610deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260056020526040902054869060ff1615610e7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b610e8c8989898989600161277f565b60405189907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015610f24576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008773ffffffffffffffffffffffffffffffffffffffff16878b87604051602401610f5a929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051610fe3919061366a565b6000604051808303816000865af19150503d8060008114611020576040519150601f19603f3d011682016040523d82523d6000602084013e611025565b606091505b50909b9a5050505050505050505050565b6000611040612977565b905090565b61104d612350565b6110b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b6110bd8484610550565b610c31848484846121f4565b60006110d3612706565b600088815260046020526040812054899160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003611174576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260056020526040902054879060ff1615611206576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b8985856020811015611274576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526573706f6e7365206d757374206265203e203332206279746573000000000060448201526064016105ba565b81358381146112df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f466972737420776f7264206d757374206265207265717565737449640000000060448201526064016105ba565b6112ee8e8e8e8e8e600261277f565b6040518e907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015611386576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008c73ffffffffffffffffffffffffffffffffffffffff168c8b8b6040516020016113b493929190613686565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526113ec9161366a565b6000604051808303816000865af19150503d8060008114611429576040519150601f19603f3d011682016040523d82523d6000602084013e61142e565b606091505b509098505050505050505050979650505050505050565b821580159061145357508281145b6114b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c6964206172726179206c656e67746828732900000000000000000060448201526064016105ba565b3460005b848110156116195760008484838181106114d9576114d96134f0565b90506020020135905080836114ee91906136c2565b92506000878784818110611504576115046134f0565b905060200201602081019061151991906134a0565b73ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114611570576040519150601f19603f3d011682016040523d82523d6000602084013e611575565b606091505b5050905080611606576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016105ba565b5050806116129061354e565b90506114bd565b508015610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f546f6f206d756368204554482073656e7400000000000000000000000000000060448201526064016105ba565b6040805160208082018690527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b16828401527fffffffff00000000000000000000000000000000000000000000000000000000851660548301526058808301859052835180840390910181526078909201909252805191012060009060008681526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116908216146117a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b4282111561180f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000858152600460205260408082208290555186917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a2836006600082825461185991906136c2565b90915550506040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018590527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af11580156118f1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061191591906136db565b505050505050565b60035473ffffffffffffffffffffffffffffffffffffffff16331461199e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016105ba565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560038054909116905560405173ffffffffffffffffffffffffffffffffffffffff909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6000611a286123a5565b8380611a32612977565b1015611ac0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517f4000aea000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634000aea090611b389089908990899089906004016136fd565b6020604051808303816000875af1158015611b57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b7b91906136db565b9695505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611c24576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b60208101518190611c358183612a40565b84602484015283604484015260003073ffffffffffffffffffffffffffffffffffffffff1684604051611c68919061366a565b600060405180830381855af49150503d8060008114611ca3576040519150601f19603f3d011682016040523d82523d6000602084013e611ca8565b606091505b5050905080611915576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e61626c6520746f206372656174652072657175657374000000000000000060448201526064016105ba565b6040517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b16602082015260348101859052610c319060540160405160208183030381529060405280519060200120848484611682565b611d75612350565b611ddb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b80611e42576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e646572000000000060448201526064016105ba565b60015460005b81811015611ed757600080600060018481548110611e6857611e686134f0565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055611ed08161354e565b9050611e48565b5060005b8281101561202d57600080858584818110611ef857611ef86134f0565b9050602002016020810190611f0d91906134a0565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff1615611f9e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e646572730060448201526064016105ba565b6001600080868685818110611fb557611fb56134f0565b9050602002016020810190611fca91906134a0565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556120268161354e565b9050611edb565b5061203a60018484612d49565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a083833360405161206e93929190613789565b60405180910390a1505050565b6120836123a5565b61208c81612bbc565b50565b6120976123a5565b80806120a1612977565b101561212f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af11580156121c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121e891906136db565b61074e5761074e6137c3565b6121fc612350565b612262576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b7f1bb185903e2cb2f1b303523128b60e314dea81df4f8d9b7351cadd344f6e772784848484336040516122999594939291906137f2565b60405180910390a160005b83811015610965578484828181106122be576122be6134f0565b90506020020160208101906122d391906134a0565b73ffffffffffffffffffffffffffffffffffffffff1663ee56997b84846040518363ffffffff1660e01b815260040161230d929190613842565b600060405180830381600087803b15801561232757600080fd5b505af115801561233b573d6000803e3d6000fd5b50505050806123499061354e565b90506122a4565b3360009081526020819052604081205460ff168061104057503361238960025473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b60025473ffffffffffffffffffffffffffffffffffffffff163314612426576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016105ba565b565b600080857f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036124e1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b6040517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608b901b16602082015260348101869052605401604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291815281516020928301206000818152600490935291205490935060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016156125ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4d75737420757365206120756e6971756520494400000000000000000000000060448201526064016105ba565b6125f861012c4261385e565b6040805160208082018c90527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608c901b16828401527fffffffff000000000000000000000000000000000000000000000000000000008a1660548301526058808301859052835180840390910181526078909201909252805191012090925060405180604001604052808260ff1916815260200161269787612cb2565b60ff9081169091526000868152600460209081526040909120835193909101519091167f01000000000000000000000000000000000000000000000000000000000000000260089290921c9190911790556006546126f6908a9061385e565b6006555050965096945050505050565b3360009081526020819052604090205460ff16612426576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e646572000000000000000000000060448201526064016105ba565b6040805160208082018890527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606088901b16828401527fffffffff00000000000000000000000000000000000000000000000000000000861660548301526058808301869052835180840390910181526078909201909252805191012060009060008881526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116908216146128a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b6128ac82612cb2565b60008881526004602052604090205460ff9182167f0100000000000000000000000000000000000000000000000000000000000000909104909116111561294f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f446174612076657273696f6e73206d757374206d61746368000000000000000060448201526064016105ba565b8560065461295d91906136c2565b600655505050600093845250506004602052506040812055565b6000600160065461298891906136c2565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612a12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a369190613871565b61104091906136c2565b612a4c6002602061388a565b612a5790600461385e565b81511015612ac1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c69642072657175657374206c656e6774680000000000000000000060448201526064016105ba565b7fffffffff0000000000000000000000000000000000000000000000000000000082167f3c6d41b9000000000000000000000000000000000000000000000000000000001480612b5257507fffffffff0000000000000000000000000000000000000000000000000000000082167f4042994600000000000000000000000000000000000000000000000000000000145b612bb8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4d757374207573652077686974656c69737465642066756e6374696f6e73000060448201526064016105ba565b5050565b3373ffffffffffffffffffffffffffffffffffffffff821603612c3b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016105ba565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b600060ff821115612d45576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203860448201527f206269747300000000000000000000000000000000000000000000000000000060648201526084016105ba565b5090565b828054828255906000526020600020908101928215612dc1579160200282015b82811115612dc15781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190612d69565b50612d459291505b80821115612d455760008155600101612dc9565b60008083601f840112612def57600080fd5b50813567ffffffffffffffff811115612e0757600080fd5b6020830191508360208260051b8501011115612e2257600080fd5b9250929050565b60008060208385031215612e3c57600080fd5b823567ffffffffffffffff811115612e5357600080fd5b612e5f85828601612ddd565b90969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461208c57600080fd5b60008083601f840112612e9f57600080fd5b50813567ffffffffffffffff811115612eb757600080fd5b602083019150836020828501011115612e2257600080fd5b600080600060408486031215612ee457600080fd5b8335612eef81612e6b565b9250602084013567ffffffffffffffff811115612f0b57600080fd5b612f1786828701612e8d565b9497909650939450505050565b60005b83811015612f3f578181015183820152602001612f27565b50506000910152565b6020815260008251806020840152612f67816040850160208701612f24565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6020808252825182820181905260009190848201906040850190845b81811015612fe757835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101612fb5565b50909695505050505050565b80357fffffffff000000000000000000000000000000000000000000000000000000008116811461302357600080fd5b919050565b60008060008060008060008060e0898b03121561304457600080fd5b883561304f81612e6b565b9750602089013596506040890135955061306b60608a01612ff3565b94506080890135935060a0890135925060c089013567ffffffffffffffff81111561309557600080fd5b6130a18b828c01612e8d565b999c989b5096995094979396929594505050565b6000806000604084860312156130ca57600080fd5b833567ffffffffffffffff8111156130e157600080fd5b6130ed86828701612ddd565b909450925050602084013561310181612e6b565b809150509250925092565b60008060008060008060008060006101008a8c03121561312b57600080fd5b893561313681612e6b565b985060208a0135975060408a0135965060608a013561315481612e6b565b955061316260808b01612ff3565b945060a08a0135935060c08a0135925060e08a013567ffffffffffffffff81111561318c57600080fd5b6131988c828d01612e8d565b915080935050809150509295985092959850929598565b60008060008060008060c087890312156131c857600080fd5b863595506020870135945060408701356131e181612e6b565b93506131ef60608801612ff3565b92506080870135915060a087013590509295509295509295565b6000806000806040858703121561321f57600080fd5b843567ffffffffffffffff8082111561323757600080fd5b61324388838901612ddd565b9096509450602087013591508082111561325c57600080fd5b5061326987828801612ddd565b95989497509550505050565b600080600080600080600060c0888a03121561329057600080fd5b873596506020880135955060408801356132a981612e6b565b94506132b760608901612ff3565b93506080880135925060a088013567ffffffffffffffff8111156132da57600080fd5b6132e68a828b01612e8d565b989b979a50959850939692959293505050565b6000806000806080858703121561330f57600080fd5b843593506020850135925061332660408601612ff3565b9396929550929360600135925050565b6000806000806060858703121561334c57600080fd5b843561335781612e6b565b935060208501359250604085013567ffffffffffffffff81111561337a57600080fd5b61326987828801612e8d565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000606084860312156133ca57600080fd5b83356133d581612e6b565b925060208401359150604084013567ffffffffffffffff808211156133f957600080fd5b818601915086601f83011261340d57600080fd5b81358181111561341f5761341f613386565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561346557613465613386565b8160405282815289602084870101111561347e57600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b6000602082840312156134b257600080fd5b81356134bd81612e6b565b9392505050565b600080604083850312156134d757600080fd5b82356134e281612e6b565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361357f5761357f61351f565b5060010190565b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600061010073ffffffffffffffffffffffffffffffffffffffff808d1684528b60208501528a6040850152808a166060850152507fffffffff00000000000000000000000000000000000000000000000000000000881660808401528660a08401528560c08401528060e084015261365a8184018587613596565b9c9b505050505050505050505050565b6000825161367c818460208701612f24565b9190910192915050565b7fffffffff0000000000000000000000000000000000000000000000000000000084168152818360048301376000910160040190815292915050565b818103818111156136d5576136d561351f565b92915050565b6000602082840312156136ed57600080fd5b815180151581146134bd57600080fd5b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201526000611b7b606083018486613596565b8183526000602080850194508260005b8581101561377e57813561375681612e6b565b73ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613743565b509495945050505050565b60408152600061379d604083018587613733565b905073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b606081526000613806606083018789613733565b8281036020840152613819818688613733565b91505073ffffffffffffffffffffffffffffffffffffffff831660408301529695505050505050565b602081526000613856602083018486613733565b949350505050565b808201808211156136d5576136d561351f565b60006020828403121561388357600080fd5b5051919050565b80820281158282048414176136d5576136d561351f56fea164736f6c6343000813000a60a06040523480156200001157600080fd5b50604051620016993803806200169983398101604081905262000034916200029d565b82826001600160a01b038216620000925760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c557620000c58162000199565b50506001600160a01b0384166200012b5760405162461bcd60e51b815260206004820152602360248201527f4c696e6b20746f6b656e2063616e6e6f742062652061207a65726f206164647260448201526265737360e81b606482015260840162000089565b6001600160a01b038085166080528216156200018f57816001600160a01b0316836001600160a01b03167f4e1e878dc28d5f040db5969163ff1acd75c44c3f655da2dde9c70bbd8e56dc7e836040516200018691906200038e565b60405180910390a35b50505050620003c3565b336001600160a01b03821603620001f35760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000089565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200025c57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620002945781810151838201526020016200027a565b50506000910152565b60008060008060808587031215620002b457600080fd5b620002bf8562000244565b9350620002cf6020860162000244565b9250620002df6040860162000244565b60608601519092506001600160401b0380821115620002fd57600080fd5b818701915087601f8301126200031257600080fd5b81518181111562000327576200032762000261565b604051601f8201601f19908116603f0116810190838211818310171562000352576200035262000261565b816040528281528a60208487010111156200036c57600080fd5b6200037f83602083016020880162000277565b979a9699509497505050505050565b6020815260008251806020840152620003af81604085016020870162000277565b601f01601f19169190910160400192915050565b6080516112ac620003ed6000396000818161016d0152818161037501526105d301526112ac6000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c806379ba509711610081578063ee56997b1161005b578063ee56997b14610200578063f2fde38b14610213578063fa00763a1461022657600080fd5b806379ba5097146101c75780638da5cb5b146101cf578063b64fa9e6146101ed57600080fd5b80634d3e2323116100b25780634d3e23231461015557806357970e93146101685780636fadcf72146101b457600080fd5b8063033f49f7146100d9578063181f5a77146100ee5780632408afaa14610140575b600080fd5b6100ec6100e7366004610e72565b61026f565b005b61012a6040518060400160405280601981526020017f417574686f72697a6564466f7277617264657220312e312e300000000000000081525081565b6040516101379190610ef5565b60405180910390f35b610148610287565b6040516101379190610f61565b6100ec610163366004610e72565b6102f6565b61018f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610137565b6100ec6101c2366004610e72565b61036b565b6100ec61042d565b60005473ffffffffffffffffffffffffffffffffffffffff1661018f565b6100ec6101fb366004611007565b61052a565b6100ec61020e366004611073565b6106cb565b6100ec6102213660046110b5565b6109dc565b61025f6102343660046110b5565b73ffffffffffffffffffffffffffffffffffffffff1660009081526002602052604090205460ff1690565b6040519015158152602001610137565b6102776109f0565b610282838383610a73565b505050565b606060038054806020026020016040519081016040528092919081815260200182805480156102ec57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116102c1575b5050505050905090565b6102ff836109dc565b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f4e1e878dc28d5f040db5969163ff1acd75c44c3f655da2dde9c70bbd8e56dc7e848460405161035e9291906110d7565b60405180910390a3505050565b610373610c00565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610277576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f43616e6e6f7420666f727761726420746f204c696e6b20746f6b656e0000000060448201526064015b60405180910390fd5b60015473ffffffffffffffffffffffffffffffffffffffff1633146104ae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610424565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610532610c00565b82811461059b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f417272617973206d7573742068617665207468652073616d65206c656e6774686044820152606401610424565b60005b838110156106c45760008585838181106105ba576105ba611124565b90506020020160208101906105cf91906110b5565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610686576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f43616e6e6f7420666f727761726420746f204c696e6b20746f6b656e000000006044820152606401610424565b6106b38185858581811061069c5761069c611124565b90506020028101906106ae9190611153565b610a73565b506106bd816111b8565b905061059e565b5050505050565b6106d3610c79565b610739576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e646572730000006044820152606401610424565b806107a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e64657200000000006044820152606401610424565b60035460005b8181101561083657600060026000600384815481106107c7576107c7611124565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905561082f816111b8565b90506107a6565b5060005b8281101561098e576002600085858481811061085857610858611124565b905060200201602081019061086d91906110b5565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff16156108fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e64657273006044820152606401610424565b60016002600086868581811061091657610916611124565b905060200201602081019061092b91906110b5565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055610987816111b8565b905061083a565b5061099b60038484610dac565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a08383336040516109cf93929190611217565b60405180910390a1505050565b6109e46109f0565b6109ed81610cb7565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610a71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610424565b565b73ffffffffffffffffffffffffffffffffffffffff83163b610af1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e74726163740000000000006044820152606401610424565b6000808473ffffffffffffffffffffffffffffffffffffffff168484604051610b1b92919061128f565b6000604051808303816000865af19150503d8060008114610b58576040519150601f19603f3d011682016040523d82523d6000602084013e610b5d565b606091505b5091509150816106c4578051600003610bf8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f466f727761726465642063616c6c20726576657274656420776974686f75742060448201527f726561736f6e00000000000000000000000000000000000000000000000000006064820152608401610424565b805181602001fd5b3360009081526002602052604090205460ff16610a71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e64657200000000000000000000006044820152606401610424565b600033610c9b60005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b3373ffffffffffffffffffffffffffffffffffffffff821603610d36576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610424565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610e24579160200282015b82811115610e245781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190610dcc565b50610e30929150610e34565b5090565b5b80821115610e305760008155600101610e35565b803573ffffffffffffffffffffffffffffffffffffffff81168114610e6d57600080fd5b919050565b600080600060408486031215610e8757600080fd5b610e9084610e49565b9250602084013567ffffffffffffffff80821115610ead57600080fd5b818601915086601f830112610ec157600080fd5b813581811115610ed057600080fd5b876020828501011115610ee257600080fd5b6020830194508093505050509250925092565b600060208083528351808285015260005b81811015610f2257858101830151858201604001528201610f06565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b6020808252825182820181905260009190848201906040850190845b81811015610faf57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101610f7d565b50909695505050505050565b60008083601f840112610fcd57600080fd5b50813567ffffffffffffffff811115610fe557600080fd5b6020830191508360208260051b850101111561100057600080fd5b9250929050565b6000806000806040858703121561101d57600080fd5b843567ffffffffffffffff8082111561103557600080fd5b61104188838901610fbb565b9096509450602087013591508082111561105a57600080fd5b5061106787828801610fbb565b95989497509550505050565b6000806020838503121561108657600080fd5b823567ffffffffffffffff81111561109d57600080fd5b6110a985828601610fbb565b90969095509350505050565b6000602082840312156110c757600080fd5b6110d082610e49565b9392505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261118857600080fd5b83018035915067ffffffffffffffff8211156111a357600080fd5b60200191503681900382131561100057600080fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611210577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b6040808252810183905260008460608301825b868110156112655773ffffffffffffffffffffffffffffffffffffffff61125084610e49565b1682526020928301929091019060010161122a565b50809250505073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b818382376000910190815291905056fea164736f6c6343000813000aa164736f6c6343000813000a", } var OperatorFactoryABI = OperatorFactoryMetaData.ABI diff --git a/core/gethwrappers/generated/operator_wrapper/operator_wrapper.go b/core/gethwrappers/generated/operator_wrapper/operator_wrapper.go index db0ca418b2c..8af02ea4057 100644 --- a/core/gethwrappers/generated/operator_wrapper/operator_wrapper.go +++ b/core/gethwrappers/generated/operator_wrapper/operator_wrapper.go @@ -32,7 +32,7 @@ var ( var OperatorMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"changedBy\",\"type\":\"address\"}],\"name\":\"AuthorizedSendersChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"CancelOracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"specId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"callbackAddr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"cancelExpiration\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dataVersion\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"OracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"OracleResponse\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"acceptedContract\",\"type\":\"address\"}],\"name\":\"OwnableContractAccepted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"targets\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"changedBy\",\"type\":\"address\"}],\"name\":\"TargetsUpdatedAuthorizedSenders\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"EXPIRYTIME\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"targets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"}],\"name\":\"acceptAuthorizedReceivers\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"ownable\",\"type\":\"address[]\"}],\"name\":\"acceptOwnableContracts\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunc\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"}],\"name\":\"cancelOracleRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunc\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"}],\"name\":\"cancelOracleRequestByRequester\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable[]\",\"name\":\"receivers\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"}],\"name\":\"distributeFunds\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"callbackAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"data\",\"type\":\"bytes32\"}],\"name\":\"fulfillOracleRequest\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"callbackAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"fulfillOracleRequest2\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAuthorizedSenders\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getChainlinkToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"isAuthorizedSender\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"specId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dataVersion\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"operatorRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"specId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callbackAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dataVersion\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"oracleRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"ownerForward\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"ownerTransferAndCall\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"}],\"name\":\"setAuthorizedSenders\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"targets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"}],\"name\":\"setAuthorizedSendersOn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"ownable\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnableContracts\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawable\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x60a060405260016006553480156200001657600080fd5b5060405162003d3238038062003d328339810160408190526200003991620001ab565b808060006001600160a01b038216620000995760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0384811691909117909155811615620000cc57620000cc81620000e2565b505050506001600160a01b0316608052620001e3565b336001600160a01b038216036200013c5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000090565b600380546001600160a01b0319166001600160a01b03838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b80516001600160a01b0381168114620001a657600080fd5b919050565b60008060408385031215620001bf57600080fd5b620001ca836200018e565b9150620001da602084016200018e565b90509250929050565b608051613aed62000245600039600081816101ec0152818161075e015281816109f301528181610c4f0152818161187c01528181611ae601528181611b8601528181611f21015281816123ba0152818161266d0152612bf50152613aed6000f3fe6080604052600436106101965760003560e01c80636ae0bc76116100e1578063a4c0ed361161008a578063f2fde38b11610064578063f2fde38b146104aa578063f3fef3a3146104ca578063fa00763a146104ea578063fc4a03ed1461053057600080fd5b8063a4c0ed361461044a578063eb007d991461046a578063ee56997b1461048a57600080fd5b806379ba5097116100bb57806379ba5097146103ea5780638da5cb5b146103ff578063902fc3701461042a57600080fd5b80636ae0bc76146103975780636bd59ec0146103b75780636ee4d553146103ca57600080fd5b80633ec5bc1411610143578063501883011161011d578063501883011461033e57806352043783146103615780635ffa62881461037757600080fd5b80633ec5bc14146102ce57806340429946146102ee5780634ab0d1901461030e57600080fd5b8063181f5a7711610174578063181f5a77146102365780632408afaa1461028c5780633c6d41b9146102ae57600080fd5b806301994b991461019b578063033f49f7146101bd578063165d35e1146101dd575b600080fd5b3480156101a757600080fd5b506101bb6101b6366004613068565b610550565b005b3480156101c957600080fd5b506101bb6101d836600461310e565b610753565b3480156101e957600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561024257600080fd5b5061027f6040518060400160405280600e81526020017f4f70657261746f7220312e302e3000000000000000000000000000000000000081525081565b60405161022d9190613187565b34801561029857600080fd5b506102a161096c565b60405161022d91906131d8565b3480156102ba57600080fd5b506101bb6102c9366004613267565b6109db565b3480156102da57600080fd5b506101bb6102e93660046132f4565b610ae3565b3480156102fa57600080fd5b506101bb61030936600461334b565b610c37565b34801561031a57600080fd5b5061032e6103293660046133ee565b610d40565b604051901515815260200161022d565b34801561034a57600080fd5b50610353611036565b60405190815260200161022d565b34801561036d57600080fd5b5061035361012c81565b34801561038357600080fd5b506101bb610392366004613448565b611045565b3480156103a357600080fd5b5061032e6103b23660046134b4565b6110c9565b6101bb6103c5366004613448565b611445565b3480156103d657600080fd5b506101bb6103e5366004613538565b611682565b3480156103f657600080fd5b506101bb611906565b34801561040b57600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff1661020c565b34801561043657600080fd5b5061032e610445366004613575565b611a07565b34801561045657600080fd5b506101bb6104653660046135f4565b611b6e565b34801561047657600080fd5b506101bb610485366004613538565b611cfc565b34801561049657600080fd5b506101bb6104a5366004613068565b611fac565b3480156104b657600080fd5b506101bb6104c53660046136df565b6122ba565b3480156104d657600080fd5b506101bb6104e5366004613703565b6122ce565b3480156104f657600080fd5b5061032e6105053660046136df565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b34801561053c57600080fd5b506101bb61054b366004613448565b612433565b61055861258f565b6105c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064015b60405180910390fd5b60005b8181101561074e576001600560008585858181106105e6576105e661372f565b90506020020160208101906105fb91906136df565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790558282828181106106605761066061372f565b905060200201602081019061067591906136df565b73ffffffffffffffffffffffffffffffffffffffff167f615a0c1cb00a60d4acd77ec67acf2f17f223ef0932d591052fabc33643fe7e8260405160405180910390a28282828181106106c9576106c961372f565b90506020020160208101906106de91906136df565b73ffffffffffffffffffffffffffffffffffffffff166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561072557600080fd5b505af1158015610739573d6000803e3d6000fd5b50505050806107479061378d565b90506105c6565b505050565b61075b6125e4565b827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610811576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff84163b61088f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e747261637400000000000060448201526064016105ba565b60008473ffffffffffffffffffffffffffffffffffffffff1684846040516108b89291906137c5565b6000604051808303816000865af19150503d80600081146108f5576040519150601f19603f3d011682016040523d82523d6000602084013e6108fa565b606091505b5050905080610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f466f727761726465642063616c6c206661696c6564000000000000000000000060448201526064016105ba565b5050505050565b606060018054806020026020016040519081016040528092919081815260200182805480156109d157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116109a6575b5050505050905090565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610a7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610a8b8a8a8c8a8a8a612667565b91509150877fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658b848c8e8c878c8c8c604051610acf9998979695949392919061381e565b60405180910390a250505050505050505050565b610aeb6125e4565b60005b82811015610c3157600060056000868685818110610b0e57610b0e61372f565b9050602002016020810190610b2391906136df565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055838382818110610b8857610b8861372f565b9050602002016020810190610b9d91906136df565b6040517ff2fde38b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152919091169063f2fde38b90602401600060405180830381600087803b158015610c0857600080fd5b505af1158015610c1c573d6000803e3d6000fd5b5050505080610c2a9061378d565b9050610aee565b50505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610cd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610ce78b8b8a8a8a8a612667565b91509150887fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658c848d8f8c878c8c8c604051610d2b9998979695949392919061381e565b60405180910390a25050505050505050505050565b6000610d4a612945565b600087815260046020526040812054889160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003610deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260056020526040902054869060ff1615610e7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b610e8c898989898960016129be565b60405189907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015610f24576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008773ffffffffffffffffffffffffffffffffffffffff16878b87604051602401610f5a929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051610fe391906138a9565b6000604051808303816000865af19150503d8060008114611020576040519150601f19603f3d011682016040523d82523d6000602084013e611025565b606091505b50909b9a5050505050505050505050565b6000611040612bb6565b905090565b61104d61258f565b6110b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b6110bd8484610550565b610c3184848484612433565b60006110d3612945565b600088815260046020526040812054899160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003611174576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260056020526040902054879060ff1615611206576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b8985856020811015611274576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526573706f6e7365206d757374206265203e203332206279746573000000000060448201526064016105ba565b81358381146112df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f466972737420776f7264206d757374206265207265717565737449640000000060448201526064016105ba565b6112ee8e8e8e8e8e60026129be565b6040518e907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015611386576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008c73ffffffffffffffffffffffffffffffffffffffff168c8b8b6040516020016113b4939291906138c5565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526113ec916138a9565b6000604051808303816000865af19150503d8060008114611429576040519150601f19603f3d011682016040523d82523d6000602084013e61142e565b606091505b509098505050505050505050979650505050505050565b821580159061145357508281145b6114b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c6964206172726179206c656e67746828732900000000000000000060448201526064016105ba565b3460005b848110156116195760008484838181106114d9576114d961372f565b90506020020135905080836114ee9190613901565b925060008787848181106115045761150461372f565b905060200201602081019061151991906136df565b73ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114611570576040519150601f19603f3d011682016040523d82523d6000602084013e611575565b606091505b5050905080611606576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016105ba565b5050806116129061378d565b90506114bd565b508015610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f546f6f206d756368204554482073656e7400000000000000000000000000000060448201526064016105ba565b6040805160208082018690527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b16828401527fffffffff00000000000000000000000000000000000000000000000000000000851660548301526058808301859052835180840390910181526078909201909252805191012060009060008681526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116908216146117a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b4282111561180f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000858152600460205260408082208290555186917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018590527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af11580156118da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118fe919061391a565b505050505050565b60035473ffffffffffffffffffffffffffffffffffffffff163314611987576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016105ba565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560038054909116905560405173ffffffffffffffffffffffffffffffffffffffff909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6000611a116125e4565b8380611a1b612bb6565b1015611aa9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517f4000aea000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634000aea090611b2190899089908990899060040161393c565b6020604051808303816000875af1158015611b40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b64919061391a565b9695505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611c0d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b60208101518190611c1e8183612c7f565b84602484015283604484015260003073ffffffffffffffffffffffffffffffffffffffff1684604051611c5191906138a9565b600060405180830381855af49150503d8060008114611c8c576040519150601f19603f3d011682016040523d82523d6000602084013e611c91565b606091505b50509050806118fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e61626c6520746f206372656174652072657175657374000000000000000060448201526064016105ba565b604080513360601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660208083018290526034808401899052845180850390910181526054840185528051908201206074840188905260948401929092527fffffffff00000000000000000000000000000000000000000000000000000000861660a884015260ac8084018690528451808503909101815260cc9093019093528151919092012060009060008381526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614611e4a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b42831115611eb4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000828152600460205260408082208290555183917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018690527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015611f7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa3919061391a565b50505050505050565b611fb461258f565b61201a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b80612081576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e646572000000000060448201526064016105ba565b60015460005b81811015612116576000806000600184815481106120a7576120a761372f565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905561210f8161378d565b9050612087565b5060005b8281101561226c576000808585848181106121375761213761372f565b905060200201602081019061214c91906136df565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff16156121dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e646572730060448201526064016105ba565b60016000808686858181106121f4576121f461372f565b905060200201602081019061220991906136df565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556122658161378d565b905061211a565b5061227960018484612f88565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a08383336040516122ad939291906139c8565b60405180910390a1505050565b6122c26125e4565b6122cb81612dfb565b50565b6122d66125e4565b80806122e0612bb6565b101561236e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015612403573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612427919061391a565b61074e5761074e613a02565b61243b61258f565b6124a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b7f1bb185903e2cb2f1b303523128b60e314dea81df4f8d9b7351cadd344f6e772784848484336040516124d8959493929190613a31565b60405180910390a160005b83811015610965578484828181106124fd576124fd61372f565b905060200201602081019061251291906136df565b73ffffffffffffffffffffffffffffffffffffffff1663ee56997b84846040518363ffffffff1660e01b815260040161254c929190613a81565b600060405180830381600087803b15801561256657600080fd5b505af115801561257a573d6000803e3d6000fd5b50505050806125889061378d565b90506124e3565b3360009081526020819052604081205460ff16806110405750336125c860025473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b60025473ffffffffffffffffffffffffffffffffffffffff163314612665576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016105ba565b565b600080857f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612720576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b6040517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608b901b16602082015260348101869052605401604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291815281516020928301206000818152600490935291205490935060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00161561282b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4d75737420757365206120756e6971756520494400000000000000000000000060448201526064016105ba565b61283761012c42613a9d565b6040805160208082018c90527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608c901b16828401527fffffffff000000000000000000000000000000000000000000000000000000008a1660548301526058808301859052835180840390910181526078909201909252805191012090925060405180604001604052808260ff191681526020016128d687612ef1565b60ff9081169091526000868152600460209081526040909120835193909101519091167f01000000000000000000000000000000000000000000000000000000000000000260089290921c919091179055600654612935908a90613a9d565b6006555050965096945050505050565b3360009081526020819052604090205460ff16612665576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e646572000000000000000000000060448201526064016105ba565b6040805160208082018890527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606088901b16828401527fffffffff00000000000000000000000000000000000000000000000000000000861660548301526058808301869052835180840390910181526078909201909252805191012060009060008881526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614612ae2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b612aeb82612ef1565b60008881526004602052604090205460ff9182167f01000000000000000000000000000000000000000000000000000000000000009091049091161115612b8e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f446174612076657273696f6e73206d757374206d61746368000000000000000060448201526064016105ba565b85600654612b9c9190613901565b600655505050600093845250506004602052506040812055565b60006001600654612bc79190613901565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612c51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c759190613ab0565b6110409190613901565b612c8b60026020613ac9565b612c96906004613a9d565b81511015612d00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c69642072657175657374206c656e6774680000000000000000000060448201526064016105ba565b7fffffffff0000000000000000000000000000000000000000000000000000000082167f3c6d41b9000000000000000000000000000000000000000000000000000000001480612d9157507fffffffff0000000000000000000000000000000000000000000000000000000082167f4042994600000000000000000000000000000000000000000000000000000000145b612df7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4d757374207573652077686974656c69737465642066756e6374696f6e73000060448201526064016105ba565b5050565b3373ffffffffffffffffffffffffffffffffffffffff821603612e7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016105ba565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b600060ff821115612f84576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203860448201527f206269747300000000000000000000000000000000000000000000000000000060648201526084016105ba565b5090565b828054828255906000526020600020908101928215613000579160200282015b828111156130005781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190612fa8565b50612f849291505b80821115612f845760008155600101613008565b60008083601f84011261302e57600080fd5b50813567ffffffffffffffff81111561304657600080fd5b6020830191508360208260051b850101111561306157600080fd5b9250929050565b6000806020838503121561307b57600080fd5b823567ffffffffffffffff81111561309257600080fd5b61309e8582860161301c565b90969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff811681146122cb57600080fd5b60008083601f8401126130de57600080fd5b50813567ffffffffffffffff8111156130f657600080fd5b60208301915083602082850101111561306157600080fd5b60008060006040848603121561312357600080fd5b833561312e816130aa565b9250602084013567ffffffffffffffff81111561314a57600080fd5b613156868287016130cc565b9497909650939450505050565b60005b8381101561317e578181015183820152602001613166565b50506000910152565b60208152600082518060208401526131a6816040850160208701613163565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6020808252825182820181905260009190848201906040850190845b8181101561322657835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016131f4565b50909695505050505050565b80357fffffffff000000000000000000000000000000000000000000000000000000008116811461326257600080fd5b919050565b60008060008060008060008060e0898b03121561328357600080fd5b883561328e816130aa565b975060208901359650604089013595506132aa60608a01613232565b94506080890135935060a0890135925060c089013567ffffffffffffffff8111156132d457600080fd5b6132e08b828c016130cc565b999c989b5096995094979396929594505050565b60008060006040848603121561330957600080fd5b833567ffffffffffffffff81111561332057600080fd5b61332c8682870161301c565b9094509250506020840135613340816130aa565b809150509250925092565b60008060008060008060008060006101008a8c03121561336a57600080fd5b8935613375816130aa565b985060208a0135975060408a0135965060608a0135613393816130aa565b95506133a160808b01613232565b945060a08a0135935060c08a0135925060e08a013567ffffffffffffffff8111156133cb57600080fd5b6133d78c828d016130cc565b915080935050809150509295985092959850929598565b60008060008060008060c0878903121561340757600080fd5b86359550602087013594506040870135613420816130aa565b935061342e60608801613232565b92506080870135915060a087013590509295509295509295565b6000806000806040858703121561345e57600080fd5b843567ffffffffffffffff8082111561347657600080fd5b6134828883890161301c565b9096509450602087013591508082111561349b57600080fd5b506134a88782880161301c565b95989497509550505050565b600080600080600080600060c0888a0312156134cf57600080fd5b873596506020880135955060408801356134e8816130aa565b94506134f660608901613232565b93506080880135925060a088013567ffffffffffffffff81111561351957600080fd5b6135258a828b016130cc565b989b979a50959850939692959293505050565b6000806000806080858703121561354e57600080fd5b843593506020850135925061356560408601613232565b9396929550929360600135925050565b6000806000806060858703121561358b57600080fd5b8435613596816130aa565b935060208501359250604085013567ffffffffffffffff8111156135b957600080fd5b6134a8878288016130cc565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060006060848603121561360957600080fd5b8335613614816130aa565b925060208401359150604084013567ffffffffffffffff8082111561363857600080fd5b818601915086601f83011261364c57600080fd5b81358181111561365e5761365e6135c5565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156136a4576136a46135c5565b816040528281528960208487010111156136bd57600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b6000602082840312156136f157600080fd5b81356136fc816130aa565b9392505050565b6000806040838503121561371657600080fd5b8235613721816130aa565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036137be576137be61375e565b5060010190565b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600061010073ffffffffffffffffffffffffffffffffffffffff808d1684528b60208501528a6040850152808a166060850152507fffffffff00000000000000000000000000000000000000000000000000000000881660808401528660a08401528560c08401528060e084015261389981840185876137d5565b9c9b505050505050505050505050565b600082516138bb818460208701613163565b9190910192915050565b7fffffffff0000000000000000000000000000000000000000000000000000000084168152818360048301376000910160040190815292915050565b818103818111156139145761391461375e565b92915050565b60006020828403121561392c57600080fd5b815180151581146136fc57600080fd5b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201526000611b646060830184866137d5565b8183526000602080850194508260005b858110156139bd578135613995816130aa565b73ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613982565b509495945050505050565b6040815260006139dc604083018587613972565b905073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b606081526000613a45606083018789613972565b8281036020840152613a58818688613972565b91505073ffffffffffffffffffffffffffffffffffffffff831660408301529695505050505050565b602081526000613a95602083018486613972565b949350505050565b808201808211156139145761391461375e565b600060208284031215613ac257600080fd5b5051919050565b80820281158282048414176139145761391461375e56fea164736f6c6343000813000a", + Bin: "0x60a060405260016006553480156200001657600080fd5b5060405162003aec38038062003aec8339810160408190526200003991620001ab565b808060006001600160a01b038216620000995760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0384811691909117909155811615620000cc57620000cc81620000e2565b505050506001600160a01b0316608052620001e3565b336001600160a01b038216036200013c5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000090565b600380546001600160a01b0319166001600160a01b03838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b80516001600160a01b0381168114620001a657600080fd5b919050565b60008060408385031215620001bf57600080fd5b620001ca836200018e565b9150620001da602084016200018e565b90509250929050565b6080516138ae6200023e600039600081816101ec0152818161075e015281816109f301528181610c4f0152818161189301528181611afd01528181611b9d0152818161217b0152818161242e01526129b601526138ae6000f3fe6080604052600436106101965760003560e01c80636ae0bc76116100e1578063a4c0ed361161008a578063f2fde38b11610064578063f2fde38b146104aa578063f3fef3a3146104ca578063fa00763a146104ea578063fc4a03ed1461053057600080fd5b8063a4c0ed361461044a578063eb007d991461046a578063ee56997b1461048a57600080fd5b806379ba5097116100bb57806379ba5097146103ea5780638da5cb5b146103ff578063902fc3701461042a57600080fd5b80636ae0bc76146103975780636bd59ec0146103b75780636ee4d553146103ca57600080fd5b80633ec5bc1411610143578063501883011161011d578063501883011461033e57806352043783146103615780635ffa62881461037757600080fd5b80633ec5bc14146102ce57806340429946146102ee5780634ab0d1901461030e57600080fd5b8063181f5a7711610174578063181f5a77146102365780632408afaa1461028c5780633c6d41b9146102ae57600080fd5b806301994b991461019b578063033f49f7146101bd578063165d35e1146101dd575b600080fd5b3480156101a757600080fd5b506101bb6101b6366004612e29565b610550565b005b3480156101c957600080fd5b506101bb6101d8366004612ecf565b610753565b3480156101e957600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561024257600080fd5b5061027f6040518060400160405280600e81526020017f4f70657261746f7220312e302e3000000000000000000000000000000000000081525081565b60405161022d9190612f48565b34801561029857600080fd5b506102a161096c565b60405161022d9190612f99565b3480156102ba57600080fd5b506101bb6102c9366004613028565b6109db565b3480156102da57600080fd5b506101bb6102e93660046130b5565b610ae3565b3480156102fa57600080fd5b506101bb61030936600461310c565b610c37565b34801561031a57600080fd5b5061032e6103293660046131af565b610d40565b604051901515815260200161022d565b34801561034a57600080fd5b50610353611036565b60405190815260200161022d565b34801561036d57600080fd5b5061035361012c81565b34801561038357600080fd5b506101bb610392366004613209565b611045565b3480156103a357600080fd5b5061032e6103b2366004613275565b6110c9565b6101bb6103c5366004613209565b611445565b3480156103d657600080fd5b506101bb6103e53660046132f9565b611682565b3480156103f657600080fd5b506101bb61191d565b34801561040b57600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff1661020c565b34801561043657600080fd5b5061032e610445366004613336565b611a1e565b34801561045657600080fd5b506101bb6104653660046133b5565b611b85565b34801561047657600080fd5b506101bb6104853660046132f9565b611d13565b34801561049657600080fd5b506101bb6104a5366004612e29565b611d6d565b3480156104b657600080fd5b506101bb6104c53660046134a0565b61207b565b3480156104d657600080fd5b506101bb6104e53660046134c4565b61208f565b3480156104f657600080fd5b5061032e6105053660046134a0565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b34801561053c57600080fd5b506101bb61054b366004613209565b6121f4565b610558612350565b6105c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064015b60405180910390fd5b60005b8181101561074e576001600560008585858181106105e6576105e66134f0565b90506020020160208101906105fb91906134a0565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055828282818110610660576106606134f0565b905060200201602081019061067591906134a0565b73ffffffffffffffffffffffffffffffffffffffff167f615a0c1cb00a60d4acd77ec67acf2f17f223ef0932d591052fabc33643fe7e8260405160405180910390a28282828181106106c9576106c96134f0565b90506020020160208101906106de91906134a0565b73ffffffffffffffffffffffffffffffffffffffff166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561072557600080fd5b505af1158015610739573d6000803e3d6000fd5b50505050806107479061354e565b90506105c6565b505050565b61075b6123a5565b827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610811576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff84163b61088f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e747261637400000000000060448201526064016105ba565b60008473ffffffffffffffffffffffffffffffffffffffff1684846040516108b8929190613586565b6000604051808303816000865af19150503d80600081146108f5576040519150601f19603f3d011682016040523d82523d6000602084013e6108fa565b606091505b5050905080610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f466f727761726465642063616c6c206661696c6564000000000000000000000060448201526064016105ba565b5050505050565b606060018054806020026020016040519081016040528092919081815260200182805480156109d157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116109a6575b5050505050905090565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610a7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610a8b8a8a8c8a8a8a612428565b91509150877fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658b848c8e8c878c8c8c604051610acf999897969594939291906135df565b60405180910390a250505050505050505050565b610aeb6123a5565b60005b82811015610c3157600060056000868685818110610b0e57610b0e6134f0565b9050602002016020810190610b2391906134a0565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055838382818110610b8857610b886134f0565b9050602002016020810190610b9d91906134a0565b6040517ff2fde38b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152919091169063f2fde38b90602401600060405180830381600087803b158015610c0857600080fd5b505af1158015610c1c573d6000803e3d6000fd5b5050505080610c2a9061354e565b9050610aee565b50505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610cd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610ce78b8b8a8a8a8a612428565b91509150887fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658c848d8f8c878c8c8c604051610d2b999897969594939291906135df565b60405180910390a25050505050505050505050565b6000610d4a612706565b600087815260046020526040812054889160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003610deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260056020526040902054869060ff1615610e7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b610e8c8989898989600161277f565b60405189907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015610f24576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008773ffffffffffffffffffffffffffffffffffffffff16878b87604051602401610f5a929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051610fe3919061366a565b6000604051808303816000865af19150503d8060008114611020576040519150601f19603f3d011682016040523d82523d6000602084013e611025565b606091505b50909b9a5050505050505050505050565b6000611040612977565b905090565b61104d612350565b6110b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b6110bd8484610550565b610c31848484846121f4565b60006110d3612706565b600088815260046020526040812054899160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003611174576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260056020526040902054879060ff1615611206576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b8985856020811015611274576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526573706f6e7365206d757374206265203e203332206279746573000000000060448201526064016105ba565b81358381146112df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f466972737420776f7264206d757374206265207265717565737449640000000060448201526064016105ba565b6112ee8e8e8e8e8e600261277f565b6040518e907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015611386576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008c73ffffffffffffffffffffffffffffffffffffffff168c8b8b6040516020016113b493929190613686565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526113ec9161366a565b6000604051808303816000865af19150503d8060008114611429576040519150601f19603f3d011682016040523d82523d6000602084013e61142e565b606091505b509098505050505050505050979650505050505050565b821580159061145357508281145b6114b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c6964206172726179206c656e67746828732900000000000000000060448201526064016105ba565b3460005b848110156116195760008484838181106114d9576114d96134f0565b90506020020135905080836114ee91906136c2565b92506000878784818110611504576115046134f0565b905060200201602081019061151991906134a0565b73ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114611570576040519150601f19603f3d011682016040523d82523d6000602084013e611575565b606091505b5050905080611606576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016105ba565b5050806116129061354e565b90506114bd565b508015610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f546f6f206d756368204554482073656e7400000000000000000000000000000060448201526064016105ba565b6040805160208082018690527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b16828401527fffffffff00000000000000000000000000000000000000000000000000000000851660548301526058808301859052835180840390910181526078909201909252805191012060009060008681526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116908216146117a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b4282111561180f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000858152600460205260408082208290555186917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a2836006600082825461185991906136c2565b90915550506040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018590527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af11580156118f1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061191591906136db565b505050505050565b60035473ffffffffffffffffffffffffffffffffffffffff16331461199e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016105ba565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560038054909116905560405173ffffffffffffffffffffffffffffffffffffffff909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6000611a286123a5565b8380611a32612977565b1015611ac0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517f4000aea000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634000aea090611b389089908990899089906004016136fd565b6020604051808303816000875af1158015611b57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b7b91906136db565b9695505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611c24576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b60208101518190611c358183612a40565b84602484015283604484015260003073ffffffffffffffffffffffffffffffffffffffff1684604051611c68919061366a565b600060405180830381855af49150503d8060008114611ca3576040519150601f19603f3d011682016040523d82523d6000602084013e611ca8565b606091505b5050905080611915576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e61626c6520746f206372656174652072657175657374000000000000000060448201526064016105ba565b6040517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b16602082015260348101859052610c319060540160405160208183030381529060405280519060200120848484611682565b611d75612350565b611ddb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b80611e42576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e646572000000000060448201526064016105ba565b60015460005b81811015611ed757600080600060018481548110611e6857611e686134f0565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055611ed08161354e565b9050611e48565b5060005b8281101561202d57600080858584818110611ef857611ef86134f0565b9050602002016020810190611f0d91906134a0565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff1615611f9e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e646572730060448201526064016105ba565b6001600080868685818110611fb557611fb56134f0565b9050602002016020810190611fca91906134a0565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556120268161354e565b9050611edb565b5061203a60018484612d49565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a083833360405161206e93929190613789565b60405180910390a1505050565b6120836123a5565b61208c81612bbc565b50565b6120976123a5565b80806120a1612977565b101561212f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af11580156121c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121e891906136db565b61074e5761074e6137c3565b6121fc612350565b612262576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b7f1bb185903e2cb2f1b303523128b60e314dea81df4f8d9b7351cadd344f6e772784848484336040516122999594939291906137f2565b60405180910390a160005b83811015610965578484828181106122be576122be6134f0565b90506020020160208101906122d391906134a0565b73ffffffffffffffffffffffffffffffffffffffff1663ee56997b84846040518363ffffffff1660e01b815260040161230d929190613842565b600060405180830381600087803b15801561232757600080fd5b505af115801561233b573d6000803e3d6000fd5b50505050806123499061354e565b90506122a4565b3360009081526020819052604081205460ff168061104057503361238960025473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b60025473ffffffffffffffffffffffffffffffffffffffff163314612426576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016105ba565b565b600080857f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036124e1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b6040517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608b901b16602082015260348101869052605401604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291815281516020928301206000818152600490935291205490935060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016156125ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4d75737420757365206120756e6971756520494400000000000000000000000060448201526064016105ba565b6125f861012c4261385e565b6040805160208082018c90527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608c901b16828401527fffffffff000000000000000000000000000000000000000000000000000000008a1660548301526058808301859052835180840390910181526078909201909252805191012090925060405180604001604052808260ff1916815260200161269787612cb2565b60ff9081169091526000868152600460209081526040909120835193909101519091167f01000000000000000000000000000000000000000000000000000000000000000260089290921c9190911790556006546126f6908a9061385e565b6006555050965096945050505050565b3360009081526020819052604090205460ff16612426576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e646572000000000000000000000060448201526064016105ba565b6040805160208082018890527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606088901b16828401527fffffffff00000000000000000000000000000000000000000000000000000000861660548301526058808301869052835180840390910181526078909201909252805191012060009060008881526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116908216146128a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b6128ac82612cb2565b60008881526004602052604090205460ff9182167f0100000000000000000000000000000000000000000000000000000000000000909104909116111561294f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f446174612076657273696f6e73206d757374206d61746368000000000000000060448201526064016105ba565b8560065461295d91906136c2565b600655505050600093845250506004602052506040812055565b6000600160065461298891906136c2565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612a12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a369190613871565b61104091906136c2565b612a4c6002602061388a565b612a5790600461385e565b81511015612ac1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c69642072657175657374206c656e6774680000000000000000000060448201526064016105ba565b7fffffffff0000000000000000000000000000000000000000000000000000000082167f3c6d41b9000000000000000000000000000000000000000000000000000000001480612b5257507fffffffff0000000000000000000000000000000000000000000000000000000082167f4042994600000000000000000000000000000000000000000000000000000000145b612bb8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4d757374207573652077686974656c69737465642066756e6374696f6e73000060448201526064016105ba565b5050565b3373ffffffffffffffffffffffffffffffffffffffff821603612c3b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016105ba565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b600060ff821115612d45576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203860448201527f206269747300000000000000000000000000000000000000000000000000000060648201526084016105ba565b5090565b828054828255906000526020600020908101928215612dc1579160200282015b82811115612dc15781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190612d69565b50612d459291505b80821115612d455760008155600101612dc9565b60008083601f840112612def57600080fd5b50813567ffffffffffffffff811115612e0757600080fd5b6020830191508360208260051b8501011115612e2257600080fd5b9250929050565b60008060208385031215612e3c57600080fd5b823567ffffffffffffffff811115612e5357600080fd5b612e5f85828601612ddd565b90969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461208c57600080fd5b60008083601f840112612e9f57600080fd5b50813567ffffffffffffffff811115612eb757600080fd5b602083019150836020828501011115612e2257600080fd5b600080600060408486031215612ee457600080fd5b8335612eef81612e6b565b9250602084013567ffffffffffffffff811115612f0b57600080fd5b612f1786828701612e8d565b9497909650939450505050565b60005b83811015612f3f578181015183820152602001612f27565b50506000910152565b6020815260008251806020840152612f67816040850160208701612f24565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6020808252825182820181905260009190848201906040850190845b81811015612fe757835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101612fb5565b50909695505050505050565b80357fffffffff000000000000000000000000000000000000000000000000000000008116811461302357600080fd5b919050565b60008060008060008060008060e0898b03121561304457600080fd5b883561304f81612e6b565b9750602089013596506040890135955061306b60608a01612ff3565b94506080890135935060a0890135925060c089013567ffffffffffffffff81111561309557600080fd5b6130a18b828c01612e8d565b999c989b5096995094979396929594505050565b6000806000604084860312156130ca57600080fd5b833567ffffffffffffffff8111156130e157600080fd5b6130ed86828701612ddd565b909450925050602084013561310181612e6b565b809150509250925092565b60008060008060008060008060006101008a8c03121561312b57600080fd5b893561313681612e6b565b985060208a0135975060408a0135965060608a013561315481612e6b565b955061316260808b01612ff3565b945060a08a0135935060c08a0135925060e08a013567ffffffffffffffff81111561318c57600080fd5b6131988c828d01612e8d565b915080935050809150509295985092959850929598565b60008060008060008060c087890312156131c857600080fd5b863595506020870135945060408701356131e181612e6b565b93506131ef60608801612ff3565b92506080870135915060a087013590509295509295509295565b6000806000806040858703121561321f57600080fd5b843567ffffffffffffffff8082111561323757600080fd5b61324388838901612ddd565b9096509450602087013591508082111561325c57600080fd5b5061326987828801612ddd565b95989497509550505050565b600080600080600080600060c0888a03121561329057600080fd5b873596506020880135955060408801356132a981612e6b565b94506132b760608901612ff3565b93506080880135925060a088013567ffffffffffffffff8111156132da57600080fd5b6132e68a828b01612e8d565b989b979a50959850939692959293505050565b6000806000806080858703121561330f57600080fd5b843593506020850135925061332660408601612ff3565b9396929550929360600135925050565b6000806000806060858703121561334c57600080fd5b843561335781612e6b565b935060208501359250604085013567ffffffffffffffff81111561337a57600080fd5b61326987828801612e8d565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000606084860312156133ca57600080fd5b83356133d581612e6b565b925060208401359150604084013567ffffffffffffffff808211156133f957600080fd5b818601915086601f83011261340d57600080fd5b81358181111561341f5761341f613386565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561346557613465613386565b8160405282815289602084870101111561347e57600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b6000602082840312156134b257600080fd5b81356134bd81612e6b565b9392505050565b600080604083850312156134d757600080fd5b82356134e281612e6b565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361357f5761357f61351f565b5060010190565b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600061010073ffffffffffffffffffffffffffffffffffffffff808d1684528b60208501528a6040850152808a166060850152507fffffffff00000000000000000000000000000000000000000000000000000000881660808401528660a08401528560c08401528060e084015261365a8184018587613596565b9c9b505050505050505050505050565b6000825161367c818460208701612f24565b9190910192915050565b7fffffffff0000000000000000000000000000000000000000000000000000000084168152818360048301376000910160040190815292915050565b818103818111156136d5576136d561351f565b92915050565b6000602082840312156136ed57600080fd5b815180151581146134bd57600080fd5b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201526000611b7b606083018486613596565b8183526000602080850194508260005b8581101561377e57813561375681612e6b565b73ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613743565b509495945050505050565b60408152600061379d604083018587613733565b905073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b606081526000613806606083018789613733565b8281036020840152613819818688613733565b91505073ffffffffffffffffffffffffffffffffffffffff831660408301529695505050505050565b602081526000613856602083018486613733565b949350505050565b808201808211156136d5576136d561351f565b60006020828403121561388357600080fd5b5051919050565b80820281158282048414176136d5576136d561351f56fea164736f6c6343000813000a", } var OperatorABI = OperatorMetaData.ABI diff --git a/core/gethwrappers/generated/simple_log_upkeep_counter_wrapper/simple_log_upkeep_counter_wrapper.go b/core/gethwrappers/generated/simple_log_upkeep_counter_wrapper/simple_log_upkeep_counter_wrapper.go index 1409bcb1548..bfd6644e11e 100644 --- a/core/gethwrappers/generated/simple_log_upkeep_counter_wrapper/simple_log_upkeep_counter_wrapper.go +++ b/core/gethwrappers/generated/simple_log_upkeep_counter_wrapper/simple_log_upkeep_counter_wrapper.go @@ -34,6 +34,7 @@ type CheckData struct { CheckBurnAmount *big.Int PerformBurnAmount *big.Int EventSig [32]byte + Feeds []string } type Log struct { @@ -48,15 +49,15 @@ type Log struct { } var SimpleLogUpkeepCounterMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"initialBlock\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"lastBlock\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"previousBlock\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"counter\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timeToPerform\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isRecovered\",\"type\":\"bool\"}],\"name\":\"PerformingUpkeep\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"checkBurnAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"performBurnAmount\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"eventSig\",\"type\":\"bytes32\"}],\"internalType\":\"structCheckData\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_checkDataConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"txHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"source\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"topics\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structLog\",\"name\":\"log\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"}],\"name\":\"checkLog\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"dummyMap\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initialBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isRecovered\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"previousPerformBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeToPerform\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b5060006002819055436001556003819055600455610d12806100336000396000f3fe608060405234801561001057600080fd5b50600436106100be5760003560e01c80637145f11b11610076578063917d895f1161005b578063917d895f1461016b578063c6066f0d14610174578063eb950ce71461017d57600080fd5b80637145f11b1461012f578063806b984f1461016257600080fd5b80634585e33b116100a75780634585e33b1461010057806361bc221a14610115578063697794731461011e57600080fd5b80632cb15864146100c357806340691db4146100df575b600080fd5b6100cc60035481565b6040519081526020015b60405180910390f35b6100f26100ed3660046106c6565b61018a565b6040516100d692919061092d565b61011361010e366004610628565b6102c2565b005b6100cc60045481565b61011361012c36600461066a565b50565b61015261013d36600461060f565b60006020819052908152604090205460ff1681565b60405190151581526020016100d6565b6100cc60015481565b6100cc60025481565b6100cc60055481565b6006546101529060ff1681565b6000606081808061019d8688018861083b565b92509250925060005a905060006101b5600143610c61565b40905060008515610224575b855a6101cd9085610c61565b1015610224578080156101ee575060008281526020819052604090205460ff165b604080516020810185905230918101919091529091506060016040516020818303038152906040528051906020012091506101c1565b8361023260c08d018d610a9d565b600281811061024357610243610ca7565b9050602002013514156102875760018b438c8c60405160200161026994939291906109aa565b604051602081830303815290604052975097505050505050506102ba565b60008b438c8c6040516020016102a094939291906109aa565b604051602081830303815290604052975097505050505050505b935093915050565b6003546102ce57436003555b4360019081556004546102e091610c49565b600455600154600255600080806102f984860186610738565b92509250925082602001514261030f9190610c61565b600555600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556060830151821461037157600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b60008060008380602001905181019061038a9190610867565b92509250925060005a905060006103a2600143610c61565b40905060008415610411575b845a6103ba9085610c61565b1015610411578080156103db575060008281526020819052604090205460ff165b604080516020810185905230918101919091529091506060016040516020818303038152906040528051906020012091506103ae565b600354600154600254600454600554600654604080519687526020870195909552938501929092526060840152608083015260ff16151560a082015232907f29eff4cb37911c3ea85db4630638cc5474fdd0631ec42215aef1d7ec96c8e63d9060c00160405180910390a25050505050505050505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146104ad57600080fd5b919050565b600082601f8301126104c357600080fd5b8135602067ffffffffffffffff8211156104df576104df610cd6565b8160051b6104ee828201610b2f565b83815282810190868401838801850189101561050957600080fd5b600093505b8584101561052c57803583526001939093019291840191840161050e565b50979650505050505050565b60008083601f84011261054a57600080fd5b50813567ffffffffffffffff81111561056257600080fd5b60208301915083602082850101111561057a57600080fd5b9250929050565b600082601f83011261059257600080fd5b813567ffffffffffffffff8111156105ac576105ac610cd6565b6105dd60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601610b2f565b8181528460208386010111156105f257600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561062157600080fd5b5035919050565b6000806020838503121561063b57600080fd5b823567ffffffffffffffff81111561065257600080fd5b61065e85828601610538565b90969095509350505050565b60006060828403121561067c57600080fd5b6040516060810181811067ffffffffffffffff8211171561069f5761069f610cd6565b80604052508235815260208301356020820152604083013560408201528091505092915050565b6000806000604084860312156106db57600080fd5b833567ffffffffffffffff808211156106f357600080fd5b90850190610100828803121561070857600080fd5b9093506020850135908082111561071e57600080fd5b5061072b86828701610538565b9497909650939450505050565b60008060006060848603121561074d57600080fd5b833567ffffffffffffffff8082111561076557600080fd5b90850190610100828803121561077a57600080fd5b610782610b05565b82358152602083013560208201526040830135604082015260608301356060820152608083013560808201526107ba60a08401610489565b60a082015260c0830135828111156107d157600080fd5b6107dd898286016104b2565b60c08301525060e0830135828111156107f557600080fd5b61080189828601610581565b60e083015250945060208601359350604086013591508082111561082457600080fd5b5061083186828701610581565b9150509250925092565b60008060006060848603121561085057600080fd5b505081359360208301359350604090920135919050565b60008060006060848603121561087c57600080fd5b8351925060208401519150604084015190509250925092565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156108c757600080fd5b8260051b8083602087013760009401602001938452509192915050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b821515815260006020604081840152835180604085015260005b8181101561096357858101830151858201606001528201610947565b81811115610975576000606083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201606001949350505050565b606081528435606082015260208501356080820152604085013560a0820152606085013560c0820152608085013560e082015260006109eb60a08701610489565b61010073ffffffffffffffffffffffffffffffffffffffff821681850152610a1660c0890189610b7e565b925081610120860152610a2e61016086018483610895565b92505050610a3f60e0880188610be5565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa085840301610140860152610a758382846108e4565b925050508560208401528281036040840152610a928185876108e4565b979650505050505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610ad257600080fd5b83018035915067ffffffffffffffff821115610aed57600080fd5b6020019150600581901b360382131561057a57600080fd5b604051610100810167ffffffffffffffff81118282101715610b2957610b29610cd6565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610b7657610b76610cd6565b604052919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610bb357600080fd5b830160208101925035905067ffffffffffffffff811115610bd357600080fd5b8060051b360383131561057a57600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610c1a57600080fd5b830160208101925035905067ffffffffffffffff811115610c3a57600080fd5b80360383131561057a57600080fd5b60008219821115610c5c57610c5c610c78565b500190565b600082821015610c7357610c73610c78565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + ABI: "[{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_isStreamsLookup\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"feeds\",\"type\":\"string[]\"},{\"internalType\":\"string\",\"name\":\"timeParamKey\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"StreamsLookup\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"initialBlock\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"lastBlock\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"previousBlock\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"counter\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timeToPerform\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isRecovered\",\"type\":\"bool\"}],\"name\":\"PerformingUpkeep\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"checkBurnAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"performBurnAmount\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"eventSig\",\"type\":\"bytes32\"},{\"internalType\":\"string[]\",\"name\":\"feeds\",\"type\":\"string[]\"}],\"internalType\":\"structCheckData\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_checkDataConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"errCode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkErrorHandler\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"txHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"source\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"topics\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structLog\",\"name\":\"log\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"}],\"name\":\"checkLog\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"dummyMap\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feedParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initialBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isStreamsLookup\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"previousPerformBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParam\",\"type\":\"string\"}],\"name\":\"setFeedParamKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"value\",\"type\":\"bool\"}],\"name\":\"setShouldRetryOnErrorBool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"timeParam\",\"type\":\"string\"}],\"name\":\"setTimeParamKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"shouldRetryOnError\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeToPerform\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x60c060405260076080819052666665656449447360c81b60a090815262000028919081620000bd565b5060408051808201909152600980825268074696d657374616d760bc1b60209092019182526200005b91600891620000bd565b503480156200006957600080fd5b5060405162001af938038062001af98339810160408190526200008c9162000163565b60006002819055436001556003819055600455600680549115156101000261ff0019909216919091179055620001cb565b828054620000cb906200018e565b90600052602060002090601f016020900481019282620000ef57600085556200013a565b82601f106200010a57805160ff19168380011785556200013a565b828001600101855582156200013a579182015b828111156200013a5782518255916020019190600101906200011d565b50620001489291506200014c565b5090565b5b808211156200014857600081556001016200014d565b6000602082840312156200017657600080fd5b815180151581146200018757600080fd5b9392505050565b600181811c90821680620001a357607f821691505b60208210811415620001c557634e487b7160e01b600052602260045260246000fd5b50919050565b61191e80620001db6000396000f3fe608060405234801561001057600080fd5b50600436106101365760003560e01c8063601d5a71116100b2578063917d895f11610081578063afb28d1f11610066578063afb28d1f146102a7578063c6066f0d146102bc578063c98f10b0146102c557600080fd5b8063917d895f1461028b5780639525d5741461029457600080fd5b8063601d5a711461024357806361bc221a146102565780637145f11b1461025f578063806b984f1461028257600080fd5b806340691db41161010957806342eb3d92116100ee57806342eb3d921461020a5780634585e33b1461021d5780634b56a42e1461023057600080fd5b806340691db4146101e657806342b0fe9e146101f957600080fd5b80630fb172fb1461013b57806313fab5901461016557806323148cee146101ad5780632cb15864146101cf575b600080fd5b61014e610149366004611104565b6102cd565b60405161015c92919061138e565b60405180910390f35b6101ab610173366004610cbd565b6006805491151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff909216919091179055565b005b6006546101bf90610100900460ff1681565b604051901515815260200161015c565b6101d860035481565b60405190815260200161015c565b61014e6101f4366004610f8e565b6103d4565b6101ab610207366004610d77565b50565b6006546101bf9062010000900460ff1681565b6101ab61022b366004610cf8565b610659565b61014e61023e366004610be3565b6108c5565b6101ab610251366004610d3a565b610919565b6101d860045481565b6101bf61026d366004610cdf565b60006020819052908152604090205460ff1681565b6101d860015481565b6101d860025481565b6101ab6102a2366004610d3a565b610930565b6102af610943565b60405161015c91906113a9565b6101d860055481565b6102af6109d1565b6040805160028082526060828101909352600092918391816020015b60608152602001906001900390816102e95750506040805160208101889052919250016040516020818303038152906040528160008151811061032e5761032e611891565b60200260200101819052508360405160200161034a91906113a9565b6040516020818303038152906040528160018151811061036c5761036c611891565b60200260200101819052506000818560405160200161038c9291906112fa565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905260065462010000900460ff169450925050505b9250929050565b60006060816103e584860186610d77565b905060005a905060006103f96001436117c7565b8351904091506000901561046c575b83515a61041590856117c7565b101561046c57808015610436575060008281526020819052604090205460ff165b60408051602081018590523091810191909152909150606001604051602081830303815290604052805190602001209150610408565b60408051600280825260608201909252600091816020015b606081526020019060019003908161048457905050604080516000602082015291925001604051602081830303815290604052816000815181106104ca576104ca611891565b602002602001018190525060006040516020016104f0919060ff91909116815260200190565b6040516020818303038152906040528160018151811061051257610512611891565b602002602001018190525060008a438b8b604051602001610536949392919061147b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291815287015190915061057760c08d018d611576565b600281811061058857610588611891565b90506020020135141561062257600654610100900460ff16156105ef5760608601516040517ff055e4a20000000000000000000000000000000000000000000000000000000081526105e691600791600890429086906004016113bc565b60405180910390fd5b600182826040516020016106049291906112fa565b60405160208183030381529060405297509750505050505050610651565b600082826040516020016106379291906112fa565b604051602081830303815290604052975097505050505050505b935093915050565b60035461066557436003555b436001908155600454610677916117af565b600455600154600255600061068e82840184610be3565b9150506000806000838060200190518101906106aa9190611000565b9250925092508260200151426106c091906117c7565b600555600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556060830151821461072257600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b6000818060200190518101906107389190610e79565b905060005a9050600061074c6001436117c7565b409050600083604001518760c0015160028151811061076d5761076d611891565b6020026020010151146107dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c6964206576656e74207369676e617475726500000000000000000060448201526064016105e6565b60208401511561084e575b83602001515a6107f790856117c7565b101561084e57808015610818575060008281526020819052604090205460ff165b604080516020810185905230918101919091529091506060016040516020818303038152906040528051906020012091506107e7565b600354600154600254600454600554600654604080519687526020870195909552938501929092526060840152608083015260ff16151560a082015232907f29eff4cb37911c3ea85db4630638cc5474fdd0631ec42215aef1d7ec96c8e63d9060c00160405180910390a250505050505050505050565b60006060600084846040516020016108de9291906112fa565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181529190526001969095509350505050565b805161092c9060089060208401906109de565b5050565b805161092c9060079060208401906109de565b600780546109509061180e565b80601f016020809104026020016040519081016040528092919081815260200182805461097c9061180e565b80156109c95780601f1061099e576101008083540402835291602001916109c9565b820191906000526020600020905b8154815290600101906020018083116109ac57829003601f168201915b505050505081565b600880546109509061180e565b8280546109ea9061180e565b90600052602060002090601f016020900481019282610a0c5760008555610a52565b82601f10610a2557805160ff1916838001178555610a52565b82800160010185558215610a52579182015b82811115610a52578251825591602001919060010190610a37565b50610a5e929150610a62565b5090565b5b80821115610a5e5760008155600101610a63565b6000610a8a610a858461169e565b61162b565b9050828152838383011115610a9e57600080fd5b610aac8360208301846117de565b9392505050565b8051610abe816118ef565b919050565b600082601f830112610ad457600080fd5b81516020610ae4610a858361167a565b80838252828201915082860187848660051b8901011115610b0457600080fd5b60005b85811015610b2357815184529284019290840190600101610b07565b5090979650505050505050565b60008083601f840112610b4257600080fd5b50813567ffffffffffffffff811115610b5a57600080fd5b6020830191508360208285010111156103cd57600080fd5b600082601f830112610b8357600080fd5b8135610b91610a858261169e565b818152846020838601011115610ba657600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f830112610bd457600080fd5b610aac83835160208501610a77565b60008060408385031215610bf657600080fd5b823567ffffffffffffffff80821115610c0e57600080fd5b818501915085601f830112610c2257600080fd5b81356020610c32610a858361167a565b8083825282820191508286018a848660051b8901011115610c5257600080fd5b60005b85811015610c8d57813587811115610c6c57600080fd5b610c7a8d87838c0101610b72565b8552509284019290840190600101610c55565b50909750505086013592505080821115610ca657600080fd5b50610cb385828601610b72565b9150509250929050565b600060208284031215610ccf57600080fd5b81358015158114610aac57600080fd5b600060208284031215610cf157600080fd5b5035919050565b60008060208385031215610d0b57600080fd5b823567ffffffffffffffff811115610d2257600080fd5b610d2e85828601610b30565b90969095509350505050565b600060208284031215610d4c57600080fd5b813567ffffffffffffffff811115610d6357600080fd5b610d6f84828501610b72565b949350505050565b60006020808385031215610d8a57600080fd5b823567ffffffffffffffff80821115610da257600080fd5b9084019060808287031215610db657600080fd5b610dbe6115de565b82358152838301358482015260408301356040820152606083013582811115610de657600080fd5b80840193505086601f840112610dfb57600080fd5b8235610e09610a858261167a565b8082825286820191508686018a888560051b8901011115610e2957600080fd5b6000805b85811015610e6457823588811115610e43578283fd5b610e518e8c838d0101610b72565b8652509389019391890191600101610e2d565b50505060608401525090979650505050505050565b60006020808385031215610e8c57600080fd5b825167ffffffffffffffff80821115610ea457600080fd5b9084019060808287031215610eb857600080fd5b610ec06115de565b82518152838301518482015260408084015181830152606084015183811115610ee857600080fd5b80850194505087601f850112610efd57600080fd5b8351610f0b610a858261167a565b8082825287820191508787018b898560051b8a01011115610f2b57600080fd5b60005b84811015610f7957815188811115610f4557600080fd5b8901603f81018e13610f5657600080fd5b610f668e8c830151898401610a77565b8552509289019290890190600101610f2e565b50506060850152509198975050505050505050565b600080600060408486031215610fa357600080fd5b833567ffffffffffffffff80821115610fbb57600080fd5b908501906101008288031215610fd057600080fd5b90935060208501359080821115610fe657600080fd5b50610ff386828701610b30565b9497909650939450505050565b60008060006060848603121561101557600080fd5b835167ffffffffffffffff8082111561102d57600080fd5b90850190610100828803121561104257600080fd5b61104a611607565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015261108260a08401610ab3565b60a082015260c08301518281111561109957600080fd5b6110a589828601610ac3565b60c08301525060e0830151828111156110bd57600080fd5b6110c989828601610bc3565b60e0830152506020870151604088015191965094509150808211156110ed57600080fd5b506110fa86828701610bc3565b9150509250925092565b6000806040838503121561111757600080fd5b82359150602083013567ffffffffffffffff81111561113557600080fd5b610cb385828601610b72565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561117357600080fd5b8260051b8083602087013760009401602001938452509192915050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600081518084526111f18160208601602086016117de565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b8054600090600181811c908083168061123d57607f831692505b6020808410821415611278577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b8388526020880182801561129357600181146112c2576112ed565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008716825282820197506112ed565b60008981526020902060005b878110156112e7578154848201529086019084016112ce565b83019850505b5050505050505092915050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b8381101561136f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa088870301855261135d8683516111d9565b95509382019390820190600101611323565b50508584038187015250505061138581856111d9565b95945050505050565b8215158152604060208201526000610d6f60408301846111d9565b602081526000610aac60208301846111d9565b60a0815260006113cf60a0830188611223565b6020838203818501528188518084528284019150828160051b850101838b0160005b8381101561143d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe087840301855261142b8383516111d9565b948601949250908501906001016113f1565b50508681036040880152611451818b611223565b945050505050846060840152828103608084015261146f81856111d9565b98975050505050505050565b606081528435606082015260208501356080820152604085013560a0820152606085013560c0820152608085013560e0820152600060a08601356114be816118ef565b6101006114e28185018373ffffffffffffffffffffffffffffffffffffffff169052565b6114ef60c08901896116e4565b92508161012086015261150761016086018483611141565b9250505061151860e088018861174b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08584030161014086015261154e838284611190565b92505050856020840152828103604084015261156b818587611190565b979650505050505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126115ab57600080fd5b83018035915067ffffffffffffffff8211156115c657600080fd5b6020019150600581901b36038213156103cd57600080fd5b6040516080810167ffffffffffffffff81118282101715611601576116016118c0565b60405290565b604051610100810167ffffffffffffffff81118282101715611601576116016118c0565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611672576116726118c0565b604052919050565b600067ffffffffffffffff821115611694576116946118c0565b5060051b60200190565b600067ffffffffffffffff8211156116b8576116b86118c0565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261171957600080fd5b830160208101925035905067ffffffffffffffff81111561173957600080fd5b8060051b36038313156103cd57600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261178057600080fd5b830160208101925035905067ffffffffffffffff8111156117a057600080fd5b8036038313156103cd57600080fd5b600082198211156117c2576117c2611862565b500190565b6000828210156117d9576117d9611862565b500390565b60005b838110156117f95781810151838201526020016117e1565b83811115611808576000848401525b50505050565b600181811c9082168061182257607f821691505b6020821081141561185c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461020757600080fdfea164736f6c6343000806000a", } var SimpleLogUpkeepCounterABI = SimpleLogUpkeepCounterMetaData.ABI var SimpleLogUpkeepCounterBin = SimpleLogUpkeepCounterMetaData.Bin -func DeploySimpleLogUpkeepCounter(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *SimpleLogUpkeepCounter, error) { +func DeploySimpleLogUpkeepCounter(auth *bind.TransactOpts, backend bind.ContractBackend, _isStreamsLookup bool) (common.Address, *types.Transaction, *SimpleLogUpkeepCounter, error) { parsed, err := SimpleLogUpkeepCounterMetaData.GetAbi() if err != nil { return common.Address{}, nil, nil, err @@ -65,7 +66,7 @@ func DeploySimpleLogUpkeepCounter(auth *bind.TransactOpts, backend bind.Contract return common.Address{}, nil, nil, errors.New("GetABI returned nil") } - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(SimpleLogUpkeepCounterBin), backend) + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(SimpleLogUpkeepCounterBin), backend, _isStreamsLookup) if err != nil { return common.Address{}, nil, nil, err } @@ -188,6 +189,59 @@ func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterTransactorRaw) Transact(opt return _SimpleLogUpkeepCounter.Contract.contract.Transact(opts, method, params...) } +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) CheckCallback(opts *bind.CallOpts, values [][]byte, extraData []byte) (bool, []byte, error) { + var out []interface{} + err := _SimpleLogUpkeepCounter.contract.Call(opts, &out, "checkCallback", values, extraData) + + if err != nil { + return *new(bool), *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + out1 := *abi.ConvertType(out[1], new([]byte)).(*[]byte) + + return out0, out1, err + +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterSession) CheckCallback(values [][]byte, extraData []byte) (bool, []byte, error) { + return _SimpleLogUpkeepCounter.Contract.CheckCallback(&_SimpleLogUpkeepCounter.CallOpts, values, extraData) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerSession) CheckCallback(values [][]byte, extraData []byte) (bool, []byte, error) { + return _SimpleLogUpkeepCounter.Contract.CheckCallback(&_SimpleLogUpkeepCounter.CallOpts, values, extraData) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) CheckErrorHandler(opts *bind.CallOpts, errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) { + var out []interface{} + err := _SimpleLogUpkeepCounter.contract.Call(opts, &out, "checkErrorHandler", errCode, extraData) + + outstruct := new(CheckErrorHandler) + if err != nil { + return *outstruct, err + } + + outstruct.UpkeepNeeded = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.PerformData = *abi.ConvertType(out[1], new([]byte)).(*[]byte) + + return *outstruct, err + +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterSession) CheckErrorHandler(errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) { + return _SimpleLogUpkeepCounter.Contract.CheckErrorHandler(&_SimpleLogUpkeepCounter.CallOpts, errCode, extraData) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerSession) CheckErrorHandler(errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) { + return _SimpleLogUpkeepCounter.Contract.CheckErrorHandler(&_SimpleLogUpkeepCounter.CallOpts, errCode, extraData) +} + func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) CheckLog(opts *bind.CallOpts, log Log, checkData []byte) (bool, []byte, error) { var out []interface{} err := _SimpleLogUpkeepCounter.contract.Call(opts, &out, "checkLog", log, checkData) @@ -255,6 +309,28 @@ func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerSession) DummyMap(arg return _SimpleLogUpkeepCounter.Contract.DummyMap(&_SimpleLogUpkeepCounter.CallOpts, arg0) } +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) FeedParamKey(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _SimpleLogUpkeepCounter.contract.Call(opts, &out, "feedParamKey") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterSession) FeedParamKey() (string, error) { + return _SimpleLogUpkeepCounter.Contract.FeedParamKey(&_SimpleLogUpkeepCounter.CallOpts) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerSession) FeedParamKey() (string, error) { + return _SimpleLogUpkeepCounter.Contract.FeedParamKey(&_SimpleLogUpkeepCounter.CallOpts) +} + func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) InitialBlock(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _SimpleLogUpkeepCounter.contract.Call(opts, &out, "initialBlock") @@ -277,9 +353,9 @@ func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerSession) InitialBlock return _SimpleLogUpkeepCounter.Contract.InitialBlock(&_SimpleLogUpkeepCounter.CallOpts) } -func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) IsRecovered(opts *bind.CallOpts) (bool, error) { +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) IsStreamsLookup(opts *bind.CallOpts) (bool, error) { var out []interface{} - err := _SimpleLogUpkeepCounter.contract.Call(opts, &out, "isRecovered") + err := _SimpleLogUpkeepCounter.contract.Call(opts, &out, "isStreamsLookup") if err != nil { return *new(bool), err @@ -291,12 +367,12 @@ func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) IsRecovered(opts *b } -func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterSession) IsRecovered() (bool, error) { - return _SimpleLogUpkeepCounter.Contract.IsRecovered(&_SimpleLogUpkeepCounter.CallOpts) +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterSession) IsStreamsLookup() (bool, error) { + return _SimpleLogUpkeepCounter.Contract.IsStreamsLookup(&_SimpleLogUpkeepCounter.CallOpts) } -func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerSession) IsRecovered() (bool, error) { - return _SimpleLogUpkeepCounter.Contract.IsRecovered(&_SimpleLogUpkeepCounter.CallOpts) +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerSession) IsStreamsLookup() (bool, error) { + return _SimpleLogUpkeepCounter.Contract.IsStreamsLookup(&_SimpleLogUpkeepCounter.CallOpts) } func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) LastBlock(opts *bind.CallOpts) (*big.Int, error) { @@ -343,6 +419,50 @@ func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerSession) PreviousPerf return _SimpleLogUpkeepCounter.Contract.PreviousPerformBlock(&_SimpleLogUpkeepCounter.CallOpts) } +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) ShouldRetryOnError(opts *bind.CallOpts) (bool, error) { + var out []interface{} + err := _SimpleLogUpkeepCounter.contract.Call(opts, &out, "shouldRetryOnError") + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterSession) ShouldRetryOnError() (bool, error) { + return _SimpleLogUpkeepCounter.Contract.ShouldRetryOnError(&_SimpleLogUpkeepCounter.CallOpts) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerSession) ShouldRetryOnError() (bool, error) { + return _SimpleLogUpkeepCounter.Contract.ShouldRetryOnError(&_SimpleLogUpkeepCounter.CallOpts) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) TimeParamKey(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _SimpleLogUpkeepCounter.contract.Call(opts, &out, "timeParamKey") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterSession) TimeParamKey() (string, error) { + return _SimpleLogUpkeepCounter.Contract.TimeParamKey(&_SimpleLogUpkeepCounter.CallOpts) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerSession) TimeParamKey() (string, error) { + return _SimpleLogUpkeepCounter.Contract.TimeParamKey(&_SimpleLogUpkeepCounter.CallOpts) +} + func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) TimeToPerform(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _SimpleLogUpkeepCounter.contract.Call(opts, &out, "timeToPerform") @@ -389,6 +509,42 @@ func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterTransactorSession) PerformU return _SimpleLogUpkeepCounter.Contract.PerformUpkeep(&_SimpleLogUpkeepCounter.TransactOpts, performData) } +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterTransactor) SetFeedParamKey(opts *bind.TransactOpts, feedParam string) (*types.Transaction, error) { + return _SimpleLogUpkeepCounter.contract.Transact(opts, "setFeedParamKey", feedParam) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterSession) SetFeedParamKey(feedParam string) (*types.Transaction, error) { + return _SimpleLogUpkeepCounter.Contract.SetFeedParamKey(&_SimpleLogUpkeepCounter.TransactOpts, feedParam) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterTransactorSession) SetFeedParamKey(feedParam string) (*types.Transaction, error) { + return _SimpleLogUpkeepCounter.Contract.SetFeedParamKey(&_SimpleLogUpkeepCounter.TransactOpts, feedParam) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterTransactor) SetShouldRetryOnErrorBool(opts *bind.TransactOpts, value bool) (*types.Transaction, error) { + return _SimpleLogUpkeepCounter.contract.Transact(opts, "setShouldRetryOnErrorBool", value) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterSession) SetShouldRetryOnErrorBool(value bool) (*types.Transaction, error) { + return _SimpleLogUpkeepCounter.Contract.SetShouldRetryOnErrorBool(&_SimpleLogUpkeepCounter.TransactOpts, value) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterTransactorSession) SetShouldRetryOnErrorBool(value bool) (*types.Transaction, error) { + return _SimpleLogUpkeepCounter.Contract.SetShouldRetryOnErrorBool(&_SimpleLogUpkeepCounter.TransactOpts, value) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterTransactor) SetTimeParamKey(opts *bind.TransactOpts, timeParam string) (*types.Transaction, error) { + return _SimpleLogUpkeepCounter.contract.Transact(opts, "setTimeParamKey", timeParam) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterSession) SetTimeParamKey(timeParam string) (*types.Transaction, error) { + return _SimpleLogUpkeepCounter.Contract.SetTimeParamKey(&_SimpleLogUpkeepCounter.TransactOpts, timeParam) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterTransactorSession) SetTimeParamKey(timeParam string) (*types.Transaction, error) { + return _SimpleLogUpkeepCounter.Contract.SetTimeParamKey(&_SimpleLogUpkeepCounter.TransactOpts, timeParam) +} + type SimpleLogUpkeepCounterPerformingUpkeepIterator struct { Event *SimpleLogUpkeepCounterPerformingUpkeep @@ -522,6 +678,11 @@ func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterFilterer) ParsePerformingUp return event, nil } +type CheckErrorHandler struct { + UpkeepNeeded bool + PerformData []byte +} + func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounter) ParseLog(log types.Log) (generated.AbigenLog, error) { switch log.Topics[0] { case _SimpleLogUpkeepCounter.abi.Events["PerformingUpkeep"].ID: @@ -541,26 +702,44 @@ func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounter) Address() common.Address } type SimpleLogUpkeepCounterInterface interface { + CheckCallback(opts *bind.CallOpts, values [][]byte, extraData []byte) (bool, []byte, error) + + CheckErrorHandler(opts *bind.CallOpts, errCode *big.Int, extraData []byte) (CheckErrorHandler, + + error) + CheckLog(opts *bind.CallOpts, log Log, checkData []byte) (bool, []byte, error) Counter(opts *bind.CallOpts) (*big.Int, error) DummyMap(opts *bind.CallOpts, arg0 [32]byte) (bool, error) + FeedParamKey(opts *bind.CallOpts) (string, error) + InitialBlock(opts *bind.CallOpts) (*big.Int, error) - IsRecovered(opts *bind.CallOpts) (bool, error) + IsStreamsLookup(opts *bind.CallOpts) (bool, error) LastBlock(opts *bind.CallOpts) (*big.Int, error) PreviousPerformBlock(opts *bind.CallOpts) (*big.Int, error) + ShouldRetryOnError(opts *bind.CallOpts) (bool, error) + + TimeParamKey(opts *bind.CallOpts) (string, error) + TimeToPerform(opts *bind.CallOpts) (*big.Int, error) CheckDataConfig(opts *bind.TransactOpts, arg0 CheckData) (*types.Transaction, error) PerformUpkeep(opts *bind.TransactOpts, performData []byte) (*types.Transaction, error) + SetFeedParamKey(opts *bind.TransactOpts, feedParam string) (*types.Transaction, error) + + SetShouldRetryOnErrorBool(opts *bind.TransactOpts, value bool) (*types.Transaction, error) + + SetTimeParamKey(opts *bind.TransactOpts, timeParam string) (*types.Transaction, error) + FilterPerformingUpkeep(opts *bind.FilterOpts, from []common.Address) (*SimpleLogUpkeepCounterPerformingUpkeepIterator, error) WatchPerformingUpkeep(opts *bind.WatchOpts, sink chan<- *SimpleLogUpkeepCounterPerformingUpkeep, from []common.Address) (event.Subscription, error) diff --git a/core/gethwrappers/generated/trusted_blockhash_store/trusted_blockhash_store.go b/core/gethwrappers/generated/trusted_blockhash_store/trusted_blockhash_store.go index c571b0a7002..30415621ae2 100644 --- a/core/gethwrappers/generated/trusted_blockhash_store/trusted_blockhash_store.go +++ b/core/gethwrappers/generated/trusted_blockhash_store/trusted_blockhash_store.go @@ -32,7 +32,7 @@ var ( var TrustedBlockhashStoreMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"whitelist\",\"type\":\"address[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidRecentBlockhash\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrustedBlockhashes\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInWhitelist\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"getBlockhash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_whitelist\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_whitelistStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"whitelist\",\"type\":\"address[]\"}],\"name\":\"setWhitelist\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"store\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"storeEarliest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"blockNums\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"blockhashes\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"recentBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"recentBlockhash\",\"type\":\"bytes32\"}],\"name\":\"storeTrusted\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"header\",\"type\":\"bytes\"}],\"name\":\"storeVerifyHeader\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60806040523480156200001157600080fd5b50604051620014ec380380620014ec8339810160408190526200003491620003e8565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d9565b505050620000d2816200018560201b60201c565b5062000517565b6001600160a01b038116331415620001345760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6200018f620002ec565b60006004805480602002602001604051908101604052809291908181526020018280548015620001e957602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311620001ca575b5050855193945062000207936004935060208701925090506200034a565b5060005b81518110156200027757600060036000848481518110620002305762000230620004eb565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff1916911515919091179055806200026e81620004c1565b9150506200020b565b5060005b8251811015620002e757600160036000858481518110620002a057620002a0620004eb565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff191691151591909117905580620002de81620004c1565b9150506200027b565b505050565b6000546001600160a01b03163314620003485760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000082565b565b828054828255906000526020600020908101928215620003a2579160200282015b82811115620003a257825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906200036b565b50620003b0929150620003b4565b5090565b5b80821115620003b05760008155600101620003b5565b80516001600160a01b0381168114620003e357600080fd5b919050565b60006020808385031215620003fc57600080fd5b82516001600160401b03808211156200041457600080fd5b818501915085601f8301126200042957600080fd5b8151818111156200043e576200043e62000501565b8060051b604051601f19603f8301168101818110858211171562000466576200046662000501565b604052828152858101935084860182860187018a10156200048657600080fd5b600095505b83861015620004b4576200049f81620003cb565b8552600195909501949386019386016200048b565b5098975050505050505050565b6000600019821415620004e457634e487b7160e01b600052601160045260246000fd5b5060010190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b610fc580620005276000396000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c80638da5cb5b11610081578063f2fde38b1161005b578063f2fde38b146101b5578063f4217648146101c8578063fadff0e1146101db57600080fd5b80638da5cb5b14610143578063e9413d3814610161578063e9ecc1541461018257600080fd5b80636057361d116100b25780636057361d1461012057806379ba50971461013357806383b6d6b71461013b57600080fd5b80633b69ad60146100ce5780635c7de309146100e3575b600080fd5b6100e16100dc366004610d07565b6101ee565b005b6100f66100f1366004610d9e565b610326565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6100e161012e366004610d9e565b61035d565b6100e16103e8565b6100e16104e5565b60005473ffffffffffffffffffffffffffffffffffffffff166100f6565b61017461016f366004610d9e565b6104ff565b604051908152602001610117565b6101a5610190366004610c38565b60036020526000908152604090205460ff1681565b6040519015158152602001610117565b6100e16101c3366004610c38565b61057b565b6100e16101d6366004610c53565b61058f565b6100e16101e9366004610db7565b610745565b60006101f9836107e8565b9050818114610234576040517fd2f69c9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526003602052604090205460ff1661027d576040517f5b0aa2ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8584146102b6576040517fbd75093300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8681101561031c578585828181106102d3576102d3610f5a565b90506020020135600260008a8a858181106102f0576102f0610f5a565b90506020020135815260200190815260200160002081905550808061031490610ef2565b9150506102b9565b5050505050505050565b6004818154811061033657600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b6000610368826107e8565b9050806103d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f626c6f636b68617368286e29206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b60009182526002602052604090912055565b60015473ffffffffffffffffffffffffffffffffffffffff163314610469576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016103cd565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6104fd6101006104f36108ed565b61012e9190610edb565b565b60008181526002602052604081205480610575576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f626c6f636b68617368206e6f7420666f756e6420696e2073746f72650000000060448201526064016103cd565b92915050565b61058361098a565b61058c81610a0b565b50565b61059761098a565b600060048054806020026020016040519081016040528092919081815260200182805480156105fc57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116105d1575b5050855193945061061893600493506020870192509050610b24565b5060005b81518110156106ac5760006003600084848151811061063d5761063d610f5a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055806106a481610ef2565b91505061061c565b5060005b8251811015610740576001600360008584815181106106d1576106d1610f5a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790558061073881610ef2565b9150506106b0565b505050565b60026000610754846001610ec3565b8152602001908152602001600020548180519060200120146107d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f6865616465722068617320756e6b6e6f776e20626c6f636b686173680000000060448201526064016103cd565b6024015160009182526002602052604090912055565b6000466107f481610b01565b156108dd576101008367ffffffffffffffff1661080f6108ed565b6108199190610edb565b118061083657506108286108ed565b8367ffffffffffffffff1610155b156108445750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152606490632b407a829060240160206040518083038186803b15801561089e57600080fd5b505afa1580156108b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d69190610d85565b9392505050565b505067ffffffffffffffff164090565b6000466108f981610b01565b1561098357606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561094557600080fd5b505afa158015610959573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097d9190610d85565b91505090565b4391505090565b60005473ffffffffffffffffffffffffffffffffffffffff1633146104fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016103cd565b73ffffffffffffffffffffffffffffffffffffffff8116331415610a8b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016103cd565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600061a4b1821480610b15575062066eed82145b8061057557505062066eee1490565b828054828255906000526020600020908101928215610b9e579160200282015b82811115610b9e57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190610b44565b50610baa929150610bae565b5090565b5b80821115610baa5760008155600101610baf565b803573ffffffffffffffffffffffffffffffffffffffff81168114610be757600080fd5b919050565b60008083601f840112610bfe57600080fd5b50813567ffffffffffffffff811115610c1657600080fd5b6020830191508360208260051b8501011115610c3157600080fd5b9250929050565b600060208284031215610c4a57600080fd5b6108d682610bc3565b60006020808385031215610c6657600080fd5b823567ffffffffffffffff80821115610c7e57600080fd5b818501915085601f830112610c9257600080fd5b813581811115610ca457610ca4610f89565b8060051b9150610cb5848301610e74565b8181528481019084860184860187018a1015610cd057600080fd5b600095505b83861015610cfa57610ce681610bc3565b835260019590950194918601918601610cd5565b5098975050505050505050565b60008060008060008060808789031215610d2057600080fd5b863567ffffffffffffffff80821115610d3857600080fd5b610d448a838b01610bec565b90985096506020890135915080821115610d5d57600080fd5b50610d6a89828a01610bec565b979a9699509760408101359660609091013595509350505050565b600060208284031215610d9757600080fd5b5051919050565b600060208284031215610db057600080fd5b5035919050565b60008060408385031215610dca57600080fd5b8235915060208084013567ffffffffffffffff80821115610dea57600080fd5b818601915086601f830112610dfe57600080fd5b813581811115610e1057610e10610f89565b610e40847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601610e74565b91508082528784828501011115610e5657600080fd5b80848401858401376000848284010152508093505050509250929050565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610ebb57610ebb610f89565b604052919050565b60008219821115610ed657610ed6610f2b565b500190565b600082821015610eed57610eed610f2b565b500390565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610f2457610f24610f2b565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + Bin: "0x60806040523480156200001157600080fd5b50604051620014b8380380620014b88339810160408190526200003491620003fd565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d9565b505050620000d2816200018460201b60201c565b506200050d565b336001600160a01b03821603620001335760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6200018e620002eb565b60006004805480602002602001604051908101604052809291908181526020018280548015620001e857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311620001c9575b50508551939450620002069360049350602087019250905062000349565b5060005b815181101562000276576000600360008484815181106200022f576200022f620004cf565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff1916911515919091179055806200026d81620004e5565b9150506200020a565b5060005b8251811015620002e6576001600360008584815181106200029f576200029f620004cf565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff191691151591909117905580620002dd81620004e5565b9150506200027a565b505050565b6000546001600160a01b03163314620003475760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000082565b565b828054828255906000526020600020908101928215620003a1579160200282015b82811115620003a157825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906200036a565b50620003af929150620003b3565b5090565b5b80821115620003af5760008155600101620003b4565b634e487b7160e01b600052604160045260246000fd5b80516001600160a01b0381168114620003f857600080fd5b919050565b600060208083850312156200041157600080fd5b82516001600160401b03808211156200042957600080fd5b818501915085601f8301126200043e57600080fd5b815181811115620004535762000453620003ca565b8060051b604051601f19603f830116810181811085821117156200047b576200047b620003ca565b6040529182528482019250838101850191888311156200049a57600080fd5b938501935b82851015620004c357620004b385620003e0565b845293850193928501926200049f565b98975050505050505050565b634e487b7160e01b600052603260045260246000fd5b6000600182016200050657634e487b7160e01b600052601160045260246000fd5b5060010190565b610f9b806200051d6000396000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c80638da5cb5b11610081578063f2fde38b1161005b578063f2fde38b146101b5578063f4217648146101c8578063fadff0e1146101db57600080fd5b80638da5cb5b14610143578063e9413d3814610161578063e9ecc1541461018257600080fd5b80636057361d116100b25780636057361d1461012057806379ba50971461013357806383b6d6b71461013b57600080fd5b80633b69ad60146100ce5780635c7de309146100e3575b600080fd5b6100e16100dc366004610bf6565b6101ee565b005b6100f66100f1366004610c74565b610326565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6100e161012e366004610c74565b61035d565b6100e16103ec565b6100e16104e9565b60005473ffffffffffffffffffffffffffffffffffffffff166100f6565b61017461016f366004610c74565b610503565b604051908152602001610117565b6101a5610190366004610cb6565b60036020526000908152604090205460ff1681565b6040519015158152602001610117565b6100e16101c3366004610cb6565b610581565b6100e16101d6366004610d4f565b610595565b6100e16101e9366004610dfc565b61074b565b60006101f9836107ee565b9050818114610234576040517fd2f69c9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526003602052604090205460ff1661027d576040517f5b0aa2ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8584146102b6576040517fbd75093300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8681101561031c578585828181106102d3576102d3610eb9565b90506020020135600260008a8a858181106102f0576102f0610eb9565b90506020020135815260200190815260200160002081905550808061031490610f17565b9150506102b9565b5050505050505050565b6004818154811061033657600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b6000610368826107ee565b905060008190036103da576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f626c6f636b68617368286e29206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b60009182526002602052604090912055565b60015473ffffffffffffffffffffffffffffffffffffffff16331461046d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016103d1565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6105016101006104f76108e4565b61012e9190610f4f565b565b60008181526002602052604081205480820361057b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f626c6f636b68617368206e6f7420666f756e6420696e2073746f72650000000060448201526064016103d1565b92915050565b610589610972565b610592816109f3565b50565b61059d610972565b6000600480548060200260200160405190810160405280929190818152602001828054801561060257602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116105d7575b5050855193945061061e93600493506020870192509050610b0b565b5060005b81518110156106b25760006003600084848151811061064357610643610eb9565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055806106aa81610f17565b915050610622565b5060005b8251811015610746576001600360008584815181106106d7576106d7610eb9565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790558061073e81610f17565b9150506106b6565b505050565b6002600061075a846001610f62565b8152602001908152602001600020548180519060200120146107d8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f6865616465722068617320756e6b6e6f776e20626c6f636b686173680000000060448201526064016103d1565b6024015160009182526002602052604090912055565b6000466107fa81610ae8565b156108d4576101008367ffffffffffffffff166108156108e4565b61081f9190610f4f565b118061083c575061082e6108e4565b8367ffffffffffffffff1610155b1561084a5750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152606490632b407a8290602401602060405180830381865afa1580156108a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108cd9190610f75565b9392505050565b505067ffffffffffffffff164090565b6000466108f081610ae8565b1561096b57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610941573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109659190610f75565b91505090565b4391505090565b60005473ffffffffffffffffffffffffffffffffffffffff163314610501576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016103d1565b3373ffffffffffffffffffffffffffffffffffffffff821603610a72576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016103d1565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600061a4b1821480610afc575062066eed82145b8061057b57505062066eee1490565b828054828255906000526020600020908101928215610b85579160200282015b82811115610b8557825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190610b2b565b50610b91929150610b95565b5090565b5b80821115610b915760008155600101610b96565b60008083601f840112610bbc57600080fd5b50813567ffffffffffffffff811115610bd457600080fd5b6020830191508360208260051b8501011115610bef57600080fd5b9250929050565b60008060008060008060808789031215610c0f57600080fd5b863567ffffffffffffffff80821115610c2757600080fd5b610c338a838b01610baa565b90985096506020890135915080821115610c4c57600080fd5b50610c5989828a01610baa565b979a9699509760408101359660609091013595509350505050565b600060208284031215610c8657600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610cb157600080fd5b919050565b600060208284031215610cc857600080fd5b6108cd82610c8d565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610d4757610d47610cd1565b604052919050565b60006020808385031215610d6257600080fd5b823567ffffffffffffffff80821115610d7a57600080fd5b818501915085601f830112610d8e57600080fd5b813581811115610da057610da0610cd1565b8060051b9150610db1848301610d00565b8181529183018401918481019088841115610dcb57600080fd5b938501935b83851015610df057610de185610c8d565b82529385019390850190610dd0565b98975050505050505050565b60008060408385031215610e0f57600080fd5b8235915060208084013567ffffffffffffffff80821115610e2f57600080fd5b818601915086601f830112610e4357600080fd5b813581811115610e5557610e55610cd1565b610e85847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601610d00565b91508082528784828501011115610e9b57600080fd5b80848401858401376000848284010152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610f4857610f48610ee8565b5060010190565b8181038181111561057b5761057b610ee8565b8082018082111561057b5761057b610ee8565b600060208284031215610f8757600080fd5b505191905056fea164736f6c6343000813000a", } var TrustedBlockhashStoreABI = TrustedBlockhashStoreMetaData.ABI diff --git a/core/gethwrappers/generated/vrf_consumer_v2_plus_upgradeable_example/vrf_consumer_v2_plus_upgradeable_example.go b/core/gethwrappers/generated/vrf_consumer_v2_plus_upgradeable_example/vrf_consumer_v2_plus_upgradeable_example.go index deb678c4ebb..8770fd0befe 100644 --- a/core/gethwrappers/generated/vrf_consumer_v2_plus_upgradeable_example/vrf_consumer_v2_plus_upgradeable_example.go +++ b/core/gethwrappers/generated/vrf_consumer_v2_plus_upgradeable_example/vrf_consumer_v2_plus_upgradeable_example.go @@ -32,7 +32,7 @@ var ( var VRFConsumerV2PlusUpgradeableExampleMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"COORDINATOR\",\"outputs\":[{\"internalType\":\"contractIVRFCoordinatorV2Plus\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINKTOKEN\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"createSubscriptionAndFund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"minReqConfs\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"}],\"name\":\"requestRandomness\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_gasAvailable\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_randomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_subId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"topUpSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"}],\"name\":\"updateSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b506110c1806100206000396000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c806355380dfb11610081578063e89e106a1161005b578063e89e106a146101ce578063f08c5daa146101d7578063f6eaffc8146101e057600080fd5b806355380dfb14610192578063706da1ca146101b2578063cf62c8ab146101bb57600080fd5b806336bfffed116100b257806336bfffed146101275780633b2bcbf11461013a578063485cc9551461017f57600080fd5b80631fe543e3146100d95780632e75964e146100ee5780632fa4e44214610114575b600080fd5b6100ec6100e7366004610d95565b6101f3565b005b6101016100fc366004610d03565b610284565b6040519081526020015b60405180910390f35b6100ec610122366004610e39565b610381565b6100ec610135366004610c36565b6104a3565b60345461015a9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161010b565b6100ec61018d366004610c03565b6105db565b60355461015a9073ffffffffffffffffffffffffffffffffffffffff1681565b61010160365481565b6100ec6101c9366004610e39565b6107c5565b61010160335481565b61010160375481565b6101016101ee366004610d63565b61093c565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314610276576000546040517f1cf993f40000000000000000000000000000000000000000000000000000000081523360048201526201000090910473ffffffffffffffffffffffffffffffffffffffff1660248201526044015b60405180910390fd5b610280828261095d565b5050565b6040805160c081018252868152602080820187905261ffff86168284015263ffffffff80861660608401528416608083015282519081018352600080825260a083019190915260345492517f9b1c385e000000000000000000000000000000000000000000000000000000008152909273ffffffffffffffffffffffffffffffffffffffff1690639b1c385e9061031f908490600401610f1e565b602060405180830381600087803b15801561033957600080fd5b505af115801561034d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103719190610d7c565b6033819055979650505050505050565b6036546103ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f737562206e6f7420736574000000000000000000000000000000000000000000604482015260640161026d565b60355460345460365460408051602081019290925273ffffffffffffffffffffffffffffffffffffffff93841693634000aea09316918591015b6040516020818303038152906040526040518463ffffffff1660e01b815260040161045193929190610ed2565b602060405180830381600087803b15801561046b57600080fd5b505af115801561047f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102809190610cda565b60365461050c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f7375624944206e6f742073657400000000000000000000000000000000000000604482015260640161026d565b60005b815181101561028057603454603654835173ffffffffffffffffffffffffffffffffffffffff9092169163bec4c08c919085908590811061055257610552611056565b60200260200101516040518363ffffffff1660e01b815260040161059692919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b1580156105b057600080fd5b505af11580156105c4573d6000803e3d6000fd5b5050505080806105d390610ff6565b91505061050f565b600054610100900460ff16158080156105fb5750600054600160ff909116105b806106155750303b158015610615575060005460ff166001145b6106a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161026d565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156106ff57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b610708836109df565b6034805473ffffffffffffffffffffffffffffffffffffffff8086167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255603580549285169290911691909117905580156107c057600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6036546103ea57603460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a21a23e46040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561083657600080fd5b505af115801561084a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086e9190610d7c565b60368190556034546040517fbec4c08c000000000000000000000000000000000000000000000000000000008152600481019290925230602483015273ffffffffffffffffffffffffffffffffffffffff169063bec4c08c90604401600060405180830381600087803b1580156108e457600080fd5b505af11580156108f8573d6000803e3d6000fd5b5050505060355460345460365460405173ffffffffffffffffffffffffffffffffffffffff93841693634000aea09316918591610424919060200190815260200190565b6032818154811061094c57600080fd5b600091825260209091200154905081565b60335482146109c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265717565737420494420697320696e636f7272656374000000000000000000604482015260640161026d565b5a60375580516107c0906032906020840190610b66565b600054610100900460ff16610a76576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161026d565b73ffffffffffffffffffffffffffffffffffffffff8116610b19576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f6d75737420676976652076616c696420636f6f7264696e61746f72206164647260448201527f6573730000000000000000000000000000000000000000000000000000000000606482015260840161026d565b6000805473ffffffffffffffffffffffffffffffffffffffff90921662010000027fffffffffffffffffffff0000000000000000000000000000000000000000ffff909216919091179055565b828054828255906000526020600020908101928215610ba1579160200282015b82811115610ba1578251825591602001919060010190610b86565b50610bad929150610bb1565b5090565b5b80821115610bad5760008155600101610bb2565b803573ffffffffffffffffffffffffffffffffffffffff81168114610bea57600080fd5b919050565b803563ffffffff81168114610bea57600080fd5b60008060408385031215610c1657600080fd5b610c1f83610bc6565b9150610c2d60208401610bc6565b90509250929050565b60006020808385031215610c4957600080fd5b823567ffffffffffffffff811115610c6057600080fd5b8301601f81018513610c7157600080fd5b8035610c84610c7f82610fd2565b610f83565b80828252848201915084840188868560051b8701011115610ca457600080fd5b600094505b83851015610cce57610cba81610bc6565b835260019490940193918501918501610ca9565b50979650505050505050565b600060208284031215610cec57600080fd5b81518015158114610cfc57600080fd5b9392505050565b600080600080600060a08688031215610d1b57600080fd5b8535945060208601359350604086013561ffff81168114610d3b57600080fd5b9250610d4960608701610bef565b9150610d5760808701610bef565b90509295509295909350565b600060208284031215610d7557600080fd5b5035919050565b600060208284031215610d8e57600080fd5b5051919050565b60008060408385031215610da857600080fd5b8235915060208084013567ffffffffffffffff811115610dc757600080fd5b8401601f81018613610dd857600080fd5b8035610de6610c7f82610fd2565b80828252848201915084840189868560051b8701011115610e0657600080fd5b600094505b83851015610e29578035835260019490940193918501918501610e0b565b5080955050505050509250929050565b600060208284031215610e4b57600080fd5b81356bffffffffffffffffffffffff81168114610cfc57600080fd5b6000815180845260005b81811015610e8d57602081850181015186830182015201610e71565b81811115610e9f576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff841681526bffffffffffffffffffffffff83166020820152606060408201526000610f156060830184610e67565b95945050505050565b60208152815160208201526020820151604082015261ffff60408301511660608201526000606083015163ffffffff80821660808501528060808601511660a0850152505060a083015160c080840152610f7b60e0840182610e67565b949350505050565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610fca57610fca611085565b604052919050565b600067ffffffffffffffff821115610fec57610fec611085565b5060051b60200190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561104f577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + Bin: "0x608060405234801561001057600080fd5b50611087806100206000396000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c806355380dfb11610081578063e89e106a1161005b578063e89e106a146101ce578063f08c5daa146101d7578063f6eaffc8146101e057600080fd5b806355380dfb14610192578063706da1ca146101b2578063cf62c8ab146101bb57600080fd5b806336bfffed116100b257806336bfffed146101275780633b2bcbf11461013a578063485cc9551461017f57600080fd5b80631fe543e3146100d95780632e75964e146100ee5780632fa4e44214610114575b600080fd5b6100ec6100e7366004610c44565b6101f3565b005b6101016100fc366004610cff565b610284565b6040519081526020015b60405180910390f35b6100ec610122366004610d5f565b610372565b6100ec610135366004610db8565b610488565b60345461015a9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161010b565b6100ec61018d366004610e50565b6105c3565b60355461015a9073ffffffffffffffffffffffffffffffffffffffff1681565b61010160365481565b6100ec6101c9366004610d5f565b6107ad565b61010160335481565b61010160375481565b6101016101ee366004610e83565b610918565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314610276576000546040517f1cf993f40000000000000000000000000000000000000000000000000000000081523360048201526201000090910473ffffffffffffffffffffffffffffffffffffffff1660248201526044015b60405180910390fd5b6102808282610939565b5050565b6040805160c081018252868152602080820187905261ffff86168284015263ffffffff80861660608401528416608083015282519081018352600080825260a083019190915260345492517f9b1c385e000000000000000000000000000000000000000000000000000000008152909273ffffffffffffffffffffffffffffffffffffffff1690639b1c385e9061031f908490600401610f00565b6020604051808303816000875af115801561033e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103629190610f65565b6033819055979650505050505050565b6036546000036103de576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f737562206e6f7420736574000000000000000000000000000000000000000000604482015260640161026d565b60355460345460365460408051602081019290925273ffffffffffffffffffffffffffffffffffffffff93841693634000aea09316918591015b6040516020818303038152906040526040518463ffffffff1660e01b815260040161044593929190610f7e565b6020604051808303816000875af1158015610464573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102809190610fca565b6036546000036104f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f7375624944206e6f742073657400000000000000000000000000000000000000604482015260640161026d565b60005b815181101561028057603454603654835173ffffffffffffffffffffffffffffffffffffffff9092169163bec4c08c919085908590811061053a5761053a610fec565b60200260200101516040518363ffffffff1660e01b815260040161057e92919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b15801561059857600080fd5b505af11580156105ac573d6000803e3d6000fd5b5050505080806105bb9061101b565b9150506104f7565b600054610100900460ff16158080156105e35750600054600160ff909116105b806105fd5750303b1580156105fd575060005460ff166001145b610689576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161026d565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156106e757600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6106f0836109bb565b6034805473ffffffffffffffffffffffffffffffffffffffff8086167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255603580549285169290911691909117905580156107a857600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6036546000036103de57603460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a21a23e46040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610826573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061084a9190610f65565b60368190556034546040517fbec4c08c000000000000000000000000000000000000000000000000000000008152600481019290925230602483015273ffffffffffffffffffffffffffffffffffffffff169063bec4c08c90604401600060405180830381600087803b1580156108c057600080fd5b505af11580156108d4573d6000803e3d6000fd5b5050505060355460345460365460405173ffffffffffffffffffffffffffffffffffffffff93841693634000aea09316918591610418919060200190815260200190565b6032818154811061092857600080fd5b600091825260209091200154905081565b60335482146109a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265717565737420494420697320696e636f7272656374000000000000000000604482015260640161026d565b5a60375580516107a8906032906020840190610b42565b600054610100900460ff16610a52576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161026d565b73ffffffffffffffffffffffffffffffffffffffff8116610af5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f6d75737420676976652076616c696420636f6f7264696e61746f72206164647260448201527f6573730000000000000000000000000000000000000000000000000000000000606482015260840161026d565b6000805473ffffffffffffffffffffffffffffffffffffffff90921662010000027fffffffffffffffffffff0000000000000000000000000000000000000000ffff909216919091179055565b828054828255906000526020600020908101928215610b7d579160200282015b82811115610b7d578251825591602001919060010190610b62565b50610b89929150610b8d565b5090565b5b80821115610b895760008155600101610b8e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610c1857610c18610ba2565b604052919050565b600067ffffffffffffffff821115610c3a57610c3a610ba2565b5060051b60200190565b60008060408385031215610c5757600080fd5b8235915060208084013567ffffffffffffffff811115610c7657600080fd5b8401601f81018613610c8757600080fd5b8035610c9a610c9582610c20565b610bd1565b81815260059190911b82018301908381019088831115610cb957600080fd5b928401925b82841015610cd757833582529284019290840190610cbe565b80955050505050509250929050565b803563ffffffff81168114610cfa57600080fd5b919050565b600080600080600060a08688031215610d1757600080fd5b8535945060208601359350604086013561ffff81168114610d3757600080fd5b9250610d4560608701610ce6565b9150610d5360808701610ce6565b90509295509295909350565b600060208284031215610d7157600080fd5b81356bffffffffffffffffffffffff81168114610d8d57600080fd5b9392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610cfa57600080fd5b60006020808385031215610dcb57600080fd5b823567ffffffffffffffff811115610de257600080fd5b8301601f81018513610df357600080fd5b8035610e01610c9582610c20565b81815260059190911b82018301908381019087831115610e2057600080fd5b928401925b82841015610e4557610e3684610d94565b82529284019290840190610e25565b979650505050505050565b60008060408385031215610e6357600080fd5b610e6c83610d94565b9150610e7a60208401610d94565b90509250929050565b600060208284031215610e9557600080fd5b5035919050565b6000815180845260005b81811015610ec257602081850181015186830182015201610ea6565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152815160208201526020820151604082015261ffff60408301511660608201526000606083015163ffffffff80821660808501528060808601511660a0850152505060a083015160c080840152610f5d60e0840182610e9c565b949350505050565b600060208284031215610f7757600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff841681526bffffffffffffffffffffffff83166020820152606060408201526000610fc16060830184610e9c565b95945050505050565b600060208284031215610fdc57600080fd5b81518015158114610d8d57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611073577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b506001019056fea164736f6c6343000813000a", } var VRFConsumerV2PlusUpgradeableExampleABI = VRFConsumerV2PlusUpgradeableExampleMetaData.ABI diff --git a/core/gethwrappers/generated/vrf_coordinator_v2_5/vrf_coordinator_v2_5.go b/core/gethwrappers/generated/vrf_coordinator_v2_5/vrf_coordinator_v2_5.go index 119fba7d2e4..84dfa7de904 100644 --- a/core/gethwrappers/generated/vrf_coordinator_v2_5/vrf_coordinator_v2_5.go +++ b/core/gethwrappers/generated/vrf_coordinator_v2_5/vrf_coordinator_v2_5.go @@ -30,15 +30,6 @@ var ( _ = abi.ConvertType ) -type VRFCoordinatorV25RequestCommitment struct { - BlockNum uint64 - SubId *big.Int - CallbackGasLimit uint32 - NumWords uint32 - Sender common.Address - ExtraArgs []byte -} - type VRFProof struct { Pk [2]*big.Int Gamma [2]*big.Int @@ -51,6 +42,15 @@ type VRFProof struct { ZInv *big.Int } +type VRFTypesRequestCommitmentV2Plus struct { + BlockNum uint64 + SubId *big.Int + CallbackGasLimit uint32 + NumWords uint32 + Sender common.Address + ExtraArgs []byte +} + type VRFV2PlusClientRandomWordsRequest struct { KeyHash [32]byte SubId *big.Int @@ -61,8 +61,8 @@ type VRFV2PlusClientRandomWordsRequest struct { } var VRFCoordinatorV25MetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"blockhashStore\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"internalBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"externalBalance\",\"type\":\"uint256\"}],\"name\":\"BalanceInvariantViolated\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"BlockhashNotInStore\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorNotRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToSendNative\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToTransferLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"GasLimitTooBig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"gasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxGas\",\"type\":\"uint256\"}],\"name\":\"GasPriceExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectCommitment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"have\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"want\",\"type\":\"uint256\"}],\"name\":\"InsufficientGasForConsumer\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidExtraArgsTag\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"premiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"max\",\"type\":\"uint8\"}],\"name\":\"InvalidPremiumPercentage\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"have\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"min\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"max\",\"type\":\"uint16\"}],\"name\":\"InvalidRequestConfirmations\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkAlreadySet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"flatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeNativePPM\",\"type\":\"uint32\"}],\"name\":\"LinkDiscountTooHigh\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkNotSet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"have\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"max\",\"type\":\"uint32\"}],\"name\":\"MsgDataTooBig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"}],\"name\":\"MustBeRequestedOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoCorrespondingRequest\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"NoSuchProvingKey\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"NumWordsTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PendingRequestExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"ProvingKeyAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Reentrant\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyConsumers\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"nativePremiumPercentage\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"linkPremiumPercentage\",\"type\":\"uint8\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorDeregistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"}],\"name\":\"FallbackWeiPerUnitLinkUsed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"MigrationCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"NativeFundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"maxGas\",\"type\":\"uint64\"}],\"name\":\"ProvingKeyDeregistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"maxGas\",\"type\":\"uint64\"}],\"name\":\"ProvingKeyRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"outputSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"payment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"nativePayment\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"onlyPremium\",\"type\":\"bool\"}],\"name\":\"RandomWordsFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"preSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RandomWordsRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountLink\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountNative\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldNativeBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newNativeBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFundedWithNative\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BLOCKHASH_STORE\",\"outputs\":[{\"internalType\":\"contractBlockhashStoreInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK_NATIVE_FEED\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_CONSUMERS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_NUM_WORDS\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_REQUEST_CONFIRMATIONS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"deregisterMigratableCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"}],\"name\":\"deregisterProvingKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256[2]\",\"name\":\"pk\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"gamma\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"c\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"s\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"uWitness\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"cGammaWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"sHashWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"zInv\",\"type\":\"uint256\"}],\"internalType\":\"structVRF.Proof\",\"name\":\"proof\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"blockNum\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFCoordinatorV2_5.RequestCommitment\",\"name\":\"rc\",\"type\":\"tuple\"},{\"internalType\":\"bool\",\"name\":\"onlyPremium\",\"type\":\"bool\"}],\"name\":\"fulfillRandomWords\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"payment\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"fundSubscriptionWithNative\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveSubscriptionIds\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"getSubscription\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"nativeBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint64\",\"name\":\"reqCount\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicKey\",\"type\":\"uint256[2]\"}],\"name\":\"hashOfKey\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"}],\"name\":\"migrate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"ownerCancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"pendingRequestExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverNativeFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"registerMigratableCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint64\",\"name\":\"maxGas\",\"type\":\"uint64\"}],\"name\":\"registerProvingKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFV2PlusClient.RandomWordsRequest\",\"name\":\"req\",\"type\":\"tuple\"}],\"name\":\"requestRandomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"requestSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_config\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"reentrancyLock\",\"type\":\"bool\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"nativePremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"linkPremiumPercentage\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_currentSubNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fallbackWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_provingKeyHashes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_provingKeys\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"exists\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"maxGas\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requestCommitments\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalNativeBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"nativePremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"linkPremiumPercentage\",\"type\":\"uint8\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkNativeFeed\",\"type\":\"address\"}],\"name\":\"setLINKAndLINKNativeFeed\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"withdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b5060405162005ee138038062005ee1833981016040819052620000349162000183565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d7565b50505060601b6001600160601b031916608052620001b5565b6001600160a01b038116331415620001325760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019657600080fd5b81516001600160a01b0381168114620001ae57600080fd5b9392505050565b60805160601c615d06620001db6000396000818161055001526132fa0152615d066000f3fe60806040526004361061021c5760003560e01c80638402595e11610124578063b2a7cac5116100a6578063b2a7cac514610732578063bec4c08c14610752578063caf70c4a14610772578063cb63179714610792578063d98e620e146107b2578063da2f2610146107d2578063dac83d2914610831578063dc311dd314610851578063e72f6e3014610882578063ee9d2d38146108a2578063f2fde38b146108cf57600080fd5b80638402595e146105c757806386fe91c7146105e75780638da5cb5b1461060757806395b55cfc146106255780639b1c385e146106385780639d40a6fd14610658578063a21a23e414610690578063a4c0ed36146106a5578063a63e0bfb146106c5578063aa433aff146106e5578063aefb212f1461070557600080fd5b8063405b84fa116101ad578063405b84fa1461044e57806340d6bb821461046e57806341af6c871461049957806351cff8d9146104c95780635d06b4ab146104e957806364d51a2a14610509578063659827441461051e578063689c45171461053e57806372e9d5651461057257806379ba5097146105925780637a5a2aef146105a757600080fd5b806304104edb14610221578063043bd6ae14610243578063088070f51461026c57806308821d581461033a5780630ae095401461035a57806315c48b841461037a57806318e3dd27146103a25780631b6b6d23146103e15780632f622e6b1461040e578063301f42e91461042e575b600080fd5b34801561022d57600080fd5b5061024161023c3660046150bd565b6108ef565b005b34801561024f57600080fd5b5061025960105481565b6040519081526020015b60405180910390f35b34801561027857600080fd5b50600c546102dd9061ffff81169063ffffffff62010000820481169160ff600160301b8204811692600160381b8304811692600160581b8104821692600160781b8204831692600160981b83041691600160b81b8104821691600160c01b9091041689565b6040805161ffff909a168a5263ffffffff98891660208b01529615159689019690965293861660608801529185166080870152841660a08601529290921660c084015260ff91821660e08401521661010082015261012001610263565b34801561034657600080fd5b5061024161035536600461519b565b610a5c565b34801561036657600080fd5b50610241610375366004615485565b610c06565b34801561038657600080fd5b5061038f60c881565b60405161ffff9091168152602001610263565b3480156103ae57600080fd5b50600a546103c990600160601b90046001600160601b031681565b6040516001600160601b039091168152602001610263565b3480156103ed57600080fd5b50600254610401906001600160a01b031681565b60405161026391906156b6565b34801561041a57600080fd5b506102416104293660046150bd565b610c4e565b34801561043a57600080fd5b506103c96104493660046152a1565b610d9a565b34801561045a57600080fd5b50610241610469366004615485565b61104d565b34801561047a57600080fd5b506104846101f481565b60405163ffffffff9091168152602001610263565b3480156104a557600080fd5b506104b96104b4366004615224565b6113ff565b6040519015158152602001610263565b3480156104d557600080fd5b506102416104e43660046150bd565b611515565b3480156104f557600080fd5b506102416105043660046150bd565b6116a3565b34801561051557600080fd5b5061038f606481565b34801561052a57600080fd5b506102416105393660046150da565b61175a565b34801561054a57600080fd5b506104017f000000000000000000000000000000000000000000000000000000000000000081565b34801561057e57600080fd5b50600354610401906001600160a01b031681565b34801561059e57600080fd5b506102416117ba565b3480156105b357600080fd5b506102416105c23660046151b7565b611864565b3480156105d357600080fd5b506102416105e23660046150bd565b611994565b3480156105f357600080fd5b50600a546103c9906001600160601b031681565b34801561061357600080fd5b506000546001600160a01b0316610401565b610241610633366004615224565b611aa6565b34801561064457600080fd5b5061025961065336600461538f565b611bca565b34801561066457600080fd5b50600754610678906001600160401b031681565b6040516001600160401b039091168152602001610263565b34801561069c57600080fd5b50610259611f61565b3480156106b157600080fd5b506102416106c0366004615113565b612135565b3480156106d157600080fd5b506102416106e03660046153e4565b6122b1565b3480156106f157600080fd5b50610241610700366004615224565b61257d565b34801561071157600080fd5b506107256107203660046154aa565b6125c5565b604051610263919061572d565b34801561073e57600080fd5b5061024161074d366004615224565b6126c7565b34801561075e57600080fd5b5061024161076d366004615485565b6127bc565b34801561077e57600080fd5b5061025961078d3660046151eb565b6128ae565b34801561079e57600080fd5b506102416107ad366004615485565b6128de565b3480156107be57600080fd5b506102596107cd366004615224565b612b41565b3480156107de57600080fd5b506108126107ed366004615224565b600d6020526000908152604090205460ff81169061010090046001600160401b031682565b6040805192151583526001600160401b03909116602083015201610263565b34801561083d57600080fd5b5061024161084c366004615485565b612b62565b34801561085d57600080fd5b5061087161086c366004615224565b612bf9565b604051610263959493929190615917565b34801561088e57600080fd5b5061024161089d3660046150bd565b612ce7565b3480156108ae57600080fd5b506102596108bd366004615224565b600f6020526000908152604090205481565b3480156108db57600080fd5b506102416108ea3660046150bd565b612eba565b6108f7612ecb565b60115460005b81811015610a3457826001600160a01b03166011828154811061092257610922615c62565b6000918252602090912001546001600160a01b03161415610a2457601161094a600184615b12565b8154811061095a5761095a615c62565b600091825260209091200154601180546001600160a01b03909216918390811061098657610986615c62565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060118054806109c5576109c5615c4c565b600082815260209020810160001990810180546001600160a01b03191690550190556040517ff80a1a97fd42251f3c33cda98635e7399253033a6774fe37cd3f650b5282af3790610a179085906156b6565b60405180910390a1505050565b610a2d81615bca565b90506108fd565b5081604051635428d44960e01b8152600401610a5091906156b6565b60405180910390fd5b50565b610a64612ecb565b604080518082018252600091610a939190849060029083908390808284376000920191909152506128ae915050565b6000818152600d602090815260409182902082518084019093525460ff811615158084526101009091046001600160401b03169183019190915291925090610af157604051631dfd6e1360e21b815260048101839052602401610a50565b6000828152600d6020526040812080546001600160481b0319169055600e54905b81811015610bc25783600e8281548110610b2e57610b2e615c62565b90600052602060002001541415610bb257600e610b4c600184615b12565b81548110610b5c57610b5c615c62565b9060005260206000200154600e8281548110610b7a57610b7a615c62565b600091825260209091200155600e805480610b9757610b97615c4c565b60019003818190600052602060002001600090559055610bc2565b610bbb81615bca565b9050610b12565b507f9b6868e0eb737bcd72205360baa6bfd0ba4e4819a33ade2db384e8a8025639a5838360200151604051610bf8929190615740565b60405180910390a150505050565b81610c1081612f20565b610c18612f81565b610c21836113ff565b15610c3f57604051631685ecdd60e31b815260040160405180910390fd5b610c498383612fac565b505050565b610c56612f81565b610c5e612ecb565b600b54600160601b90046001600160601b0316610c8e57604051631e9acf1760e31b815260040160405180910390fd5b600b8054600160601b90046001600160601b0316908190600c610cb18380615b4e565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a600c8282829054906101000a90046001600160601b0316610cf99190615b4e565b92506101000a8154816001600160601b0302191690836001600160601b031602179055506000826001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114610d73576040519150601f19603f3d011682016040523d82523d6000602084013e610d78565b606091505b5050905080610c495760405163950b247960e01b815260040160405180910390fd5b6000610da4612f81565b60005a9050610324361115610dd657604051630f28961b60e01b81523660048201526103246024820152604401610a50565b6000610de28686613160565b90506000610df88583600001516020015161341c565b60408301516060888101519293509163ffffffff16806001600160401b03811115610e2557610e25615c78565b604051908082528060200260200182016040528015610e4e578160200160208202803683370190505b50925060005b81811015610eb65760408051602081018590529081018290526060016040516020818303038152906040528051906020012060001c848281518110610e9b57610e9b615c62565b6020908102919091010152610eaf81615bca565b9050610e54565b5050602080850180516000908152600f9092526040822082905551610edc908a8561346a565b60208a8101516000908152600690915260409020805491925090601890610f1290600160c01b90046001600160401b0316615be5565b91906101000a8154816001600160401b0302191690836001600160401b0316021790555060008960a0015160018b60a0015151610f4f9190615b12565b81518110610f5f57610f5f615c62565b60209101015160f81c60011490506000610f7b8887848d613505565b90995090508015610fc65760208088015160105460408051928352928201527f6ca648a381f22ead7e37773d934e64885dcf861fbfbb26c40354cbf0c4662d1a910160405180910390a15b50610fd688828c6020015161353d565b6020808b015187820151604080518781526001600160601b038d16948101949094528415159084015284151560608401528b1515608084015290917faeb4b4786571e184246d39587f659abf0e26f41f6a3358692250382c0cdb47b79060a00160405180910390a3505050505050505b9392505050565b611055612f81565b61105e81613690565b61107d5780604051635428d44960e01b8152600401610a5091906156b6565b60008060008061108c86612bf9565b945094505093509350336001600160a01b0316826001600160a01b0316146110ef5760405162461bcd60e51b81526020600482015260166024820152752737ba1039bab139b1b934b83a34b7b71037bbb732b960511b6044820152606401610a50565b6110f8866113ff565b1561113e5760405162461bcd60e51b815260206004820152601660248201527550656e64696e6720726571756573742065786973747360501b6044820152606401610a50565b6040805160c0810182526001815260208082018990526001600160a01b03851682840152606082018490526001600160601b038088166080840152861660a0830152915190916000916111939184910161576a565b60405160208183030381529060405290506111ad886136fc565b505060405163ce3f471960e01b81526001600160a01b0388169063ce3f4719906001600160601b038816906111e6908590600401615757565b6000604051808303818588803b1580156111ff57600080fd5b505af1158015611213573d6000803e3d6000fd5b50506002546001600160a01b03161580159350915061123c905057506001600160601b03861615155b156113065760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb90611273908a908a906004016156fd565b602060405180830381600087803b15801561128d57600080fd5b505af11580156112a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112c59190615207565b6113065760405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742066756e647360701b6044820152606401610a50565b600c805460ff60301b1916600160301b17905560005b83518110156113ad5783818151811061133757611337615c62565b60200260200101516001600160a01b0316638ea98117896040518263ffffffff1660e01b815260040161136a91906156b6565b600060405180830381600087803b15801561138457600080fd5b505af1158015611398573d6000803e3d6000fd5b50505050806113a690615bca565b905061131c565b50600c805460ff60301b191690556040517fd63ca8cb945956747ee69bfdc3ea754c24a4caf7418db70e46052f7850be4187906113ed9089908b906156ca565b60405180910390a15050505050505050565b6000818152600560205260408120600201805480611421575060009392505050565b600e5460005b8281101561150957600084828154811061144357611443615c62565b60009182526020822001546001600160a01b031691505b838110156114f65760006114be600e838154811061147a5761147a615c62565b60009182526020808320909101546001600160a01b03871683526004825260408084208e855290925291205485908c906001600160401b03610100909104166138a4565b506000818152600f6020526040902054909150156114e55750600198975050505050505050565b506114ef81615bca565b905061145a565b50508061150290615bca565b9050611427565b50600095945050505050565b61151d612f81565b611525612ecb565b6002546001600160a01b031661154e5760405163c1f0c0a160e01b815260040160405180910390fd5b600b546001600160601b031661157757604051631e9acf1760e31b815260040160405180910390fd5b600b80546001600160601b031690819060006115938380615b4e565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a60008282829054906101000a90046001600160601b03166115db9190615b4e565b82546001600160601b039182166101009390930a92830291909202199091161790555060025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb9061163090859085906004016156fd565b602060405180830381600087803b15801561164a57600080fd5b505af115801561165e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116829190615207565b61169f57604051631e9acf1760e31b815260040160405180910390fd5b5050565b6116ab612ecb565b6116b481613690565b156116d4578060405163ac8a27ef60e01b8152600401610a5091906156b6565b601180546001810182556000919091527f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c680180546001600160a01b0319166001600160a01b0383161790556040517fb7cabbfc11e66731fc77de0444614282023bcbd41d16781c753a431d0af016259061174f9083906156b6565b60405180910390a150565b611762612ecb565b6002546001600160a01b03161561178c57604051631688c53760e11b815260040160405180910390fd5b600280546001600160a01b039384166001600160a01b03199182161790915560038054929093169116179055565b6001546001600160a01b0316331461180d5760405162461bcd60e51b815260206004820152601660248201527526bab9ba10313290383937b837b9b2b21037bbb732b960511b6044820152606401610a50565b60008054336001600160a01b0319808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b61186c612ecb565b60408051808201825260009161189b9190859060029083908390808284376000920191909152506128ae915050565b6000818152600d602052604090205490915060ff16156118d157604051634a0b8fa760e01b815260048101829052602401610a50565b60408051808201825260018082526001600160401b0385811660208085019182526000878152600d9091528581209451855492516001600160481b031990931690151568ffffffffffffffff00191617610100929093169190910291909117909255600e805491820181559091527fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd01829055517f9b911b2c240bfbef3b6a8f7ed6ee321d1258bb2a3fe6becab52ac1cd3210afd390610a179083908590615740565b61199c612ecb565b600a544790600160601b90046001600160601b0316818111156119dc576040516354ced18160e11b81526004810182905260248101839052604401610a50565b81811015610c495760006119f08284615b12565b90506000846001600160a01b03168260405160006040518083038185875af1925050503d8060008114611a3f576040519150601f19603f3d011682016040523d82523d6000602084013e611a44565b606091505b5050905080611a665760405163950b247960e01b815260040160405180910390fd5b7f4aed7c8eed0496c8c19ea2681fcca25741c1602342e38b045d9f1e8e905d2e9c8583604051611a979291906156ca565b60405180910390a15050505050565b611aae612f81565b6000818152600560205260409020546001600160a01b0316611ae357604051630fb532db60e11b815260040160405180910390fd5b60008181526006602052604090208054600160601b90046001600160601b0316903490600c611b128385615abd565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555034600a600c8282829054906101000a90046001600160601b0316611b5a9190615abd565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f7603b205d03651ee812f803fccde89f1012e545a9c99f0abfea9cedd0fd8e902823484611bad9190615a5e565b604080519283526020830191909152015b60405180910390a25050565b6000611bd4612f81565b602080830135600081815260059092526040909120546001600160a01b0316611c1057604051630fb532db60e11b815260040160405180910390fd5b3360009081526004602090815260408083208484528083529281902081518083019092525460ff811615158083526101009091046001600160401b03169282019290925290611c765782336040516379bfd40160e01b8152600401610a509291906157df565b600c5461ffff16611c8d60608701604088016153c9565b61ffff161080611cb0575060c8611caa60608701604088016153c9565b61ffff16115b15611cf657611cc560608601604087016153c9565b600c5460405163539c34bb60e11b815261ffff92831660048201529116602482015260c86044820152606401610a50565b600c5462010000900463ffffffff16611d1560808701606088016154cc565b63ffffffff161115611d6557611d3160808601606087016154cc565b600c54604051637aebf00f60e11b815263ffffffff9283166004820152620100009091049091166024820152604401610a50565b6101f4611d7860a08701608088016154cc565b63ffffffff161115611dbe57611d9460a08601608087016154cc565b6040516311ce1afb60e21b815263ffffffff90911660048201526101f46024820152604401610a50565b806020018051611dcd90615be5565b6001600160401b031690526020810151600090611df090873590339087906138a4565b90955090506000611e14611e0f611e0a60a08a018a61596c565b61391d565b61399a565b905085611e1f613a0b565b86611e3060808b0160608c016154cc565b611e4060a08c0160808d016154cc565b3386604051602001611e58979695949392919061586a565b60405160208183030381529060405280519060200120600f600088815260200190815260200160002081905550336001600160a01b03168588600001357feb0e3652e0f44f417695e6e90f2f42c99b65cd7169074c5a654b16b9748c3a4e89868c6040016020810190611ecb91906153c9565b8d6060016020810190611ede91906154cc565b8e6080016020810190611ef191906154cc565b89604051611f049695949392919061582b565b60405180910390a450506000928352602091825260409092208251815492909301516001600160401b03166101000268ffffffffffffffff0019931515939093166001600160481b0319909216919091179190911790555b919050565b6000611f6b612f81565b6007546001600160401b031633611f83600143615b12565b6040516001600160601b0319606093841b81166020830152914060348201523090921b1660548201526001600160c01b031960c083901b16606882015260700160408051601f1981840301815291905280516020909101209150611fe8816001615a76565b6007805467ffffffffffffffff19166001600160401b03928316179055604080516000808252608082018352602080830182815283850183815260608086018581528a86526006855287862093518454935191516001600160601b039182166001600160c01b031990951694909417600160601b9190921602176001600160c01b0316600160c01b9290981691909102969096179055835194850184523385528481018281528585018481528884526005835294909220855181546001600160a01b03199081166001600160a01b0392831617835593516001830180549095169116179092559251805192949391926120e79260028501920190614dd7565b506120f791506008905084613a9b565b50827f1d3015d7ba850fa198dc7b1a3f5d42779313a681035f77c8c03764c61005518d3360405161212891906156b6565b60405180910390a2505090565b61213d612f81565b6002546001600160a01b03163314612168576040516344b0e3c360e01b815260040160405180910390fd5b6020811461218957604051638129bbcd60e01b815260040160405180910390fd5b600061219782840184615224565b6000818152600560205260409020549091506001600160a01b03166121cf57604051630fb532db60e11b815260040160405180910390fd5b600081815260066020526040812080546001600160601b0316918691906121f68385615abd565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555084600a60008282829054906101000a90046001600160601b031661223e9190615abd565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f1ced9348ff549fceab2ac57cd3a9de38edaaab274b725ee82c23e8fc8c4eec7a8287846122919190615a5e565b6040805192835260208301919091520160405180910390a2505050505050565b6122b9612ecb565b60c861ffff8a1611156122f35760405163539c34bb60e11b815261ffff8a1660048201819052602482015260c86044820152606401610a50565b60008513612317576040516321ea67b360e11b815260048101869052602401610a50565b8363ffffffff168363ffffffff161115612354576040516313c06e5960e11b815263ffffffff808516600483015285166024820152604401610a50565b609b60ff8316111561238557604051631d66288d60e11b815260ff83166004820152609b6024820152604401610a50565b609b60ff821611156123b657604051631d66288d60e11b815260ff82166004820152609b6024820152604401610a50565b604080516101208101825261ffff8b1680825263ffffffff808c16602084018190526000848601528b8216606085018190528b8316608086018190528a841660a08701819052938a1660c0870181905260ff808b1660e08901819052908a16610100909801889052600c8054600160c01b90990260ff60c01b19600160b81b9093029290921661ffff60b81b19600160981b90940263ffffffff60981b19600160781b9099029890981667ffffffffffffffff60781b19600160581b90960263ffffffff60581b19600160381b9098029790971668ffffffffffffffffff60301b196201000090990265ffffffffffff19909c16909a179a909a1796909616979097179390931791909116959095179290921793909316929092179190911790556010869055517f2c6b6b12413678366b05b145c5f00745bdd00e739131ab5de82484a50c9d78b69061256a908b908b908b908b908b908b908b908b908b9061ffff99909916895263ffffffff97881660208a0152958716604089015293861660608801526080870192909252841660a086015290921660c084015260ff91821660e0840152166101008201526101200190565b60405180910390a1505050505050505050565b612585612ecb565b6000818152600560205260409020546001600160a01b0316806125bb57604051630fb532db60e11b815260040160405180910390fd5b61169f8282612fac565b606060006125d36008613aa7565b90508084106125f557604051631390f2a160e01b815260040160405180910390fd5b60006126018486615a5e565b90508181118061260f575083155b612619578061261b565b815b905060006126298683615b12565b9050806001600160401b0381111561264357612643615c78565b60405190808252806020026020018201604052801561266c578160200160208202803683370190505b50935060005b818110156126bc5761268f6126878883615a5e565b600890613ab1565b8582815181106126a1576126a1615c62565b60209081029190910101526126b581615bca565b9050612672565b505050505b92915050565b6126cf612f81565b6000818152600560205260409020546001600160a01b03168061270557604051630fb532db60e11b815260040160405180910390fd5b6000828152600560205260409020600101546001600160a01b0316331461275c576000828152600560205260409081902060010154905163d084e97560e01b8152610a50916001600160a01b0316906004016156b6565b600082815260056020526040908190208054336001600160a01b031991821681178355600190920180549091169055905183917fd4114ab6e9af9f597c52041f32d62dc57c5c4e4c0d4427006069635e216c938691611bbe9185916156e3565b816127c681612f20565b6127ce612f81565b6001600160a01b03821660009081526004602090815260408083208684529091529020805460ff16156128015750505050565b6000848152600560205260409020600201805460641415612835576040516305a48e0f60e01b815260040160405180910390fd5b8154600160ff1990911681178355815490810182556000828152602090200180546001600160a01b0319166001600160a01b03861617905560405185907f1e980d04aa7648e205713e5e8ea3808672ac163d10936d36f91b2c88ac1575e19061289f9087906156b6565b60405180910390a25050505050565b6000816040516020016128c1919061571f565b604051602081830303815290604052805190602001209050919050565b816128e881612f20565b6128f0612f81565b6128f9836113ff565b1561291757604051631685ecdd60e31b815260040160405180910390fd5b6001600160a01b038216600090815260046020908152604080832086845290915290205460ff1661295f5782826040516379bfd40160e01b8152600401610a509291906157df565b6000838152600560209081526040808320600201805482518185028101850190935280835291929091908301828280156129c257602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116129a4575b505050505090506000600182516129d99190615b12565b905060005b8251811015612ae357846001600160a01b0316838281518110612a0357612a03615c62565b60200260200101516001600160a01b03161415612ad3576000838381518110612a2e57612a2e615c62565b6020026020010151905080600560008981526020019081526020016000206002018381548110612a6057612a60615c62565b600091825260208083209190910180546001600160a01b0319166001600160a01b039490941693909317909255888152600590915260409020600201805480612aab57612aab615c4c565b600082815260209020810160001990810180546001600160a01b031916905501905550612ae3565b612adc81615bca565b90506129de565b506001600160a01b038416600090815260046020908152604080832088845290915290819020805460ff191690555185907f32158c6058347c1601b2d12bc696ac6901d8a9a9aa3ba10c27ab0a983e8425a79061289f9087906156b6565b600e8181548110612b5157600080fd5b600091825260209091200154905081565b81612b6c81612f20565b612b74612f81565b600083815260056020526040902060018101546001600160a01b03848116911614612bf3576001810180546001600160a01b0319166001600160a01b03851617905560405184907f21a4dad170a6bf476c31bbcf4a16628295b0e450672eec25d7c93308e05344a190612bea90339087906156e3565b60405180910390a25b50505050565b600081815260056020526040812054819081906001600160a01b0316606081612c3557604051630fb532db60e11b815260040160405180910390fd5b600086815260066020908152604080832054600583529281902060020180548251818502810185019093528083526001600160601b0380861695600160601b810490911694600160c01b9091046001600160401b0316938893929091839190830182828015612ccd57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612caf575b505050505090509450945094509450945091939590929450565b612cef612ecb565b6002546001600160a01b0316612d185760405163c1f0c0a160e01b815260040160405180910390fd5b6002546040516370a0823160e01b81526000916001600160a01b0316906370a0823190612d499030906004016156b6565b60206040518083038186803b158015612d6157600080fd5b505afa158015612d75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d99919061523d565b600a549091506001600160601b031681811115612dd3576040516354ced18160e11b81526004810182905260248101839052604401610a50565b81811015610c49576000612de78284615b12565b60025460405163a9059cbb60e01b81529192506001600160a01b03169063a9059cbb90612e1a90879085906004016156ca565b602060405180830381600087803b158015612e3457600080fd5b505af1158015612e48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e6c9190615207565b612e8957604051631f01ff1360e21b815260040160405180910390fd5b7f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b4366008482604051610bf89291906156ca565b612ec2612ecb565b610a5981613abd565b6000546001600160a01b03163314612f1e5760405162461bcd60e51b815260206004820152601660248201527527b7363c9031b0b63630b1363290313c9037bbb732b960511b6044820152606401610a50565b565b6000818152600560205260409020546001600160a01b031680612f5657604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b0382161461169f5780604051636c51fda960e11b8152600401610a5091906156b6565b600c54600160301b900460ff1615612f1e5760405163769dd35360e11b815260040160405180910390fd5b600080612fb8846136fc565b60025491935091506001600160a01b031615801590612fdf57506001600160601b03821615155b1561308e5760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb9061301f9086906001600160601b038716906004016156ca565b602060405180830381600087803b15801561303957600080fd5b505af115801561304d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130719190615207565b61308e57604051631e9acf1760e31b815260040160405180910390fd5b6000836001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d80600081146130e4576040519150601f19603f3d011682016040523d82523d6000602084013e6130e9565b606091505b505090508061310b5760405163950b247960e01b815260040160405180910390fd5b604080516001600160a01b03861681526001600160601b03808616602083015284169181019190915285907f8c74ce8b8cf87f5eb001275c8be27eb34ea2b62bfab6814fcc62192bb63e81c49060600161289f565b6040805160a0810182526000606082018181526080830182905282526020820181905291810191909152600061319984600001516128ae565b6000818152600d602090815260409182902082518084019093525460ff811615158084526101009091046001600160401b031691830191909152919250906131f757604051631dfd6e1360e21b815260048101839052602401610a50565b6000828660800151604051602001613219929190918252602082015260400190565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091508061325f57604051631b44092560e11b815260040160405180910390fd5b85516020808801516040808a015160608b015160808c015160a08d0151935161328e978a9790969591016158c3565b6040516020818303038152906040528051906020012081146132c35760405163354a450b60e21b815260040160405180910390fd5b60006132d28760000151613b61565b9050806133aa578651604051631d2827a760e31b81526001600160401b0390911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e9413d389060240160206040518083038186803b15801561334457600080fd5b505afa158015613358573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061337c919061523d565b9050806133aa57865160405163175dadad60e01b81526001600160401b039091166004820152602401610a50565b60008860800151826040516020016133cc929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c905060006133f38a83613c43565b604080516060810182529788526020880196909652948601949094525092979650505050505050565b6000816001600160401b03163a111561346257821561344557506001600160401b0381166126c1565b3a8260405163435e532d60e11b8152600401610a50929190615740565b503a92915050565b6000806000631fe543e360e01b868560405160240161348a92919061580a565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252600c805460ff60301b1916600160301b1790559086015160808701519192506134ee9163ffffffff9091169083613cae565b600c805460ff60301b191690559695505050505050565b600080831561352457613519868685613cfa565b600091509150613534565b61352f868685613e0b565b915091505b94509492505050565b600081815260066020526040902082156135fc5780546001600160601b03600160601b909104811690851681101561358857604051631e9acf1760e31b815260040160405180910390fd5b6135928582615b4e565b8254600160601b600160c01b031916600160601b6001600160601b039283168102919091178455600b805488939192600c926135d2928692900416615abd565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555050612bf3565b80546001600160601b0390811690851681101561362c57604051631e9acf1760e31b815260040160405180910390fd5b6136368582615b4e565b82546001600160601b0319166001600160601b03918216178355600b8054879260009161366591859116615abd565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505050505050565b601154600090815b818110156136f257836001600160a01b0316601182815481106136bd576136bd615c62565b6000918252602090912001546001600160a01b031614156136e2575060019392505050565b6136eb81615bca565b9050613698565b5060009392505050565b60008181526005602090815260408083206006909252822054600290910180546001600160601b0380841694600160601b90940416925b8181101561379e576004600084838154811061375157613751615c62565b60009182526020808320909101546001600160a01b031683528281019390935260409182018120898252909252902080546001600160481b031916905561379781615bca565b9050613733565b50600085815260056020526040812080546001600160a01b031990811682556001820180549091169055906137d66002830182614e3c565b50506000858152600660205260408120556137f2600886613ffd565b506001600160601b0384161561384557600a80548591906000906138209084906001600160601b0316615b4e565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b6001600160601b0383161561389d5782600a600c8282829054906101000a90046001600160601b03166138789190615b4e565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b5050915091565b6040805160208082018790526001600160a01b03959095168183015260608101939093526001600160401b03919091166080808401919091528151808403909101815260a08301825280519084012060c083019490945260e0808301859052815180840390910181526101009092019052805191012091565b6040805160208101909152600081528161394657506040805160208101909152600081526126c1565b63125fa26760e31b6139588385615b6e565b6001600160e01b0319161461398057604051632923fee760e11b815260040160405180910390fd5b61398d8260048186615a34565b8101906110469190615256565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa826040516024016139d391511515815260200190565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915292915050565b600046613a1781614009565b15613a945760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015613a5657600080fd5b505afa158015613a6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a8e919061523d565b91505090565b4391505090565b6000611046838361402c565b60006126c1825490565b6000611046838361407b565b6001600160a01b038116331415613b105760405162461bcd60e51b815260206004820152601760248201527621b0b73737ba103a3930b739b332b9103a379039b2b63360491b6044820152606401610a50565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600046613b6d81614009565b15613c3457610100836001600160401b0316613b87613a0b565b613b919190615b12565b1180613bad5750613ba0613a0b565b836001600160401b031610155b15613bbb5750600092915050565b6040516315a03d4160e11b81526001600160401b0384166004820152606490632b407a82906024015b60206040518083038186803b158015613bfc57600080fd5b505afa158015613c10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611046919061523d565b50506001600160401b03164090565b6000613c778360000151846020015185604001518660600151868860a001518960c001518a60e001518b61010001516140a5565b60038360200151604051602001613c8f9291906157f6565b60408051601f1981840301815291905280516020909101209392505050565b60005a611388811015613cc057600080fd5b611388810390508460408204820311613cd857600080fd5b50823b613ce457600080fd5b60008083516020850160008789f1949350505050565b600080613d3d6000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506142c192505050565b905060005a600c54613d5d908890600160581b900463ffffffff16615a5e565b613d679190615b12565b613d719086615af3565b600c54909150600090613d9690600160781b900463ffffffff1664e8d4a51000615af3565b90508415613de257600c548190606490600160b81b900460ff16613dba8587615a5e565b613dc49190615af3565b613dce9190615adf565b613dd89190615a5e565b9350505050611046565b600c548190606490613dfe90600160b81b900460ff1682615a98565b60ff16613dba8587615a5e565b600080600080613e1961438f565b9150915060008213613e41576040516321ea67b360e11b815260048101839052602401610a50565b6000613e836000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506142c192505050565b9050600083825a600c54613ea5908d90600160581b900463ffffffff16615a5e565b613eaf9190615b12565b613eb9908b615af3565b613ec39190615a5e565b613ed590670de0b6b3a7640000615af3565b613edf9190615adf565b600c54909150600090613f089063ffffffff600160981b8204811691600160781b900416615b29565b613f1d9063ffffffff1664e8d4a51000615af3565b9050600085613f3483670de0b6b3a7640000615af3565b613f3e9190615adf565b905060008915613f7f57600c548290606490613f6490600160c01b900460ff1687615af3565b613f6e9190615adf565b613f789190615a5e565b9050613fbf565b600c548290606490613f9b90600160c01b900460ff1682615a98565b613fa89060ff1687615af3565b613fb29190615adf565b613fbc9190615a5e565b90505b6b033b2e3c9fd0803ce8000000811115613fec5760405163e80fa38160e01b815260040160405180910390fd5b9b949a509398505050505050505050565b60006110468383614465565b600061a4b182148061401d575062066eed82145b806126c157505062066eee1490565b6000818152600183016020526040812054614073575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556126c1565b5060006126c1565b600082600001828154811061409257614092615c62565b9060005260206000200154905092915050565b6140ae89614558565b6140f75760405162461bcd60e51b815260206004820152601a6024820152797075626c6963206b6579206973206e6f74206f6e20637572766560301b6044820152606401610a50565b61410088614558565b6141445760405162461bcd60e51b815260206004820152601560248201527467616d6d61206973206e6f74206f6e20637572766560581b6044820152606401610a50565b61414d83614558565b6141995760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e2063757276650000006044820152606401610a50565b6141a282614558565b6141ee5760405162461bcd60e51b815260206004820152601c60248201527f73486173685769746e657373206973206e6f74206f6e206375727665000000006044820152606401610a50565b6141fa878a888761461b565b6142425760405162461bcd60e51b81526020600482015260196024820152786164647228632a706b2b732a6729213d5f755769746e65737360381b6044820152606401610a50565b600061424e8a8761473e565b90506000614261898b878b8689896147a2565b90506000614272838d8d8a866148c1565b9050808a146142b35760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606401610a50565b505050505050505050505050565b6000466142cd81614009565b1561430c57606c6001600160a01b031663c6f7de0e6040518163ffffffff1660e01b815260040160206040518083038186803b158015613bfc57600080fd5b61431581614901565b1561438657600f602160991b016001600160a01b03166349948e0e84604051806080016040528060488152602001615cb26048913960405160200161435b92919061560c565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401613be49190615757565b50600092915050565b600c5460035460408051633fabe5a360e21b815290516000938493600160381b90910463ffffffff169284926001600160a01b039092169163feaf968c9160048082019260a092909190829003018186803b1580156143ed57600080fd5b505afa158015614401573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061442591906154e7565b50919650909250505063ffffffff82161580159061445157506144488142615b12565b8263ffffffff16105b9250821561445f5760105493505b50509091565b6000818152600183016020526040812054801561454e576000614489600183615b12565b855490915060009061449d90600190615b12565b90508181146145025760008660000182815481106144bd576144bd615c62565b90600052602060002001549050808760000184815481106144e0576144e0615c62565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061451357614513615c4c565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506126c1565b60009150506126c1565b80516000906401000003d019116145a65760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420782d6f7264696e61746560701b6044820152606401610a50565b60208201516401000003d019116145f45760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420792d6f7264696e61746560701b6044820152606401610a50565b60208201516401000003d0199080096146148360005b602002015161493b565b1492915050565b60006001600160a01b0382166146615760405162461bcd60e51b815260206004820152600b60248201526a626164207769746e65737360a81b6044820152606401610a50565b60208401516000906001161561467857601c61467b565b601b5b9050600070014551231950b75fc4402da1732fc9bebe1985876000602002015109865170014551231950b75fc4402da1732fc9bebe19918203925060009190890987516040805160008082526020820180845287905260ff88169282019290925260608101929092526080820183905291925060019060a0016020604051602081039080840390855afa158015614716573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b614746614e5a565b6147736001848460405160200161475f93929190615695565b60405160208183030381529060405261495f565b90505b61477f81614558565b6126c157805160408051602081019290925261479b910161475f565b9050614776565b6147aa614e5a565b825186516401000003d01990819006910614156148095760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e637400006044820152606401610a50565b6148148789886149ad565b6148595760405162461bcd60e51b8152602060048201526016602482015275119a5c9cdd081b5d5b0818da1958dac819985a5b195960521b6044820152606401610a50565b6148648486856149ad565b6148aa5760405162461bcd60e51b815260206004820152601760248201527614d958dbdb99081b5d5b0818da1958dac819985a5b1959604a1b6044820152606401610a50565b6148b5868484614ad5565b98975050505050505050565b6000600286868685876040516020016148df9695949392919061563b565b60408051601f1981840301815291905280516020909101209695505050505050565b6000600a82148061491357506101a482145b80614920575062aa37dc82145b8061492c575061210582145b806126c157505062014a331490565b6000806401000003d01980848509840990506401000003d019600782089392505050565b614967614e5a565b61497082614b98565b815261498561498082600061460a565b614bd3565b602082018190526002900660011415611f5c576020810180516401000003d019039052919050565b6000826149ea5760405162461bcd60e51b815260206004820152600b60248201526a3d32b9379039b1b0b630b960a91b6044820152606401610a50565b83516020850151600090614a0090600290615c0c565b15614a0c57601c614a0f565b601b5b9050600070014551231950b75fc4402da1732fc9bebe198387096040805160008082526020820180845281905260ff86169282019290925260608101869052608081018390529192509060019060a0016020604051602081039080840390855afa158015614a81573d6000803e3d6000fd5b505050602060405103519050600086604051602001614aa091906155fa565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b614add614e5a565b835160208086015185519186015160009384938493614afe93909190614bf3565b919450925090506401000003d019858209600114614b5a5760405162461bcd60e51b815260206004820152601960248201527834b73b2d1036bab9ba1031329034b73b32b939b29037b3103d60391b6044820152606401610a50565b60405180604001604052806401000003d01980614b7957614b79615c36565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d0198110611f5c57604080516020808201939093528151808203840181529082019091528051910120614ba0565b60006126c1826002614bec6401000003d0196001615a5e565b901c614cd3565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a0890506000614c3383838585614d6a565b9098509050614c4488828e88614d8e565b9098509050614c5588828c87614d8e565b90985090506000614c688d878b85614d8e565b9098509050614c7988828686614d6a565b9098509050614c8a88828e89614d8e565b9098509050818114614cbf576401000003d019818a0998506401000003d01982890997506401000003d0198183099650614cc3565b8196505b5050505050509450945094915050565b600080614cde614e78565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a0820152614d10614e96565b60208160c0846005600019fa925082614d605760405162461bcd60e51b81526020600482015260126024820152716269674d6f64457870206661696c7572652160701b6044820152606401610a50565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b828054828255906000526020600020908101928215614e2c579160200282015b82811115614e2c57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614df7565b50614e38929150614eb4565b5090565b5080546000825590600052602060002090810190610a599190614eb4565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b80821115614e385760008155600101614eb5565b8035611f5c81615c8e565b80604081018310156126c157600080fd5b600082601f830112614ef657600080fd5b604051604081018181106001600160401b0382111715614f1857614f18615c78565b8060405250808385604086011115614f2f57600080fd5b60005b6002811015614f51578135835260209283019290910190600101614f32565b509195945050505050565b8035611f5c81615ca3565b600060c08284031215614f7957600080fd5b614f816159b9565b9050614f8c8261507b565b815260208083013581830152614fa460408401615067565b6040830152614fb560608401615067565b60608301526080830135614fc881615c8e565b608083015260a08301356001600160401b0380821115614fe757600080fd5b818501915085601f830112614ffb57600080fd5b81358181111561500d5761500d615c78565b61501f601f8201601f19168501615a04565b9150808252868482850101111561503557600080fd5b80848401858401376000848284010152508060a085015250505092915050565b803561ffff81168114611f5c57600080fd5b803563ffffffff81168114611f5c57600080fd5b80356001600160401b0381168114611f5c57600080fd5b803560ff81168114611f5c57600080fd5b805169ffffffffffffffffffff81168114611f5c57600080fd5b6000602082840312156150cf57600080fd5b813561104681615c8e565b600080604083850312156150ed57600080fd5b82356150f881615c8e565b9150602083013561510881615c8e565b809150509250929050565b6000806000806060858703121561512957600080fd5b843561513481615c8e565b93506020850135925060408501356001600160401b038082111561515757600080fd5b818701915087601f83011261516b57600080fd5b81358181111561517a57600080fd5b88602082850101111561518c57600080fd5b95989497505060200194505050565b6000604082840312156151ad57600080fd5b6110468383614ed4565b600080606083850312156151ca57600080fd5b6151d48484614ed4565b91506151e26040840161507b565b90509250929050565b6000604082840312156151fd57600080fd5b6110468383614ee5565b60006020828403121561521957600080fd5b815161104681615ca3565b60006020828403121561523657600080fd5b5035919050565b60006020828403121561524f57600080fd5b5051919050565b60006020828403121561526857600080fd5b604051602081018181106001600160401b038211171561528a5761528a615c78565b604052823561529881615ca3565b81529392505050565b60008060008385036101e08112156152b857600080fd5b6101a0808212156152c857600080fd5b6152d06159e1565b91506152dc8787614ee5565b82526152eb8760408801614ee5565b60208301526080860135604083015260a0860135606083015260c0860135608083015261531a60e08701614ec9565b60a083015261010061532e88828901614ee5565b60c0840152615341886101408901614ee5565b60e0840152610180870135908301529093508401356001600160401b0381111561536a57600080fd5b61537686828701614f67565b9250506153866101c08501614f5c565b90509250925092565b6000602082840312156153a157600080fd5b81356001600160401b038111156153b757600080fd5b820160c0818503121561104657600080fd5b6000602082840312156153db57600080fd5b61104682615055565b60008060008060008060008060006101208a8c03121561540357600080fd5b61540c8a615055565b985061541a60208b01615067565b975061542860408b01615067565b965061543660608b01615067565b955060808a0135945061544b60a08b01615067565b935061545960c08b01615067565b925061546760e08b01615092565b91506154766101008b01615092565b90509295985092959850929598565b6000806040838503121561549857600080fd5b82359150602083013561510881615c8e565b600080604083850312156154bd57600080fd5b50508035926020909101359150565b6000602082840312156154de57600080fd5b61104682615067565b600080600080600060a086880312156154ff57600080fd5b615508866150a3565b945060208601519350604086015192506060860151915061552b608087016150a3565b90509295509295909350565b600081518084526020808501945080840160005b838110156155705781516001600160a01b03168752958201959082019060010161554b565b509495945050505050565b8060005b6002811015612bf357815184526020938401939091019060010161557f565b600081518084526020808501945080840160005b83811015615570578151875295820195908201906001016155b2565b600081518084526155e6816020860160208601615b9e565b601f01601f19169290920160200192915050565b615604818361557b565b604001919050565b6000835161561e818460208801615b9e565b835190830190615632818360208801615b9e565b01949350505050565b86815261564b602082018761557b565b615658606082018661557b565b61566560a082018561557b565b61567260e082018461557b565b60609190911b6001600160601b0319166101208201526101340195945050505050565b8381526156a5602082018461557b565b606081019190915260800192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039290921682526001600160601b0316602082015260400190565b604081016126c1828461557b565b602081526000611046602083018461559e565b9182526001600160401b0316602082015260400190565b60208152600061104660208301846155ce565b6020815260ff82511660208201526020820151604082015260018060a01b0360408301511660608201526000606083015160c060808401526157af60e0840182615537565b60808501516001600160601b0390811660a0868101919091529095015190941660c0909301929092525090919050565b9182526001600160a01b0316602082015260400190565b82815260608101611046602083018461557b565b828152604060208201526000615823604083018461559e565b949350505050565b86815285602082015261ffff85166040820152600063ffffffff808616606084015280851660808401525060c060a08301526148b560c08301846155ce565b878152602081018790526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c082018190526000906158b6908301846155ce565b9998505050505050505050565b8781526001600160401b03871660208201526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c082018190526000906158b6908301846155ce565b6001600160601b038681168252851660208201526001600160401b03841660408201526001600160a01b038316606082015260a06080820181905260009061596190830184615537565b979650505050505050565b6000808335601e1984360301811261598357600080fd5b8301803591506001600160401b0382111561599d57600080fd5b6020019150368190038213156159b257600080fd5b9250929050565b60405160c081016001600160401b03811182821017156159db576159db615c78565b60405290565b60405161012081016001600160401b03811182821017156159db576159db615c78565b604051601f8201601f191681016001600160401b0381118282101715615a2c57615a2c615c78565b604052919050565b60008085851115615a4457600080fd5b83861115615a5157600080fd5b5050820193919092039150565b60008219821115615a7157615a71615c20565b500190565b60006001600160401b0380831681851680830382111561563257615632615c20565b600060ff821660ff84168060ff03821115615ab557615ab5615c20565b019392505050565b60006001600160601b0382811684821680830382111561563257615632615c20565b600082615aee57615aee615c36565b500490565b6000816000190483118215151615615b0d57615b0d615c20565b500290565b600082821015615b2457615b24615c20565b500390565b600063ffffffff83811690831681811015615b4657615b46615c20565b039392505050565b60006001600160601b0383811690831681811015615b4657615b46615c20565b6001600160e01b03198135818116916004851015615b965780818660040360031b1b83161692505b505092915050565b60005b83811015615bb9578181015183820152602001615ba1565b83811115612bf35750506000910152565b6000600019821415615bde57615bde615c20565b5060010190565b60006001600160401b0380831681811415615c0257615c02615c20565b6001019392505050565b600082615c1b57615c1b615c36565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610a5957600080fd5b8015158114610a5957600080fdfe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000806000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"blockhashStore\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"internalBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"externalBalance\",\"type\":\"uint256\"}],\"name\":\"BalanceInvariantViolated\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"BlockhashNotInStore\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorNotRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToSendNative\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToTransferLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"GasLimitTooBig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"gasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxGas\",\"type\":\"uint256\"}],\"name\":\"GasPriceExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectCommitment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidExtraArgsTag\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"premiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"max\",\"type\":\"uint8\"}],\"name\":\"InvalidPremiumPercentage\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"have\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"min\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"max\",\"type\":\"uint16\"}],\"name\":\"InvalidRequestConfirmations\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkAlreadySet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"flatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeNativePPM\",\"type\":\"uint32\"}],\"name\":\"LinkDiscountTooHigh\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkNotSet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"have\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"max\",\"type\":\"uint32\"}],\"name\":\"MsgDataTooBig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"}],\"name\":\"MustBeRequestedOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoCorrespondingRequest\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"NoSuchProvingKey\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"NumWordsTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PendingRequestExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"ProvingKeyAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Reentrant\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyConsumers\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"nativePremiumPercentage\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"linkPremiumPercentage\",\"type\":\"uint8\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorDeregistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"}],\"name\":\"FallbackWeiPerUnitLinkUsed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"MigrationCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"NativeFundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"maxGas\",\"type\":\"uint64\"}],\"name\":\"ProvingKeyDeregistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"maxGas\",\"type\":\"uint64\"}],\"name\":\"ProvingKeyRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"outputSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"payment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"nativePayment\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"onlyPremium\",\"type\":\"bool\"}],\"name\":\"RandomWordsFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"preSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RandomWordsRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountLink\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountNative\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldNativeBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newNativeBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFundedWithNative\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BLOCKHASH_STORE\",\"outputs\":[{\"internalType\":\"contractBlockhashStoreInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK_NATIVE_FEED\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_CONSUMERS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_NUM_WORDS\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_REQUEST_CONFIRMATIONS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"deregisterMigratableCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"}],\"name\":\"deregisterProvingKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256[2]\",\"name\":\"pk\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"gamma\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"c\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"s\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"uWitness\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"cGammaWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"sHashWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"zInv\",\"type\":\"uint256\"}],\"internalType\":\"structVRF.Proof\",\"name\":\"proof\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"blockNum\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFTypes.RequestCommitmentV2Plus\",\"name\":\"rc\",\"type\":\"tuple\"},{\"internalType\":\"bool\",\"name\":\"onlyPremium\",\"type\":\"bool\"}],\"name\":\"fulfillRandomWords\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"payment\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"fundSubscriptionWithNative\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveSubscriptionIds\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"getSubscription\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"nativeBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint64\",\"name\":\"reqCount\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"subOwner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicKey\",\"type\":\"uint256[2]\"}],\"name\":\"hashOfKey\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"}],\"name\":\"migrate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"ownerCancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"pendingRequestExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverNativeFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"registerMigratableCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint64\",\"name\":\"maxGas\",\"type\":\"uint64\"}],\"name\":\"registerProvingKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFV2PlusClient.RandomWordsRequest\",\"name\":\"req\",\"type\":\"tuple\"}],\"name\":\"requestRandomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"requestSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_config\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"reentrancyLock\",\"type\":\"bool\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"nativePremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"linkPremiumPercentage\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_currentSubNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fallbackWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_provingKeyHashes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_provingKeys\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"exists\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"maxGas\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requestCommitments\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalNativeBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"nativePremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"linkPremiumPercentage\",\"type\":\"uint8\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkNativeFeed\",\"type\":\"address\"}],\"name\":\"setLINKAndLINKNativeFeed\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"withdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60a06040523480156200001157600080fd5b5060405162005ff138038062005ff183398101604081905262000034916200017e565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d3565b5050506001600160a01b0316608052620001b0565b336001600160a01b038216036200012d5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019157600080fd5b81516001600160a01b0381168114620001a957600080fd5b9392505050565b608051615e1e620001d3600039600081816105d201526134d00152615e1e6000f3fe60806040526004361061028c5760003560e01c80638402595e11610164578063b2a7cac5116100c6578063da2f26101161008a578063e72f6e3011610064578063e72f6e3014610904578063ee9d2d3814610924578063f2fde38b1461095157600080fd5b8063da2f261014610854578063dac83d29146108b3578063dc311dd3146108d357600080fd5b8063b2a7cac5146107b4578063bec4c08c146107d4578063caf70c4a146107f4578063cb63179714610814578063d98e620e1461083457600080fd5b80639d40a6fd11610128578063a63e0bfb11610102578063a63e0bfb14610747578063aa433aff14610767578063aefb212f1461078757600080fd5b80639d40a6fd146106da578063a21a23e414610712578063a4c0ed361461072757600080fd5b80638402595e1461064957806386fe91c7146106695780638da5cb5b1461068957806395b55cfc146106a75780639b1c385e146106ba57600080fd5b8063405b84fa1161020d57806364d51a2a116101d157806372e9d565116101ab57806372e9d565146105f457806379ba5097146106145780637a5a2aef1461062957600080fd5b806364d51a2a1461058b57806365982744146105a0578063689c4517146105c057600080fd5b8063405b84fa146104d057806340d6bb82146104f057806341af6c871461051b57806351cff8d91461054b5780635d06b4ab1461056b57600080fd5b806315c48b841161025457806315c48b84146103f157806318e3dd27146104195780631b6b6d23146104585780632f622e6b14610490578063301f42e9146104b057600080fd5b806304104edb14610291578063043bd6ae146102b3578063088070f5146102dc57806308821d58146103b15780630ae09540146103d1575b600080fd5b34801561029d57600080fd5b506102b16102ac3660046150af565b610971565b005b3480156102bf57600080fd5b506102c960105481565b6040519081526020015b60405180910390f35b3480156102e857600080fd5b50600c546103549061ffff81169063ffffffff62010000820481169160ff660100000000000082048116926701000000000000008304811692600160581b8104821692600160781b8204831692600160981b83041691600160b81b8104821691600160c01b9091041689565b6040805161ffff909a168a5263ffffffff98891660208b01529615159689019690965293861660608801529185166080870152841660a08601529290921660c084015260ff91821660e084015216610100820152610120016102d3565b3480156103bd57600080fd5b506102b16103cc3660046150dd565b610aea565b3480156103dd57600080fd5b506102b16103ec3660046150f9565b610ca7565b3480156103fd57600080fd5b5061040660c881565b60405161ffff90911681526020016102d3565b34801561042557600080fd5b50600a5461044090600160601b90046001600160601b031681565b6040516001600160601b0390911681526020016102d3565b34801561046457600080fd5b50600254610478906001600160a01b031681565b6040516001600160a01b0390911681526020016102d3565b34801561049c57600080fd5b506102b16104ab3660046150af565b610cef565b3480156104bc57600080fd5b506104406104cb36600461535b565b610e3e565b3480156104dc57600080fd5b506102b16104eb3660046150f9565b611154565b3480156104fc57600080fd5b506105066101f481565b60405163ffffffff90911681526020016102d3565b34801561052757600080fd5b5061053b610536366004615449565b611536565b60405190151581526020016102d3565b34801561055757600080fd5b506102b16105663660046150af565b6115ea565b34801561057757600080fd5b506102b16105863660046150af565b61176c565b34801561059757600080fd5b50610406606481565b3480156105ac57600080fd5b506102b16105bb366004615462565b61182a565b3480156105cc57600080fd5b506104787f000000000000000000000000000000000000000000000000000000000000000081565b34801561060057600080fd5b50600354610478906001600160a01b031681565b34801561062057600080fd5b506102b161188a565b34801561063557600080fd5b506102b1610644366004615490565b61193b565b34801561065557600080fd5b506102b16106643660046150af565b611a6f565b34801561067557600080fd5b50600a54610440906001600160601b031681565b34801561069557600080fd5b506000546001600160a01b0316610478565b6102b16106b5366004615449565b611b8a565b3480156106c657600080fd5b506102c96106d53660046154c4565b611cae565b3480156106e657600080fd5b506007546106fa906001600160401b031681565b6040516001600160401b0390911681526020016102d3565b34801561071e57600080fd5b506102c96120f4565b34801561073357600080fd5b506102b16107423660046154fe565b6122db565b34801561075357600080fd5b506102b16107623660046155a9565b612457565b34801561077357600080fd5b506102b1610782366004615449565b61273e565b34801561079357600080fd5b506107a76107a236600461564a565b612786565b6040516102d391906156a7565b3480156107c057600080fd5b506102b16107cf366004615449565b612888565b3480156107e057600080fd5b506102b16107ef3660046150f9565b61298c565b34801561080057600080fd5b506102c961080f3660046156ba565b612a7f565b34801561082057600080fd5b506102b161082f3660046150f9565b612aaf565b34801561084057600080fd5b506102c961084f366004615449565b612d1d565b34801561086057600080fd5b5061089461086f366004615449565b600d6020526000908152604090205460ff81169061010090046001600160401b031682565b6040805192151583526001600160401b039091166020830152016102d3565b3480156108bf57600080fd5b506102b16108ce3660046150f9565b612d3e565b3480156108df57600080fd5b506108f36108ee366004615449565b612dd8565b6040516102d395949392919061570f565b34801561091057600080fd5b506102b161091f3660046150af565b612ec6565b34801561093057600080fd5b506102c961093f366004615449565b600f6020526000908152604090205481565b34801561095d57600080fd5b506102b161096c3660046150af565b613087565b610979613098565b60115460005b81811015610abd57826001600160a01b0316601182815481106109a4576109a4615764565b6000918252602090912001546001600160a01b031603610aad5760116109cb600184615790565b815481106109db576109db615764565b600091825260209091200154601180546001600160a01b039092169183908110610a0757610a07615764565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506011805480610a4657610a466157a3565b6000828152602090819020600019908301810180546001600160a01b03191690559091019091556040516001600160a01b03851681527ff80a1a97fd42251f3c33cda98635e7399253033a6774fe37cd3f650b5282af3791015b60405180910390a1505050565b610ab6816157b9565b905061097f565b50604051635428d44960e01b81526001600160a01b03831660048201526024015b60405180910390fd5b50565b610af2613098565b604080518082018252600091610b21919084906002908390839080828437600092019190915250612a7f915050565b6000818152600d602090815260409182902082518084019093525460ff811615158084526101009091046001600160401b03169183019190915291925090610b7f57604051631dfd6e1360e21b815260048101839052602401610ade565b6000828152600d60205260408120805468ffffffffffffffffff19169055600e54905b81811015610c515783600e8281548110610bbe57610bbe615764565b906000526020600020015403610c4157600e610bdb600184615790565b81548110610beb57610beb615764565b9060005260206000200154600e8281548110610c0957610c09615764565b600091825260209091200155600e805480610c2657610c266157a3565b60019003818190600052602060002001600090559055610c51565b610c4a816157b9565b9050610ba2565b507f9b6868e0eb737bcd72205360baa6bfd0ba4e4819a33ade2db384e8a8025639a5838360200151604051610c999291909182526001600160401b0316602082015260400190565b60405180910390a150505050565b81610cb1816130f4565b610cb961315e565b610cc283611536565b15610ce057604051631685ecdd60e31b815260040160405180910390fd5b610cea838361318c565b505050565b610cf761315e565b610cff613098565b600b54600160601b90046001600160601b0316600003610d3257604051631e9acf1760e31b815260040160405180910390fd5b600b8054600160601b90046001600160601b0316908190600c610d5583806157d2565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a600c8282829054906101000a90046001600160601b0316610d9d91906157d2565b92506101000a8154816001600160601b0302191690836001600160601b031602179055506000826001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114610e17576040519150601f19603f3d011682016040523d82523d6000602084013e610e1c565b606091505b5050905080610cea5760405163950b247960e01b815260040160405180910390fd5b6000610e4861315e565b60005a9050610324361115610e7a57604051630f28961b60e01b81523660048201526103246024820152604401610ade565b6000610e868686613332565b90506000610e9c858360000151602001516135e3565b60408301516060888101519293509163ffffffff16806001600160401b03811115610ec957610ec9615129565b604051908082528060200260200182016040528015610ef2578160200160208202803683370190505b50925060005b81811015610f5a5760408051602081018590529081018290526060016040516020818303038152906040528051906020012060001c848281518110610f3f57610f3f615764565b6020908102919091010152610f53816157b9565b9050610ef8565b5050602080850180516000908152600f9092526040822082905551610f80908a8561363e565b60208a8101516000908152600690915260409020805491925090601890610fb690600160c01b90046001600160401b03166157f2565b82546101009290920a6001600160401b0381810219909316918316021790915560808a01516001600160a01b03166000908152600460209081526040808320828e0151845290915290208054909160099161101991600160481b90910416615818565b91906101000a8154816001600160401b0302191690836001600160401b0316021790555060008960a0015160018b60a00151516110569190615790565b8151811061106657611066615764565b60209101015160f81c600114905060006110828887848d6136e2565b909950905080156110cd5760208088015160105460408051928352928201527f6ca648a381f22ead7e37773d934e64885dcf861fbfbb26c40354cbf0c4662d1a910160405180910390a15b506110dd88828c6020015161371a565b6020808b015187820151604080518781526001600160601b038d16948101949094528415159084015284151560608401528b1515608084015290917faeb4b4786571e184246d39587f659abf0e26f41f6a3358692250382c0cdb47b79060a00160405180910390a3505050505050505b9392505050565b61115c61315e565b61116581613887565b61118d57604051635428d44960e01b81526001600160a01b0382166004820152602401610ade565b60008060008061119c86612dd8565b945094505093509350336001600160a01b0316826001600160a01b0316146112065760405162461bcd60e51b815260206004820152601660248201527f4e6f7420737562736372697074696f6e206f776e6572000000000000000000006044820152606401610ade565b61120f86611536565b1561125c5760405162461bcd60e51b815260206004820152601660248201527f50656e64696e67207265717565737420657869737473000000000000000000006044820152606401610ade565b6040805160c0810182526001815260208082018990526001600160a01b03851682840152606082018490526001600160601b038088166080840152861660a0830152915190916000916112b19184910161583b565b60405160208183030381529060405290506112cb886138f2565b505060405163ce3f471960e01b81526001600160a01b0388169063ce3f4719906001600160601b03881690611304908590600401615900565b6000604051808303818588803b15801561131d57600080fd5b505af1158015611331573d6000803e3d6000fd5b50506002546001600160a01b03161580159350915061135a905057506001600160601b03861615155b1561142a5760025460405163a9059cbb60e01b81526001600160a01b0389811660048301526001600160601b03891660248301529091169063a9059cbb906044016020604051808303816000875af11580156113ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113de9190615913565b61142a5760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742066756e647300000000000000000000000000006044820152606401610ade565b600c805466ff0000000000001916660100000000000017905560005b83518110156114d95783818151811061146157611461615764565b6020908102919091010151604051638ea9811760e01b81526001600160a01b038a8116600483015290911690638ea9811790602401600060405180830381600087803b1580156114b057600080fd5b505af11580156114c4573d6000803e3d6000fd5b50505050806114d2906157b9565b9050611446565b50600c805466ff00000000000019169055604080516001600160a01b0389168152602081018a90527fd63ca8cb945956747ee69bfdc3ea754c24a4caf7418db70e46052f7850be4187910160405180910390a15050505050505050565b6000818152600560205260408120600201805480830361155a575060009392505050565b60005b818110156115df5760006004600085848154811061157d5761157d615764565b60009182526020808320909101546001600160a01b0316835282810193909352604091820181208982529092529020546001600160401b03600160481b9091041611156115cf57506001949350505050565b6115d8816157b9565b905061155d565b506000949350505050565b6115f261315e565b6115fa613098565b6002546001600160a01b03166116235760405163c1f0c0a160e01b815260040160405180910390fd5b600b546001600160601b031660000361164f57604051631e9acf1760e31b815260040160405180910390fd5b600b80546001600160601b0316908190600061166b83806157d2565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a60008282829054906101000a90046001600160601b03166116b391906157d2565b82546101009290920a6001600160601b0381810219909316918316021790915560025460405163a9059cbb60e01b81526001600160a01b03868116600483015292851660248201529116915063a9059cbb906044016020604051808303816000875af1158015611727573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061174b9190615913565b61176857604051631e9acf1760e31b815260040160405180910390fd5b5050565b611774613098565b61177d81613887565b156117a65760405163ac8a27ef60e01b81526001600160a01b0382166004820152602401610ade565b601180546001810182556000919091527f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c680180546001600160a01b0319166001600160a01b0383169081179091556040519081527fb7cabbfc11e66731fc77de0444614282023bcbd41d16781c753a431d0af016259060200160405180910390a150565b611832613098565b6002546001600160a01b03161561185c57604051631688c53760e11b815260040160405180910390fd5b600280546001600160a01b039384166001600160a01b03199182161790915560038054929093169116179055565b6001546001600160a01b031633146118e45760405162461bcd60e51b815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610ade565b60008054336001600160a01b0319808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b611943613098565b604080518082018252600091611972919085906002908390839080828437600092019190915250612a7f915050565b6000818152600d602052604090205490915060ff16156119a857604051634a0b8fa760e01b815260048101829052602401610ade565b60408051808201825260018082526001600160401b0385811660208085018281526000888152600d835287812096518754925168ffffffffffffffffff1990931690151568ffffffffffffffff00191617610100929095169190910293909317909455600e805493840181559091527fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd9091018490558251848152918201527f9b911b2c240bfbef3b6a8f7ed6ee321d1258bb2a3fe6becab52ac1cd3210afd39101610aa0565b611a77613098565b600a544790600160601b90046001600160601b031681811115611ab7576040516354ced18160e11b81526004810182905260248101839052604401610ade565b81811015610cea576000611acb8284615790565b90506000846001600160a01b03168260405160006040518083038185875af1925050503d8060008114611b1a576040519150601f19603f3d011682016040523d82523d6000602084013e611b1f565b606091505b5050905080611b415760405163950b247960e01b815260040160405180910390fd5b604080516001600160a01b0387168152602081018490527f4aed7c8eed0496c8c19ea2681fcca25741c1602342e38b045d9f1e8e905d2e9c910160405180910390a15050505050565b611b9261315e565b6000818152600560205260409020546001600160a01b0316611bc757604051630fb532db60e11b815260040160405180910390fd5b60008181526006602052604090208054600160601b90046001600160601b0316903490600c611bf68385615930565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555034600a600c8282829054906101000a90046001600160601b0316611c3e9190615930565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f7603b205d03651ee812f803fccde89f1012e545a9c99f0abfea9cedd0fd8e902823484611c919190615950565b604080519283526020830191909152015b60405180910390a25050565b6000611cb861315e565b602080830135600081815260059092526040909120546001600160a01b0316611cf457604051630fb532db60e11b815260040160405180910390fd5b336000908152600460209081526040808320848452808352928190208151606081018352905460ff811615158083526001600160401b036101008304811695840195909552600160481b9091049093169181019190915290611d72576040516379bfd40160e01b815260048101849052336024820152604401610ade565b600c5461ffff16611d896060870160408801615963565b61ffff161080611dac575060c8611da66060870160408801615963565b61ffff16115b15611df257611dc16060860160408701615963565b600c5460405163539c34bb60e11b815261ffff92831660048201529116602482015260c86044820152606401610ade565b600c5462010000900463ffffffff16611e11608087016060880161597e565b63ffffffff161115611e6157611e2d608086016060870161597e565b600c54604051637aebf00f60e11b815263ffffffff9283166004820152620100009091049091166024820152604401610ade565b6101f4611e7460a087016080880161597e565b63ffffffff161115611eba57611e9060a086016080870161597e565b6040516311ce1afb60e21b815263ffffffff90911660048201526101f46024820152604401610ade565b806020018051611ec9906157f2565b6001600160401b03169052604081018051611ee3906157f2565b6001600160401b03908116909152602082810151604080518935818501819052338284015260608201899052929094166080808601919091528151808603909101815260a08501825280519084012060c085019290925260e08085018390528151808603909101815261010090940190528251929091019190912060009190955090506000611f85611f80611f7b60a08a018a615999565b613aa4565b613b25565b905085611f90613b96565b86611fa160808b0160608c0161597e565b611fb160a08c0160808d0161597e565b3386604051602001611fc997969594939291906159e6565b60405160208183030381529060405280519060200120600f600088815260200190815260200160002081905550336001600160a01b03168588600001357feb0e3652e0f44f417695e6e90f2f42c99b65cd7169074c5a654b16b9748c3a4e89868c604001602081019061203c9190615963565b8d606001602081019061204f919061597e565b8e6080016020810190612062919061597e565b8960405161207596959493929190615a3d565b60405180910390a45050600092835260209182526040928390208151815493830151929094015168ffffffffffffffffff1990931693151568ffffffffffffffff001916939093176101006001600160401b03928316021770ffffffffffffffff0000000000000000001916600160481b91909216021790555b919050565b60006120fe61315e565b6007546001600160401b031633612116600143615790565b6040516bffffffffffffffffffffffff19606093841b81166020830152914060348201523090921b1660548201526001600160c01b031960c083901b16606882015260700160408051601f1981840301815291905280516020909101209150612180816001615a7c565b6007805467ffffffffffffffff19166001600160401b03928316179055604080516000808252608082018352602080830182815283850183815260608086018581528a86526006855287862093518454935191516001600160601b039182166001600160c01b031990951694909417600160601b91909216021777ffffffffffffffffffffffffffffffffffffffffffffffff16600160c01b9290981691909102969096179055835194850184523385528481018281528585018481528884526005835294909220855181546001600160a01b03199081166001600160a01b0392831617835593516001830180549095169116179092559251805192949391926122909260028501920190614f9d565b506122a091506008905084613c17565b5060405133815283907f1d3015d7ba850fa198dc7b1a3f5d42779313a681035f77c8c03764c61005518d9060200160405180910390a2505090565b6122e361315e565b6002546001600160a01b0316331461230e576040516344b0e3c360e01b815260040160405180910390fd5b6020811461232f57604051638129bbcd60e01b815260040160405180910390fd5b600061233d82840184615449565b6000818152600560205260409020549091506001600160a01b031661237557604051630fb532db60e11b815260040160405180910390fd5b600081815260066020526040812080546001600160601b03169186919061239c8385615930565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555084600a60008282829054906101000a90046001600160601b03166123e49190615930565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f1ced9348ff549fceab2ac57cd3a9de38edaaab274b725ee82c23e8fc8c4eec7a8287846124379190615950565b6040805192835260208301919091520160405180910390a2505050505050565b61245f613098565b60c861ffff8a1611156124995760405163539c34bb60e11b815261ffff8a1660048201819052602482015260c86044820152606401610ade565b600085136124bd576040516321ea67b360e11b815260048101869052602401610ade565b8363ffffffff168363ffffffff1611156124fa576040516313c06e5960e11b815263ffffffff808516600483015285166024820152604401610ade565b609b60ff8316111561252b57604051631d66288d60e11b815260ff83166004820152609b6024820152604401610ade565b609b60ff8216111561255c57604051631d66288d60e11b815260ff82166004820152609b6024820152604401610ade565b604080516101208101825261ffff8b1680825263ffffffff808c16602084018190526000848601528b8216606085018190528b8316608086018190528a841660a08701819052938a1660c0870181905260ff808b1660e08901819052908a16610100909801889052600c8054600160c01b90990260ff60c01b19600160b81b9093029290921661ffff60b81b19600160981b90940263ffffffff60981b19600160781b9099029890981676ffffffffffffffff00000000000000000000000000000019600160581b9096026effffffff000000000000000000000019670100000000000000909802979097166effffffffffffffffff000000000000196201000090990265ffffffffffff19909c16909a179a909a1796909616979097179390931791909116959095179290921793909316929092179190911790556010869055517f2c6b6b12413678366b05b145c5f00745bdd00e739131ab5de82484a50c9d78b69061272b908b908b908b908b908b908b908b908b908b9061ffff99909916895263ffffffff97881660208a0152958716604089015293861660608801526080870192909252841660a086015290921660c084015260ff91821660e0840152166101008201526101200190565b60405180910390a1505050505050505050565b612746613098565b6000818152600560205260409020546001600160a01b03168061277c57604051630fb532db60e11b815260040160405180910390fd5b611768828261318c565b606060006127946008613c23565b90508084106127b657604051631390f2a160e01b815260040160405180910390fd5b60006127c28486615950565b9050818111806127d0575083155b6127da57806127dc565b815b905060006127ea8683615790565b9050806001600160401b0381111561280457612804615129565b60405190808252806020026020018201604052801561282d578160200160208202803683370190505b50935060005b8181101561287d576128506128488883615950565b600890613c2d565b85828151811061286257612862615764565b6020908102919091010152612876816157b9565b9050612833565b505050505b92915050565b61289061315e565b6000818152600560205260409020546001600160a01b0316806128c657604051630fb532db60e11b815260040160405180910390fd5b6000828152600560205260409020600101546001600160a01b0316331461291f576000828152600560205260409081902060010154905163d084e97560e01b81526001600160a01b039091166004820152602401610ade565b6000828152600560209081526040918290208054336001600160a01b03199182168117835560019092018054909116905582516001600160a01b03851681529182015283917fd4114ab6e9af9f597c52041f32d62dc57c5c4e4c0d4427006069635e216c93869101611ca2565b81612996816130f4565b61299e61315e565b6001600160a01b03821660009081526004602090815260408083208684529091529020805460ff16156129d15750505050565b6000848152600560205260409020600201805460631901612a05576040516305a48e0f60e01b815260040160405180910390fd5b8154600160ff199091168117835581549081018255600082815260209081902090910180546001600160a01b0319166001600160a01b03871690811790915560405190815286917f1e980d04aa7648e205713e5e8ea3808672ac163d10936d36f91b2c88ac1575e191015b60405180910390a25050505050565b600081604051602001612a929190615abf565b604051602081830303815290604052805190602001209050919050565b81612ab9816130f4565b612ac161315e565b612aca83611536565b15612ae857604051631685ecdd60e31b815260040160405180910390fd5b6001600160a01b038216600090815260046020908152604080832086845290915290205460ff16612b3e576040516379bfd40160e01b8152600481018490526001600160a01b0383166024820152604401610ade565b600083815260056020908152604080832060020180548251818502810185019093528083529192909190830182828015612ba157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612b83575b50505050509050600060018251612bb89190615790565b905060005b8251811015612cc157846001600160a01b0316838281518110612be257612be2615764565b60200260200101516001600160a01b031603612cb1576000838381518110612c0c57612c0c615764565b6020026020010151905080600560008981526020019081526020016000206002018381548110612c3e57612c3e615764565b600091825260208083209190910180546001600160a01b0319166001600160a01b039490941693909317909255888152600590915260409020600201805480612c8957612c896157a3565b600082815260209020810160001990810180546001600160a01b031916905501905550612cc1565b612cba816157b9565b9050612bbd565b506001600160a01b0384166000818152600460209081526040808320898452825291829020805460ff19169055905191825286917f32158c6058347c1601b2d12bc696ac6901d8a9a9aa3ba10c27ab0a983e8425a79101612a70565b600e8181548110612d2d57600080fd5b600091825260209091200154905081565b81612d48816130f4565b612d5061315e565b600083815260056020526040902060018101546001600160a01b03848116911614612dd2576001810180546001600160a01b0319166001600160a01b03851690811790915560408051338152602081019290925285917f21a4dad170a6bf476c31bbcf4a16628295b0e450672eec25d7c93308e05344a1910160405180910390a25b50505050565b600081815260056020526040812054819081906001600160a01b0316606081612e1457604051630fb532db60e11b815260040160405180910390fd5b600086815260066020908152604080832054600583529281902060020180548251818502810185019093528083526001600160601b0380861695600160601b810490911694600160c01b9091046001600160401b0316938893929091839190830182828015612eac57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612e8e575b505050505090509450945094509450945091939590929450565b612ece613098565b6002546001600160a01b0316612ef75760405163c1f0c0a160e01b815260040160405180910390fd5b6002546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015612f40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f649190615acd565b600a549091506001600160601b031681811115612f9e576040516354ced18160e11b81526004810182905260248101839052604401610ade565b81811015610cea576000612fb28284615790565b60025460405163a9059cbb60e01b81526001600160a01b0387811660048301526024820184905292935091169063a9059cbb906044016020604051808303816000875af1158015613007573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061302b9190615913565b61304857604051631f01ff1360e21b815260040160405180910390fd5b604080516001600160a01b0386168152602081018390527f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b4366009101610c99565b61308f613098565b610ae781613c39565b6000546001600160a01b031633146130f25760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610ade565b565b6000818152600560205260409020546001600160a01b03168061312a57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b0382161461176857604051636c51fda960e11b81526001600160a01b0382166004820152602401610ade565b600c546601000000000000900460ff16156130f25760405163769dd35360e11b815260040160405180910390fd5b600080613198846138f2565b60025491935091506001600160a01b0316158015906131bf57506001600160601b03821615155b156132605760025460405163a9059cbb60e01b81526001600160a01b0385811660048301526001600160601b03851660248301529091169063a9059cbb906044016020604051808303816000875af115801561321f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132439190615913565b61326057604051631e9acf1760e31b815260040160405180910390fd5b6000836001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d80600081146132b6576040519150601f19603f3d011682016040523d82523d6000602084013e6132bb565b606091505b50509050806132dd5760405163950b247960e01b815260040160405180910390fd5b604080516001600160a01b03861681526001600160601b03808616602083015284169181019190915285907f8c74ce8b8cf87f5eb001275c8be27eb34ea2b62bfab6814fcc62192bb63e81c490606001612a70565b6040805160a0810182526000606082018181526080830182905282526020820181905291810191909152600061336b8460000151612a7f565b6000818152600d602090815260409182902082518084019093525460ff811615158084526101009091046001600160401b031691830191909152919250906133c957604051631dfd6e1360e21b815260048101839052602401610ade565b60008286608001516040516020016133eb929190918252602082015260400190565b60408051601f1981840301815291815281516020928301206000818152600f909352908220549092509081900361343557604051631b44092560e11b815260040160405180910390fd5b85516020808801516040808a015160608b015160808c015160a08d01519351613464978a979096959101615ae6565b6040516020818303038152906040528051906020012081146134995760405163354a450b60e21b815260040160405180910390fd5b60006134a88760000151613ce2565b905080613571578651604051631d2827a760e31b81526001600160401b0390911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e9413d3890602401602060405180830381865afa15801561351f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135439190615acd565b90508061357157865160405163175dadad60e01b81526001600160401b039091166004820152602401610ade565b6000886080015182604051602001613593929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c905060006135ba8a83613db5565b604080516060810182529788526020880196909652948601949094525092979650505050505050565b6000816001600160401b03163a111561363657821561360c57506001600160401b038116612882565b60405163435e532d60e11b81523a60048201526001600160401b0383166024820152604401610ade565b503a92915050565b6000806000631fe543e360e01b868560405160240161365e929190615b39565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252600c805466ff000000000000191666010000000000001790559086015160808701519192506136c89163ffffffff9091169083613e20565b600c805466ff000000000000191690559695505050505050565b6000808315613701576136f6868685613e6c565b600091509150613711565b61370c868685613f7d565b915091505b94509492505050565b600081815260066020526040902082156137ee5780546001600160601b03600160601b909104811690851681101561376557604051631e9acf1760e31b815260040160405180910390fd5b61376f85826157d2565b82547fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff16600160601b6001600160601b039283168102919091178455600b805488939192600c926137c4928692900416615930565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555050612dd2565b80546001600160601b0390811690851681101561381e57604051631e9acf1760e31b815260040160405180910390fd5b61382885826157d2565b82546bffffffffffffffffffffffff19166001600160601b03918216178355600b8054879260009161385c91859116615930565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505050505050565b601154600090815b818110156138e857836001600160a01b0316601182815481106138b4576138b4615764565b6000918252602090912001546001600160a01b0316036138d8575060019392505050565b6138e1816157b9565b905061388f565b5060009392505050565b60008181526005602090815260408083206006909252822054600290910180546001600160601b0380841694600160601b90940416925b8181101561399e576004600084838154811061394757613947615764565b60009182526020808320909101546001600160a01b0316835282810193909352604091820181208982529092529020805470ffffffffffffffffffffffffffffffffff19169055613997816157b9565b9050613929565b50600085815260056020526040812080546001600160a01b031990811682556001820180549091169055906139d66002830182615002565b50506000858152600660205260408120556139f260088661416f565b506001600160601b03841615613a4557600a8054859190600090613a209084906001600160601b03166157d2565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b6001600160601b03831615613a9d5782600a600c8282829054906101000a90046001600160601b0316613a7891906157d2565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b5050915091565b6040805160208101909152600081526000829003613ad15750604080516020810190915260008152612882565b63125fa26760e31b613ae38385615b5a565b6001600160e01b03191614613b0b57604051632923fee760e11b815260040160405180910390fd5b613b188260048186615b8a565b81019061114d9190615bb4565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401613b5e91511515815260200190565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915292915050565b600046613ba28161417b565b15613c105760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613be6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c0a9190615acd565b91505090565b4391505090565b600061114d838361419e565b6000612882825490565b600061114d83836141ed565b336001600160a01b03821603613c915760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610ade565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600046613cee8161417b565b15613da657610100836001600160401b0316613d08613b96565b613d129190615790565b1180613d2e5750613d21613b96565b836001600160401b031610155b15613d3c5750600092915050565b6040516315a03d4160e11b81526001600160401b0384166004820152606490632b407a82906024015b602060405180830381865afa158015613d82573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061114d9190615acd565b50506001600160401b03164090565b6000613de98360000151846020015185604001518660600151868860a001518960c001518a60e001518b6101000151614217565b60038360200151604051602001613e01929190615bff565b60408051601f1981840301815291905280516020909101209392505050565b60005a611388811015613e3257600080fd5b611388810390508460408204820311613e4a57600080fd5b50823b613e5657600080fd5b60008083516020850160008789f1949350505050565b600080613eaf6000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061444292505050565b905060005a600c54613ecf908890600160581b900463ffffffff16615950565b613ed99190615790565b613ee39086615c13565b600c54909150600090613f0890600160781b900463ffffffff1664e8d4a51000615c13565b90508415613f5457600c548190606490600160b81b900460ff16613f2c8587615950565b613f369190615c13565b613f409190615c40565b613f4a9190615950565b935050505061114d565b600c548190606490613f7090600160b81b900460ff1682615c54565b60ff16613f2c8587615950565b600080600080613f8b614522565b9150915060008213613fb3576040516321ea67b360e11b815260048101839052602401610ade565b6000613ff56000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061444292505050565b9050600083825a600c54614017908d90600160581b900463ffffffff16615950565b6140219190615790565b61402b908b615c13565b6140359190615950565b61404790670de0b6b3a7640000615c13565b6140519190615c40565b600c5490915060009061407a9063ffffffff600160981b8204811691600160781b900416615c6d565b61408f9063ffffffff1664e8d4a51000615c13565b90506000856140a683670de0b6b3a7640000615c13565b6140b09190615c40565b9050600089156140f157600c5482906064906140d690600160c01b900460ff1687615c13565b6140e09190615c40565b6140ea9190615950565b9050614131565b600c54829060649061410d90600160c01b900460ff1682615c54565b61411a9060ff1687615c13565b6141249190615c40565b61412e9190615950565b90505b6b033b2e3c9fd0803ce800000081111561415e5760405163e80fa38160e01b815260040160405180910390fd5b9b949a509398505050505050505050565b600061114d83836145ed565b600061a4b182148061418f575062066eed82145b8061288257505062066eee1490565b60008181526001830160205260408120546141e557508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155612882565b506000612882565b600082600001828154811061420457614204615764565b9060005260206000200154905092915050565b614220896146e7565b61426c5760405162461bcd60e51b815260206004820152601a60248201527f7075626c6963206b6579206973206e6f74206f6e2063757276650000000000006044820152606401610ade565b614275886146e7565b6142c15760405162461bcd60e51b815260206004820152601560248201527f67616d6d61206973206e6f74206f6e20637572766500000000000000000000006044820152606401610ade565b6142ca836146e7565b6143165760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e2063757276650000006044820152606401610ade565b61431f826146e7565b61436b5760405162461bcd60e51b815260206004820152601c60248201527f73486173685769746e657373206973206e6f74206f6e206375727665000000006044820152606401610ade565b614377878a88876147c0565b6143c35760405162461bcd60e51b815260206004820152601960248201527f6164647228632a706b2b732a6729213d5f755769746e657373000000000000006044820152606401610ade565b60006143cf8a876148e3565b905060006143e2898b878b868989614947565b905060006143f3838d8d8a86614a73565b9050808a146144345760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606401610ade565b505050505050505050505050565b60004661444e8161417b565b1561449257606c6001600160a01b031663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613d82573d6000803e3d6000fd5b61449b81614ab3565b156145195773420000000000000000000000000000000000000f6001600160a01b03166349948e0e84604051806080016040528060488152602001615dca604891396040516020016144ee929190615c8a565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401613d659190615900565b50600092915050565b600c5460035460408051633fabe5a360e21b81529051600093849367010000000000000090910463ffffffff169284926001600160a01b039092169163feaf968c9160048082019260a0929091908290030181865afa158015614589573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145ad9190615cd3565b50919650909250505063ffffffff8216158015906145d957506145d08142615790565b8263ffffffff16105b925082156145e75760105493505b50509091565b600081815260018301602052604081205480156146d6576000614611600183615790565b855490915060009061462590600190615790565b905081811461468a57600086600001828154811061464557614645615764565b906000526020600020015490508087600001848154811061466857614668615764565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061469b5761469b6157a3565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612882565b6000915050612882565b5092915050565b80516000906401000003d019116147405760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420782d6f7264696e61746500000000000000000000000000006044820152606401610ade565b60208201516401000003d019116147995760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420792d6f7264696e61746500000000000000000000000000006044820152606401610ade565b60208201516401000003d0199080096147b98360005b6020020151614aed565b1492915050565b60006001600160a01b0382166148065760405162461bcd60e51b815260206004820152600b60248201526a626164207769746e65737360a81b6044820152606401610ade565b60208401516000906001161561481d57601c614820565b601b5b9050600070014551231950b75fc4402da1732fc9bebe1985876000602002015109865170014551231950b75fc4402da1732fc9bebe19918203925060009190890987516040805160008082526020820180845287905260ff88169282019290925260608101929092526080820183905291925060019060a0016020604051602081039080840390855afa1580156148bb573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b6148eb615020565b6149186001848460405160200161490493929190615d23565b604051602081830303815290604052614b11565b90505b614924816146e7565b6128825780516040805160208101929092526149409101614904565b905061491b565b61494f615020565b825186516401000003d01991829006919006036149ae5760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e637400006044820152606401610ade565b6149b9878988614b5e565b614a055760405162461bcd60e51b815260206004820152601660248201527f4669727374206d756c20636865636b206661696c6564000000000000000000006044820152606401610ade565b614a10848685614b5e565b614a5c5760405162461bcd60e51b815260206004820152601760248201527f5365636f6e64206d756c20636865636b206661696c65640000000000000000006044820152606401610ade565b614a67868484614c89565b98975050505050505050565b600060028686868587604051602001614a9196959493929190615d44565b60408051601f1981840301815291905280516020909101209695505050505050565b6000600a821480614ac557506101a482145b80614ad2575062aa37dc82145b80614ade575061210582145b8061288257505062014a331490565b6000806401000003d01980848509840990506401000003d019600782089392505050565b614b19615020565b614b2282614d50565b8152614b37614b328260006147af565b614d8b565b60208201819052600290066001036120ef576020810180516401000003d019039052919050565b600082600003614b9e5760405162461bcd60e51b815260206004820152600b60248201526a3d32b9379039b1b0b630b960a91b6044820152606401610ade565b83516020850151600090614bb490600290615da3565b15614bc057601c614bc3565b601b5b9050600070014551231950b75fc4402da1732fc9bebe198387096040805160008082526020820180845281905260ff86169282019290925260608101869052608081018390529192509060019060a0016020604051602081039080840390855afa158015614c35573d6000803e3d6000fd5b505050602060405103519050600086604051602001614c549190615db7565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b614c91615020565b835160208086015185519186015160009384938493614cb293909190614dab565b919450925090506401000003d019858209600114614d125760405162461bcd60e51b815260206004820152601960248201527f696e765a206d75737420626520696e7665727365206f66207a000000000000006044820152606401610ade565b60405180604001604052806401000003d01980614d3157614d31615c2a565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d01981106120ef57604080516020808201939093528151808203840181529082019091528051910120614d58565b6000612882826002614da46401000003d0196001615950565b901c614e8b565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a0890506000614deb83838585614f30565b9098509050614dfc88828e88614f54565b9098509050614e0d88828c87614f54565b90985090506000614e208d878b85614f54565b9098509050614e3188828686614f30565b9098509050614e4288828e89614f54565b9098509050818114614e77576401000003d019818a0998506401000003d01982890997506401000003d0198183099650614e7b565b8196505b5050505050509450945094915050565b600080614e9661503e565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a0820152614ec861505c565b60208160c0846005600019fa925082600003614f265760405162461bcd60e51b815260206004820152601260248201527f6269674d6f64457870206661696c7572652100000000000000000000000000006044820152606401610ade565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b828054828255906000526020600020908101928215614ff2579160200282015b82811115614ff257825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614fbd565b50614ffe92915061507a565b5090565b5080546000825590600052602060002090810190610ae7919061507a565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b80821115614ffe576000815560010161507b565b6001600160a01b0381168114610ae757600080fd5b80356120ef8161508f565b6000602082840312156150c157600080fd5b813561114d8161508f565b806040810183101561288257600080fd5b6000604082840312156150ef57600080fd5b61114d83836150cc565b6000806040838503121561510c57600080fd5b82359150602083013561511e8161508f565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b60405160c081016001600160401b038111828210171561516157615161615129565b60405290565b60405161012081016001600160401b038111828210171561516157615161615129565b604051601f8201601f191681016001600160401b03811182821017156151b2576151b2615129565b604052919050565b600082601f8301126151cb57600080fd5b604051604081018181106001600160401b03821117156151ed576151ed615129565b806040525080604084018581111561520457600080fd5b845b8181101561521e578035835260209283019201615206565b509195945050505050565b80356001600160401b03811681146120ef57600080fd5b803563ffffffff811681146120ef57600080fd5b600060c0828403121561526657600080fd5b61526e61513f565b905061527982615229565b81526020808301358183015261529160408401615240565b60408301526152a260608401615240565b606083015260808301356152b58161508f565b608083015260a08301356001600160401b03808211156152d457600080fd5b818501915085601f8301126152e857600080fd5b8135818111156152fa576152fa615129565b61530c601f8201601f1916850161518a565b9150808252868482850101111561532257600080fd5b80848401858401376000848284010152508060a085015250505092915050565b8015158114610ae757600080fd5b80356120ef81615342565b60008060008385036101e081121561537257600080fd5b6101a08082121561538257600080fd5b61538a615167565b915061539687876151ba565b82526153a587604088016151ba565b60208301526080860135604083015260a0860135606083015260c086013560808301526153d460e087016150a4565b60a08301526101006153e8888289016151ba565b60c08401526153fb8861014089016151ba565b60e0840152610180870135908301529093508401356001600160401b0381111561542457600080fd5b61543086828701615254565b9250506154406101c08501615350565b90509250925092565b60006020828403121561545b57600080fd5b5035919050565b6000806040838503121561547557600080fd5b82356154808161508f565b9150602083013561511e8161508f565b600080606083850312156154a357600080fd5b6154ad84846150cc565b91506154bb60408401615229565b90509250929050565b6000602082840312156154d657600080fd5b81356001600160401b038111156154ec57600080fd5b820160c0818503121561114d57600080fd5b6000806000806060858703121561551457600080fd5b843561551f8161508f565b93506020850135925060408501356001600160401b038082111561554257600080fd5b818701915087601f83011261555657600080fd5b81358181111561556557600080fd5b88602082850101111561557757600080fd5b95989497505060200194505050565b803561ffff811681146120ef57600080fd5b803560ff811681146120ef57600080fd5b60008060008060008060008060006101208a8c0312156155c857600080fd5b6155d18a615586565b98506155df60208b01615240565b97506155ed60408b01615240565b96506155fb60608b01615240565b955060808a0135945061561060a08b01615240565b935061561e60c08b01615240565b925061562c60e08b01615598565b915061563b6101008b01615598565b90509295985092959850929598565b6000806040838503121561565d57600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b8381101561569c57815187529582019590820190600101615680565b509495945050505050565b60208152600061114d602083018461566c565b6000604082840312156156cc57600080fd5b61114d83836151ba565b600081518084526020808501945080840160005b8381101561569c5781516001600160a01b0316875295820195908201906001016156ea565b60006001600160601b0380881683528087166020840152506001600160401b03851660408301526001600160a01b038416606083015260a0608083015261575960a08301846156d6565b979650505050505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b818103818111156128825761288261577a565b634e487b7160e01b600052603160045260246000fd5b6000600182016157cb576157cb61577a565b5060010190565b6001600160601b038281168282160390808211156146e0576146e061577a565b60006001600160401b0380831681810361580e5761580e61577a565b6001019392505050565b60006001600160401b038216806158315761583161577a565b6000190192915050565b6020815260ff8251166020820152602082015160408201526001600160a01b0360408301511660608201526000606083015160c0608084015261588160e08401826156d6565b905060808401516001600160601b0380821660a08601528060a08701511660c086015250508091505092915050565b60005b838110156158cb5781810151838201526020016158b3565b50506000910152565b600081518084526158ec8160208601602086016158b0565b601f01601f19169290920160200192915050565b60208152600061114d60208301846158d4565b60006020828403121561592557600080fd5b815161114d81615342565b6001600160601b038181168382160190808211156146e0576146e061577a565b808201808211156128825761288261577a565b60006020828403121561597557600080fd5b61114d82615586565b60006020828403121561599057600080fd5b61114d82615240565b6000808335601e198436030181126159b057600080fd5b8301803591506001600160401b038211156159ca57600080fd5b6020019150368190038213156159df57600080fd5b9250929050565b878152866020820152856040820152600063ffffffff80871660608401528086166080840152506001600160a01b03841660a083015260e060c0830152615a3060e08301846158d4565b9998505050505050505050565b86815285602082015261ffff85166040820152600063ffffffff808616606084015280851660808401525060c060a0830152614a6760c08301846158d4565b6001600160401b038181168382160190808211156146e0576146e061577a565b8060005b6002811015612dd2578151845260209384019390910190600101615aa0565b604081016128828284615a9c565b600060208284031215615adf57600080fd5b5051919050565b8781526001600160401b0387166020820152856040820152600063ffffffff80871660608401528086166080840152506001600160a01b03841660a083015260e060c0830152615a3060e08301846158d4565b828152604060208201526000615b52604083018461566c565b949350505050565b6001600160e01b03198135818116916004851015615b825780818660040360031b1b83161692505b505092915050565b60008085851115615b9a57600080fd5b83861115615ba757600080fd5b5050820193919092039150565b600060208284031215615bc657600080fd5b604051602081018181106001600160401b0382111715615be857615be8615129565b6040528235615bf681615342565b81529392505050565b8281526060810161114d6020830184615a9c565b80820281158282048414176128825761288261577a565b634e487b7160e01b600052601260045260246000fd5b600082615c4f57615c4f615c2a565b500490565b60ff81811683821601908111156128825761288261577a565b63ffffffff8281168282160390808211156146e0576146e061577a565b60008351615c9c8184602088016158b0565b835190830190615cb08183602088016158b0565b01949350505050565b805169ffffffffffffffffffff811681146120ef57600080fd5b600080600080600060a08688031215615ceb57600080fd5b615cf486615cb9565b9450602086015193506040860151925060608601519150615d1760808701615cb9565b90509295509295909350565b838152615d336020820184615a9c565b606081019190915260800192915050565b868152615d546020820187615a9c565b615d616060820186615a9c565b615d6e60a0820185615a9c565b615d7b60e0820184615a9c565b60609190911b6bffffffffffffffffffffffff19166101208201526101340195945050505050565b600082615db257615db2615c2a565b500690565b615dc18183615a9c565b60400191905056fe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000813000a", } var VRFCoordinatorV25ABI = VRFCoordinatorV25MetaData.ABI @@ -369,7 +369,7 @@ func (_VRFCoordinatorV25 *VRFCoordinatorV25Caller) GetSubscription(opts *bind.Ca outstruct.Balance = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) outstruct.NativeBalance = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) outstruct.ReqCount = *abi.ConvertType(out[2], new(uint64)).(*uint64) - outstruct.Owner = *abi.ConvertType(out[3], new(common.Address)).(*common.Address) + outstruct.SubOwner = *abi.ConvertType(out[3], new(common.Address)).(*common.Address) outstruct.Consumers = *abi.ConvertType(out[4], new([]common.Address)).(*[]common.Address) return *outstruct, err @@ -737,15 +737,15 @@ func (_VRFCoordinatorV25 *VRFCoordinatorV25TransactorSession) DeregisterProvingK return _VRFCoordinatorV25.Contract.DeregisterProvingKey(&_VRFCoordinatorV25.TransactOpts, publicProvingKey) } -func (_VRFCoordinatorV25 *VRFCoordinatorV25Transactor) FulfillRandomWords(opts *bind.TransactOpts, proof VRFProof, rc VRFCoordinatorV25RequestCommitment, onlyPremium bool) (*types.Transaction, error) { +func (_VRFCoordinatorV25 *VRFCoordinatorV25Transactor) FulfillRandomWords(opts *bind.TransactOpts, proof VRFProof, rc VRFTypesRequestCommitmentV2Plus, onlyPremium bool) (*types.Transaction, error) { return _VRFCoordinatorV25.contract.Transact(opts, "fulfillRandomWords", proof, rc, onlyPremium) } -func (_VRFCoordinatorV25 *VRFCoordinatorV25Session) FulfillRandomWords(proof VRFProof, rc VRFCoordinatorV25RequestCommitment, onlyPremium bool) (*types.Transaction, error) { +func (_VRFCoordinatorV25 *VRFCoordinatorV25Session) FulfillRandomWords(proof VRFProof, rc VRFTypesRequestCommitmentV2Plus, onlyPremium bool) (*types.Transaction, error) { return _VRFCoordinatorV25.Contract.FulfillRandomWords(&_VRFCoordinatorV25.TransactOpts, proof, rc, onlyPremium) } -func (_VRFCoordinatorV25 *VRFCoordinatorV25TransactorSession) FulfillRandomWords(proof VRFProof, rc VRFCoordinatorV25RequestCommitment, onlyPremium bool) (*types.Transaction, error) { +func (_VRFCoordinatorV25 *VRFCoordinatorV25TransactorSession) FulfillRandomWords(proof VRFProof, rc VRFTypesRequestCommitmentV2Plus, onlyPremium bool) (*types.Transaction, error) { return _VRFCoordinatorV25.Contract.FulfillRandomWords(&_VRFCoordinatorV25.TransactOpts, proof, rc, onlyPremium) } @@ -3612,7 +3612,7 @@ type GetSubscription struct { Balance *big.Int NativeBalance *big.Int ReqCount uint64 - Owner common.Address + SubOwner common.Address Consumers []common.Address } type SConfig struct { @@ -3828,7 +3828,7 @@ type VRFCoordinatorV25Interface interface { DeregisterProvingKey(opts *bind.TransactOpts, publicProvingKey [2]*big.Int) (*types.Transaction, error) - FulfillRandomWords(opts *bind.TransactOpts, proof VRFProof, rc VRFCoordinatorV25RequestCommitment, onlyPremium bool) (*types.Transaction, error) + FulfillRandomWords(opts *bind.TransactOpts, proof VRFProof, rc VRFTypesRequestCommitmentV2Plus, onlyPremium bool) (*types.Transaction, error) FundSubscriptionWithNative(opts *bind.TransactOpts, subId *big.Int) (*types.Transaction, error) diff --git a/core/gethwrappers/generated/vrf_coordinator_v2_plus_v2_example/vrf_coordinator_v2_plus_v2_example.go b/core/gethwrappers/generated/vrf_coordinator_v2_plus_v2_example/vrf_coordinator_v2_plus_v2_example.go index 3d9efea9f73..934d64ea39b 100644 --- a/core/gethwrappers/generated/vrf_coordinator_v2_plus_v2_example/vrf_coordinator_v2_plus_v2_example.go +++ b/core/gethwrappers/generated/vrf_coordinator_v2_plus_v2_example/vrf_coordinator_v2_plus_v2_example.go @@ -39,7 +39,7 @@ type VRFV2PlusClientRandomWordsRequest struct { var VRFCoordinatorV2PlusV2ExampleMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"prevCoordinator\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"transferredValue\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"expectedValue\",\"type\":\"uint96\"}],\"name\":\"InvalidNativeBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"requestVersion\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"expectedVersion\",\"type\":\"uint8\"}],\"name\":\"InvalidVersion\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"previousCoordinator\",\"type\":\"address\"}],\"name\":\"MustBePreviousCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SubscriptionIDCollisionFound\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"name\":\"fulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestID\",\"type\":\"uint256\"}],\"name\":\"generateFakeRandomness\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"getSubscription\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"linkBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"nativeBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint64\",\"name\":\"reqCount\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedData\",\"type\":\"bytes\"}],\"name\":\"onMigration\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFV2PlusClient.RandomWordsRequest\",\"name\":\"req\",\"type\":\"tuple\"}],\"name\":\"requestRandomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_link\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_prevCoordinator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requestConsumerMapping\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_subscriptions\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"linkBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"nativeBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint64\",\"name\":\"reqCount\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalLinkBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalNativeBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x6080604052600060035534801561001557600080fd5b506040516111d73803806111d783398101604081905261003491610081565b600580546001600160a01b039384166001600160a01b031991821617909155600480549290931691161790556100b4565b80516001600160a01b038116811461007c57600080fd5b919050565b6000806040838503121561009457600080fd5b61009d83610065565b91506100ab60208401610065565b90509250929050565b611114806100c36000396000f3fe6080604052600436106100c75760003560e01c8063ce3f471911610074578063dc311dd31161004e578063dc311dd314610361578063e89e106a14610392578063ed8b558f146103a857600080fd5b8063ce3f4719146102ff578063d6100d1c14610314578063da4f5e6d1461033457600080fd5b806386175f58116100a557806386175f581461026157806393f3acb6146102a45780639b1c385e146102d157600080fd5b80630495f265146100cc578063086597b3146101bd57806318e3dd271461020f575b600080fd5b3480156100d857600080fd5b506101636100e7366004610ec8565b600060208190529081526040902080546001909101546bffffffffffffffffffffffff808316926c01000000000000000000000000810490911691780100000000000000000000000000000000000000000000000090910467ffffffffffffffff169073ffffffffffffffffffffffffffffffffffffffff1684565b604080516bffffffffffffffffffffffff958616815294909316602085015267ffffffffffffffff9091169183019190915273ffffffffffffffffffffffffffffffffffffffff1660608201526080015b60405180910390f35b3480156101c957600080fd5b506004546101ea9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101b4565b34801561021b57600080fd5b50600254610244906c0100000000000000000000000090046bffffffffffffffffffffffff1681565b6040516bffffffffffffffffffffffff90911681526020016101b4565b34801561026d57600080fd5b506101ea61027c366004610ec8565b60016020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b3480156102b057600080fd5b506102c46102bf366004610ec8565b6103cd565b6040516101b49190610f1c565b3480156102dd57600080fd5b506102f16102ec366004610dca565b610478565b6040519081526020016101b4565b61031261030d366004610d58565b6105aa565b005b34801561032057600080fd5b5061031261032f366004610ec8565b61095e565b34801561034057600080fd5b506005546101ea9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561036d57600080fd5b5061038161037c366004610ec8565b6109e6565b6040516101b4959493929190610f50565b34801561039e57600080fd5b506102f160035481565b3480156103b457600080fd5b50600254610244906bffffffffffffffffffffffff1681565b60408051600180825281830190925260609160009190602080830190803683370190505090508260405160200161043b918152604060208201819052600a908201527f6e6f742072616e646f6d00000000000000000000000000000000000000000000606082015260800190565b6040516020818303038152906040528051906020012060001c81600081518110610467576104676110a9565b602090810291909101015292915050565b60208181013560009081528082526040808220815160a08101835281546bffffffffffffffffffffffff80821683526c01000000000000000000000000820416828701527801000000000000000000000000000000000000000000000000900467ffffffffffffffff1681840152600182015473ffffffffffffffffffffffffffffffffffffffff166060820152600282018054845181880281018801909552808552949586959294608086019390929183018282801561056f57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610544575b50505050508152505090508060400151600161058b919061102b565b67ffffffffffffffff1660408201526105a333610b42565b9392505050565b60045473ffffffffffffffffffffffffffffffffffffffff16331461062357600480546040517ff5828f73000000000000000000000000000000000000000000000000000000008152339281019290925273ffffffffffffffffffffffffffffffffffffffff1660248201526044015b60405180910390fd5b600061063182840184610e05565b9050806000015160ff166001146106835780516040517f8df4607c00000000000000000000000000000000000000000000000000000000815260ff90911660048201526001602482015260440161061a565b8060a001516bffffffffffffffffffffffff1634146106ea5760a08101516040517f6acf13500000000000000000000000000000000000000000000000000000000081523460048201526bffffffffffffffffffffffff909116602482015260440161061a565b602080820151600090815290819052604090206001015473ffffffffffffffffffffffffffffffffffffffff161561074e576040517f4d5f486a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160a080820183526080808501516bffffffffffffffffffffffff9081168452918501518216602080850191825260008587018181528888015173ffffffffffffffffffffffffffffffffffffffff9081166060808a019182528b0151968901968752848b0151845283855298909220875181549551925167ffffffffffffffff1678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff9389166c01000000000000000000000000027fffffffffffffffff000000000000000000000000000000000000000000000000909716919098161794909417169490941782559451600182018054919094167fffffffffffffffffffffffff000000000000000000000000000000000000000090911617909255518051929391926108989260028501920190610bae565b50505060a081015160028054600c906108d09084906c0100000000000000000000000090046bffffffffffffffffffffffff16611057565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508060800151600260008282829054906101000a90046bffffffffffffffffffffffff1661092b9190611057565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550505050565b60008181526001602052604090205473ffffffffffffffffffffffffffffffffffffffff1680631fe543e383610993816103cd565b6040518363ffffffff1660e01b81526004016109b0929190610f2f565b600060405180830381600087803b1580156109ca57600080fd5b505af11580156109de573d6000803e3d6000fd5b505050505050565b60008181526020819052604081206001015481908190819060609073ffffffffffffffffffffffffffffffffffffffff16610a4d576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000868152602081815260409182902080546001820154600290920180548551818602810186019096528086526bffffffffffffffffffffffff808416966c01000000000000000000000000850490911695780100000000000000000000000000000000000000000000000090940467ffffffffffffffff169473ffffffffffffffffffffffffffffffffffffffff169390918391830182828015610b2857602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610afd575b505050505090509450945094509450945091939590929450565b60006003546001610b539190611013565b6003819055600081815260016020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff94909416939093179092555090565b828054828255906000526020600020908101928215610c28579160200282015b82811115610c2857825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190610bce565b50610c34929150610c38565b5090565b5b80821115610c345760008155600101610c39565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c7157600080fd5b919050565b600082601f830112610c8757600080fd5b8135602067ffffffffffffffff80831115610ca457610ca46110d8565b8260051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108482111715610ce757610ce76110d8565b60405284815283810192508684018288018501891015610d0657600080fd5b600092505b85831015610d3057610d1c81610c4d565b845292840192600192909201918401610d0b565b50979650505050505050565b80356bffffffffffffffffffffffff81168114610c7157600080fd5b60008060208385031215610d6b57600080fd5b823567ffffffffffffffff80821115610d8357600080fd5b818501915085601f830112610d9757600080fd5b813581811115610da657600080fd5b866020828501011115610db857600080fd5b60209290920196919550909350505050565b600060208284031215610ddc57600080fd5b813567ffffffffffffffff811115610df357600080fd5b820160c081850312156105a357600080fd5b600060208284031215610e1757600080fd5b813567ffffffffffffffff80821115610e2f57600080fd5b9083019060c08286031215610e4357600080fd5b610e4b610fea565b823560ff81168114610e5c57600080fd5b815260208381013590820152610e7460408401610c4d565b6040820152606083013582811115610e8b57600080fd5b610e9787828601610c76565b606083015250610ea960808401610d3c565b6080820152610eba60a08401610d3c565b60a082015295945050505050565b600060208284031215610eda57600080fd5b5035919050565b600081518084526020808501945080840160005b83811015610f1157815187529582019590820190600101610ef5565b509495945050505050565b6020815260006105a36020830184610ee1565b828152604060208201526000610f486040830184610ee1565b949350505050565b600060a082016bffffffffffffffffffffffff808916845260208189168186015267ffffffffffffffff8816604086015273ffffffffffffffffffffffffffffffffffffffff9150818716606086015260a0608086015282865180855260c087019150828801945060005b81811015610fd9578551851683529483019491830191600101610fbb565b50909b9a5050505050505050505050565b60405160c0810167ffffffffffffffff8111828210171561100d5761100d6110d8565b60405290565b600082198211156110265761102661107a565b500190565b600067ffffffffffffffff80831681851680830382111561104e5761104e61107a565b01949350505050565b60006bffffffffffffffffffffffff80831681851680830382111561104e5761104e5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + Bin: "0x6080604052600060035534801561001557600080fd5b506040516111d03803806111d083398101604081905261003491610081565b600580546001600160a01b039384166001600160a01b031991821617909155600480549290931691161790556100b4565b80516001600160a01b038116811461007c57600080fd5b919050565b6000806040838503121561009457600080fd5b61009d83610065565b91506100ab60208401610065565b90509250929050565b61110d806100c36000396000f3fe6080604052600436106100c75760003560e01c8063ce3f471911610074578063dc311dd31161004e578063dc311dd314610361578063e89e106a14610392578063ed8b558f146103a857600080fd5b8063ce3f4719146102ff578063d6100d1c14610314578063da4f5e6d1461033457600080fd5b806386175f58116100a557806386175f581461026157806393f3acb6146102a45780639b1c385e146102d157600080fd5b80630495f265146100cc578063086597b3146101bd57806318e3dd271461020f575b600080fd5b3480156100d857600080fd5b506101636100e7366004610c4d565b600060208190529081526040902080546001909101546bffffffffffffffffffffffff808316926c01000000000000000000000000810490911691780100000000000000000000000000000000000000000000000090910467ffffffffffffffff169073ffffffffffffffffffffffffffffffffffffffff1684565b604080516bffffffffffffffffffffffff958616815294909316602085015267ffffffffffffffff9091169183019190915273ffffffffffffffffffffffffffffffffffffffff1660608201526080015b60405180910390f35b3480156101c957600080fd5b506004546101ea9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101b4565b34801561021b57600080fd5b50600254610244906c0100000000000000000000000090046bffffffffffffffffffffffff1681565b6040516bffffffffffffffffffffffff90911681526020016101b4565b34801561026d57600080fd5b506101ea61027c366004610c4d565b60016020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b3480156102b057600080fd5b506102c46102bf366004610c4d565b6103cd565b6040516101b49190610ca1565b3480156102dd57600080fd5b506102f16102ec366004610cb4565b610478565b6040519081526020016101b4565b61031261030d366004610cef565b6105aa565b005b34801561032057600080fd5b5061031261032f366004610c4d565b61095e565b34801561034057600080fd5b506005546101ea9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561036d57600080fd5b5061038161037c366004610c4d565b6109e6565b6040516101b4959493929190610d61565b34801561039e57600080fd5b506102f160035481565b3480156103b457600080fd5b50600254610244906bffffffffffffffffffffffff1681565b60408051600180825281830190925260609160009190602080830190803683370190505090508260405160200161043b918152604060208201819052600a908201527f6e6f742072616e646f6d00000000000000000000000000000000000000000000606082015260800190565b6040516020818303038152906040528051906020012060001c8160008151811061046757610467610e2a565b602090810291909101015292915050565b60208181013560009081528082526040808220815160a08101835281546bffffffffffffffffffffffff80821683526c01000000000000000000000000820416828701527801000000000000000000000000000000000000000000000000900467ffffffffffffffff1681840152600182015473ffffffffffffffffffffffffffffffffffffffff166060820152600282018054845181880281018801909552808552949586959294608086019390929183018282801561056f57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610544575b50505050508152505090508060400151600161058b9190610e88565b67ffffffffffffffff1660408201526105a333610b42565b9392505050565b60045473ffffffffffffffffffffffffffffffffffffffff16331461062357600480546040517ff5828f73000000000000000000000000000000000000000000000000000000008152339281019290925273ffffffffffffffffffffffffffffffffffffffff1660248201526044015b60405180910390fd5b600061063182840184610fde565b9050806000015160ff166001146106835780516040517f8df4607c00000000000000000000000000000000000000000000000000000000815260ff90911660048201526001602482015260440161061a565b8060a001516bffffffffffffffffffffffff1634146106ea5760a08101516040517f6acf13500000000000000000000000000000000000000000000000000000000081523460048201526bffffffffffffffffffffffff909116602482015260440161061a565b602080820151600090815290819052604090206001015473ffffffffffffffffffffffffffffffffffffffff161561074e576040517f4d5f486a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160a080820183526080808501516bffffffffffffffffffffffff9081168452918501518216602080850191825260008587018181528888015173ffffffffffffffffffffffffffffffffffffffff9081166060808a019182528b0151968901968752848b0151845283855298909220875181549551925167ffffffffffffffff1678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff9389166c01000000000000000000000000027fffffffffffffffff000000000000000000000000000000000000000000000000909716919098161794909417169490941782559451600182018054919094167fffffffffffffffffffffffff000000000000000000000000000000000000000090911617909255518051929391926108989260028501920190610bae565b50505060a081015160028054600c906108d09084906c0100000000000000000000000090046bffffffffffffffffffffffff166110a1565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508060800151600260008282829054906101000a90046bffffffffffffffffffffffff1661092b91906110a1565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550505050565b60008181526001602052604090205473ffffffffffffffffffffffffffffffffffffffff1680631fe543e383610993816103cd565b6040518363ffffffff1660e01b81526004016109b09291906110c6565b600060405180830381600087803b1580156109ca57600080fd5b505af11580156109de573d6000803e3d6000fd5b505050505050565b60008181526020819052604081206001015481908190819060609073ffffffffffffffffffffffffffffffffffffffff16610a4d576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000868152602081815260409182902080546001820154600290920180548551818602810186019096528086526bffffffffffffffffffffffff808416966c01000000000000000000000000850490911695780100000000000000000000000000000000000000000000000090940467ffffffffffffffff169473ffffffffffffffffffffffffffffffffffffffff169390918391830182828015610b2857602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610afd575b505050505090509450945094509450945091939590929450565b60006003546001610b5391906110e7565b6003819055600081815260016020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff94909416939093179092555090565b828054828255906000526020600020908101928215610c28579160200282015b82811115610c2857825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190610bce565b50610c34929150610c38565b5090565b5b80821115610c345760008155600101610c39565b600060208284031215610c5f57600080fd5b5035919050565b600081518084526020808501945080840160005b83811015610c9657815187529582019590820190600101610c7a565b509495945050505050565b6020815260006105a36020830184610c66565b600060208284031215610cc657600080fd5b813567ffffffffffffffff811115610cdd57600080fd5b820160c081850312156105a357600080fd5b60008060208385031215610d0257600080fd5b823567ffffffffffffffff80821115610d1a57600080fd5b818501915085601f830112610d2e57600080fd5b813581811115610d3d57600080fd5b866020828501011115610d4f57600080fd5b60209290920196919550909350505050565b600060a082016bffffffffffffffffffffffff808916845260208189168186015267ffffffffffffffff8816604086015273ffffffffffffffffffffffffffffffffffffffff9150818716606086015260a0608086015282865180855260c087019150828801945060005b81811015610dea578551851683529483019491830191600101610dcc565b50909b9a5050505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b67ffffffffffffffff818116838216019080821115610ea957610ea9610e59565b5092915050565b60405160c0810167ffffffffffffffff81118282101715610ed357610ed3610dfb565b60405290565b803573ffffffffffffffffffffffffffffffffffffffff81168114610efd57600080fd5b919050565b600082601f830112610f1357600080fd5b8135602067ffffffffffffffff80831115610f3057610f30610dfb565b8260051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108482111715610f7357610f73610dfb565b604052938452858101830193838101925087851115610f9157600080fd5b83870191505b84821015610fb757610fa882610ed9565b83529183019190830190610f97565b979650505050505050565b80356bffffffffffffffffffffffff81168114610efd57600080fd5b600060208284031215610ff057600080fd5b813567ffffffffffffffff8082111561100857600080fd5b9083019060c0828603121561101c57600080fd5b611024610eb0565b823560ff8116811461103557600080fd5b81526020838101359082015261104d60408401610ed9565b604082015260608301358281111561106457600080fd5b61107087828601610f02565b60608301525061108260808401610fc2565b608082015261109360a08401610fc2565b60a082015295945050505050565b6bffffffffffffffffffffffff818116838216019080821115610ea957610ea9610e59565b8281526040602082015260006110df6040830184610c66565b949350505050565b808201808211156110fa576110fa610e59565b9291505056fea164736f6c6343000813000a", } var VRFCoordinatorV2PlusV2ExampleABI = VRFCoordinatorV2PlusV2ExampleMetaData.ABI diff --git a/core/gethwrappers/generated/vrf_malicious_consumer_v2_plus/vrf_malicious_consumer_v2_plus.go b/core/gethwrappers/generated/vrf_malicious_consumer_v2_plus/vrf_malicious_consumer_v2_plus.go index c889b8ef67e..50df8e4312c 100644 --- a/core/gethwrappers/generated/vrf_malicious_consumer_v2_plus/vrf_malicious_consumer_v2_plus.go +++ b/core/gethwrappers/generated/vrf_malicious_consumer_v2_plus/vrf_malicious_consumer_v2_plus.go @@ -32,7 +32,7 @@ var ( var VRFMaliciousConsumerV2PlusMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"vrfCoordinator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"}],\"name\":\"OnlyOwnerOrCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"vrfCoordinator\",\"type\":\"address\"}],\"name\":\"CoordinatorSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"createSubscriptionAndFund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"requestRandomness\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_gasAvailable\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_randomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_vrfCoordinator\",\"outputs\":[{\"internalType\":\"contractIVRFCoordinatorV2Plus\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"name\":\"setCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"}],\"name\":\"updateSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60806040523480156200001157600080fd5b506040516200126b3803806200126b8339810160408190526200003491620001c2565b8133806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf81620000f9565b5050600280546001600160a01b039384166001600160a01b0319918216179091556005805494909316931692909217905550620001fa9050565b6001600160a01b038116331415620001545760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001bd57600080fd5b919050565b60008060408385031215620001d657600080fd5b620001e183620001a5565b9150620001f160208401620001a5565b90509250929050565b611061806200020a6000396000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c80639eccacf611610081578063f08c5daa1161005b578063f08c5daa146101bd578063f2fde38b146101c6578063f6eaffc8146101d957600080fd5b80639eccacf614610181578063cf62c8ab146101a1578063e89e106a146101b457600080fd5b806379ba5097116100b257806379ba5097146101275780638da5cb5b1461012f5780638ea981171461016e57600080fd5b80631fe543e3146100d957806336bfffed146100ee5780635e3b709f14610101575b600080fd5b6100ec6100e7366004610d35565b6101ec565b005b6100ec6100fc366004610c3d565b610272565b61011461010f366004610d03565b6103aa565b6040519081526020015b60405180910390f35b6100ec6104a0565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161011e565b6100ec61017c366004610c22565b61059d565b6002546101499073ffffffffffffffffffffffffffffffffffffffff1681565b6100ec6101af366004610dd9565b6106da565b61011460045481565b61011460065481565b6100ec6101d4366004610c22565b6108e0565b6101146101e7366004610d03565b6108f4565b60025473ffffffffffffffffffffffffffffffffffffffff163314610264576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff90911660248201526044015b60405180910390fd5b61026e8282610915565b5050565b6007546102db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f7375624944206e6f742073657400000000000000000000000000000000000000604482015260640161025b565b60005b815181101561026e57600254600754835173ffffffffffffffffffffffffffffffffffffffff9092169163bec4c08c919085908590811061032157610321610ff6565b60200260200101516040518363ffffffff1660e01b815260040161036592919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b15801561037f57600080fd5b505af1158015610393573d6000803e3d6000fd5b5050505080806103a290610f96565b9150506102de565b60088190556040805160c08101825282815260075460208083019190915260018284018190526207a1206060840152608083015282519081018352600080825260a083019190915260025492517f9b1c385e000000000000000000000000000000000000000000000000000000008152909273ffffffffffffffffffffffffffffffffffffffff1690639b1c385e90610447908490600401610ebe565b602060405180830381600087803b15801561046157600080fd5b505af1158015610475573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104999190610d1c565b9392505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610521576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161025b565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906105dd575060025473ffffffffffffffffffffffffffffffffffffffff163314155b15610661573361060260005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9384166004820152918316602483015291909116604482015260640161025b565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fd1a6a14209a385a964d036e404cb5cfb71f4000cdb03c9366292430787261be69060200160405180910390a150565b60075461081257600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a21a23e46040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561074b57600080fd5b505af115801561075f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107839190610d1c565b60078190556002546040517fbec4c08c000000000000000000000000000000000000000000000000000000008152600481019290925230602483015273ffffffffffffffffffffffffffffffffffffffff169063bec4c08c90604401600060405180830381600087803b1580156107f957600080fd5b505af115801561080d573d6000803e3d6000fd5b505050505b6005546002546007546040805160208082019390935281518082039093018352808201918290527f4000aea00000000000000000000000000000000000000000000000000000000090915273ffffffffffffffffffffffffffffffffffffffff93841693634000aea09361088e93911691869190604401610e72565b602060405180830381600087803b1580156108a857600080fd5b505af11580156108bc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061026e9190610ce1565b6108e8610a20565b6108f181610aa3565b50565b6003818154811061090457600080fd5b600091825260209091200154905081565b5a600655805161092c906003906020840190610b99565b5060048281556040805160c0810182526008548152600754602080830191909152600182840181905262030d4060608401526080830152825190810183526000815260a082015260025491517f9b1c385e000000000000000000000000000000000000000000000000000000008152909273ffffffffffffffffffffffffffffffffffffffff90921691639b1c385e916109c891859101610ebe565b602060405180830381600087803b1580156109e257600080fd5b505af11580156109f6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1a9190610d1c565b50505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610aa1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161025b565b565b73ffffffffffffffffffffffffffffffffffffffff8116331415610b23576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161025b565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610bd4579160200282015b82811115610bd4578251825591602001919060010190610bb9565b50610be0929150610be4565b5090565b5b80821115610be05760008155600101610be5565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c1d57600080fd5b919050565b600060208284031215610c3457600080fd5b61049982610bf9565b60006020808385031215610c5057600080fd5b823567ffffffffffffffff811115610c6757600080fd5b8301601f81018513610c7857600080fd5b8035610c8b610c8682610f72565b610f23565b80828252848201915084840188868560051b8701011115610cab57600080fd5b600094505b83851015610cd557610cc181610bf9565b835260019490940193918501918501610cb0565b50979650505050505050565b600060208284031215610cf357600080fd5b8151801515811461049957600080fd5b600060208284031215610d1557600080fd5b5035919050565b600060208284031215610d2e57600080fd5b5051919050565b60008060408385031215610d4857600080fd5b8235915060208084013567ffffffffffffffff811115610d6757600080fd5b8401601f81018613610d7857600080fd5b8035610d86610c8682610f72565b80828252848201915084840189868560051b8701011115610da657600080fd5b600094505b83851015610dc9578035835260019490940193918501918501610dab565b5080955050505050509250929050565b600060208284031215610deb57600080fd5b81356bffffffffffffffffffffffff8116811461049957600080fd5b6000815180845260005b81811015610e2d57602081850181015186830182015201610e11565b81811115610e3f576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff841681526bffffffffffffffffffffffff83166020820152606060408201526000610eb56060830184610e07565b95945050505050565b60208152815160208201526020820151604082015261ffff60408301511660608201526000606083015163ffffffff80821660808501528060808601511660a0850152505060a083015160c080840152610f1b60e0840182610e07565b949350505050565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610f6a57610f6a611025565b604052919050565b600067ffffffffffffffff821115610f8c57610f8c611025565b5060051b60200190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610fef577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + Bin: "0x60806040523480156200001157600080fd5b5060405162001291380380620012918339810160408190526200003491620001e8565b8133806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf8162000120565b5050506001600160a01b038116620000ea5760405163d92e233d60e01b815260040160405180910390fd5b600280546001600160a01b039283166001600160a01b031991821617909155600580549390921692169190911790555062000220565b336001600160a01b038216036200017a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001e357600080fd5b919050565b60008060408385031215620001fc57600080fd5b6200020783620001cb565b91506200021760208401620001cb565b90509250929050565b61106180620002306000396000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c80639eccacf611610081578063f08c5daa1161005b578063f08c5daa146101bd578063f2fde38b146101c6578063f6eaffc8146101d957600080fd5b80639eccacf614610181578063cf62c8ab146101a1578063e89e106a146101b457600080fd5b806379ba5097116100b257806379ba5097146101275780638da5cb5b1461012f5780638ea981171461016e57600080fd5b80631fe543e3146100d957806336bfffed146100ee5780635e3b709f14610101575b600080fd5b6100ec6100e7366004610cb1565b6101ec565b005b6100ec6100fc366004610d7c565b610272565b61011461010f366004610e14565b6103ad565b6040519081526020015b60405180910390f35b6100ec610494565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161011e565b6100ec61017c366004610e2d565b610591565b6002546101499073ffffffffffffffffffffffffffffffffffffffff1681565b6100ec6101af366004610e48565b61071b565b61011460045481565b61011460065481565b6100ec6101d4366004610e2d565b610906565b6101146101e7366004610e14565b61091a565b60025473ffffffffffffffffffffffffffffffffffffffff163314610264576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff90911660248201526044015b60405180910390fd5b61026e828261093b565b5050565b6007546000036102de576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f7375624944206e6f742073657400000000000000000000000000000000000000604482015260640161025b565b60005b815181101561026e57600254600754835173ffffffffffffffffffffffffffffffffffffffff9092169163bec4c08c919085908590811061032457610324610e76565b60200260200101516040518363ffffffff1660e01b815260040161036892919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b15801561038257600080fd5b505af1158015610396573d6000803e3d6000fd5b5050505080806103a590610ea5565b9150506102e1565b60088190556040805160c08101825282815260075460208083019190915260018284018190526207a1206060840152608083015282519081018352600080825260a083019190915260025492517f9b1c385e000000000000000000000000000000000000000000000000000000008152909273ffffffffffffffffffffffffffffffffffffffff1690639b1c385e9061044a908490600401610f68565b6020604051808303816000875af1158015610469573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061048d9190610fcd565b9392505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610515576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161025b565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906105d1575060025473ffffffffffffffffffffffffffffffffffffffff163314155b1561065557336105f660005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9384166004820152918316602483015291909116604482015260640161025b565b73ffffffffffffffffffffffffffffffffffffffff81166106a2576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fd1a6a14209a385a964d036e404cb5cfb71f4000cdb03c9366292430787261be69060200160405180910390a150565b60075460000361084757600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a21a23e46040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610794573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b89190610fcd565b60078190556002546040517fbec4c08c000000000000000000000000000000000000000000000000000000008152600481019290925230602483015273ffffffffffffffffffffffffffffffffffffffff169063bec4c08c90604401600060405180830381600087803b15801561082e57600080fd5b505af1158015610842573d6000803e3d6000fd5b505050505b6005546002546007546040805160208082019390935281518082039093018352808201918290527f4000aea00000000000000000000000000000000000000000000000000000000090915273ffffffffffffffffffffffffffffffffffffffff93841693634000aea0936108c393911691869190604401610fe6565b6020604051808303816000875af11580156108e2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061026e9190611032565b61090e610a37565b61091781610aba565b50565b6003818154811061092a57600080fd5b600091825260209091200154905081565b5a6006558051610952906003906020840190610baf565b5060048281556040805160c0810182526008548152600754602080830191909152600182840181905262030d4060608401526080830152825190810183526000815260a082015260025491517f9b1c385e000000000000000000000000000000000000000000000000000000008152909273ffffffffffffffffffffffffffffffffffffffff90921691639b1c385e916109ee91859101610f68565b6020604051808303816000875af1158015610a0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a319190610fcd565b50505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610ab8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161025b565b565b3373ffffffffffffffffffffffffffffffffffffffff821603610b39576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161025b565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610bea579160200282015b82811115610bea578251825591602001919060010190610bcf565b50610bf6929150610bfa565b5090565b5b80821115610bf65760008155600101610bfb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610c8557610c85610c0f565b604052919050565b600067ffffffffffffffff821115610ca757610ca7610c0f565b5060051b60200190565b60008060408385031215610cc457600080fd5b8235915060208084013567ffffffffffffffff811115610ce357600080fd5b8401601f81018613610cf457600080fd5b8035610d07610d0282610c8d565b610c3e565b81815260059190911b82018301908381019088831115610d2657600080fd5b928401925b82841015610d4457833582529284019290840190610d2b565b80955050505050509250929050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610d7757600080fd5b919050565b60006020808385031215610d8f57600080fd5b823567ffffffffffffffff811115610da657600080fd5b8301601f81018513610db757600080fd5b8035610dc5610d0282610c8d565b81815260059190911b82018301908381019087831115610de457600080fd5b928401925b82841015610e0957610dfa84610d53565b82529284019290840190610de9565b979650505050505050565b600060208284031215610e2657600080fd5b5035919050565b600060208284031215610e3f57600080fd5b61048d82610d53565b600060208284031215610e5a57600080fd5b81356bffffffffffffffffffffffff8116811461048d57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610efd577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b6000815180845260005b81811015610f2a57602081850181015186830182015201610f0e565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152815160208201526020820151604082015261ffff60408301511660608201526000606083015163ffffffff80821660808501528060808601511660a0850152505060a083015160c080840152610fc560e0840182610f04565b949350505050565b600060208284031215610fdf57600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff841681526bffffffffffffffffffffffff831660208201526060604082015260006110296060830184610f04565b95945050505050565b60006020828403121561104457600080fd5b8151801515811461048d57600080fdfea164736f6c6343000813000a", } var VRFMaliciousConsumerV2PlusABI = VRFMaliciousConsumerV2PlusMetaData.ABI diff --git a/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics/vrf_v2plus_load_test_with_metrics.go b/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics/vrf_v2plus_load_test_with_metrics.go index 695f0d52eca..46c83dc304f 100644 --- a/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics/vrf_v2plus_load_test_with_metrics.go +++ b/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics/vrf_v2plus_load_test_with_metrics.go @@ -31,8 +31,8 @@ var ( ) var VRFV2PlusLoadTestWithMetricsMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"}],\"name\":\"OnlyOwnerOrCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"vrfCoordinator\",\"type\":\"address\"}],\"name\":\"CoordinatorSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"getRequestStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_subId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"_keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"_nativePayment\",\"type\":\"bool\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestCount\",\"type\":\"uint16\"}],\"name\":\"requestRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_averageResponseTimeInBlocksMillions\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_averageResponseTimeInSecondsMillions\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fastestResponseTimeInBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fastestResponseTimeInSeconds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requests\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_responseCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_slowestResponseTimeInBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_slowestResponseTimeInSeconds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_vrfCoordinator\",\"outputs\":[{\"internalType\":\"contractIVRFCoordinatorV2Plus\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"name\":\"setCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x6080604052600060055560006006556103e760075560006008556103e76009556000600a5534801561003057600080fd5b506040516200148138038062001481833981016040819052610051916101ad565b8033806000816100a85760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156100d8576100d881610103565b5050600280546001600160a01b0319166001600160a01b039390931692909217909155506101dd9050565b6001600160a01b03811633141561015c5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161009f565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156101bf57600080fd5b81516001600160a01b03811681146101d657600080fd5b9392505050565b61129480620001ed6000396000f3fe608060405234801561001057600080fd5b50600436106101515760003560e01c80638ea98117116100cd578063b1e2174911610081578063d8a4676f11610066578063d8a4676f146102ec578063dc1670db14610311578063f2fde38b1461031a57600080fd5b8063b1e21749146102b5578063d826f88f146102be57600080fd5b8063a168fa89116100b2578063a168fa8914610238578063a4c52cf5146102a3578063ad00fe61146102ac57600080fd5b80638ea98117146102055780639eccacf61461021857600080fd5b8063557d2e921161012457806379ba50971161010957806379ba5097146101b557806381a4342c146101bd5780638da5cb5b146101c657600080fd5b8063557d2e92146101995780636846de20146101a257600080fd5b806301e5f828146101565780631742748e146101725780631fe543e31461017b57806339aea80a14610190575b600080fd5b61015f60065481565b6040519081526020015b60405180910390f35b61015f600a5481565b61018e610189366004610e8d565b61032d565b005b61015f60075481565b61015f60045481565b61018e6101b0366004610f7c565b6103b3565b61018e6105d3565b61015f60055481565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610169565b61018e610213366004610e1e565b6106d0565b6002546101e09073ffffffffffffffffffffffffffffffffffffffff1681565b610279610246366004610e5b565b600c602052600090815260409020805460028201546003830154600484015460059094015460ff90931693919290919085565b6040805195151586526020860194909452928401919091526060830152608082015260a001610169565b61015f60095481565b61015f60085481565b61015f600b5481565b61018e6000600581905560068190556103e76007819055600a82905560088290556009556004819055600355565b6102ff6102fa366004610e5b565b61080d565b60405161016996959493929190610ffb565b61015f60035481565b61018e610328366004610e1e565b6108f2565b60025473ffffffffffffffffffffffffffffffffffffffff1633146103a5576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff90911660248201526044015b60405180910390fd5b6103af8282610906565b5050565b6103bb610a1f565b60005b8161ffff168161ffff1610156105c95760006040518060c001604052808881526020018a81526020018961ffff1681526020018763ffffffff1681526020018563ffffffff1681526020016104226040518060200160405280891515815250610aa2565b90526002546040517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925060009173ffffffffffffffffffffffffffffffffffffffff90911690639b1c385e90610480908590600401611067565b602060405180830381600087803b15801561049a57600080fd5b505af11580156104ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104d29190610e74565b600b819055905060006104e3610b5e565b6040805160c08101825260008082528251818152602080820185528084019182524284860152606084018390526080840186905260a08401839052878352600c815293909120825181547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169015151781559051805194955091939092610571926001850192910190610d93565b506040820151600282015560608201516003820155608082015160048083019190915560a09092015160059091015580549060006105ae836111f0565b919050555050505080806105c1906111ce565b9150506103be565b5050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610654576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161039c565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590610710575060025473ffffffffffffffffffffffffffffffffffffffff163314155b15610794573361073560005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9384166004820152918316602483015291909116604482015260640161039c565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fd1a6a14209a385a964d036e404cb5cfb71f4000cdb03c9366292430787261be69060200160405180910390a150565b6000818152600c60209081526040808320815160c081018352815460ff161515815260018201805484518187028101870190955280855260609587958695869586958695919492938584019390929083018282801561088b57602002820191906000526020600020905b815481526020019060010190808311610877575b505050505081526020016002820154815260200160038201548152602001600482015481526020016005820154815250509050806000015181602001518260400151836060015184608001518560a001519650965096509650965096505091939550919395565b6108fa610a1f565b61090381610bfb565b50565b6000828152600c6020908152604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811782558351610955939290910191840190610d93565b506000828152600c6020526040902042600390910155610973610b5e565b6000838152600c602052604081206005810183905560040154909161099891906111b7565b6000848152600c60205260408120600281015460039091015492935090916109c091906111b7565b90506109d782600754600654600554600354610cf1565b600555600755600655600954600854600a546003546109fb93859390929091610cf1565b600a5560095560085560038054906000610a14836111f0565b919050555050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610aa0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161039c565b565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401610adb91511515815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915292915050565b600046610b6a81610d6c565b15610bf457606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610bb657600080fd5b505afa158015610bca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bee9190610e74565b91505090565b4391505090565b73ffffffffffffffffffffffffffffffffffffffff8116331415610c7b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161039c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000808080610d0389620f424061117a565b905086891115610d11578896505b878910610d1e5787610d20565b885b97506000808611610d315781610d5b565b610d3c866001611127565b82610d47888a61117a565b610d519190611127565b610d5b919061113f565b979a98995096979650505050505050565b600061a4b1821480610d80575062066eed82145b80610d8d575062066eee82145b92915050565b828054828255906000526020600020908101928215610dce579160200282015b82811115610dce578251825591602001919060010190610db3565b50610dda929150610dde565b5090565b5b80821115610dda5760008155600101610ddf565b803561ffff81168114610e0557600080fd5b919050565b803563ffffffff81168114610e0557600080fd5b600060208284031215610e3057600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610e5457600080fd5b9392505050565b600060208284031215610e6d57600080fd5b5035919050565b600060208284031215610e8657600080fd5b5051919050565b60008060408385031215610ea057600080fd5b8235915060208084013567ffffffffffffffff80821115610ec057600080fd5b818601915086601f830112610ed457600080fd5b813581811115610ee657610ee6611258565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715610f2957610f29611258565b604052828152858101935084860182860187018b1015610f4857600080fd5b600095505b83861015610f6b578035855260019590950194938601938601610f4d565b508096505050505050509250929050565b600080600080600080600060e0888a031215610f9757600080fd5b87359650610fa760208901610df3565b955060408801359450610fbc60608901610e0a565b935060808801358015158114610fd157600080fd5b9250610fdf60a08901610e0a565b9150610fed60c08901610df3565b905092959891949750929550565b600060c082018815158352602060c08185015281895180845260e086019150828b01935060005b8181101561103e57845183529383019391830191600101611022565b505060408501989098525050506060810193909352608083019190915260a09091015292915050565b6000602080835283518184015280840151604084015261ffff6040850151166060840152606084015163ffffffff80821660808601528060808701511660a0860152505060a084015160c08085015280518060e086015260005b818110156110de57828101840151868201610100015283016110c1565b818111156110f157600061010083880101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169390930161010001949350505050565b6000821982111561113a5761113a611229565b500190565b600082611175577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156111b2576111b2611229565b500290565b6000828210156111c9576111c9611229565b500390565b600061ffff808316818114156111e6576111e6611229565b6001019392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561122257611222611229565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"}],\"name\":\"OnlyOwnerOrCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"vrfCoordinator\",\"type\":\"address\"}],\"name\":\"CoordinatorSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"offset\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"quantity\",\"type\":\"uint256\"}],\"name\":\"getRequestBlockTimes\",\"outputs\":[{\"internalType\":\"uint32[]\",\"name\":\"\",\"type\":\"uint32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"getRequestStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_subId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"_keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"_nativePayment\",\"type\":\"bool\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestCount\",\"type\":\"uint16\"}],\"name\":\"requestRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_averageResponseTimeInBlocksMillions\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_averageResponseTimeInSecondsMillions\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fastestResponseTimeInBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fastestResponseTimeInSeconds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requestBlockTimes\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requests\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_responseCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_slowestResponseTimeInBlocks\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_slowestResponseTimeInSeconds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_vrfCoordinator\",\"outputs\":[{\"internalType\":\"contractIVRFCoordinatorV2Plus\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"name\":\"setCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x6080604052600060055560006006556103e760075560006008556103e76009556000600a553480156200003157600080fd5b506040516200176f3803806200176f8339810160408190526200005491620001dc565b803380600081620000ac5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000df57620000df8162000131565b5050506001600160a01b0381166200010a5760405163d92e233d60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055506200020e565b336001600160a01b038216036200018b5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620000a3565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060208284031215620001ef57600080fd5b81516001600160a01b03811681146200020757600080fd5b9392505050565b611551806200021e6000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c80638ea98117116100d8578063ad00fe611161008c578063d8a4676f11610066578063d8a4676f14610334578063dc1670db14610359578063f2fde38b1461036257600080fd5b8063ad00fe611461031a578063b1e2174914610323578063d826f88f1461032c57600080fd5b80639eccacf6116100bd5780639eccacf614610286578063a168fa89146102a6578063a4c52cf51461031157600080fd5b80638ea981171461024b578063958cccb71461025e57600080fd5b8063557d2e921161012f57806379ba50971161011457806379ba5097146101fb57806381a4342c146102035780638da5cb5b1461020c57600080fd5b8063557d2e92146101df5780636846de20146101e857600080fd5b80631742748e116101605780631742748e146101b85780631fe543e3146101c157806339aea80a146101d657600080fd5b806301e5f8281461017c5780630b26348614610198575b600080fd5b61018560065481565b6040519081526020015b60405180910390f35b6101ab6101a6366004611053565b610375565b60405161018f9190611075565b610185600a5481565b6101d46101cf3660046110ee565b610473565b005b61018560075481565b61018560045481565b6101d46101f6366004611201565b6104f9565b6101d461070a565b61018560055481565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161018f565b6101d4610259366004611280565b610807565b61027161026c3660046112bd565b610991565b60405163ffffffff909116815260200161018f565b6002546102269073ffffffffffffffffffffffffffffffffffffffff1681565b6102e76102b43660046112bd565b600d602052600090815260409020805460028201546003830154600484015460059094015460ff90931693919290919085565b6040805195151586526020860194909452928401919091526060830152608082015260a00161018f565b61018560095481565b61018560085481565b610185600b5481565b6101d46109cb565b6103476103423660046112bd565b610a04565b60405161018f969594939291906112d6565b61018560035481565b6101d4610370366004611280565b610ae9565b606060006103838385611371565b600c549091508111156103955750600c545b60006103a18583611384565b67ffffffffffffffff8111156103b9576103b96110bf565b6040519080825280602002602001820160405280156103e2578160200160208202803683370190505b509050845b8281101561046857600c818154811061040257610402611397565b6000918252602090912060088204015460079091166004026101000a900463ffffffff16826104318884611384565b8151811061044157610441611397565b63ffffffff9092166020928302919091019091015280610460816113c6565b9150506103e7565b509150505b92915050565b60025473ffffffffffffffffffffffffffffffffffffffff1633146104eb576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff90911660248201526044015b60405180910390fd5b6104f58282610afd565b5050565b610501610c74565b60005b8161ffff168161ffff1610156107005760006040518060c001604052808881526020018a81526020018961ffff1681526020018763ffffffff1681526020018563ffffffff1681526020016105686040518060200160405280891515815250610cf5565b90526002546040517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925060009173ffffffffffffffffffffffffffffffffffffffff90911690639b1c385e906105c69085906004016113fe565b6020604051808303816000875af11580156105e5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060991906114b8565b600b8190559050600061061a610db1565b6040805160c08101825260008082528251818152602080820185528084019182524284860152606084018390526080840186905260a08401839052878352600d815293909120825181547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690151517815590518051949550919390926106a8926001850192910190610fd2565b506040820151600282015560608201516003820155608082015160048083019190915560a09092015160059091015580549060006106e5836113c6565b919050555050505080806106f8906114d1565b915050610504565b5050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461078b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016104e2565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590610847575060025473ffffffffffffffffffffffffffffffffffffffff163314155b156108cb573361086c60005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff938416600482015291831660248301529190911660448201526064016104e2565b73ffffffffffffffffffffffffffffffffffffffff8116610918576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fd1a6a14209a385a964d036e404cb5cfb71f4000cdb03c9366292430787261be69060200160405180910390a150565b600c81815481106109a157600080fd5b9060005260206000209060089182820401919006600402915054906101000a900463ffffffff1681565b6000600581905560068190556103e76007819055600a829055600882905560095560048190556003819055610a0290600c9061101d565b565b6000818152600d60209081526040808320815160c081018352815460ff1615158152600182018054845181870281018701909552808552606095879586958695869586959194929385840193909290830182828015610a8257602002820191906000526020600020905b815481526020019060010190808311610a6e575b505050505081526020016002820154815260200160038201548152602001600482015481526020016005820154815250509050806000015181602001518260400151836060015184608001518560a001519650965096509650965096505091939550919395565b610af1610c74565b610afa81610e3f565b50565b6000828152600d6020908152604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811782558351610b4c939290910191840190610fd2565b506000828152600d6020526040902042600390910155610b6a610db1565b6000838152600d6020526040812060058101839055600401549091610b8f9190611384565b6000848152600d6020526040812060028101546003909101549293509091610bb79190611384565b9050610bce82600754600654600554600354610f34565b600555600755600655600954600854600a54600354610bf293859390929091610f34565b600a5560095560085560038054906000610c0b836113c6565b9091555050600c80546001810182556000919091527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c76008820401805460079092166004026101000a63ffffffff81810219909316949092169190910292909217909155505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610a02576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016104e2565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401610d2e91511515815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915292915050565b600046610dbd81610faf565b15610e3857606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3291906114b8565b91505090565b4391505090565b3373ffffffffffffffffffffffffffffffffffffffff821603610ebe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016104e2565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000808080610f4689620f42406114f2565b905086891115610f54578896505b878910610f615787610f63565b885b97506000808611610f745781610f9e565b610f7f866001611371565b82610f8a888a6114f2565b610f949190611371565b610f9e9190611509565b979a98995096979650505050505050565b600061a4b1821480610fc3575062066eed82145b8061046d57505062066eee1490565b82805482825590600052602060002090810192821561100d579160200282015b8281111561100d578251825591602001919060010190610ff2565b5061101992915061103e565b5090565b508054600082556007016008900490600052602060002090810190610afa91905b5b80821115611019576000815560010161103f565b6000806040838503121561106657600080fd5b50508035926020909101359150565b6020808252825182820181905260009190848201906040850190845b818110156110b357835163ffffffff1683529284019291840191600101611091565b50909695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806040838503121561110157600080fd5b8235915060208084013567ffffffffffffffff8082111561112157600080fd5b818601915086601f83011261113557600080fd5b813581811115611147576111476110bf565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110858211171561118a5761118a6110bf565b6040529182528482019250838101850191898311156111a857600080fd5b938501935b828510156111c6578435845293850193928501926111ad565b8096505050505050509250929050565b803561ffff811681146111e857600080fd5b919050565b803563ffffffff811681146111e857600080fd5b600080600080600080600060e0888a03121561121c57600080fd5b8735965061122c602089016111d6565b955060408801359450611241606089016111ed565b93506080880135801515811461125657600080fd5b925061126460a089016111ed565b915061127260c089016111d6565b905092959891949750929550565b60006020828403121561129257600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146112b657600080fd5b9392505050565b6000602082840312156112cf57600080fd5b5035919050565b600060c082018815158352602060c08185015281895180845260e086019150828b01935060005b81811015611319578451835293830193918301916001016112fd565b505060408501989098525050506060810193909352608083019190915260a09091015292915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561046d5761046d611342565b8181038181111561046d5761046d611342565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036113f7576113f7611342565b5060010190565b6000602080835283518184015280840151604084015261ffff6040850151166060840152606084015163ffffffff80821660808601528060808701511660a0860152505060a084015160c08085015280518060e086015260005b818110156114755782810184015186820161010001528301611458565b5061010092506000838287010152827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116860101935050505092915050565b6000602082840312156114ca57600080fd5b5051919050565b600061ffff8083168181036114e8576114e8611342565b6001019392505050565b808202811582820484141761046d5761046d611342565b60008261153f577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b50049056fea164736f6c6343000813000a", } var VRFV2PlusLoadTestWithMetricsABI = VRFV2PlusLoadTestWithMetricsMetaData.ABI @@ -171,6 +171,28 @@ func (_VRFV2PlusLoadTestWithMetrics *VRFV2PlusLoadTestWithMetricsTransactorRaw) return _VRFV2PlusLoadTestWithMetrics.Contract.contract.Transact(opts, method, params...) } +func (_VRFV2PlusLoadTestWithMetrics *VRFV2PlusLoadTestWithMetricsCaller) GetRequestBlockTimes(opts *bind.CallOpts, offset *big.Int, quantity *big.Int) ([]uint32, error) { + var out []interface{} + err := _VRFV2PlusLoadTestWithMetrics.contract.Call(opts, &out, "getRequestBlockTimes", offset, quantity) + + if err != nil { + return *new([]uint32), err + } + + out0 := *abi.ConvertType(out[0], new([]uint32)).(*[]uint32) + + return out0, err + +} + +func (_VRFV2PlusLoadTestWithMetrics *VRFV2PlusLoadTestWithMetricsSession) GetRequestBlockTimes(offset *big.Int, quantity *big.Int) ([]uint32, error) { + return _VRFV2PlusLoadTestWithMetrics.Contract.GetRequestBlockTimes(&_VRFV2PlusLoadTestWithMetrics.CallOpts, offset, quantity) +} + +func (_VRFV2PlusLoadTestWithMetrics *VRFV2PlusLoadTestWithMetricsCallerSession) GetRequestBlockTimes(offset *big.Int, quantity *big.Int) ([]uint32, error) { + return _VRFV2PlusLoadTestWithMetrics.Contract.GetRequestBlockTimes(&_VRFV2PlusLoadTestWithMetrics.CallOpts, offset, quantity) +} + func (_VRFV2PlusLoadTestWithMetrics *VRFV2PlusLoadTestWithMetricsCaller) GetRequestStatus(opts *bind.CallOpts, _requestId *big.Int) (GetRequestStatus, error) { @@ -337,6 +359,28 @@ func (_VRFV2PlusLoadTestWithMetrics *VRFV2PlusLoadTestWithMetricsCallerSession) return _VRFV2PlusLoadTestWithMetrics.Contract.SLastRequestId(&_VRFV2PlusLoadTestWithMetrics.CallOpts) } +func (_VRFV2PlusLoadTestWithMetrics *VRFV2PlusLoadTestWithMetricsCaller) SRequestBlockTimes(opts *bind.CallOpts, arg0 *big.Int) (uint32, error) { + var out []interface{} + err := _VRFV2PlusLoadTestWithMetrics.contract.Call(opts, &out, "s_requestBlockTimes", arg0) + + if err != nil { + return *new(uint32), err + } + + out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32) + + return out0, err + +} + +func (_VRFV2PlusLoadTestWithMetrics *VRFV2PlusLoadTestWithMetricsSession) SRequestBlockTimes(arg0 *big.Int) (uint32, error) { + return _VRFV2PlusLoadTestWithMetrics.Contract.SRequestBlockTimes(&_VRFV2PlusLoadTestWithMetrics.CallOpts, arg0) +} + +func (_VRFV2PlusLoadTestWithMetrics *VRFV2PlusLoadTestWithMetricsCallerSession) SRequestBlockTimes(arg0 *big.Int) (uint32, error) { + return _VRFV2PlusLoadTestWithMetrics.Contract.SRequestBlockTimes(&_VRFV2PlusLoadTestWithMetrics.CallOpts, arg0) +} + func (_VRFV2PlusLoadTestWithMetrics *VRFV2PlusLoadTestWithMetricsCaller) SRequestCount(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _VRFV2PlusLoadTestWithMetrics.contract.Call(opts, &out, "s_requestCount") @@ -988,6 +1032,8 @@ func (_VRFV2PlusLoadTestWithMetrics *VRFV2PlusLoadTestWithMetrics) Address() com } type VRFV2PlusLoadTestWithMetricsInterface interface { + GetRequestBlockTimes(opts *bind.CallOpts, offset *big.Int, quantity *big.Int) ([]uint32, error) + GetRequestStatus(opts *bind.CallOpts, _requestId *big.Int) (GetRequestStatus, error) @@ -1004,6 +1050,8 @@ type VRFV2PlusLoadTestWithMetricsInterface interface { SLastRequestId(opts *bind.CallOpts) (*big.Int, error) + SRequestBlockTimes(opts *bind.CallOpts, arg0 *big.Int) (uint32, error) + SRequestCount(opts *bind.CallOpts) (*big.Int, error) SRequests(opts *bind.CallOpts, arg0 *big.Int) (SRequests, diff --git a/core/gethwrappers/generated/vrf_v2plus_single_consumer/vrf_v2plus_single_consumer.go b/core/gethwrappers/generated/vrf_v2plus_single_consumer/vrf_v2plus_single_consumer.go index 7636b813948..583b647c8b4 100644 --- a/core/gethwrappers/generated/vrf_v2plus_single_consumer/vrf_v2plus_single_consumer.go +++ b/core/gethwrappers/generated/vrf_v2plus_single_consumer/vrf_v2plus_single_consumer.go @@ -32,7 +32,7 @@ var ( var VRFV2PlusSingleConsumerExampleMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"vrfCoordinator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"nativePayment\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"}],\"name\":\"OnlyOwnerOrCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"vrfCoordinator\",\"type\":\"address\"}],\"name\":\"CoordinatorSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"fundAndRequestRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"requestRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_randomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestConfig\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"nativePayment\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_vrfCoordinator\",\"outputs\":[{\"internalType\":\"contractIVRFCoordinatorV2Plus\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"name\":\"setCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"subscribe\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"topUpSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"unsubscribe\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60806040523480156200001157600080fd5b506040516200188438038062001884833981016040819052620000349162000458565b8633806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf81620001a8565b5050600280546001600160a01b03199081166001600160a01b0394851617909155600380548216938a169390931790925550600a80543392169190911790556040805160c081018252600080825263ffffffff8881166020840181905261ffff8916948401859052908716606084018190526080840187905285151560a09094018490526004929092556005805465ffffffffffff19169091176401000000009094029390931763ffffffff60301b191666010000000000009091021790915560068390556007805460ff191690911790556200019b62000254565b5050505050505062000524565b6001600160a01b038116331415620002035760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6200025e620003c8565b6040805160018082528183019092526000916020808301908036833701905050905030816000815181106200029757620002976200050e565b6001600160a01b039283166020918202929092018101919091526002546040805163288688f960e21b81529051919093169263a21a23e49260048083019391928290030181600087803b158015620002ee57600080fd5b505af115801562000303573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003299190620004f4565b600481905560025482516001600160a01b039091169163bec4c08c9184906000906200035957620003596200050e565b60200260200101516040518363ffffffff1660e01b8152600401620003919291909182526001600160a01b0316602082015260400190565b600060405180830381600087803b158015620003ac57600080fd5b505af1158015620003c1573d6000803e3d6000fd5b5050505050565b6000546001600160a01b03163314620004245760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000083565b565b80516001600160a01b03811681146200043e57600080fd5b919050565b805163ffffffff811681146200043e57600080fd5b600080600080600080600060e0888a0312156200047457600080fd5b6200047f8862000426565b96506200048f6020890162000426565b95506200049f6040890162000443565b9450606088015161ffff81168114620004b757600080fd5b9350620004c76080890162000443565b925060a0880151915060c08801518015158114620004e457600080fd5b8091505092959891949750929550565b6000602082840312156200050757600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b61135080620005346000396000f3fe608060405234801561001057600080fd5b50600436106100f45760003560e01c80638da5cb5b11610097578063e0c8628911610066578063e0c862891461025c578063e89e106a14610264578063f2fde38b1461027b578063f6eaffc81461028e57600080fd5b80638da5cb5b146101e25780638ea98117146102215780638f449a05146102345780639eccacf61461023c57600080fd5b80637262561c116100d35780637262561c1461013457806379ba5097146101475780637db9263f1461014f57806386850e93146101cf57600080fd5b8062f714ce146100f95780631fe543e31461010e5780636fd700bb14610121575b600080fd5b61010c6101073660046110bc565b6102a1565b005b61010c61011c3660046110e8565b61035a565b61010c61012f36600461108a565b6103e0565b61010c610142366004611046565b610616565b61010c6106b3565b60045460055460065460075461018b939263ffffffff8082169361ffff6401000000008404169366010000000000009093049091169160ff1686565b6040805196875263ffffffff958616602088015261ffff90941693860193909352921660608401526080830191909152151560a082015260c0015b60405180910390f35b61010c6101dd36600461108a565b6107b0565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101c6565b61010c61022f366004611046565b610886565b61010c6109c3565b6002546101fc9073ffffffffffffffffffffffffffffffffffffffff1681565b61010c610b68565b61026d60095481565b6040519081526020016101c6565b61010c610289366004611046565b610cd5565b61026d61029c36600461108a565b610ce9565b6102a9610d0a565b6003546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018590529091169063a9059cbb90604401602060405180830381600087803b15801561031d57600080fd5b505af1158015610331573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103559190611068565b505050565b60025473ffffffffffffffffffffffffffffffffffffffff1633146103d2576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff90911660248201526044015b60405180910390fd5b6103dc8282610d8d565b5050565b6103e8610d0a565b6040805160c08101825260045480825260055463ffffffff808216602080860191909152640100000000830461ffff16858701526601000000000000909204166060840152600654608084015260075460ff16151560a0840152600354600254855192830193909352929373ffffffffffffffffffffffffffffffffffffffff93841693634000aea09316918691016040516020818303038152906040526040518463ffffffff1660e01b81526004016104a493929190611242565b602060405180830381600087803b1580156104be57600080fd5b505af11580156104d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104f69190611068565b5060006040518060c001604052808360800151815260200183600001518152602001836040015161ffff168152602001836020015163ffffffff168152602001836060015163ffffffff16815260200161056360405180602001604052808660a001511515815250610e0b565b90526002546040517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690639b1c385e906105bc908490600401611280565b602060405180830381600087803b1580156105d657600080fd5b505af11580156105ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060e91906110a3565b600955505050565b61061e610d0a565b600254600480546040517f0ae095400000000000000000000000000000000000000000000000000000000081529182015273ffffffffffffffffffffffffffffffffffffffff838116602483015290911690630ae0954090604401600060405180830381600087803b15801561069357600080fd5b505af11580156106a7573d6000803e3d6000fd5b50506000600455505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610734576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016103c9565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6107b8610d0a565b6003546002546004546040805160208082019390935281518082039093018352808201918290527f4000aea00000000000000000000000000000000000000000000000000000000090915273ffffffffffffffffffffffffffffffffffffffff93841693634000aea09361083493911691869190604401611242565b602060405180830381600087803b15801561084e57600080fd5b505af1158015610862573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103dc9190611068565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906108c6575060025473ffffffffffffffffffffffffffffffffffffffff163314155b1561094a57336108eb60005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff938416600482015291831660248301529190911660448201526064016103c9565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fd1a6a14209a385a964d036e404cb5cfb71f4000cdb03c9366292430787261be69060200160405180910390a150565b6109cb610d0a565b604080516001808252818301909252600091602080830190803683370190505090503081600081518110610a0157610a016112e5565b73ffffffffffffffffffffffffffffffffffffffff928316602091820292909201810191909152600254604080517fa21a23e40000000000000000000000000000000000000000000000000000000081529051919093169263a21a23e49260048083019391928290030181600087803b158015610a7d57600080fd5b505af1158015610a91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab591906110a3565b6004819055600254825173ffffffffffffffffffffffffffffffffffffffff9091169163bec4c08c918490600090610aef57610aef6112e5565b60200260200101516040518363ffffffff1660e01b8152600401610b3392919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610b4d57600080fd5b505af1158015610b61573d6000803e3d6000fd5b5050505050565b610b70610d0a565b6040805160c08082018352600454825260055463ffffffff808216602080860191825261ffff640100000000850481168789019081526601000000000000909504841660608089019182526006546080808b0191825260075460ff16151560a0808d019182528d519b8c018e5292518b528b518b8801529851909416898c0152945186169088015251909316928501929092528551918201909552905115158152919260009290820190610c2390610e0b565b90526002546040517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690639b1c385e90610c7c908490600401611280565b602060405180830381600087803b158015610c9657600080fd5b505af1158015610caa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cce91906110a3565b6009555050565b610cdd610d0a565b610ce681610ec7565b50565b60088181548110610cf957600080fd5b600091825260209091200154905081565b60005473ffffffffffffffffffffffffffffffffffffffff163314610d8b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016103c9565b565b6009548214610df8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265717565737420494420697320696e636f727265637400000000000000000060448201526064016103c9565b8051610355906008906020840190610fbd565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401610e4491511515815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915292915050565b73ffffffffffffffffffffffffffffffffffffffff8116331415610f47576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016103c9565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610ff8579160200282015b82811115610ff8578251825591602001919060010190610fdd565b50611004929150611008565b5090565b5b808211156110045760008155600101611009565b803573ffffffffffffffffffffffffffffffffffffffff8116811461104157600080fd5b919050565b60006020828403121561105857600080fd5b6110618261101d565b9392505050565b60006020828403121561107a57600080fd5b8151801515811461106157600080fd5b60006020828403121561109c57600080fd5b5035919050565b6000602082840312156110b557600080fd5b5051919050565b600080604083850312156110cf57600080fd5b823591506110df6020840161101d565b90509250929050565b600080604083850312156110fb57600080fd5b8235915060208084013567ffffffffffffffff8082111561111b57600080fd5b818601915086601f83011261112f57600080fd5b81358181111561114157611141611314565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110858211171561118457611184611314565b604052828152858101935084860182860187018b10156111a357600080fd5b600095505b838610156111c65780358552600195909501949386019386016111a8565b508096505050505050509250929050565b6000815180845260005b818110156111fd576020818501810151868301820152016111e1565b8181111561120f576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff8416815282602082015260606040820152600061127760608301846111d7565b95945050505050565b60208152815160208201526020820151604082015261ffff60408301511660608201526000606083015163ffffffff80821660808501528060808601511660a0850152505060a083015160c0808401526112dd60e08401826111d7565b949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + Bin: "0x60806040523480156200001157600080fd5b506040516200187f3803806200187f83398101604081905262000034916200046f565b8633806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf81620001d0565b5050506001600160a01b038116620000ea5760405163d92e233d60e01b815260040160405180910390fd5b600280546001600160a01b03199081166001600160a01b039384161790915560038054821692891692909217909155600a80543392169190911790556040805160c081018252600080825263ffffffff8881166020840181905261ffff8916948401859052908716606084018190526080840187905285151560a09094018490526004929092556005805465ffffffffffff19169091176401000000009094029390931763ffffffff60301b191666010000000000009091021790915560068390556007805460ff19169091179055620001c36200027b565b505050505050506200053b565b336001600160a01b038216036200022a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b62000285620003df565b604080516001808252818301909252600091602080830190803683370190505090503081600081518110620002be57620002be6200050b565b6001600160a01b039283166020918202929092018101919091526002546040805163288688f960e21b81529051919093169263a21a23e492600480830193919282900301816000875af11580156200031a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000340919062000521565b600481905560025482516001600160a01b039091169163bec4c08c9184906000906200037057620003706200050b565b60200260200101516040518363ffffffff1660e01b8152600401620003a89291909182526001600160a01b0316602082015260400190565b600060405180830381600087803b158015620003c357600080fd5b505af1158015620003d8573d6000803e3d6000fd5b5050505050565b6000546001600160a01b031633146200043b5760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000083565b565b80516001600160a01b03811681146200045557600080fd5b919050565b805163ffffffff811681146200045557600080fd5b600080600080600080600060e0888a0312156200048b57600080fd5b62000496886200043d565b9650620004a6602089016200043d565b9550620004b6604089016200045a565b9450606088015161ffff81168114620004ce57600080fd5b9350620004de608089016200045a565b925060a0880151915060c08801518015158114620004fb57600080fd5b8091505092959891949750929550565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156200053457600080fd5b5051919050565b611334806200054b6000396000f3fe608060405234801561001057600080fd5b50600436106100f45760003560e01c80638da5cb5b11610097578063e0c8628911610066578063e0c862891461025c578063e89e106a14610264578063f2fde38b1461027b578063f6eaffc81461028e57600080fd5b80638da5cb5b146101e25780638ea98117146102215780638f449a05146102345780639eccacf61461023c57600080fd5b80637262561c116100d35780637262561c1461013457806379ba5097146101475780637db9263f1461014f57806386850e93146101cf57600080fd5b8062f714ce146100f95780631fe543e31461010e5780636fd700bb14610121575b600080fd5b61010c610107366004611038565b6102a1565b005b61010c61011c366004611093565b61034b565b61010c61012f36600461117b565b6103d1565b61010c610142366004611194565b6105e9565b61010c610686565b60045460055460065460075461018b939263ffffffff8082169361ffff6401000000008404169366010000000000009093049091169160ff1686565b6040805196875263ffffffff958616602088015261ffff90941693860193909352921660608401526080830191909152151560a082015260c0015b60405180910390f35b61010c6101dd36600461117b565b610783565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101c6565b61010c61022f366004611194565b61084a565b61010c6109d4565b6002546101fc9073ffffffffffffffffffffffffffffffffffffffff1681565b61010c610b6a565b61026d60095481565b6040519081526020016101c6565b61010c610289366004611194565b610cc8565b61026d61029c36600461117b565b610cdc565b6102a9610cfd565b6003546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018590529091169063a9059cbb906044016020604051808303816000875af1158015610322573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061034691906111b6565b505050565b60025473ffffffffffffffffffffffffffffffffffffffff1633146103c3576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff90911660248201526044015b60405180910390fd5b6103cd8282610d80565b5050565b6103d9610cfd565b6040805160c08101825260045480825260055463ffffffff808216602080860191909152640100000000830461ffff16858701526601000000000000909204166060840152600654608084015260075460ff16151560a0840152600354600254855192830193909352929373ffffffffffffffffffffffffffffffffffffffff93841693634000aea09316918691016040516020818303038152906040526040518463ffffffff1660e01b81526004016104959392919061123c565b6020604051808303816000875af11580156104b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104d891906111b6565b5060006040518060c001604052808360800151815260200183600001518152602001836040015161ffff168152602001836020015163ffffffff168152602001836060015163ffffffff16815260200161054560405180602001604052808660a001511515815250610dfe565b90526002546040517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690639b1c385e9061059e90849060040161127a565b6020604051808303816000875af11580156105bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e191906112df565b600955505050565b6105f1610cfd565b600254600480546040517f0ae095400000000000000000000000000000000000000000000000000000000081529182015273ffffffffffffffffffffffffffffffffffffffff838116602483015290911690630ae0954090604401600060405180830381600087803b15801561066657600080fd5b505af115801561067a573d6000803e3d6000fd5b50506000600455505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610707576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016103ba565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b61078b610cfd565b6003546002546004546040805160208082019390935281518082039093018352808201918290527f4000aea00000000000000000000000000000000000000000000000000000000090915273ffffffffffffffffffffffffffffffffffffffff93841693634000aea0936108079391169186919060440161123c565b6020604051808303816000875af1158015610826573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103cd91906111b6565b60005473ffffffffffffffffffffffffffffffffffffffff16331480159061088a575060025473ffffffffffffffffffffffffffffffffffffffff163314155b1561090e57336108af60005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff938416600482015291831660248301529190911660448201526064016103ba565b73ffffffffffffffffffffffffffffffffffffffff811661095b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fd1a6a14209a385a964d036e404cb5cfb71f4000cdb03c9366292430787261be69060200160405180910390a150565b6109dc610cfd565b604080516001808252818301909252600091602080830190803683370190505090503081600081518110610a1257610a126112f8565b73ffffffffffffffffffffffffffffffffffffffff928316602091820292909201810191909152600254604080517fa21a23e40000000000000000000000000000000000000000000000000000000081529051919093169263a21a23e492600480830193919282900301816000875af1158015610a93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab791906112df565b6004819055600254825173ffffffffffffffffffffffffffffffffffffffff9091169163bec4c08c918490600090610af157610af16112f8565b60200260200101516040518363ffffffff1660e01b8152600401610b3592919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610b4f57600080fd5b505af1158015610b63573d6000803e3d6000fd5b5050505050565b610b72610cfd565b6040805160c08082018352600454825260055463ffffffff808216602080860191825261ffff640100000000850481168789019081526601000000000000909504841660608089019182526006546080808b0191825260075460ff16151560a0808d019182528d519b8c018e5292518b528b518b8801529851909416898c0152945186169088015251909316928501929092528551918201909552905115158152919260009290820190610c2590610dfe565b90526002546040517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690639b1c385e90610c7e90849060040161127a565b6020604051808303816000875af1158015610c9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc191906112df565b6009555050565b610cd0610cfd565b610cd981610eba565b50565b60088181548110610cec57600080fd5b600091825260209091200154905081565b60005473ffffffffffffffffffffffffffffffffffffffff163314610d7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016103ba565b565b6009548214610deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265717565737420494420697320696e636f727265637400000000000000000060448201526064016103ba565b8051610346906008906020840190610faf565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401610e3791511515815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915292915050565b3373ffffffffffffffffffffffffffffffffffffffff821603610f39576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016103ba565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610fea579160200282015b82811115610fea578251825591602001919060010190610fcf565b50610ff6929150610ffa565b5090565b5b80821115610ff65760008155600101610ffb565b803573ffffffffffffffffffffffffffffffffffffffff8116811461103357600080fd5b919050565b6000806040838503121561104b57600080fd5b8235915061105b6020840161100f565b90509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080604083850312156110a657600080fd5b8235915060208084013567ffffffffffffffff808211156110c657600080fd5b818601915086601f8301126110da57600080fd5b8135818111156110ec576110ec611064565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110858211171561112f5761112f611064565b60405291825284820192508381018501918983111561114d57600080fd5b938501935b8285101561116b57843584529385019392850192611152565b8096505050505050509250929050565b60006020828403121561118d57600080fd5b5035919050565b6000602082840312156111a657600080fd5b6111af8261100f565b9392505050565b6000602082840312156111c857600080fd5b815180151581146111af57600080fd5b6000815180845260005b818110156111fe576020818501810151868301820152016111e2565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b73ffffffffffffffffffffffffffffffffffffffff8416815282602082015260606040820152600061127160608301846111d8565b95945050505050565b60208152815160208201526020820151604082015261ffff60408301511660608201526000606083015163ffffffff80821660808501528060808601511660a0850152505060a083015160c0808401526112d760e08401826111d8565b949350505050565b6000602082840312156112f157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea164736f6c6343000813000a", } var VRFV2PlusSingleConsumerExampleABI = VRFV2PlusSingleConsumerExampleMetaData.ABI diff --git a/core/gethwrappers/generated/vrf_v2plus_sub_owner/vrf_v2plus_sub_owner.go b/core/gethwrappers/generated/vrf_v2plus_sub_owner/vrf_v2plus_sub_owner.go index 7c63757e95a..8354b68d766 100644 --- a/core/gethwrappers/generated/vrf_v2plus_sub_owner/vrf_v2plus_sub_owner.go +++ b/core/gethwrappers/generated/vrf_v2plus_sub_owner/vrf_v2plus_sub_owner.go @@ -32,7 +32,7 @@ var ( var VRFV2PlusExternalSubOwnerExampleMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"vrfCoordinator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"}],\"name\":\"OnlyOwnerOrCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"vrfCoordinator\",\"type\":\"address\"}],\"name\":\"CoordinatorSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"nativePayment\",\"type\":\"bool\"}],\"name\":\"requestRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_randomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_vrfCoordinator\",\"outputs\":[{\"internalType\":\"contractIVRFCoordinatorV2Plus\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"name\":\"setCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b50604051610d9a380380610d9a83398101604081905261002f916101c1565b8133806000816100865760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156100b6576100b6816100fb565b5050600280546001600160a01b039384166001600160a01b031991821617909155600380549490931693811693909317909155506006805490911633179055506101f4565b6001600160a01b0381163314156101545760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161007d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146101bc57600080fd5b919050565b600080604083850312156101d457600080fd5b6101dd836101a5565b91506101eb602084016101a5565b90509250929050565b610b97806102036000396000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c80638ea9811711610076578063e89e106a1161005b578063e89e106a1461014f578063f2fde38b14610166578063f6eaffc81461017957600080fd5b80638ea981171461011c5780639eccacf61461012f57600080fd5b80631fe543e3146100a85780635b6c5de8146100bd57806379ba5097146100d05780638da5cb5b146100d8575b600080fd5b6100bb6100b6366004610934565b61018c565b005b6100bb6100cb366004610a23565b610212565b6100bb610325565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6100bb61012a3660046108c5565b610422565b6002546100f29073ffffffffffffffffffffffffffffffffffffffff1681565b61015860055481565b604051908152602001610113565b6100bb6101743660046108c5565b61055f565b610158610187366004610902565b610573565b60025473ffffffffffffffffffffffffffffffffffffffff163314610204576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff90911660248201526044015b60405180910390fd5b61020e8282610594565b5050565b61021a610617565b60006040518060c001604052808481526020018881526020018661ffff1681526020018763ffffffff1681526020018563ffffffff16815260200161026e604051806020016040528086151581525061069a565b90526002546040517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690639b1c385e906102c7908490600401610a9b565b602060405180830381600087803b1580156102e157600080fd5b505af11580156102f5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610319919061091b565b60055550505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146103a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016101fb565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590610462575060025473ffffffffffffffffffffffffffffffffffffffff163314155b156104e6573361048760005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff938416600482015291831660248301529190911660448201526064016101fb565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fd1a6a14209a385a964d036e404cb5cfb71f4000cdb03c9366292430787261be69060200160405180910390a150565b610567610617565b61057081610756565b50565b6004818154811061058357600080fd5b600091825260209091200154905081565b60055482146105ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265717565737420494420697320696e636f727265637400000000000000000060448201526064016101fb565b805161061290600490602084019061084c565b505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610698576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016101fb565b565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa826040516024016106d391511515815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915292915050565b73ffffffffffffffffffffffffffffffffffffffff81163314156107d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016101fb565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610887579160200282015b8281111561088757825182559160200191906001019061086c565b50610893929150610897565b5090565b5b808211156108935760008155600101610898565b803563ffffffff811681146108c057600080fd5b919050565b6000602082840312156108d757600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146108fb57600080fd5b9392505050565b60006020828403121561091457600080fd5b5035919050565b60006020828403121561092d57600080fd5b5051919050565b6000806040838503121561094757600080fd5b8235915060208084013567ffffffffffffffff8082111561096757600080fd5b818601915086601f83011261097b57600080fd5b81358181111561098d5761098d610b5b565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f830116810181811085821117156109d0576109d0610b5b565b604052828152858101935084860182860187018b10156109ef57600080fd5b600095505b83861015610a125780358552600195909501949386019386016109f4565b508096505050505050509250929050565b60008060008060008060c08789031215610a3c57600080fd5b86359550610a4c602088016108ac565b9450604087013561ffff81168114610a6357600080fd5b9350610a71606088016108ac565b92506080870135915060a08701358015158114610a8d57600080fd5b809150509295509295509295565b6000602080835283518184015280840151604084015261ffff6040850151166060840152606084015163ffffffff80821660808601528060808701511660a0860152505060a084015160c08085015280518060e086015260005b81811015610b125782810184015186820161010001528301610af5565b81811115610b2557600061010083880101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169390930161010001949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + Bin: "0x608060405234801561001057600080fd5b50604051610def380380610def83398101604081905261002f916101e6565b8133806000816100865760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156100b6576100b681610121565b5050506001600160a01b0381166100e05760405163d92e233d60e01b815260040160405180910390fd5b600280546001600160a01b039283166001600160a01b0319918216179091556003805493909216928116929092179055600680549091163317905550610219565b336001600160a01b038216036101795760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161007d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146101e157600080fd5b919050565b600080604083850312156101f957600080fd5b610202836101ca565b9150610210602084016101ca565b90509250929050565b610bc7806102286000396000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c80638ea9811711610076578063e89e106a1161005b578063e89e106a1461014f578063f2fde38b14610166578063f6eaffc81461017957600080fd5b80638ea981171461011c5780639eccacf61461012f57600080fd5b80631fe543e3146100a85780635b6c5de8146100bd57806379ba5097146100d05780638da5cb5b146100d8575b600080fd5b6100bb6100b6366004610918565b61018c565b005b6100bb6100cb366004610a19565b610212565b6100bb610316565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6100bb61012a366004610a91565b610413565b6002546100f29073ffffffffffffffffffffffffffffffffffffffff1681565b61015860055481565b604051908152602001610113565b6100bb610174366004610a91565b61059d565b610158610187366004610ace565b6105b1565b60025473ffffffffffffffffffffffffffffffffffffffff163314610204576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff90911660248201526044015b60405180910390fd5b61020e82826105d2565b5050565b61021a610655565b60006040518060c001604052808481526020018881526020018661ffff1681526020018763ffffffff1681526020018563ffffffff16815260200161026e60405180602001604052808615158152506106d8565b90526002546040517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690639b1c385e906102c7908490600401610ae7565b6020604051808303816000875af11580156102e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061030a9190610ba1565b60055550505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610397576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016101fb565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590610453575060025473ffffffffffffffffffffffffffffffffffffffff163314155b156104d7573361047860005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff938416600482015291831660248301529190911660448201526064016101fb565b73ffffffffffffffffffffffffffffffffffffffff8116610524576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fd1a6a14209a385a964d036e404cb5cfb71f4000cdb03c9366292430787261be69060200160405180910390a150565b6105a5610655565b6105ae81610794565b50565b600481815481106105c157600080fd5b600091825260209091200154905081565b600554821461063d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265717565737420494420697320696e636f727265637400000000000000000060448201526064016101fb565b8051610650906004906020840190610889565b505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146106d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016101fb565b565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa8260405160240161071191511515815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915292915050565b3373ffffffffffffffffffffffffffffffffffffffff821603610813576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016101fb565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b8280548282559060005260206000209081019282156108c4579160200282015b828111156108c45782518255916020019190600101906108a9565b506108d09291506108d4565b5090565b5b808211156108d057600081556001016108d5565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806040838503121561092b57600080fd5b8235915060208084013567ffffffffffffffff8082111561094b57600080fd5b818601915086601f83011261095f57600080fd5b813581811115610971576109716108e9565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f830116810181811085821117156109b4576109b46108e9565b6040529182528482019250838101850191898311156109d257600080fd5b938501935b828510156109f0578435845293850193928501926109d7565b8096505050505050509250929050565b803563ffffffff81168114610a1457600080fd5b919050565b60008060008060008060c08789031215610a3257600080fd5b86359550610a4260208801610a00565b9450604087013561ffff81168114610a5957600080fd5b9350610a6760608801610a00565b92506080870135915060a08701358015158114610a8357600080fd5b809150509295509295509295565b600060208284031215610aa357600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610ac757600080fd5b9392505050565b600060208284031215610ae057600080fd5b5035919050565b6000602080835283518184015280840151604084015261ffff6040850151166060840152606084015163ffffffff80821660808601528060808701511660a0860152505060a084015160c08085015280518060e086015260005b81811015610b5e5782810184015186820161010001528301610b41565b5061010092506000838287010152827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116860101935050505092915050565b600060208284031215610bb357600080fd5b505191905056fea164736f6c6343000813000a", } var VRFV2PlusExternalSubOwnerExampleABI = VRFV2PlusExternalSubOwnerExampleMetaData.ABI diff --git a/core/gethwrappers/generated/vrf_v2plus_upgraded_version/vrf_v2plus_upgraded_version.go b/core/gethwrappers/generated/vrf_v2plus_upgraded_version/vrf_v2plus_upgraded_version.go index 472f6acef9a..79861507e14 100644 --- a/core/gethwrappers/generated/vrf_v2plus_upgraded_version/vrf_v2plus_upgraded_version.go +++ b/core/gethwrappers/generated/vrf_v2plus_upgraded_version/vrf_v2plus_upgraded_version.go @@ -61,8 +61,8 @@ type VRFV2PlusClientRandomWordsRequest struct { } var VRFCoordinatorV2PlusUpgradedVersionMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"blockhashStore\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"internalBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"externalBalance\",\"type\":\"uint256\"}],\"name\":\"BalanceInvariantViolated\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"BlockhashNotInStore\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorNotRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToSendNative\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToTransferLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"GasLimitTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectCommitment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidExtraArgsTag\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"transferredValue\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"expectedValue\",\"type\":\"uint96\"}],\"name\":\"InvalidNativeBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"have\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"min\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"max\",\"type\":\"uint16\"}],\"name\":\"InvalidRequestConfirmations\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"requestVersion\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"expectedVersion\",\"type\":\"uint8\"}],\"name\":\"InvalidVersion\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkAlreadySet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkNotSet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"}],\"name\":\"MustBeRequestedOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoCorrespondingRequest\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"NoSuchProvingKey\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"NumWordsTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PendingRequestExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"ProvingKeyAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Reentrant\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SubscriptionIDCollisionFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyConsumers\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"nativePremiumPercentage\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"linkPremiumPercentage\",\"type\":\"uint8\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"MigrationCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"NativeFundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"ProvingKeyRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"outputSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"payment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"RandomWordsFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"preSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RandomWordsRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountLink\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountNative\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldNativeBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newNativeBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFundedWithNative\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BLOCKHASH_STORE\",\"outputs\":[{\"internalType\":\"contractBlockhashStoreInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK_NATIVE_FEED\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_CONSUMERS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_NUM_WORDS\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_REQUEST_CONFIRMATIONS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256[2]\",\"name\":\"pk\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"gamma\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"c\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"s\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"uWitness\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"cGammaWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"sHashWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"zInv\",\"type\":\"uint256\"}],\"internalType\":\"structVRF.Proof\",\"name\":\"proof\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"blockNum\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFCoordinatorV2PlusUpgradedVersion.RequestCommitment\",\"name\":\"rc\",\"type\":\"tuple\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"fulfillRandomWords\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"fundSubscriptionWithNative\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveSubscriptionIds\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRequestConfig\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"getSubscription\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"nativeBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint64\",\"name\":\"reqCount\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicKey\",\"type\":\"uint256[2]\"}],\"name\":\"hashOfKey\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"}],\"name\":\"migrate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"migrationVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedData\",\"type\":\"bytes\"}],\"name\":\"onMigration\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"ownerCancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"pendingRequestExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverNativeFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"registerMigratableCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"}],\"name\":\"registerProvingKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFV2PlusClient.RandomWordsRequest\",\"name\":\"req\",\"type\":\"tuple\"}],\"name\":\"requestRandomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"requestSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_config\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"reentrancyLock\",\"type\":\"bool\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"nativePremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"linkPremiumPercentage\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_currentSubNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_provingKeyHashes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requestCommitments\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalNativeBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"nativePremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"linkPremiumPercentage\",\"type\":\"uint8\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkNativeFeed\",\"type\":\"address\"}],\"name\":\"setLINKAndLINKNativeFeed\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"withdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b5060405162005e7438038062005e74833981016040819052620000349162000183565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d7565b50505060601b6001600160601b031916608052620001b5565b6001600160a01b038116331415620001325760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019657600080fd5b81516001600160a01b0381168114620001ae57600080fd5b9392505050565b60805160601c615c99620001db600039600081816104f401526134590152615c996000f3fe6080604052600436106101e05760003560e01c8062012291146101e5578063088070f5146102125780630ae09540146102e057806315c48b841461030257806318e3dd271461032a5780631b6b6d2314610369578063294daa49146103965780632f622e6b146103b2578063301f42e9146103d2578063405b84fa146103f257806340d6bb821461041257806341af6c871461043d57806351cff8d91461046d5780635d06b4ab1461048d57806364d51a2a146104ad57806365982744146104c2578063689c4517146104e257806372e9d5651461051657806379ba5097146105365780637bce14d11461054b5780638402595e1461056b57806386fe91c71461058b5780638da5cb5b146105ab57806395b55cfc146105c95780639b1c385e146105dc5780639d40a6fd1461060a578063a21a23e414610637578063a4c0ed361461064c578063a63e0bfb1461066c578063aa433aff1461068c578063aefb212f146106ac578063b2a7cac5146106d9578063bec4c08c146106f9578063caf70c4a14610719578063cb63179714610739578063ce3f471914610759578063d98e620e1461076c578063dac83d291461078c578063dc311dd3146107ac578063e72f6e30146107dd578063ee9d2d38146107fd578063f2fde38b1461082a575b600080fd5b3480156101f157600080fd5b506101fa61084a565b60405161020993929190615746565b60405180910390f35b34801561021e57600080fd5b50600c546102839061ffff81169063ffffffff62010000820481169160ff600160301b8204811692600160381b8304811692600160581b8104821692600160781b8204831692600160981b83041691600160b81b8104821691600160c01b9091041689565b6040805161ffff909a168a5263ffffffff98891660208b01529615159689019690965293861660608801529185166080870152841660a08601529290921660c084015260ff91821660e08401521661010082015261012001610209565b3480156102ec57600080fd5b506103006102fb3660046153b9565b6108c6565b005b34801561030e57600080fd5b5061031760c881565b60405161ffff9091168152602001610209565b34801561033657600080fd5b50600a5461035190600160601b90046001600160601b031681565b6040516001600160601b039091168152602001610209565b34801561037557600080fd5b50600254610389906001600160a01b031681565b60405161020991906155ea565b3480156103a257600080fd5b5060405160028152602001610209565b3480156103be57600080fd5b506103006103cd366004614ed3565b61090e565b3480156103de57600080fd5b506103516103ed36600461508a565b610a5a565b3480156103fe57600080fd5b5061030061040d3660046153b9565b610ef0565b34801561041e57600080fd5b506104286101f481565b60405163ffffffff9091168152602001610209565b34801561044957600080fd5b5061045d6104583660046153a0565b6112c1565b6040519015158152602001610209565b34801561047957600080fd5b50610300610488366004614ed3565b611467565b34801561049957600080fd5b506103006104a8366004614ed3565b6115f5565b3480156104b957600080fd5b50610317606481565b3480156104ce57600080fd5b506103006104dd366004614ef0565b6116ac565b3480156104ee57600080fd5b506103897f000000000000000000000000000000000000000000000000000000000000000081565b34801561052257600080fd5b50600354610389906001600160a01b031681565b34801561054257600080fd5b5061030061170c565b34801561055757600080fd5b50610300610566366004614f84565b6117b6565b34801561057757600080fd5b50610300610586366004614ed3565b6118af565b34801561059757600080fd5b50600a54610351906001600160601b031681565b3480156105b757600080fd5b506000546001600160a01b0316610389565b6103006105d73660046153a0565b6119bb565b3480156105e857600080fd5b506105fc6105f7366004615178565b611adc565b604051908152602001610209565b34801561061657600080fd5b5060075461062a906001600160401b031681565b60405161020991906158df565b34801561064357600080fd5b506105fc611e7b565b34801561065857600080fd5b50610300610667366004614f29565b61204e565b34801561067857600080fd5b506103006106873660046152ff565b6121c8565b34801561069857600080fd5b506103006106a73660046153a0565b6123d1565b3480156106b857600080fd5b506106cc6106c73660046153de565b612419565b6040516102099190615661565b3480156106e557600080fd5b506103006106f43660046153a0565b61251b565b34801561070557600080fd5b506103006107143660046153b9565b612610565b34801561072557600080fd5b506105fc610734366004614fac565b612702565b34801561074557600080fd5b506103006107543660046153b9565b612732565b610300610767366004614ffe565b61299d565b34801561077857600080fd5b506105fc6107873660046153a0565b612cdd565b34801561079857600080fd5b506103006107a73660046153b9565b612cfe565b3480156107b857600080fd5b506107cc6107c73660046153a0565b612d94565b6040516102099594939291906158f3565b3480156107e957600080fd5b506103006107f8366004614ed3565b612e82565b34801561080957600080fd5b506105fc6108183660046153a0565b600f6020526000908152604090205481565b34801561083657600080fd5b50610300610845366004614ed3565b61305d565b600c54600e805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff169391928391908301828280156108b457602002820191906000526020600020905b8154815260200190600101908083116108a0575b50505050509050925092509250909192565b816108d081613071565b6108d86130d2565b6108e1836112c1565b156108ff57604051631685ecdd60e31b815260040160405180910390fd5b61090983836130ff565b505050565b6109166130d2565b61091e6132b3565b600b54600160601b90046001600160601b031661094e57604051631e9acf1760e31b815260040160405180910390fd5b600b8054600160601b90046001600160601b0316908190600c6109718380615ad9565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a600c8282829054906101000a90046001600160601b03166109b99190615ad9565b92506101000a8154816001600160601b0302191690836001600160601b031602179055506000826001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114610a33576040519150601f19603f3d011682016040523d82523d6000602084013e610a38565b606091505b50509050806109095760405163950b247960e01b815260040160405180910390fd5b6000610a646130d2565b60005a90506000610a758686613306565b90506000856060015163ffffffff166001600160401b03811115610a9b57610a9b615c0b565b604051908082528060200260200182016040528015610ac4578160200160208202803683370190505b50905060005b866060015163ffffffff16811015610b3b57826040015181604051602001610af3929190615674565b6040516020818303038152906040528051906020012060001c828281518110610b1e57610b1e615bf5565b602090810291909101015280610b3381615b5d565b915050610aca565b50602080830180516000908152600f9092526040808320839055905190518291631fe543e360e01b91610b73919086906024016157d0565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252600c805460ff60301b1916600160301b1790559089015160808a0151919250600091610bd89163ffffffff169084613571565b600c805460ff60301b1916905560208a810151600090815260069091526040902054909150600160c01b90046001600160401b0316610c18816001615a4b565b6020808c0151600090815260069091526040812080546001600160401b0393909316600160c01b026001600160c01b039093169290921790915560a08b01518051610c6590600190615ac2565b81518110610c7557610c75615bf5565b602091010151600c5460f89190911c6001149150600090610ca6908a90600160581b900463ffffffff163a856135bd565b90508115610d9e576020808d01516000908152600690915260409020546001600160601b03808316600160601b909204161015610cf657604051631e9acf1760e31b815260040160405180910390fd5b60208c81015160009081526006909152604090208054829190600c90610d2d908490600160601b90046001600160601b0316615ad9565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600b600c8282829054906101000a90046001600160601b0316610d759190615a6d565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550610e79565b6020808d01516000908152600690915260409020546001600160601b0380831691161015610ddf57604051631e9acf1760e31b815260040160405180910390fd5b6020808d015160009081526006909152604081208054839290610e0c9084906001600160601b0316615ad9565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600b60008282829054906101000a90046001600160601b0316610e549190615a6d565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b8b6020015188602001517f49580fdfd9497e1ed5c1b1cec0495087ae8e3f1267470ec2fb015db32e3d6aa78a604001518488604051610ed6939291909283526001600160601b039190911660208301521515604082015260600190565b60405180910390a3985050505050505050505b9392505050565b610ef86130d2565b610f018161360c565b610f295780604051635428d44960e01b8152600401610f2091906155ea565b60405180910390fd5b600080600080610f3886612d94565b945094505093509350336001600160a01b0316826001600160a01b031614610f9b5760405162461bcd60e51b81526020600482015260166024820152752737ba1039bab139b1b934b83a34b7b71037bbb732b960511b6044820152606401610f20565b610fa4866112c1565b15610fea5760405162461bcd60e51b815260206004820152601660248201527550656e64696e6720726571756573742065786973747360501b6044820152606401610f20565b60006040518060c00160405280610fff600290565b60ff168152602001888152602001846001600160a01b03168152602001838152602001866001600160601b03168152602001856001600160601b0316815250905060008160405160200161105391906156b3565b604051602081830303815290604052905061106d88613676565b505060405163ce3f471960e01b81526001600160a01b0388169063ce3f4719906001600160601b038816906110a69085906004016156a0565b6000604051808303818588803b1580156110bf57600080fd5b505af11580156110d3573d6000803e3d6000fd5b50506002546001600160a01b0316158015935091506110fc905057506001600160601b03861615155b156111c65760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb90611133908a908a90600401615631565b602060405180830381600087803b15801561114d57600080fd5b505af1158015611161573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111859190614fc8565b6111c65760405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742066756e647360701b6044820152606401610f20565b600c805460ff60301b1916600160301b17905560005b835181101561126f578381815181106111f7576111f7615bf5565b60200260200101516001600160a01b0316638ea98117896040518263ffffffff1660e01b815260040161122a91906155ea565b600060405180830381600087803b15801561124457600080fd5b505af1158015611258573d6000803e3d6000fd5b50505050808061126790615b5d565b9150506111dc565b50600c805460ff60301b191690556040517fd63ca8cb945956747ee69bfdc3ea754c24a4caf7418db70e46052f7850be4187906112af9089908b906155fe565b60405180910390a15050505050505050565b6000818152600560209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152879693958601939092919083018282801561134b57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161132d575b505050505081525050905060005b81604001515181101561145d5760005b600e5481101561144a576000611413600e838154811061138b5761138b615bf5565b9060005260206000200154856040015185815181106113ac576113ac615bf5565b60200260200101518860046000896040015189815181106113cf576113cf615bf5565b6020908102919091018101516001600160a01b0316825281810192909252604090810160009081208d825290925290205461010090046001600160401b031661381e565b506000818152600f6020526040902054909150156114375750600195945050505050565b508061144281615b5d565b915050611369565b508061145581615b5d565b915050611359565b5060009392505050565b61146f6130d2565b6114776132b3565b6002546001600160a01b03166114a05760405163c1f0c0a160e01b815260040160405180910390fd5b600b546001600160601b03166114c957604051631e9acf1760e31b815260040160405180910390fd5b600b80546001600160601b031690819060006114e58380615ad9565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a60008282829054906101000a90046001600160601b031661152d9190615ad9565b82546001600160601b039182166101009390930a92830291909202199091161790555060025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb906115829085908590600401615631565b602060405180830381600087803b15801561159c57600080fd5b505af11580156115b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115d49190614fc8565b6115f157604051631e9acf1760e31b815260040160405180910390fd5b5050565b6115fd6132b3565b6116068161360c565b15611626578060405163ac8a27ef60e01b8152600401610f2091906155ea565b601280546001810182556000919091527fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec34440180546001600160a01b0319166001600160a01b0383161790556040517fb7cabbfc11e66731fc77de0444614282023bcbd41d16781c753a431d0af01625906116a19083906155ea565b60405180910390a150565b6116b46132b3565b6002546001600160a01b0316156116de57604051631688c53760e11b815260040160405180910390fd5b600280546001600160a01b039384166001600160a01b03199182161790915560038054929093169116179055565b6001546001600160a01b0316331461175f5760405162461bcd60e51b815260206004820152601660248201527526bab9ba10313290383937b837b9b2b21037bbb732b960511b6044820152606401610f20565b60008054336001600160a01b0319808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6117be6132b3565b6040805180820182526000916117ed919084906002908390839080828437600092019190915250612702915050565b6000818152600d602052604090205490915060ff161561182357604051634a0b8fa760e01b815260048101829052602401610f20565b6000818152600d6020526040808220805460ff19166001908117909155600e805491820181559092527fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd909101829055517fc9583fd3afa3d7f16eb0b88d0268e7d05c09bafa4b21e092cbd1320e1bc8089d906118a39083815260200190565b60405180910390a15050565b6118b76132b3565b600a544790600160601b90046001600160601b0316818111156118f15780826040516354ced18160e11b8152600401610f20929190615674565b818110156109095760006119058284615ac2565b90506000846001600160a01b03168260405160006040518083038185875af1925050503d8060008114611954576040519150601f19603f3d011682016040523d82523d6000602084013e611959565b606091505b505090508061197b5760405163950b247960e01b815260040160405180910390fd5b7f4aed7c8eed0496c8c19ea2681fcca25741c1602342e38b045d9f1e8e905d2e9c85836040516119ac9291906155fe565b60405180910390a15050505050565b6119c36130d2565b6000818152600560205260409020546001600160a01b03166119f857604051630fb532db60e11b815260040160405180910390fd5b60008181526006602052604090208054600160601b90046001600160601b0316903490600c611a278385615a6d565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555034600a600c8282829054906101000a90046001600160601b0316611a6f9190615a6d565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f7603b205d03651ee812f803fccde89f1012e545a9c99f0abfea9cedd0fd8e902823484611ac29190615a33565b604051611ad0929190615674565b60405180910390a25050565b6000611ae66130d2565b6020808301356000908152600590915260409020546001600160a01b0316611b2157604051630fb532db60e11b815260040160405180910390fd5b3360009081526004602090815260408083208583013584528083529281902081518083019092525460ff811615158083526101009091046001600160401b03169282019290925290611b8e578360200135336040516379bfd40160e01b8152600401610f209291906157a5565b600c5461ffff16611ba560608601604087016152e4565b61ffff161080611bc8575060c8611bc260608601604087016152e4565b61ffff16115b15611c0257611bdd60608501604086016152e4565b600c5460405163539c34bb60e11b8152610f20929161ffff169060c890600401615728565b600c5462010000900463ffffffff16611c216080860160608701615400565b63ffffffff161115611c6757611c3d6080850160608601615400565b600c54604051637aebf00f60e11b8152610f20929162010000900463ffffffff16906004016158c8565b6101f4611c7a60a0860160808701615400565b63ffffffff161115611cb457611c9660a0850160808601615400565b6101f46040516311ce1afb60e21b8152600401610f209291906158c8565b806020018051611cc390615b78565b6001600160401b031690526020818101516000918291611ceb9188359133918a01359061381e565b90925090506000611d07611d0260a0890189615948565b6138a7565b90506000611d1482613924565b905083611d1f613995565b60208a0135611d3460808c0160608d01615400565b611d4460a08d0160808e01615400565b3386604051602001611d5c9796959493929190615828565b60405160208183030381529060405280519060200120600f600086815260200190815260200160002081905550336001600160a01b0316886020013589600001357feb0e3652e0f44f417695e6e90f2f42c99b65cd7169074c5a654b16b9748c3a4e87878d6040016020810190611dd391906152e4565b8e6060016020810190611de69190615400565b8f6080016020810190611df99190615400565b89604051611e0c969594939291906157e9565b60405180910390a4505033600090815260046020908152604080832089830135845282529091208451815492909501516001600160401b031661010002610100600160481b0319951515959095166001600160481b03199092169190911793909317909255925050505b919050565b6000611e856130d2565b6007546001600160401b031633611e9d600143615ac2565b6040516001600160601b0319606093841b81166020830152914060348201523090921b1660548201526001600160c01b031960c083901b16606882015260700160408051601f1981840301815291905280516020909101209150611f02816001615a4b565b600780546001600160401b0319166001600160401b03928316179055604080516000808252608082018352602080830182815283850183815260608086018581528a86526006855287862093518454935191516001600160601b039182166001600160c01b031990951694909417600160601b9190921602176001600160c01b0316600160c01b9290981691909102969096179055835194850184523385528481018281528585018481528884526005835294909220855181546001600160a01b03199081166001600160a01b0392831617835593516001830180549095169116179092559251805192949391926120009260028501920190614b97565b5061201091506008905084613a25565b50827f1d3015d7ba850fa198dc7b1a3f5d42779313a681035f77c8c03764c61005518d3360405161204191906155ea565b60405180910390a2505090565b6120566130d2565b6002546001600160a01b03163314612081576040516344b0e3c360e01b815260040160405180910390fd5b602081146120a257604051638129bbcd60e01b815260040160405180910390fd5b60006120b0828401846153a0565b6000818152600560205260409020549091506001600160a01b03166120e857604051630fb532db60e11b815260040160405180910390fd5b600081815260066020526040812080546001600160601b03169186919061210f8385615a6d565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555084600a60008282829054906101000a90046001600160601b03166121579190615a6d565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f1ced9348ff549fceab2ac57cd3a9de38edaaab274b725ee82c23e8fc8c4eec7a8287846121aa9190615a33565b6040516121b8929190615674565b60405180910390a2505050505050565b6121d06132b3565b60c861ffff8a1611156121fd57888960c860405163539c34bb60e11b8152600401610f2093929190615728565b60008513612221576040516321ea67b360e11b815260048101869052602401610f20565b604080516101208101825261ffff8b1680825263ffffffff808c16602084018190526000848601528b8216606085018190528b8316608086018190528a841660a08701819052938a1660c0870181905260ff808b1660e08901819052908a16610100909801889052600c8054600160c01b90990260ff60c01b19600160b81b9093029290921661ffff60b81b19600160981b90940263ffffffff60981b19600160781b90990298909816600160781b600160b81b0319600160581b90960263ffffffff60581b19600160381b90980297909716600160301b600160781b03196201000090990265ffffffffffff19909c16909a179a909a1796909616979097179390931791909116959095179290921793909316929092179190911790556010869055517f95cb2ddab6d2297c29a4861691de69b3969c464aa4a9c44258b101ff02ff375a906123be908b908b908b908b908b908990899061ffff97909716875263ffffffff95861660208801529385166040870152919093166060850152608084019290925260ff91821660a08401521660c082015260e00190565b60405180910390a1505050505050505050565b6123d96132b3565b6000818152600560205260409020546001600160a01b03168061240f57604051630fb532db60e11b815260040160405180910390fd5b6115f182826130ff565b606060006124276008613a31565b905080841061244957604051631390f2a160e01b815260040160405180910390fd5b60006124558486615a33565b905081811180612463575083155b61246d578061246f565b815b9050600061247d8683615ac2565b9050806001600160401b0381111561249757612497615c0b565b6040519080825280602002602001820160405280156124c0578160200160208202803683370190505b50935060005b81811015612510576124e36124db8883615a33565b600890613a3b565b8582815181106124f5576124f5615bf5565b602090810291909101015261250981615b5d565b90506124c6565b505050505b92915050565b6125236130d2565b6000818152600560205260409020546001600160a01b03168061255957604051630fb532db60e11b815260040160405180910390fd5b6000828152600560205260409020600101546001600160a01b031633146125b0576000828152600560205260409081902060010154905163d084e97560e01b8152610f20916001600160a01b0316906004016155ea565b600082815260056020526040908190208054336001600160a01b031991821681178355600190920180549091169055905183917fd4114ab6e9af9f597c52041f32d62dc57c5c4e4c0d4427006069635e216c938691611ad0918591615617565b8161261a81613071565b6126226130d2565b6001600160a01b03821660009081526004602090815260408083208684529091529020805460ff16156126555750505050565b6000848152600560205260409020600201805460641415612689576040516305a48e0f60e01b815260040160405180910390fd5b8154600160ff1990911681178355815490810182556000828152602090200180546001600160a01b0319166001600160a01b03861617905560405185907f1e980d04aa7648e205713e5e8ea3808672ac163d10936d36f91b2c88ac1575e1906126f39087906155ea565b60405180910390a25050505050565b6000816040516020016127159190615653565b604051602081830303815290604052805190602001209050919050565b8161273c81613071565b6127446130d2565b61274d836112c1565b1561276b57604051631685ecdd60e31b815260040160405180910390fd5b6001600160a01b038216600090815260046020908152604080832086845290915290205460ff166127b35782826040516379bfd40160e01b8152600401610f209291906157a5565b60008381526005602090815260408083206002018054825181850281018501909352808352919290919083018282801561281657602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116127f8575b5050505050905060006001825161282d9190615ac2565b905060005b825181101561293957846001600160a01b031683828151811061285757612857615bf5565b60200260200101516001600160a01b0316141561292757600083838151811061288257612882615bf5565b60200260200101519050806005600089815260200190815260200160002060020183815481106128b4576128b4615bf5565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394909416939093179092558881526005909152604090206002018054806128ff576128ff615bdf565b600082815260209020810160001990810180546001600160a01b031916905501905550612939565b8061293181615b5d565b915050612832565b506001600160a01b03841660009081526004602090815260408083208884529091529081902080546001600160481b03191690555185907f32158c6058347c1601b2d12bc696ac6901d8a9a9aa3ba10c27ab0a983e8425a7906126f39087906155ea565b60006129ab828401846151b2565b9050806000015160ff166001146129e457805160405163237d181f60e21b815260ff909116600482015260016024820152604401610f20565b8060a001516001600160601b03163414612a285760a08101516040516306acf13560e41b81523460048201526001600160601b039091166024820152604401610f20565b6020808201516000908152600590915260409020546001600160a01b031615612a64576040516326afa43560e11b815260040160405180910390fd5b60005b816060015151811015612b2d57604051806040016040528060011515815260200160006001600160401b03168152506004600084606001518481518110612ab057612ab0615bf5565b6020908102919091018101516001600160a01b0316825281810192909252604090810160009081208684015182528352208251815493909201516001600160401b031661010002610100600160481b0319921515929092166001600160481b03199093169290921717905580612b2581615b5d565b915050612a67565b50604080516060808201835260808401516001600160601b03908116835260a0850151811660208085019182526000858701818152828901805183526006845288832097518854955192516001600160401b0316600160c01b026001600160c01b03938816600160601b026001600160c01b0319909716919097161794909417169390931790945584518084018652868601516001600160a01b03908116825281860184815294880151828801908152925184526005865295909220825181549087166001600160a01b0319918216178255935160018201805491909716941693909317909455925180519192612c2c92600285019290910190614b97565b5050506080810151600a8054600090612c4f9084906001600160601b0316615a6d565b92506101000a8154816001600160601b0302191690836001600160601b031602179055508060a00151600a600c8282829054906101000a90046001600160601b0316612c9b9190615a6d565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550612cd781602001516008613a2590919063ffffffff16565b50505050565b600e8181548110612ced57600080fd5b600091825260209091200154905081565b81612d0881613071565b612d106130d2565b600083815260056020526040902060018101546001600160a01b03848116911614612cd7576001810180546001600160a01b0319166001600160a01b03851617905560405184907f21a4dad170a6bf476c31bbcf4a16628295b0e450672eec25d7c93308e05344a190612d869033908790615617565b60405180910390a250505050565b600081815260056020526040812054819081906001600160a01b0316606081612dd057604051630fb532db60e11b815260040160405180910390fd5b600086815260066020908152604080832054600583529281902060020180548251818502810185019093528083526001600160601b0380861695600160601b810490911694600160c01b9091046001600160401b0316938893929091839190830182828015612e6857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612e4a575b505050505090509450945094509450945091939590929450565b612e8a6132b3565b6002546001600160a01b0316612eb35760405163c1f0c0a160e01b815260040160405180910390fd5b6002546040516370a0823160e01b81526000916001600160a01b0316906370a0823190612ee49030906004016155ea565b60206040518083038186803b158015612efc57600080fd5b505afa158015612f10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f349190614fe5565b600a549091506001600160601b031681811115612f685780826040516354ced18160e11b8152600401610f20929190615674565b81811015610909576000612f7c8284615ac2565b60025460405163a9059cbb60e01b81529192506001600160a01b03169063a9059cbb90612faf90879085906004016155fe565b602060405180830381600087803b158015612fc957600080fd5b505af1158015612fdd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130019190614fc8565b61301e57604051631f01ff1360e21b815260040160405180910390fd5b7f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600848260405161304f9291906155fe565b60405180910390a150505050565b6130656132b3565b61306e81613a47565b50565b6000818152600560205260409020546001600160a01b0316806130a757604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b038216146115f15780604051636c51fda960e11b8152600401610f2091906155ea565b600c54600160301b900460ff16156130fd5760405163769dd35360e11b815260040160405180910390fd5b565b60008061310b84613676565b60025491935091506001600160a01b03161580159061313257506001600160601b03821615155b156131e15760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb906131729086906001600160601b038716906004016155fe565b602060405180830381600087803b15801561318c57600080fd5b505af11580156131a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131c49190614fc8565b6131e157604051631e9acf1760e31b815260040160405180910390fd5b6000836001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114613237576040519150601f19603f3d011682016040523d82523d6000602084013e61323c565b606091505b505090508061325e5760405163950b247960e01b815260040160405180910390fd5b604080516001600160a01b03861681526001600160601b03808616602083015284169181019190915285907f8c74ce8b8cf87f5eb001275c8be27eb34ea2b62bfab6814fcc62192bb63e81c4906060016126f3565b6000546001600160a01b031633146130fd5760405162461bcd60e51b815260206004820152601660248201527527b7363c9031b0b63630b1363290313c9037bbb732b960511b6044820152606401610f20565b604080516060810182526000808252602082018190529181019190915260006133328460000151612702565b6000818152600d602052604090205490915060ff1661336757604051631dfd6e1360e21b815260048101829052602401610f20565b6000818560800151604051602001613380929190615674565b60408051601f1981840301815291815281516020928301206000818152600f909352912054909150806133c657604051631b44092560e11b815260040160405180910390fd5b845160208087015160408089015160608a015160808b015160a08c015193516133f5978a979096959101615874565b60405160208183030381529060405280519060200120811461342a5760405163354a450b60e21b815260040160405180910390fd5b60006134398660000151613aeb565b905080613500578551604051631d2827a760e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163e9413d389161348d91906004016158df565b60206040518083038186803b1580156134a557600080fd5b505afa1580156134b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134dd9190614fe5565b90508061350057855160405163175dadad60e01b8152610f2091906004016158df565b6000876080015182604051602001613522929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c905060006135498983613bc8565b6040805160608101825297885260208801969096529486019490945250929695505050505050565b60005a61138881101561358357600080fd5b61138881039050846040820482031161359b57600080fd5b50823b6135a757600080fd5b60008083516020850160008789f1949350505050565b600081156135ea576011546135e39086908690600160201b900463ffffffff1686613c33565b9050613604565b601154613601908690869063ffffffff1686613cd5565b90505b949350505050565b6000805b60125481101561366d57826001600160a01b03166012828154811061363757613637615bf5565b6000918252602090912001546001600160a01b0316141561365b5750600192915050565b8061366581615b5d565b915050613610565b50600092915050565b60008181526005602090815260408083206006909252822054600290910180546001600160601b0380841694600160601b90940416925b8181101561371857600460008483815481106136cb576136cb615bf5565b60009182526020808320909101546001600160a01b031683528281019390935260409182018120898252909252902080546001600160481b031916905561371181615b5d565b90506136ad565b50600085815260056020526040812080546001600160a01b031990811682556001820180549091169055906137506002830182614bfc565b505060008581526006602052604081205561376c600886613dfa565b506001600160601b038416156137bf57600a805485919060009061379a9084906001600160601b0316615ad9565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b6001600160601b038316156138175782600a600c8282829054906101000a90046001600160601b03166137f29190615ad9565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b5050915091565b60408051602081018690526001600160a01b03851691810191909152606081018390526001600160401b03821660808201526000908190819060a00160408051601f198184030181529082905280516020918201209250613883918991849101615674565b60408051808303601f19018152919052805160209091012097909650945050505050565b604080516020810190915260008152816138d05750604080516020810190915260008152612515565b63125fa26760e31b6138e28385615b01565b6001600160e01b0319161461390a57604051632923fee760e11b815260040160405180910390fd5b6139178260048186615a09565b810190610ee9919061503f565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa8260405160240161395d91511515815260200190565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915292915050565b6000466139a181613e06565b15613a1e5760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156139e057600080fd5b505afa1580156139f4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a189190614fe5565b91505090565b4391505090565b6000610ee98383613e29565b6000612515825490565b6000610ee98383613e78565b6001600160a01b038116331415613a9a5760405162461bcd60e51b815260206004820152601760248201527621b0b73737ba103a3930b739b332b9103a379039b2b63360491b6044820152606401610f20565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600046613af781613e06565b15613bb957610100836001600160401b0316613b11613995565b613b1b9190615ac2565b1180613b375750613b2a613995565b836001600160401b031610155b15613b455750600092915050565b6040516315a03d4160e11b8152606490632b407a8290613b699086906004016158df565b60206040518083038186803b158015613b8157600080fd5b505afa158015613b95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ee99190614fe5565b50506001600160401b03164090565b6000613bfc8360000151846020015185604001518660600151868860a001518960c001518a60e001518b6101000151613ea2565b60038360200151604051602001613c149291906157bc565b60408051601f1981840301815291905280516020909101209392505050565b600080613c766000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506140bd92505050565b905060005a613c858888615a33565b613c8f9190615ac2565b613c999085615aa3565b90506000613cb263ffffffff871664e8d4a51000615aa3565b905082613cbf8284615a33565b613cc99190615a33565b98975050505050505050565b600080613ce0614182565b905060008113613d06576040516321ea67b360e11b815260048101829052602401610f20565b6000613d486000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506140bd92505050565b9050600082825a613d598b8b615a33565b613d639190615ac2565b613d6d9088615aa3565b613d779190615a33565b613d8990670de0b6b3a7640000615aa3565b613d939190615a8f565b90506000613dac63ffffffff881664e8d4a51000615aa3565b9050613dc381676765c793fa10079d601b1b615ac2565b821115613de35760405163e80fa38160e01b815260040160405180910390fd5b613ded8183615a33565b9998505050505050505050565b6000610ee9838361424d565b600061a4b1821480613e1a575062066eed82145b8061251557505062066eee1490565b6000818152600183016020526040812054613e7057508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155612515565b506000612515565b6000826000018281548110613e8f57613e8f615bf5565b9060005260206000200154905092915050565b613eab89614340565b613ef45760405162461bcd60e51b815260206004820152601a6024820152797075626c6963206b6579206973206e6f74206f6e20637572766560301b6044820152606401610f20565b613efd88614340565b613f415760405162461bcd60e51b815260206004820152601560248201527467616d6d61206973206e6f74206f6e20637572766560581b6044820152606401610f20565b613f4a83614340565b613f965760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e2063757276650000006044820152606401610f20565b613f9f82614340565b613fea5760405162461bcd60e51b815260206004820152601c60248201527b73486173685769746e657373206973206e6f74206f6e20637572766560201b6044820152606401610f20565b613ff6878a8887614403565b61403e5760405162461bcd60e51b81526020600482015260196024820152786164647228632a706b2b732a6729213d5f755769746e65737360381b6044820152606401610f20565b600061404a8a87614517565b9050600061405d898b878b86898961457b565b9050600061406e838d8d8a8661468e565b9050808a146140af5760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606401610f20565b505050505050505050505050565b6000466140c981613e06565b1561410857606c6001600160a01b031663c6f7de0e6040518163ffffffff1660e01b815260040160206040518083038186803b158015613b8157600080fd5b614111816146ce565b1561366d57600f602160991b016001600160a01b03166349948e0e84604051806080016040528060488152602001615c4560489139604051602001614157929190615540565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401613b6991906156a0565b600c5460035460408051633fabe5a360e21b81529051600093600160381b900463ffffffff169283151592859283926001600160a01b03169163feaf968c9160048083019260a0929190829003018186803b1580156141e057600080fd5b505afa1580156141f4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614218919061541b565b50945090925084915050801561423c57506142338242615ac2565b8463ffffffff16105b156136045750601054949350505050565b60008181526001830160205260408120548015614336576000614271600183615ac2565b855490915060009061428590600190615ac2565b90508181146142ea5760008660000182815481106142a5576142a5615bf5565b90600052602060002001549050808760000184815481106142c8576142c8615bf5565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806142fb576142fb615bdf565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612515565b6000915050612515565b80516000906401000003d0191161438e5760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420782d6f7264696e61746560701b6044820152606401610f20565b60208201516401000003d019116143dc5760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420792d6f7264696e61746560701b6044820152606401610f20565b60208201516401000003d0199080096143fc8360005b6020020151614708565b1492915050565b60006001600160a01b0382166144495760405162461bcd60e51b815260206004820152600b60248201526a626164207769746e65737360a81b6044820152606401610f20565b60208401516000906001161561446057601c614463565b601b5b9050600070014551231950b75fc4402da1732fc9bebe1985876000602002015109865170014551231950b75fc4402da1732fc9bebe19918203925060009190890987516040805160008082526020909101918290529293506001916144cd91869188918790615682565b6020604051602081039080840390855afa1580156144ef573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b61451f614c1a565b61454c60018484604051602001614538939291906155c9565b60405160208183030381529060405261472c565b90505b61455881614340565b6125155780516040805160208101929092526145749101614538565b905061454f565b614583614c1a565b825186516401000003d01990819006910614156145e25760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e637400006044820152606401610f20565b6145ed87898861477a565b6146325760405162461bcd60e51b8152602060048201526016602482015275119a5c9cdd081b5d5b0818da1958dac819985a5b195960521b6044820152606401610f20565b61463d84868561477a565b6146835760405162461bcd60e51b815260206004820152601760248201527614d958dbdb99081b5d5b0818da1958dac819985a5b1959604a1b6044820152606401610f20565b613cc9868484614895565b6000600286868685876040516020016146ac9695949392919061556f565b60408051601f1981840301815291905280516020909101209695505050505050565b6000600a8214806146e057506101a482145b806146ed575062aa37dc82145b806146f9575061210582145b8061251557505062014a331490565b6000806401000003d01980848509840990506401000003d019600782089392505050565b614734614c1a565b61473d82614958565b815261475261474d8260006143f2565b614993565b602082018190526002900660011415611e76576020810180516401000003d019039052919050565b6000826147b75760405162461bcd60e51b815260206004820152600b60248201526a3d32b9379039b1b0b630b960a91b6044820152606401610f20565b835160208501516000906147cd90600290615b9f565b156147d957601c6147dc565b601b5b9050600070014551231950b75fc4402da1732fc9bebe1983870960408051600080825260209091019182905291925060019061481f908390869088908790615682565b6020604051602081039080840390855afa158015614841573d6000803e3d6000fd5b505050602060405103519050600086604051602001614860919061552e565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b61489d614c1a565b8351602080860151855191860151600093849384936148be939091906149b3565b919450925090506401000003d01985820960011461491a5760405162461bcd60e51b815260206004820152601960248201527834b73b2d1036bab9ba1031329034b73b32b939b29037b3103d60391b6044820152606401610f20565b60405180604001604052806401000003d0198061493957614939615bc9565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d0198110611e7657604080516020808201939093528151808203840181529082019091528051910120614960565b60006125158260026149ac6401000003d0196001615a33565b901c614a93565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a08905060006149f383838585614b2a565b9098509050614a0488828e88614b4e565b9098509050614a1588828c87614b4e565b90985090506000614a288d878b85614b4e565b9098509050614a3988828686614b2a565b9098509050614a4a88828e89614b4e565b9098509050818114614a7f576401000003d019818a0998506401000003d01982890997506401000003d0198183099650614a83565b8196505b5050505050509450945094915050565b600080614a9e614c38565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a0820152614ad0614c56565b60208160c0846005600019fa925082614b205760405162461bcd60e51b81526020600482015260126024820152716269674d6f64457870206661696c7572652160701b6044820152606401610f20565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b828054828255906000526020600020908101928215614bec579160200282015b82811115614bec57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614bb7565b50614bf8929150614c74565b5090565b508054600082559060005260206000209081019061306e9190614c74565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b80821115614bf85760008155600101614c75565b8035611e7681615c21565b600082601f830112614ca557600080fd5b604080519081016001600160401b0381118282101715614cc757614cc7615c0b565b8060405250808385604086011115614cde57600080fd5b60005b6002811015614d00578135835260209283019290910190600101614ce1565b509195945050505050565b8035611e7681615c36565b60008083601f840112614d2857600080fd5b5081356001600160401b03811115614d3f57600080fd5b602083019150836020828501011115614d5757600080fd5b9250929050565b600082601f830112614d6f57600080fd5b81356001600160401b03811115614d8857614d88615c0b565b614d9b601f8201601f19166020016159d9565b818152846020838601011115614db057600080fd5b816020850160208301376000918101602001919091529392505050565b600060c08284031215614ddf57600080fd5b614de761598e565b905081356001600160401b038082168214614e0157600080fd5b81835260208401356020840152614e1a60408501614e80565b6040840152614e2b60608501614e80565b6060840152614e3c60808501614c89565b608084015260a0840135915080821115614e5557600080fd5b50614e6284828501614d5e565b60a08301525092915050565b803561ffff81168114611e7657600080fd5b803563ffffffff81168114611e7657600080fd5b803560ff81168114611e7657600080fd5b80516001600160501b0381168114611e7657600080fd5b80356001600160601b0381168114611e7657600080fd5b600060208284031215614ee557600080fd5b8135610ee981615c21565b60008060408385031215614f0357600080fd5b8235614f0e81615c21565b91506020830135614f1e81615c21565b809150509250929050565b60008060008060608587031215614f3f57600080fd5b8435614f4a81615c21565b93506020850135925060408501356001600160401b03811115614f6c57600080fd5b614f7887828801614d16565b95989497509550505050565b600060408284031215614f9657600080fd5b82604083011115614fa657600080fd5b50919050565b600060408284031215614fbe57600080fd5b610ee98383614c94565b600060208284031215614fda57600080fd5b8151610ee981615c36565b600060208284031215614ff757600080fd5b5051919050565b6000806020838503121561501157600080fd5b82356001600160401b0381111561502757600080fd5b61503385828601614d16565b90969095509350505050565b60006020828403121561505157600080fd5b604051602081016001600160401b038111828210171561507357615073615c0b565b604052823561508181615c36565b81529392505050565b60008060008385036101e08112156150a157600080fd5b6101a0808212156150b157600080fd5b6150b96159b6565b91506150c58787614c94565b82526150d48760408801614c94565b60208301526080860135604083015260a0860135606083015260c0860135608083015261510360e08701614c89565b60a083015261010061511788828901614c94565b60c084015261512a886101408901614c94565b60e0840152610180870135908301529093508401356001600160401b0381111561515357600080fd5b61515f86828701614dcd565b92505061516f6101c08501614d0b565b90509250925092565b60006020828403121561518a57600080fd5b81356001600160401b038111156151a057600080fd5b820160c08185031215610ee957600080fd5b600060208083850312156151c557600080fd5b82356001600160401b03808211156151dc57600080fd5b9084019060c082870312156151f057600080fd5b6151f861598e565b61520183614e94565b81528383013584820152604083013561521981615c21565b604082015260608301358281111561523057600080fd5b8301601f8101881361524157600080fd5b80358381111561525357615253615c0b565b8060051b93506152648685016159d9565b8181528681019083880186850189018c101561527f57600080fd5b600096505b838710156152ae578035945061529985615c21565b84835260019690960195918801918801615284565b506060850152506152c491505060808401614ebc565b60808201526152d560a08401614ebc565b60a08201529695505050505050565b6000602082840312156152f657600080fd5b610ee982614e6e565b60008060008060008060008060006101208a8c03121561531e57600080fd5b6153278a614e6e565b985061533560208b01614e80565b975061534360408b01614e80565b965061535160608b01614e80565b955060808a0135945061536660a08b01614e80565b935061537460c08b01614e80565b925061538260e08b01614e94565b91506153916101008b01614e94565b90509295985092959850929598565b6000602082840312156153b257600080fd5b5035919050565b600080604083850312156153cc57600080fd5b823591506020830135614f1e81615c21565b600080604083850312156153f157600080fd5b50508035926020909101359150565b60006020828403121561541257600080fd5b610ee982614e80565b600080600080600060a0868803121561543357600080fd5b61543c86614ea5565b945060208601519350604086015192506060860151915061545f60808701614ea5565b90509295509295909350565b600081518084526020808501945080840160005b838110156154a45781516001600160a01b03168752958201959082019060010161547f565b509495945050505050565b8060005b6002811015612cd75781518452602093840193909101906001016154b3565b600081518084526020808501945080840160005b838110156154a4578151875295820195908201906001016154e6565b6000815180845261551a816020860160208601615b31565b601f01601f19169290920160200192915050565b61553881836154af565b604001919050565b60008351615552818460208801615b31565b835190830190615566818360208801615b31565b01949350505050565b86815261557f60208201876154af565b61558c60608201866154af565b61559960a08201856154af565b6155a660e08201846154af565b60609190911b6001600160601b0319166101208201526101340195945050505050565b8381526155d960208201846154af565b606081019190915260800192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039290921682526001600160601b0316602082015260400190565b6040810161251582846154af565b602081526000610ee960208301846154d2565b918252602082015260400190565b93845260ff9290921660208401526040830152606082015260800190565b602081526000610ee96020830184615502565b6020815260ff82511660208201526020820151604082015260018060a01b0360408301511660608201526000606083015160c060808401526156f860e084018261546b565b60808501516001600160601b0390811660a0868101919091529095015190941660c0909301929092525090919050565b61ffff93841681529183166020830152909116604082015260600190565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b818110156157975784518352938301939183019160010161577b565b509098975050505050505050565b9182526001600160a01b0316602082015260400190565b82815260608101610ee960208301846154af565b82815260406020820152600061360460408301846154d2565b86815285602082015261ffff85166040820152600063ffffffff808616606084015280851660808401525060c060a0830152613cc960c0830184615502565b878152602081018790526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c08201819052600090613ded90830184615502565b8781526001600160401b03871660208201526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c08201819052600090613ded90830184615502565b63ffffffff92831681529116602082015260400190565b6001600160401b0391909116815260200190565b6001600160601b038681168252851660208201526001600160401b03841660408201526001600160a01b038316606082015260a06080820181905260009061593d9083018461546b565b979650505050505050565b6000808335601e1984360301811261595f57600080fd5b8301803591506001600160401b0382111561597957600080fd5b602001915036819003821315614d5757600080fd5b60405160c081016001600160401b03811182821017156159b0576159b0615c0b565b60405290565b60405161012081016001600160401b03811182821017156159b0576159b0615c0b565b604051601f8201601f191681016001600160401b0381118282101715615a0157615a01615c0b565b604052919050565b60008085851115615a1957600080fd5b83861115615a2657600080fd5b5050820193919092039150565b60008219821115615a4657615a46615bb3565b500190565b60006001600160401b0382811684821680830382111561556657615566615bb3565b60006001600160601b0382811684821680830382111561556657615566615bb3565b600082615a9e57615a9e615bc9565b500490565b6000816000190483118215151615615abd57615abd615bb3565b500290565b600082821015615ad457615ad4615bb3565b500390565b60006001600160601b0383811690831681811015615af957615af9615bb3565b039392505050565b6001600160e01b03198135818116916004851015615b295780818660040360031b1b83161692505b505092915050565b60005b83811015615b4c578181015183820152602001615b34565b83811115612cd75750506000910152565b6000600019821415615b7157615b71615bb3565b5060010190565b60006001600160401b0382811680821415615b9557615b95615bb3565b6001019392505050565b600082615bae57615bae615bc9565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461306e57600080fd5b801515811461306e57600080fdfe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000806000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"blockhashStore\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"internalBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"externalBalance\",\"type\":\"uint256\"}],\"name\":\"BalanceInvariantViolated\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"BlockhashNotInStore\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorNotRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToSendNative\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToTransferLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"GasLimitTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectCommitment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidExtraArgsTag\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"transferredValue\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"expectedValue\",\"type\":\"uint96\"}],\"name\":\"InvalidNativeBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"have\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"min\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"max\",\"type\":\"uint16\"}],\"name\":\"InvalidRequestConfirmations\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"requestVersion\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"expectedVersion\",\"type\":\"uint8\"}],\"name\":\"InvalidVersion\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkAlreadySet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkNotSet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"}],\"name\":\"MustBeRequestedOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoCorrespondingRequest\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"NoSuchProvingKey\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"NumWordsTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PendingRequestExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"ProvingKeyAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Reentrant\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SubscriptionIDCollisionFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyConsumers\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"nativePremiumPercentage\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"linkPremiumPercentage\",\"type\":\"uint8\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"MigrationCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"NativeFundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"ProvingKeyRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"outputSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"payment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"RandomWordsFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"preSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RandomWordsRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountLink\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountNative\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldNativeBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newNativeBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFundedWithNative\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BLOCKHASH_STORE\",\"outputs\":[{\"internalType\":\"contractBlockhashStoreInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK_NATIVE_FEED\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_CONSUMERS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_NUM_WORDS\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_REQUEST_CONFIRMATIONS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256[2]\",\"name\":\"pk\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"gamma\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"c\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"s\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"uWitness\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"cGammaWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"sHashWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"zInv\",\"type\":\"uint256\"}],\"internalType\":\"structVRF.Proof\",\"name\":\"proof\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"blockNum\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFCoordinatorV2PlusUpgradedVersion.RequestCommitment\",\"name\":\"rc\",\"type\":\"tuple\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"fulfillRandomWords\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"fundSubscriptionWithNative\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveSubscriptionIds\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRequestConfig\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"getSubscription\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"nativeBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint64\",\"name\":\"reqCount\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"subOwner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicKey\",\"type\":\"uint256[2]\"}],\"name\":\"hashOfKey\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"}],\"name\":\"migrate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"migrationVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedData\",\"type\":\"bytes\"}],\"name\":\"onMigration\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"ownerCancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"pendingRequestExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverNativeFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"registerMigratableCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"}],\"name\":\"registerProvingKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFV2PlusClient.RandomWordsRequest\",\"name\":\"req\",\"type\":\"tuple\"}],\"name\":\"requestRandomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"requestSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_config\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"reentrancyLock\",\"type\":\"bool\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"nativePremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"linkPremiumPercentage\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_currentSubNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_provingKeyHashes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requestCommitments\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalNativeBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"nativePremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"linkPremiumPercentage\",\"type\":\"uint8\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkNativeFeed\",\"type\":\"address\"}],\"name\":\"setLINKAndLINKNativeFeed\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"withdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60a06040523480156200001157600080fd5b5060405162005e3438038062005e3483398101604081905262000034916200017e565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d3565b5050506001600160a01b0316608052620001b0565b336001600160a01b038216036200012d5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019157600080fd5b81516001600160a01b0381168114620001a957600080fd5b9392505050565b608051615c61620001d3600039600081816104f401526134790152615c616000f3fe6080604052600436106101e05760003560e01c8062012291146101e5578063088070f5146102125780630ae09540146102e057806315c48b841461030257806318e3dd271461032a5780631b6b6d2314610369578063294daa49146103965780632f622e6b146103b2578063301f42e9146103d2578063405b84fa146103f257806340d6bb821461041257806341af6c871461043d57806351cff8d91461046d5780635d06b4ab1461048d57806364d51a2a146104ad57806365982744146104c2578063689c4517146104e257806372e9d5651461051657806379ba5097146105365780637bce14d11461054b5780638402595e1461056b57806386fe91c71461058b5780638da5cb5b146105ab57806395b55cfc146105c95780639b1c385e146105dc5780639d40a6fd1461060a578063a21a23e414610637578063a4c0ed361461064c578063a63e0bfb1461066c578063aa433aff1461068c578063aefb212f146106ac578063b2a7cac5146106d9578063bec4c08c146106f9578063caf70c4a14610719578063cb63179714610739578063ce3f471914610759578063d98e620e1461076c578063dac83d291461078c578063dc311dd3146107ac578063e72f6e30146107dd578063ee9d2d38146107fd578063f2fde38b1461082a575b600080fd5b3480156101f157600080fd5b506101fa61084a565b60405161020993929190614c80565b60405180910390f35b34801561021e57600080fd5b50600c546102839061ffff81169063ffffffff62010000820481169160ff600160301b8204811692600160381b8304811692600160581b8104821692600160781b8204831692600160981b83041691600160b81b8104821691600160c01b9091041689565b6040805161ffff909a168a5263ffffffff98891660208b01529615159689019690965293861660608801529185166080870152841660a08601529290921660c084015260ff91821660e08401521661010082015261012001610209565b3480156102ec57600080fd5b506103006102fb366004614cff565b6108c6565b005b34801561030e57600080fd5b5061031760c881565b60405161ffff9091168152602001610209565b34801561033657600080fd5b50600a5461035190600160601b90046001600160601b031681565b6040516001600160601b039091168152602001610209565b34801561037557600080fd5b50600254610389906001600160a01b031681565b6040516102099190614d2f565b3480156103a257600080fd5b5060405160028152602001610209565b3480156103be57600080fd5b506103006103cd366004614d43565b61090e565b3480156103de57600080fd5b506103516103ed366004614f9d565b610a5d565b3480156103fe57600080fd5b5061030061040d366004614cff565b610ef3565b34801561041e57600080fd5b506104286101f481565b60405163ffffffff9091168152602001610209565b34801561044957600080fd5b5061045d61045836600461508b565b6112b5565b6040519015158152602001610209565b34801561047957600080fd5b50610300610488366004614d43565b61145b565b34801561049957600080fd5b506103006104a8366004614d43565b6115dd565b3480156104b957600080fd5b50610317606481565b3480156104ce57600080fd5b506103006104dd3660046150a4565b611694565b3480156104ee57600080fd5b506103897f000000000000000000000000000000000000000000000000000000000000000081565b34801561052257600080fd5b50600354610389906001600160a01b031681565b34801561054257600080fd5b506103006116f4565b34801561055757600080fd5b506103006105663660046150d2565b61179e565b34801561057757600080fd5b50610300610586366004614d43565b611897565b34801561059757600080fd5b50600a54610351906001600160601b031681565b3480156105b757600080fd5b506000546001600160a01b0316610389565b6103006105d736600461508b565b6119a3565b3480156105e857600080fd5b506105fc6105f73660046150fa565b611ac4565b604051908152602001610209565b34801561061657600080fd5b5060075461062a906001600160401b031681565b6040516102099190615134565b34801561064357600080fd5b506105fc611e95565b34801561065857600080fd5b50610300610667366004615190565b612068565b34801561067857600080fd5b5061030061068736600461520e565b6121e2565b34801561069857600080fd5b506103006106a736600461508b565b6123eb565b3480156106b857600080fd5b506106cc6106c73660046152af565b612433565b604051610209919061530c565b3480156106e557600080fd5b506103006106f436600461508b565b612535565b34801561070557600080fd5b50610300610714366004614cff565b61262a565b34801561072557600080fd5b506105fc61073436600461531f565b61271c565b34801561074557600080fd5b50610300610754366004614cff565b61274c565b61030061076736600461533b565b6129b6565b34801561077857600080fd5b506105fc61078736600461508b565b612d26565b34801561079857600080fd5b506103006107a7366004614cff565b612d47565b3480156107b857600080fd5b506107cc6107c736600461508b565b612ddd565b6040516102099594939291906153b5565b3480156107e957600080fd5b506103006107f8366004614d43565b612ecb565b34801561080957600080fd5b506105fc61081836600461508b565b600f6020526000908152604090205481565b34801561083657600080fd5b50610300610845366004614d43565b613088565b600c54600e805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff169391928391908301828280156108b457602002820191906000526020600020905b8154815260200190600101908083116108a0575b50505050509050925092509250909192565b816108d08161309c565b6108d86130fd565b6108e1836112b5565b156108ff57604051631685ecdd60e31b815260040160405180910390fd5b610909838361312a565b505050565b6109166130fd565b61091e6132cf565b600b54600160601b90046001600160601b031660000361095157604051631e9acf1760e31b815260040160405180910390fd5b600b8054600160601b90046001600160601b0316908190600c6109748380615420565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a600c8282829054906101000a90046001600160601b03166109bc9190615420565b92506101000a8154816001600160601b0302191690836001600160601b031602179055506000826001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114610a36576040519150601f19603f3d011682016040523d82523d6000602084013e610a3b565b606091505b50509050806109095760405163950b247960e01b815260040160405180910390fd5b6000610a676130fd565b60005a90506000610a788686613322565b90506000856060015163ffffffff166001600160401b03811115610a9e57610a9e614d60565b604051908082528060200260200182016040528015610ac7578160200160208202803683370190505b50905060005b866060015163ffffffff16811015610b3e57826040015181604051602001610af6929190615440565b6040516020818303038152906040528051906020012060001c828281518110610b2157610b2161544e565b602090810291909101015280610b3681615464565b915050610acd565b50602080830180516000908152600f9092526040808320839055905190518291631fe543e360e01b91610b769190869060240161547d565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252600c805460ff60301b1916600160301b1790559089015160808a0151919250600091610bdb9163ffffffff169084613582565b600c805460ff60301b1916905560208a810151600090815260069091526040902054909150600160c01b90046001600160401b0316610c1b816001615496565b6020808c0151600090815260069091526040812080546001600160401b0393909316600160c01b026001600160c01b039093169290921790915560a08b01518051610c68906001906154b6565b81518110610c7857610c7861544e565b602091010151600c5460f89190911c6001149150600090610ca9908a90600160581b900463ffffffff163a856135ce565b90508115610da1576020808d01516000908152600690915260409020546001600160601b03808316600160601b909204161015610cf957604051631e9acf1760e31b815260040160405180910390fd5b60208c81015160009081526006909152604090208054829190600c90610d30908490600160601b90046001600160601b0316615420565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600b600c8282829054906101000a90046001600160601b0316610d7891906154c9565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550610e7c565b6020808d01516000908152600690915260409020546001600160601b0380831691161015610de257604051631e9acf1760e31b815260040160405180910390fd5b6020808d015160009081526006909152604081208054839290610e0f9084906001600160601b0316615420565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600b60008282829054906101000a90046001600160601b0316610e5791906154c9565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b8b6020015188602001517f49580fdfd9497e1ed5c1b1cec0495087ae8e3f1267470ec2fb015db32e3d6aa78a604001518488604051610ed9939291909283526001600160601b039190911660208301521515604082015260600190565b60405180910390a3985050505050505050505b9392505050565b610efb6130fd565b610f048161361d565b610f2c5780604051635428d44960e01b8152600401610f239190614d2f565b60405180910390fd5b600080600080610f3b86612ddd565b945094505093509350336001600160a01b0316826001600160a01b031614610f9e5760405162461bcd60e51b81526020600482015260166024820152752737ba1039bab139b1b934b83a34b7b71037bbb732b960511b6044820152606401610f23565b610fa7866112b5565b15610fed5760405162461bcd60e51b815260206004820152601660248201527550656e64696e6720726571756573742065786973747360501b6044820152606401610f23565b60006040518060c00160405280611002600290565b60ff168152602001888152602001846001600160a01b03168152602001838152602001866001600160601b03168152602001856001600160601b0316815250905060008160405160200161105691906154e9565b604051602081830303815290604052905061107088613686565b505060405163ce3f471960e01b81526001600160a01b0388169063ce3f4719906001600160601b038816906110a99085906004016155ae565b6000604051808303818588803b1580156110c257600080fd5b505af11580156110d6573d6000803e3d6000fd5b50506002546001600160a01b0316158015935091506110ff905057506001600160601b03861615155b156111ba5760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb90611136908a908a906004016155c1565b6020604051808303816000875af1158015611155573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061117991906155e3565b6111ba5760405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742066756e647360701b6044820152606401610f23565b600c805460ff60301b1916600160301b17905560005b8351811015611263578381815181106111eb576111eb61544e565b60200260200101516001600160a01b0316638ea98117896040518263ffffffff1660e01b815260040161121e9190614d2f565b600060405180830381600087803b15801561123857600080fd5b505af115801561124c573d6000803e3d6000fd5b50505050808061125b90615464565b9150506111d0565b50600c805460ff60301b191690556040517fd63ca8cb945956747ee69bfdc3ea754c24a4caf7418db70e46052f7850be4187906112a39089908b90615600565b60405180910390a15050505050505050565b6000818152600560209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152879693958601939092919083018282801561133f57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611321575b505050505081525050905060005b8160400151518110156114515760005b600e5481101561143e576000611407600e838154811061137f5761137f61544e565b9060005260206000200154856040015185815181106113a0576113a061544e565b60200260200101518860046000896040015189815181106113c3576113c361544e565b6020908102919091018101516001600160a01b0316825281810192909252604090810160009081208d825290925290205461010090046001600160401b031661382e565b506000818152600f60205260409020549091501561142b5750600195945050505050565b508061143681615464565b91505061135d565b508061144981615464565b91505061134d565b5060009392505050565b6114636130fd565b61146b6132cf565b6002546001600160a01b03166114945760405163c1f0c0a160e01b815260040160405180910390fd5b600b546001600160601b03166000036114c057604051631e9acf1760e31b815260040160405180910390fd5b600b80546001600160601b031690819060006114dc8380615420565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a60008282829054906101000a90046001600160601b03166115249190615420565b82546001600160601b039182166101009390930a92830291909202199091161790555060025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb9061157990859085906004016155c1565b6020604051808303816000875af1158015611598573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115bc91906155e3565b6115d957604051631e9acf1760e31b815260040160405180910390fd5b5050565b6115e56132cf565b6115ee8161361d565b1561160e578060405163ac8a27ef60e01b8152600401610f239190614d2f565b601280546001810182556000919091527fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec34440180546001600160a01b0319166001600160a01b0383161790556040517fb7cabbfc11e66731fc77de0444614282023bcbd41d16781c753a431d0af0162590611689908390614d2f565b60405180910390a150565b61169c6132cf565b6002546001600160a01b0316156116c657604051631688c53760e11b815260040160405180910390fd5b600280546001600160a01b039384166001600160a01b03199182161790915560038054929093169116179055565b6001546001600160a01b031633146117475760405162461bcd60e51b815260206004820152601660248201527526bab9ba10313290383937b837b9b2b21037bbb732b960511b6044820152606401610f23565b60008054336001600160a01b0319808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6117a66132cf565b6040805180820182526000916117d591908490600290839083908082843760009201919091525061271c915050565b6000818152600d602052604090205490915060ff161561180b57604051634a0b8fa760e01b815260048101829052602401610f23565b6000818152600d6020526040808220805460ff19166001908117909155600e805491820181559092527fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd909101829055517fc9583fd3afa3d7f16eb0b88d0268e7d05c09bafa4b21e092cbd1320e1bc8089d9061188b9083815260200190565b60405180910390a15050565b61189f6132cf565b600a544790600160601b90046001600160601b0316818111156118d95780826040516354ced18160e11b8152600401610f23929190615440565b818110156109095760006118ed82846154b6565b90506000846001600160a01b03168260405160006040518083038185875af1925050503d806000811461193c576040519150601f19603f3d011682016040523d82523d6000602084013e611941565b606091505b50509050806119635760405163950b247960e01b815260040160405180910390fd5b7f4aed7c8eed0496c8c19ea2681fcca25741c1602342e38b045d9f1e8e905d2e9c8583604051611994929190615600565b60405180910390a15050505050565b6119ab6130fd565b6000818152600560205260409020546001600160a01b03166119e057604051630fb532db60e11b815260040160405180910390fd5b60008181526006602052604090208054600160601b90046001600160601b0316903490600c611a0f83856154c9565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555034600a600c8282829054906101000a90046001600160601b0316611a5791906154c9565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f7603b205d03651ee812f803fccde89f1012e545a9c99f0abfea9cedd0fd8e902823484611aaa9190615619565b604051611ab8929190615440565b60405180910390a25050565b6000611ace6130fd565b6020808301356000908152600590915260409020546001600160a01b0316611b0957604051630fb532db60e11b815260040160405180910390fd5b336000908152600460209081526040808320858301358452808352928190208151606081018352905460ff811615158083526001600160401b036101008304811695840195909552600160481b9091049093169181019190915290611b89578360200135336040516379bfd40160e01b8152600401610f2392919061562c565b600c5461ffff16611ba06060860160408701615643565b61ffff161080611bc3575060c8611bbd6060860160408701615643565b61ffff16115b15611bfd57611bd86060850160408601615643565b600c5460405163539c34bb60e11b8152610f23929161ffff169060c89060040161565e565b600c5462010000900463ffffffff16611c1c608086016060870161567c565b63ffffffff161115611c6257611c38608085016060860161567c565b600c54604051637aebf00f60e11b8152610f23929162010000900463ffffffff1690600401615697565b6101f4611c7560a086016080870161567c565b63ffffffff161115611caf57611c9160a085016080860161567c565b6101f46040516311ce1afb60e21b8152600401610f23929190615697565b806020018051611cbe906156ae565b6001600160401b031690526020818101516000918291611ce69188359133918a01359061382e565b90925090506000611d02611cfd60a08901896156dc565b6138b7565b90506000611d0f82613938565b905083611d1a6139a9565b60208a0135611d2f60808c0160608d0161567c565b611d3f60a08d0160808e0161567c565b3386604051602001611d579796959493929190615722565b60405160208183030381529060405280519060200120600f600086815260200190815260200160002081905550336001600160a01b0316886020013589600001357feb0e3652e0f44f417695e6e90f2f42c99b65cd7169074c5a654b16b9748c3a4e87878d6040016020810190611dce9190615643565b8e6060016020810190611de1919061567c565b8f6080016020810190611df4919061567c565b89604051611e079695949392919061576e565b60405180910390a45050336000908152600460209081526040808320898301358452825291829020855181549287015193909601516001600160401b03908116600160481b02600160481b600160881b03199190941661010002610100600160481b0319971515979097166001600160481b031990931692909217959095171617909255925050505b919050565b6000611e9f6130fd565b6007546001600160401b031633611eb76001436154b6565b6040516001600160601b0319606093841b81166020830152914060348201523090921b1660548201526001600160c01b031960c083901b16606882015260700160408051601f1981840301815291905280516020909101209150611f1c816001615496565b600780546001600160401b0319166001600160401b03928316179055604080516000808252608082018352602080830182815283850183815260608086018581528a86526006855287862093518454935191516001600160601b039182166001600160c01b031990951694909417600160601b9190921602176001600160c01b0316600160c01b9290981691909102969096179055835194850184523385528481018281528585018481528884526005835294909220855181546001600160a01b03199081166001600160a01b03928316178355935160018301805490951691161790925592518051929493919261201a9260028501920190614b8e565b5061202a91506008905084613a2a565b50827f1d3015d7ba850fa198dc7b1a3f5d42779313a681035f77c8c03764c61005518d3360405161205b9190614d2f565b60405180910390a2505090565b6120706130fd565b6002546001600160a01b0316331461209b576040516344b0e3c360e01b815260040160405180910390fd5b602081146120bc57604051638129bbcd60e01b815260040160405180910390fd5b60006120ca8284018461508b565b6000818152600560205260409020549091506001600160a01b031661210257604051630fb532db60e11b815260040160405180910390fd5b600081815260066020526040812080546001600160601b03169186919061212983856154c9565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555084600a60008282829054906101000a90046001600160601b031661217191906154c9565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f1ced9348ff549fceab2ac57cd3a9de38edaaab274b725ee82c23e8fc8c4eec7a8287846121c49190615619565b6040516121d2929190615440565b60405180910390a2505050505050565b6121ea6132cf565b60c861ffff8a16111561221757888960c860405163539c34bb60e11b8152600401610f239392919061565e565b6000851361223b576040516321ea67b360e11b815260048101869052602401610f23565b604080516101208101825261ffff8b1680825263ffffffff808c16602084018190526000848601528b8216606085018190528b8316608086018190528a841660a08701819052938a1660c0870181905260ff808b1660e08901819052908a16610100909801889052600c8054600160c01b90990260ff60c01b19600160b81b9093029290921661ffff60b81b19600160981b90940263ffffffff60981b19600160781b90990298909816600160781b600160b81b0319600160581b90960263ffffffff60581b19600160381b90980297909716600160301b600160781b03196201000090990265ffffffffffff19909c16909a179a909a1796909616979097179390931791909116959095179290921793909316929092179190911790556010869055517f95cb2ddab6d2297c29a4861691de69b3969c464aa4a9c44258b101ff02ff375a906123d8908b908b908b908b908b908990899061ffff97909716875263ffffffff95861660208801529385166040870152919093166060850152608084019290925260ff91821660a08401521660c082015260e00190565b60405180910390a1505050505050505050565b6123f36132cf565b6000818152600560205260409020546001600160a01b03168061242957604051630fb532db60e11b815260040160405180910390fd5b6115d9828261312a565b606060006124416008613a36565b905080841061246357604051631390f2a160e01b815260040160405180910390fd5b600061246f8486615619565b90508181118061247d575083155b6124875780612489565b815b9050600061249786836154b6565b9050806001600160401b038111156124b1576124b1614d60565b6040519080825280602002602001820160405280156124da578160200160208202803683370190505b50935060005b8181101561252a576124fd6124f58883615619565b600890613a40565b85828151811061250f5761250f61544e565b602090810291909101015261252381615464565b90506124e0565b505050505b92915050565b61253d6130fd565b6000818152600560205260409020546001600160a01b03168061257357604051630fb532db60e11b815260040160405180910390fd5b6000828152600560205260409020600101546001600160a01b031633146125ca576000828152600560205260409081902060010154905163d084e97560e01b8152610f23916001600160a01b031690600401614d2f565b600082815260056020526040908190208054336001600160a01b031991821681178355600190920180549091169055905183917fd4114ab6e9af9f597c52041f32d62dc57c5c4e4c0d4427006069635e216c938691611ab89185916157ad565b816126348161309c565b61263c6130fd565b6001600160a01b03821660009081526004602090815260408083208684529091529020805460ff161561266f5750505050565b60008481526005602052604090206002018054606319016126a3576040516305a48e0f60e01b815260040160405180910390fd5b8154600160ff1990911681178355815490810182556000828152602090200180546001600160a01b0319166001600160a01b03861617905560405185907f1e980d04aa7648e205713e5e8ea3808672ac163d10936d36f91b2c88ac1575e19061270d908790614d2f565b60405180910390a25050505050565b60008160405160200161272f91906157ea565b604051602081830303815290604052805190602001209050919050565b816127568161309c565b61275e6130fd565b612767836112b5565b1561278557604051631685ecdd60e31b815260040160405180910390fd5b6001600160a01b038216600090815260046020908152604080832086845290915290205460ff166127cd5782826040516379bfd40160e01b8152600401610f2392919061562c565b60008381526005602090815260408083206002018054825181850281018501909352808352919290919083018282801561283057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612812575b5050505050905060006001825161284791906154b6565b905060005b825181101561295257846001600160a01b03168382815181106128715761287161544e565b60200260200101516001600160a01b03160361294057600083838151811061289b5761289b61544e565b60200260200101519050806005600089815260200190815260200160002060020183815481106128cd576128cd61544e565b600091825260208083209190910180546001600160a01b0319166001600160a01b039490941693909317909255888152600590915260409020600201805480612918576129186157f8565b600082815260209020810160001990810180546001600160a01b031916905501905550612952565b8061294a81615464565b91505061284c565b506001600160a01b03841660009081526004602090815260408083208884529091529081902080546001600160881b03191690555185907f32158c6058347c1601b2d12bc696ac6901d8a9a9aa3ba10c27ab0a983e8425a79061270d908790614d2f565b60006129c482840184615825565b9050806000015160ff166001146129fd57805160405163237d181f60e21b815260ff909116600482015260016024820152604401610f23565b8060a001516001600160601b03163414612a415760a08101516040516306acf13560e41b81523460048201526001600160601b039091166024820152604401610f23565b6020808201516000908152600590915260409020546001600160a01b031615612a7d576040516326afa43560e11b815260040160405180910390fd5b60005b816060015151811015612b7657604051806060016040528060011515815260200160006001600160401b0316815260200160006001600160401b03168152506004600084606001518481518110612ad957612ad961544e565b6020908102919091018101516001600160a01b0316825281810192909252604090810160009081208684015182528352819020835181549385015194909201516001600160481b0319909316911515610100600160481b031916919091176101006001600160401b039485160217600160481b600160881b031916600160481b939092169290920217905580612b6e81615464565b915050612a80565b50604080516060808201835260808401516001600160601b03908116835260a0850151811660208085019182526000858701818152828901805183526006845288832097518854955192516001600160401b0316600160c01b026001600160c01b03938816600160601b026001600160c01b0319909716919097161794909417169390931790945584518084018652868601516001600160a01b03908116825281860184815294880151828801908152925184526005865295909220825181549087166001600160a01b0319918216178255935160018201805491909716941693909317909455925180519192612c7592600285019290910190614b8e565b5050506080810151600a8054600090612c989084906001600160601b03166154c9565b92506101000a8154816001600160601b0302191690836001600160601b031602179055508060a00151600a600c8282829054906101000a90046001600160601b0316612ce491906154c9565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550612d2081602001516008613a2a90919063ffffffff16565b50505050565b600e8181548110612d3657600080fd5b600091825260209091200154905081565b81612d518161309c565b612d596130fd565b600083815260056020526040902060018101546001600160a01b03848116911614612d20576001810180546001600160a01b0319166001600160a01b03851617905560405184907f21a4dad170a6bf476c31bbcf4a16628295b0e450672eec25d7c93308e05344a190612dcf90339087906157ad565b60405180910390a250505050565b600081815260056020526040812054819081906001600160a01b0316606081612e1957604051630fb532db60e11b815260040160405180910390fd5b600086815260066020908152604080832054600583529281902060020180548251818502810185019093528083526001600160601b0380861695600160601b810490911694600160c01b9091046001600160401b0316938893929091839190830182828015612eb157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612e93575b505050505090509450945094509450945091939590929450565b612ed36132cf565b6002546001600160a01b0316612efc5760405163c1f0c0a160e01b815260040160405180910390fd5b6002546040516370a0823160e01b81526000916001600160a01b0316906370a0823190612f2d903090600401614d2f565b602060405180830381865afa158015612f4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f6e9190615950565b600a549091506001600160601b031681811115612fa25780826040516354ced18160e11b8152600401610f23929190615440565b81811015610909576000612fb682846154b6565b60025460405163a9059cbb60e01b81529192506001600160a01b03169063a9059cbb90612fe99087908590600401615600565b6020604051808303816000875af1158015613008573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061302c91906155e3565b61304957604051631f01ff1360e21b815260040160405180910390fd5b7f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600848260405161307a929190615600565b60405180910390a150505050565b6130906132cf565b61309981613a4c565b50565b6000818152600560205260409020546001600160a01b0316806130d257604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b038216146115d95780604051636c51fda960e11b8152600401610f239190614d2f565b600c54600160301b900460ff16156131285760405163769dd35360e11b815260040160405180910390fd5b565b60008061313684613686565b60025491935091506001600160a01b03161580159061315d57506001600160601b03821615155b156131fd5760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb9061319d9086906001600160601b03871690600401615600565b6020604051808303816000875af11580156131bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131e091906155e3565b6131fd57604051631e9acf1760e31b815260040160405180910390fd5b6000836001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114613253576040519150601f19603f3d011682016040523d82523d6000602084013e613258565b606091505b505090508061327a5760405163950b247960e01b815260040160405180910390fd5b604080516001600160a01b03861681526001600160601b03808616602083015284169181019190915285907f8c74ce8b8cf87f5eb001275c8be27eb34ea2b62bfab6814fcc62192bb63e81c49060600161270d565b6000546001600160a01b031633146131285760405162461bcd60e51b815260206004820152601660248201527527b7363c9031b0b63630b1363290313c9037bbb732b960511b6044820152606401610f23565b6040805160608101825260008082526020820181905291810191909152600061334e846000015161271c565b6000818152600d602052604090205490915060ff1661338357604051631dfd6e1360e21b815260048101829052602401610f23565b600081856080015160405160200161339c929190615440565b60408051601f1981840301815291815281516020928301206000818152600f90935290822054909250908190036133e657604051631b44092560e11b815260040160405180910390fd5b845160208087015160408089015160608a015160808b015160a08c01519351613415978a979096959101615969565b60405160208183030381529060405280519060200120811461344a5760405163354a450b60e21b815260040160405180910390fd5b60006134598660000151613aef565b905080613511578551604051631d2827a760e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163e9413d38916134ad9190600401615134565b602060405180830381865afa1580156134ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134ee9190615950565b90508061351157855160405163175dadad60e01b8152610f239190600401615134565b6000876080015182604051602001613533929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c9050600061355a8983613bbd565b6040805160608101825297885260208801969096529486019490945250929695505050505050565b60005a61138881101561359457600080fd5b6113888103905084604082048203116135ac57600080fd5b50823b6135b857600080fd5b60008083516020850160008789f1949350505050565b600081156135fb576011546135f49086908690600160201b900463ffffffff1686613c28565b9050613615565b601154613612908690869063ffffffff1686613cca565b90505b949350505050565b6000805b60125481101561367d57826001600160a01b0316601282815481106136485761364861544e565b6000918252602090912001546001600160a01b03160361366b5750600192915050565b8061367581615464565b915050613621565b50600092915050565b60008181526005602090815260408083206006909252822054600290910180546001600160601b0380841694600160601b90940416925b8181101561372857600460008483815481106136db576136db61544e565b60009182526020808320909101546001600160a01b031683528281019390935260409182018120898252909252902080546001600160881b031916905561372181615464565b90506136bd565b50600085815260056020526040812080546001600160a01b031990811682556001820180549091169055906137606002830182614bf3565b505060008581526006602052604081205561377c600886613def565b506001600160601b038416156137cf57600a80548591906000906137aa9084906001600160601b0316615420565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b6001600160601b038316156138275782600a600c8282829054906101000a90046001600160601b03166138029190615420565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b5050915091565b60408051602081018690526001600160a01b03851691810191909152606081018390526001600160401b03821660808201526000908190819060a00160408051601f198184030181529082905280516020918201209250613893918991849101615440565b60408051808303601f19018152919052805160209091012097909650945050505050565b60408051602081019091526000815260008290036138e4575060408051602081019091526000815261252f565b63125fa26760e31b6138f683856159bd565b6001600160e01b0319161461391e57604051632923fee760e11b815260040160405180910390fd5b61392b82600481866159ed565b810190610eec9190615a17565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa8260405160240161397191511515815260200190565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915292915050565b6000466139b581613dfb565b15613a235760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156139f9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a1d9190615950565b91505090565b4391505090565b6000610eec8383613e1e565b600061252f825490565b6000610eec8383613e6d565b336001600160a01b03821603613a9e5760405162461bcd60e51b815260206004820152601760248201527621b0b73737ba103a3930b739b332b9103a379039b2b63360491b6044820152606401610f23565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600046613afb81613dfb565b15613bae57610100836001600160401b0316613b156139a9565b613b1f91906154b6565b1180613b3b5750613b2e6139a9565b836001600160401b031610155b15613b495750600092915050565b6040516315a03d4160e11b8152606490632b407a8290613b6d908690600401615134565b602060405180830381865afa158015613b8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eec9190615950565b50506001600160401b03164090565b6000613bf18360000151846020015185604001518660600151868860a001518960c001518a60e001518b6101000151613e97565b60038360200151604051602001613c09929190615a62565b60408051601f1981840301815291905280516020909101209392505050565b600080613c6b6000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506140b292505050565b905060005a613c7a8888615619565b613c8491906154b6565b613c8e9085615a76565b90506000613ca763ffffffff871664e8d4a51000615a76565b905082613cb48284615619565b613cbe9190615619565b98975050505050505050565b600080613cd561417c565b905060008113613cfb576040516321ea67b360e11b815260048101829052602401610f23565b6000613d3d6000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506140b292505050565b9050600082825a613d4e8b8b615619565b613d5891906154b6565b613d629088615a76565b613d6c9190615619565b613d7e90670de0b6b3a7640000615a76565b613d889190615aa3565b90506000613da163ffffffff881664e8d4a51000615a76565b9050613db881676765c793fa10079d601b1b6154b6565b821115613dd85760405163e80fa38160e01b815260040160405180910390fd5b613de28183615619565b9998505050505050505050565b6000610eec8383614238565b600061a4b1821480613e0f575062066eed82145b8061252f57505062066eee1490565b6000818152600183016020526040812054613e655750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561252f565b50600061252f565b6000826000018281548110613e8457613e8461544e565b9060005260206000200154905092915050565b613ea089614332565b613ee95760405162461bcd60e51b815260206004820152601a6024820152797075626c6963206b6579206973206e6f74206f6e20637572766560301b6044820152606401610f23565b613ef288614332565b613f365760405162461bcd60e51b815260206004820152601560248201527467616d6d61206973206e6f74206f6e20637572766560581b6044820152606401610f23565b613f3f83614332565b613f8b5760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e2063757276650000006044820152606401610f23565b613f9482614332565b613fdf5760405162461bcd60e51b815260206004820152601c60248201527b73486173685769746e657373206973206e6f74206f6e20637572766560201b6044820152606401610f23565b613feb878a88876143f5565b6140335760405162461bcd60e51b81526020600482015260196024820152786164647228632a706b2b732a6729213d5f755769746e65737360381b6044820152606401610f23565b600061403f8a87614509565b90506000614052898b878b86898961456d565b90506000614063838d8d8a86614680565b9050808a146140a45760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606401610f23565b505050505050505050505050565b6000466140be81613dfb565b1561410257606c6001600160a01b031663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613b8a573d6000803e3d6000fd5b61410b816146c0565b1561367d57600f602160991b016001600160a01b03166349948e0e84604051806080016040528060488152602001615c0d60489139604051602001614151929190615ab7565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401613b6d91906155ae565b600c5460035460408051633fabe5a360e21b81529051600093600160381b900463ffffffff169283151592859283926001600160a01b03169163feaf968c9160048083019260a09291908290030181865afa1580156141df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142039190615afd565b509450909250849150508015614227575061421e82426154b6565b8463ffffffff16105b156136155750601054949350505050565b6000818152600183016020526040812054801561432157600061425c6001836154b6565b8554909150600090614270906001906154b6565b90508181146142d55760008660000182815481106142905761429061544e565b90600052602060002001549050808760000184815481106142b3576142b361544e565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806142e6576142e66157f8565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061252f565b600091505061252f565b5092915050565b80516000906401000003d019116143805760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420782d6f7264696e61746560701b6044820152606401610f23565b60208201516401000003d019116143ce5760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420792d6f7264696e61746560701b6044820152606401610f23565b60208201516401000003d0199080096143ee8360005b60200201516146fa565b1492915050565b60006001600160a01b03821661443b5760405162461bcd60e51b815260206004820152600b60248201526a626164207769746e65737360a81b6044820152606401610f23565b60208401516000906001161561445257601c614455565b601b5b9050600070014551231950b75fc4402da1732fc9bebe1985876000602002015109865170014551231950b75fc4402da1732fc9bebe19918203925060009190890987516040805160008082526020909101918290529293506001916144bf91869188918790615b4d565b6020604051602081039080840390855afa1580156144e1573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b614511614c11565b61453e6001848460405160200161452a93929190615b6b565b60405160208183030381529060405261471e565b90505b61454a81614332565b61252f578051604080516020810192909252614566910161452a565b9050614541565b614575614c11565b825186516401000003d01991829006919006036145d45760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e637400006044820152606401610f23565b6145df87898861476b565b6146245760405162461bcd60e51b8152602060048201526016602482015275119a5c9cdd081b5d5b0818da1958dac819985a5b195960521b6044820152606401610f23565b61462f84868561476b565b6146755760405162461bcd60e51b815260206004820152601760248201527614d958dbdb99081b5d5b0818da1958dac819985a5b1959604a1b6044820152606401610f23565b613cbe868484614889565b60006002868686858760405160200161469e96959493929190615b8c565b60408051601f1981840301815291905280516020909101209695505050505050565b6000600a8214806146d257506101a482145b806146df575062aa37dc82145b806146eb575061210582145b8061252f57505062014a331490565b6000806401000003d01980848509840990506401000003d019600782089392505050565b614726614c11565b61472f8261494c565b815261474461473f8260006143e4565b614987565b6020820181905260029006600103611e90576020810180516401000003d019039052919050565b6000826000036147ab5760405162461bcd60e51b815260206004820152600b60248201526a3d32b9379039b1b0b630b960a91b6044820152606401610f23565b835160208501516000906147c190600290615be6565b156147cd57601c6147d0565b601b5b9050600070014551231950b75fc4402da1732fc9bebe19838709604080516000808252602090910191829052919250600190614813908390869088908790615b4d565b6020604051602081039080840390855afa158015614835573d6000803e3d6000fd5b5050506020604051035190506000866040516020016148549190615bfa565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b614891614c11565b8351602080860151855191860151600093849384936148b2939091906149a7565b919450925090506401000003d01985820960011461490e5760405162461bcd60e51b815260206004820152601960248201527834b73b2d1036bab9ba1031329034b73b32b939b29037b3103d60391b6044820152606401610f23565b60405180604001604052806401000003d0198061492d5761492d615a8d565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d0198110611e9057604080516020808201939093528151808203840181529082019091528051910120614954565b600061252f8260026149a06401000003d0196001615619565b901c614a87565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a08905060006149e783838585614b21565b90985090506149f888828e88614b45565b9098509050614a0988828c87614b45565b90985090506000614a1c8d878b85614b45565b9098509050614a2d88828686614b21565b9098509050614a3e88828e89614b45565b9098509050818114614a73576401000003d019818a0998506401000003d01982890997506401000003d0198183099650614a77565b8196505b5050505050509450945094915050565b600080614a92614c2f565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a0820152614ac4614c4d565b60208160c0846005600019fa925082600003614b175760405162461bcd60e51b81526020600482015260126024820152716269674d6f64457870206661696c7572652160701b6044820152606401610f23565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b828054828255906000526020600020908101928215614be3579160200282015b82811115614be357825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614bae565b50614bef929150614c6b565b5090565b50805460008255906000526020600020908101906130999190614c6b565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b80821115614bef5760008155600101614c6c565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b81811015614cd157845183529383019391830191600101614cb5565b509098975050505050505050565b6001600160a01b038116811461309957600080fd5b8035611e9081614cdf565b60008060408385031215614d1257600080fd5b823591506020830135614d2481614cdf565b809150509250929050565b6001600160a01b0391909116815260200190565b600060208284031215614d5557600080fd5b8135610eec81614cdf565b634e487b7160e01b600052604160045260246000fd5b60405160c081016001600160401b0381118282101715614d9857614d98614d60565b60405290565b60405161012081016001600160401b0381118282101715614d9857614d98614d60565b604051601f8201601f191681016001600160401b0381118282101715614de957614de9614d60565b604052919050565b600082601f830112614e0257600080fd5b604080519081016001600160401b0381118282101715614e2457614e24614d60565b8060405250806040840185811115614e3b57600080fd5b845b81811015614e55578035835260209283019201614e3d565b509195945050505050565b803563ffffffff81168114611e9057600080fd5b600082601f830112614e8557600080fd5b81356001600160401b03811115614e9e57614e9e614d60565b614eb1601f8201601f1916602001614dc1565b818152846020838601011115614ec657600080fd5b816020850160208301376000918101602001919091529392505050565b600060c08284031215614ef557600080fd5b614efd614d76565b905081356001600160401b038082168214614f1757600080fd5b81835260208401356020840152614f3060408501614e60565b6040840152614f4160608501614e60565b6060840152614f5260808501614cf4565b608084015260a0840135915080821115614f6b57600080fd5b50614f7884828501614e74565b60a08301525092915050565b801515811461309957600080fd5b8035611e9081614f84565b60008060008385036101e0811215614fb457600080fd5b6101a080821215614fc457600080fd5b614fcc614d9e565b9150614fd88787614df1565b8252614fe78760408801614df1565b60208301526080860135604083015260a0860135606083015260c0860135608083015261501660e08701614cf4565b60a083015261010061502a88828901614df1565b60c084015261503d886101408901614df1565b60e0840152610180870135908301529093508401356001600160401b0381111561506657600080fd5b61507286828701614ee3565b9250506150826101c08501614f92565b90509250925092565b60006020828403121561509d57600080fd5b5035919050565b600080604083850312156150b757600080fd5b82356150c281614cdf565b91506020830135614d2481614cdf565b6000604082840312156150e457600080fd5b826040830111156150f457600080fd5b50919050565b60006020828403121561510c57600080fd5b81356001600160401b0381111561512257600080fd5b820160c08185031215610eec57600080fd5b6001600160401b0391909116815260200190565b60008083601f84011261515a57600080fd5b5081356001600160401b0381111561517157600080fd5b60208301915083602082850101111561518957600080fd5b9250929050565b600080600080606085870312156151a657600080fd5b84356151b181614cdf565b93506020850135925060408501356001600160401b038111156151d357600080fd5b6151df87828801615148565b95989497509550505050565b803561ffff81168114611e9057600080fd5b803560ff81168114611e9057600080fd5b60008060008060008060008060006101208a8c03121561522d57600080fd5b6152368a6151eb565b985061524460208b01614e60565b975061525260408b01614e60565b965061526060608b01614e60565b955060808a0135945061527560a08b01614e60565b935061528360c08b01614e60565b925061529160e08b016151fd565b91506152a06101008b016151fd565b90509295985092959850929598565b600080604083850312156152c257600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b83811015615301578151875295820195908201906001016152e5565b509495945050505050565b602081526000610eec60208301846152d1565b60006040828403121561533157600080fd5b610eec8383614df1565b6000806020838503121561534e57600080fd5b82356001600160401b0381111561536457600080fd5b61537085828601615148565b90969095509350505050565b600081518084526020808501945080840160005b838110156153015781516001600160a01b031687529582019590820190600101615390565b6001600160601b038681168252851660208201526001600160401b03841660408201526001600160a01b038316606082015260a0608082018190526000906153ff9083018461537c565b979650505050505050565b634e487b7160e01b600052601160045260246000fd5b6001600160601b0382811682821603908082111561432b5761432b61540a565b918252602082015260400190565b634e487b7160e01b600052603260045260246000fd5b6000600182016154765761547661540a565b5060010190565b82815260406020820152600061361560408301846152d1565b6001600160401b0381811683821601908082111561432b5761432b61540a565b8181038181111561252f5761252f61540a565b6001600160601b0381811683821601908082111561432b5761432b61540a565b6020815260ff82511660208201526020820151604082015260018060a01b0360408301511660608201526000606083015160c0608084015261552e60e084018261537c565b60808501516001600160601b0390811660a0868101919091529095015190941660c0909301929092525090919050565b60005b83811015615579578181015183820152602001615561565b50506000910152565b6000815180845261559a81602086016020860161555e565b601f01601f19169290920160200192915050565b602081526000610eec6020830184615582565b6001600160a01b039290921682526001600160601b0316602082015260400190565b6000602082840312156155f557600080fd5b8151610eec81614f84565b6001600160a01b03929092168252602082015260400190565b8082018082111561252f5761252f61540a565b9182526001600160a01b0316602082015260400190565b60006020828403121561565557600080fd5b610eec826151eb565b61ffff93841681529183166020830152909116604082015260600190565b60006020828403121561568e57600080fd5b610eec82614e60565b63ffffffff92831681529116602082015260400190565b60006001600160401b038281166002600160401b031981016156d2576156d261540a565b6001019392505050565b6000808335601e198436030181126156f357600080fd5b8301803591506001600160401b0382111561570d57600080fd5b60200191503681900382131561518957600080fd5b878152602081018790526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c08201819052600090613de290830184615582565b86815285602082015261ffff85166040820152600063ffffffff808616606084015280851660808401525060c060a0830152613cbe60c0830184615582565b6001600160a01b0392831681529116602082015260400190565b8060005b6002811015612d205781518452602093840193909101906001016157cb565b6040810161252f82846157c7565b634e487b7160e01b600052603160045260246000fd5b80356001600160601b0381168114611e9057600080fd5b6000602080838503121561583857600080fd5b82356001600160401b038082111561584f57600080fd5b9084019060c0828703121561586357600080fd5b61586b614d76565b615874836151fd565b81528383013584820152604083013561588c81614cdf565b60408201526060830135828111156158a357600080fd5b8301601f810188136158b457600080fd5b8035838111156158c6576158c6614d60565b8060051b93506158d7868501614dc1565b818152938201860193868101908a8611156158f157600080fd5b928701925b8584101561591b578335925061590b83614cdf565b82825292870192908701906158f6565b6060850152506159309150506080840161580e565b608082015261594160a0840161580e565b60a08201529695505050505050565b60006020828403121561596257600080fd5b5051919050565b8781526001600160401b03871660208201526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c08201819052600090613de290830184615582565b6001600160e01b031981358181169160048510156159e55780818660040360031b1b83161692505b505092915050565b600080858511156159fd57600080fd5b83861115615a0a57600080fd5b5050820193919092039150565b600060208284031215615a2957600080fd5b604051602081016001600160401b0381118282101715615a4b57615a4b614d60565b6040528235615a5981614f84565b81529392505050565b82815260608101610eec60208301846157c7565b808202811582820484141761252f5761252f61540a565b634e487b7160e01b600052601260045260246000fd5b600082615ab257615ab2615a8d565b500490565b60008351615ac981846020880161555e565b835190830190615add81836020880161555e565b01949350505050565b80516001600160501b0381168114611e9057600080fd5b600080600080600060a08688031215615b1557600080fd5b615b1e86615ae6565b9450602086015193506040860151925060608601519150615b4160808701615ae6565b90509295509295909350565b93845260ff9290921660208401526040830152606082015260800190565b838152615b7b60208201846157c7565b606081019190915260800192915050565b868152615b9c60208201876157c7565b615ba960608201866157c7565b615bb660a08201856157c7565b615bc360e08201846157c7565b60609190911b6001600160601b0319166101208201526101340195945050505050565b600082615bf557615bf5615a8d565b500690565b615c0481836157c7565b60400191905056fe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000813000a", } var VRFCoordinatorV2PlusUpgradedVersionABI = VRFCoordinatorV2PlusUpgradedVersionMetaData.ABI @@ -393,7 +393,7 @@ func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionC outstruct.Balance = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) outstruct.NativeBalance = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) outstruct.ReqCount = *abi.ConvertType(out[2], new(uint64)).(*uint64) - outstruct.Owner = *abi.ConvertType(out[3], new(common.Address)).(*common.Address) + outstruct.SubOwner = *abi.ConvertType(out[3], new(common.Address)).(*common.Address) outstruct.Consumers = *abi.ConvertType(out[4], new([]common.Address)).(*[]common.Address) return *outstruct, err @@ -3236,7 +3236,7 @@ type GetSubscription struct { Balance *big.Int NativeBalance *big.Int ReqCount uint64 - Owner common.Address + SubOwner common.Address Consumers []common.Address } type SConfig struct { diff --git a/core/gethwrappers/generated/vrfv2plus_client/vrfv2plus_client.go b/core/gethwrappers/generated/vrfv2plus_client/vrfv2plus_client.go index f6a65a63f27..829c23b31a7 100644 --- a/core/gethwrappers/generated/vrfv2plus_client/vrfv2plus_client.go +++ b/core/gethwrappers/generated/vrfv2plus_client/vrfv2plus_client.go @@ -30,7 +30,7 @@ var ( var VRFV2PlusClientMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[],\"name\":\"EXTRA_ARGS_V1_TAG\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x60a0610038600b82828239805160001a607314602b57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe730000000000000000000000000000000000000000301460806040526004361060335760003560e01c8063f7514ab4146038575b600080fd5b605e7f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa81565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f3fea164736f6c6343000806000a", + Bin: "0x60a0610038600b82828239805160001a607314602b57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe730000000000000000000000000000000000000000301460806040526004361060335760003560e01c8063f7514ab4146038575b600080fd5b605e7f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa81565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f3fea164736f6c6343000813000a", } var VRFV2PlusClientABI = VRFV2PlusClientMetaData.ABI diff --git a/core/gethwrappers/generated/vrfv2plus_consumer_example/vrfv2plus_consumer_example.go b/core/gethwrappers/generated/vrfv2plus_consumer_example/vrfv2plus_consumer_example.go index db21c54df3b..b0a5ac6c4c1 100644 --- a/core/gethwrappers/generated/vrfv2plus_consumer_example/vrfv2plus_consumer_example.go +++ b/core/gethwrappers/generated/vrfv2plus_consumer_example/vrfv2plus_consumer_example.go @@ -32,7 +32,7 @@ var ( var VRFV2PlusConsumerExampleMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"vrfCoordinator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"}],\"name\":\"OnlyOwnerOrCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"vrfCoordinator\",\"type\":\"address\"}],\"name\":\"CoordinatorSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"createSubscriptionAndFund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscriptionAndFundNative\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"idx\",\"type\":\"uint256\"}],\"name\":\"getRandomness\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"randomWord\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"nativePayment\",\"type\":\"bool\"}],\"name\":\"requestRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_linkToken\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_recentRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requests\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_subId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_vrfCoordinator\",\"outputs\":[{\"internalType\":\"contractIVRFCoordinatorV2Plus\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_vrfCoordinatorApiV1\",\"outputs\":[{\"internalType\":\"contractIVRFCoordinatorV2Plus\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"name\":\"setCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"setSubId\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"topUpSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"topUpSubscriptionNative\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"}],\"name\":\"updateSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60806040523480156200001157600080fd5b50604051620019f8380380620019f88339810160408190526200003491620001cc565b8133806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf8162000103565b5050600280546001600160a01b03199081166001600160a01b0394851617909155600580548216958416959095179094555060038054909316911617905562000204565b6001600160a01b0381163314156200015e5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001c757600080fd5b919050565b60008060408385031215620001e057600080fd5b620001eb83620001af565b9150620001fb60208401620001af565b90509250929050565b6117e480620002146000396000f3fe6080604052600436106101445760003560e01c806380980043116100c0578063b96dbba711610074578063de367c8e11610059578063de367c8e146103c0578063eff27017146103ed578063f2fde38b1461040d57600080fd5b8063b96dbba714610398578063cf62c8ab146103a057600080fd5b80638ea98117116100a55780638ea98117146102c45780639eccacf6146102e4578063a168fa891461031157600080fd5b806380980043146102795780638da5cb5b1461029957600080fd5b806336bfffed11610117578063706da1ca116100fc578063706da1ca146101fc5780637725135b1461021257806379ba50971461026457600080fd5b806336bfffed146101c65780635d7d53e3146101e657600080fd5b80631d2b2afd146101495780631fe543e31461015357806329e5d831146101735780632fa4e442146101a6575b600080fd5b61015161042d565b005b34801561015f57600080fd5b5061015161016e36600461141d565b610528565b34801561017f57600080fd5b5061019361018e3660046114c1565b6105a9565b6040519081526020015b60405180910390f35b3480156101b257600080fd5b506101516101c136600461154e565b6106e6565b3480156101d257600080fd5b506101516101e136600461132a565b610808565b3480156101f257600080fd5b5061019360045481565b34801561020857600080fd5b5061019360065481565b34801561021e57600080fd5b5060035461023f9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019d565b34801561027057600080fd5b50610151610940565b34801561028557600080fd5b506101516102943660046113eb565b600655565b3480156102a557600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff1661023f565b3480156102d057600080fd5b506101516102df366004611308565b610a3d565b3480156102f057600080fd5b5060025461023f9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561031d57600080fd5b5061036661032c3660046113eb565b6007602052600090815260409020805460019091015460ff821691610100900473ffffffffffffffffffffffffffffffffffffffff169083565b60408051931515845273ffffffffffffffffffffffffffffffffffffffff90921660208401529082015260600161019d565b610151610b7a565b3480156103ac57600080fd5b506101516103bb36600461154e565b610be0565b3480156103cc57600080fd5b5060055461023f9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103f957600080fd5b506101516104083660046114e3565b610c27565b34801561041957600080fd5b50610151610428366004611308565b610e12565b60065461049b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f737562206e6f742073657400000000000000000000000000000000000000000060448201526064015b60405180910390fd5b6005546006546040517f95b55cfc000000000000000000000000000000000000000000000000000000008152600481019190915273ffffffffffffffffffffffffffffffffffffffff909116906395b55cfc9034906024015b6000604051808303818588803b15801561050d57600080fd5b505af1158015610521573d6000803e3d6000fd5b5050505050565b60025473ffffffffffffffffffffffffffffffffffffffff16331461059b576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091166024820152604401610492565b6105a58282610e26565b5050565b60008281526007602090815260408083208151608081018352815460ff811615158252610100900473ffffffffffffffffffffffffffffffffffffffff16818501526001820154818401526002820180548451818702810187019095528085528695929460608601939092919083018282801561064557602002820191906000526020600020905b815481526020019060010190808311610631575b50505050508152505090508060400151600014156106bf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265717565737420494420697320696e636f72726563740000000000000000006044820152606401610492565b806060015183815181106106d5576106d561176b565b602002602001015191505092915050565b60065461074f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f737562206e6f74207365740000000000000000000000000000000000000000006044820152606401610492565b60035460025460065460408051602081019290925273ffffffffffffffffffffffffffffffffffffffff93841693634000aea09316918591015b6040516020818303038152906040526040518463ffffffff1660e01b81526004016107b6939291906115e7565b602060405180830381600087803b1580156107d057600080fd5b505af11580156107e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a591906113ce565b600654610871576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f7375624944206e6f7420736574000000000000000000000000000000000000006044820152606401610492565b60005b81518110156105a557600554600654835173ffffffffffffffffffffffffffffffffffffffff9092169163bec4c08c91908590859081106108b7576108b761176b565b60200260200101516040518363ffffffff1660e01b81526004016108fb92919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b15801561091557600080fd5b505af1158015610929573d6000803e3d6000fd5b5050505080806109389061170b565b915050610874565b60015473ffffffffffffffffffffffffffffffffffffffff1633146109c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610492565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590610a7d575060025473ffffffffffffffffffffffffffffffffffffffff163314155b15610b015733610aa260005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff93841660048201529183166024830152919091166044820152606401610492565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fd1a6a14209a385a964d036e404cb5cfb71f4000cdb03c9366292430787261be69060200160405180910390a150565b610b82610ef1565b506005546006546040517f95b55cfc000000000000000000000000000000000000000000000000000000008152600481019190915273ffffffffffffffffffffffffffffffffffffffff909116906395b55cfc9034906024016104f4565b610be8610ef1565b5060035460025460065460408051602081019290925273ffffffffffffffffffffffffffffffffffffffff93841693634000aea0931691859101610789565b60006040518060c0016040528084815260200160065481526020018661ffff1681526020018763ffffffff1681526020018563ffffffff168152602001610c7d6040518060200160405280861515815250611036565b90526002546040517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925060009173ffffffffffffffffffffffffffffffffffffffff90911690639b1c385e90610cdb908590600401611633565b602060405180830381600087803b158015610cf557600080fd5b505af1158015610d09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2d9190611404565b604080516080810182526000808252336020808401918252838501868152855184815280830187526060860190815287855260078352959093208451815493517fffffffffffffffffffffff0000000000000000000000000000000000000000009094169015157fffffffffffffffffffffff0000000000000000000000000000000000000000ff161761010073ffffffffffffffffffffffffffffffffffffffff9094169390930292909217825591516001820155925180519495509193849392610e0092600285019291019061126b565b50505060049190915550505050505050565b610e1a6110f2565b610e2381611175565b50565b6004548214610e91576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265717565737420494420697320696e636f72726563740000000000000000006044820152606401610492565b60008281526007602090815260409091208251610eb69260029092019184019061126b565b5050600090815260076020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b60006006546000141561102f57600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a21a23e46040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610f6857600080fd5b505af1158015610f7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa09190611404565b60068190556005546040517fbec4c08c000000000000000000000000000000000000000000000000000000008152600481019290925230602483015273ffffffffffffffffffffffffffffffffffffffff169063bec4c08c90604401600060405180830381600087803b15801561101657600080fd5b505af115801561102a573d6000803e3d6000fd5b505050505b5060065490565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa8260405160240161106f91511515815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915292915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611173576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610492565b565b73ffffffffffffffffffffffffffffffffffffffff81163314156111f5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610492565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b8280548282559060005260206000209081019282156112a6579160200282015b828111156112a657825182559160200191906001019061128b565b506112b29291506112b6565b5090565b5b808211156112b257600081556001016112b7565b803573ffffffffffffffffffffffffffffffffffffffff811681146112ef57600080fd5b919050565b803563ffffffff811681146112ef57600080fd5b60006020828403121561131a57600080fd5b611323826112cb565b9392505050565b6000602080838503121561133d57600080fd5b823567ffffffffffffffff81111561135457600080fd5b8301601f8101851361136557600080fd5b8035611378611373826116e7565b611698565b80828252848201915084840188868560051b870101111561139857600080fd5b600094505b838510156113c2576113ae816112cb565b83526001949094019391850191850161139d565b50979650505050505050565b6000602082840312156113e057600080fd5b8151611323816117c9565b6000602082840312156113fd57600080fd5b5035919050565b60006020828403121561141657600080fd5b5051919050565b6000806040838503121561143057600080fd5b8235915060208084013567ffffffffffffffff81111561144f57600080fd5b8401601f8101861361146057600080fd5b803561146e611373826116e7565b80828252848201915084840189868560051b870101111561148e57600080fd5b600094505b838510156114b1578035835260019490940193918501918501611493565b5080955050505050509250929050565b600080604083850312156114d457600080fd5b50508035926020909101359150565b600080600080600060a086880312156114fb57600080fd5b611504866112f4565b9450602086013561ffff8116811461151b57600080fd5b9350611529604087016112f4565b9250606086013591506080860135611540816117c9565b809150509295509295909350565b60006020828403121561156057600080fd5b81356bffffffffffffffffffffffff8116811461132357600080fd5b6000815180845260005b818110156115a257602081850181015186830182015201611586565b818111156115b4576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff841681526bffffffffffffffffffffffff8316602082015260606040820152600061162a606083018461157c565b95945050505050565b60208152815160208201526020820151604082015261ffff60408301511660608201526000606083015163ffffffff80821660808501528060808601511660a0850152505060a083015160c08084015261169060e084018261157c565b949350505050565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156116df576116df61179a565b604052919050565b600067ffffffffffffffff8211156117015761170161179a565b5060051b60200190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415611764577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b8015158114610e2357600080fdfea164736f6c6343000806000a", + Bin: "0x60806040523480156200001157600080fd5b5060405162001a2f38038062001a2f8339810160408190526200003491620001f3565b8133806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf816200012b565b5050506001600160a01b038116620000ea5760405163d92e233d60e01b815260040160405180910390fd5b600280546001600160a01b03199081166001600160a01b0393841617909155600580548216948316949094179093556003805490931691161790556200022b565b336001600160a01b03821603620001855760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001ee57600080fd5b919050565b600080604083850312156200020757600080fd5b6200021283620001d6565b91506200022260208401620001d6565b90509250929050565b6117f4806200023b6000396000f3fe6080604052600436106101445760003560e01c806380980043116100c0578063b96dbba711610074578063de367c8e11610059578063de367c8e146103c0578063eff27017146103ed578063f2fde38b1461040d57600080fd5b8063b96dbba714610398578063cf62c8ab146103a057600080fd5b80638ea98117116100a55780638ea98117146102c45780639eccacf6146102e4578063a168fa891461031157600080fd5b806380980043146102795780638da5cb5b1461029957600080fd5b806336bfffed11610117578063706da1ca116100fc578063706da1ca146101fc5780637725135b1461021257806379ba50971461026457600080fd5b806336bfffed146101c65780635d7d53e3146101e657600080fd5b80631d2b2afd146101495780631fe543e31461015357806329e5d831146101735780632fa4e442146101a6575b600080fd5b61015161042d565b005b34801561015f57600080fd5b5061015161016e366004611393565b61052b565b34801561017f57600080fd5b5061019361018e366004611435565b6105ac565b6040519081526020015b60405180910390f35b3480156101b257600080fd5b506101516101c1366004611457565b6106e8565b3480156101d257600080fd5b506101516101e13660046114b5565b6107fe565b3480156101f257600080fd5b5061019360045481565b34801561020857600080fd5b5061019360065481565b34801561021e57600080fd5b5060035461023f9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019d565b34801561027057600080fd5b50610151610939565b34801561028557600080fd5b5061015161029436600461154d565b600655565b3480156102a557600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff1661023f565b3480156102d057600080fd5b506101516102df366004611566565b610a36565b3480156102f057600080fd5b5060025461023f9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561031d57600080fd5b5061036661032c36600461154d565b6007602052600090815260409020805460019091015460ff821691610100900473ffffffffffffffffffffffffffffffffffffffff169083565b60408051931515845273ffffffffffffffffffffffffffffffffffffffff90921660208401529082015260600161019d565b610151610bc0565b3480156103ac57600080fd5b506101516103bb366004611457565b610c26565b3480156103cc57600080fd5b5060055461023f9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103f957600080fd5b506101516104083660046115a3565b610c6d565b34801561041957600080fd5b50610151610428366004611566565b610e49565b60065460000361049e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f737562206e6f742073657400000000000000000000000000000000000000000060448201526064015b60405180910390fd5b6005546006546040517f95b55cfc000000000000000000000000000000000000000000000000000000008152600481019190915273ffffffffffffffffffffffffffffffffffffffff909116906395b55cfc9034906024015b6000604051808303818588803b15801561051057600080fd5b505af1158015610524573d6000803e3d6000fd5b5050505050565b60025473ffffffffffffffffffffffffffffffffffffffff16331461059e576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091166024820152604401610495565b6105a88282610e5d565b5050565b60008281526007602090815260408083208151608081018352815460ff811615158252610100900473ffffffffffffffffffffffffffffffffffffffff16818501526001820154818401526002820180548451818702810187019095528085528695929460608601939092919083018282801561064857602002820191906000526020600020905b815481526020019060010190808311610634575b505050505081525050905080604001516000036106c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265717565737420494420697320696e636f72726563740000000000000000006044820152606401610495565b806060015183815181106106d7576106d761160e565b602002602001015191505092915050565b600654600003610754576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f737562206e6f74207365740000000000000000000000000000000000000000006044820152606401610495565b60035460025460065460408051602081019290925273ffffffffffffffffffffffffffffffffffffffff93841693634000aea09316918591015b6040516020818303038152906040526040518463ffffffff1660e01b81526004016107bb939291906116a1565b6020604051808303816000875af11580156107da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a891906116ed565b60065460000361086a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f7375624944206e6f7420736574000000000000000000000000000000000000006044820152606401610495565b60005b81518110156105a857600554600654835173ffffffffffffffffffffffffffffffffffffffff9092169163bec4c08c91908590859081106108b0576108b061160e565b60200260200101516040518363ffffffff1660e01b81526004016108f492919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b15801561090e57600080fd5b505af1158015610922573d6000803e3d6000fd5b5050505080806109319061170a565b91505061086d565b60015473ffffffffffffffffffffffffffffffffffffffff1633146109ba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610495565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590610a76575060025473ffffffffffffffffffffffffffffffffffffffff163314155b15610afa5733610a9b60005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff93841660048201529183166024830152919091166044820152606401610495565b73ffffffffffffffffffffffffffffffffffffffff8116610b47576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fd1a6a14209a385a964d036e404cb5cfb71f4000cdb03c9366292430787261be69060200160405180910390a150565b610bc8610f28565b506005546006546040517f95b55cfc000000000000000000000000000000000000000000000000000000008152600481019190915273ffffffffffffffffffffffffffffffffffffffff909116906395b55cfc9034906024016104f7565b610c2e610f28565b5060035460025460065460408051602081019290925273ffffffffffffffffffffffffffffffffffffffff93841693634000aea093169185910161078e565b60006040518060c0016040528084815260200160065481526020018661ffff1681526020018763ffffffff1681526020018563ffffffff168152602001610cc3604051806020016040528086151581525061105d565b90526002546040517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925060009173ffffffffffffffffffffffffffffffffffffffff90911690639b1c385e90610d21908590600401611769565b6020604051808303816000875af1158015610d40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6491906117ce565b604080516080810182526000808252336020808401918252838501868152855184815280830187526060860190815287855260078352959093208451815493517fffffffffffffffffffffff0000000000000000000000000000000000000000009094169015157fffffffffffffffffffffff0000000000000000000000000000000000000000ff161761010073ffffffffffffffffffffffffffffffffffffffff9094169390930292909217825591516001820155925180519495509193849392610e37926002850192910190611291565b50505060049190915550505050505050565b610e51611119565b610e5a8161119c565b50565b6004548214610ec8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265717565737420494420697320696e636f72726563740000000000000000006044820152606401610495565b60008281526007602090815260409091208251610eed92600290920191840190611291565b5050600090815260076020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b600060065460000361105657600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a21a23e46040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610fa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc791906117ce565b60068190556005546040517fbec4c08c000000000000000000000000000000000000000000000000000000008152600481019290925230602483015273ffffffffffffffffffffffffffffffffffffffff169063bec4c08c90604401600060405180830381600087803b15801561103d57600080fd5b505af1158015611051573d6000803e3d6000fd5b505050505b5060065490565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa8260405160240161109691511515815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915292915050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461119a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610495565b565b3373ffffffffffffffffffffffffffffffffffffffff82160361121b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610495565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b8280548282559060005260206000209081019282156112cc579160200282015b828111156112cc5782518255916020019190600101906112b1565b506112d89291506112dc565b5090565b5b808211156112d857600081556001016112dd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611367576113676112f1565b604052919050565b600067ffffffffffffffff821115611389576113896112f1565b5060051b60200190565b600080604083850312156113a657600080fd5b8235915060208084013567ffffffffffffffff8111156113c557600080fd5b8401601f810186136113d657600080fd5b80356113e96113e48261136f565b611320565b81815260059190911b8201830190838101908883111561140857600080fd5b928401925b828410156114265783358252928401929084019061140d565b80955050505050509250929050565b6000806040838503121561144857600080fd5b50508035926020909101359150565b60006020828403121561146957600080fd5b81356bffffffffffffffffffffffff8116811461148557600080fd5b9392505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146114b057600080fd5b919050565b600060208083850312156114c857600080fd5b823567ffffffffffffffff8111156114df57600080fd5b8301601f810185136114f057600080fd5b80356114fe6113e48261136f565b81815260059190911b8201830190838101908783111561151d57600080fd5b928401925b82841015611542576115338461148c565b82529284019290840190611522565b979650505050505050565b60006020828403121561155f57600080fd5b5035919050565b60006020828403121561157857600080fd5b6114858261148c565b803563ffffffff811681146114b057600080fd5b8015158114610e5a57600080fd5b600080600080600060a086880312156115bb57600080fd5b6115c486611581565b9450602086013561ffff811681146115db57600080fd5b93506115e960408701611581565b925060608601359150608086013561160081611595565b809150509295509295909350565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000815180845260005b8181101561166357602081850181015186830182015201611647565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b73ffffffffffffffffffffffffffffffffffffffff841681526bffffffffffffffffffffffff831660208201526060604082015260006116e4606083018461163d565b95945050505050565b6000602082840312156116ff57600080fd5b815161148581611595565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611762577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b60208152815160208201526020820151604082015261ffff60408301511660608201526000606083015163ffffffff80821660808501528060808601511660a0850152505060a083015160c0808401526117c660e084018261163d565b949350505050565b6000602082840312156117e057600080fd5b505191905056fea164736f6c6343000813000a", } var VRFV2PlusConsumerExampleABI = VRFV2PlusConsumerExampleMetaData.ABI diff --git a/core/gethwrappers/generated/vrfv2plus_malicious_migrator/vrfv2plus_malicious_migrator.go b/core/gethwrappers/generated/vrfv2plus_malicious_migrator/vrfv2plus_malicious_migrator.go index d87facd2326..3c1b0d2df57 100644 --- a/core/gethwrappers/generated/vrfv2plus_malicious_migrator/vrfv2plus_malicious_migrator.go +++ b/core/gethwrappers/generated/vrfv2plus_malicious_migrator/vrfv2plus_malicious_migrator.go @@ -32,7 +32,7 @@ var ( var VRFV2PlusMaliciousMigratorMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"vrfCoordinator\",\"type\":\"address\"}],\"name\":\"CoordinatorSet\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"setCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b506040516102e03803806102e083398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b61024d806100936000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80638ea9811714610030575b600080fd5b61004361003e36600461012a565b610045565b005b600080546040805160c081018252838152602080820185905281830185905260608201859052608082018590528251908101835293845260a0810193909352517f9b1c385e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911691639b1c385e916100d49190600401610180565b602060405180830381600087803b1580156100ee57600080fd5b505af1158015610102573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101269190610167565b5050565b60006020828403121561013c57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461016057600080fd5b9392505050565b60006020828403121561017957600080fd5b5051919050565b6000602080835283518184015280840151604084015261ffff6040850151166060840152606084015163ffffffff80821660808601528060808701511660a0860152505060a084015160c08085015280518060e086015260005b818110156101f757828101840151868201610100015283016101da565b8181111561020a57600061010083880101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016939093016101000194935050505056fea164736f6c6343000806000a", + Bin: "0x608060405234801561001057600080fd5b506040516102cb3803806102cb83398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b610238806100936000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80638ea9811714610030575b600080fd5b61004361003e36600461011b565b610045565b005b600080546040805160c081018252838152602080820185905281830185905260608201859052608082018590528251908101835293845260a0810193909352517f9b1c385e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911691639b1c385e916100d49190600401610158565b6020604051808303816000875af11580156100f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101179190610212565b5050565b60006020828403121561012d57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461015157600080fd5b9392505050565b6000602080835283518184015280840151604084015261ffff6040850151166060840152606084015163ffffffff80821660808601528060808701511660a0860152505060a084015160c08085015280518060e086015260005b818110156101cf57828101840151868201610100015283016101b2565b5061010092506000838287010152827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116860101935050505092915050565b60006020828403121561022457600080fd5b505191905056fea164736f6c6343000813000a", } var VRFV2PlusMaliciousMigratorABI = VRFV2PlusMaliciousMigratorMetaData.ABI diff --git a/core/gethwrappers/generated/vrfv2plus_reverting_example/vrfv2plus_reverting_example.go b/core/gethwrappers/generated/vrfv2plus_reverting_example/vrfv2plus_reverting_example.go index 42c6fa57459..73b85e12f80 100644 --- a/core/gethwrappers/generated/vrfv2plus_reverting_example/vrfv2plus_reverting_example.go +++ b/core/gethwrappers/generated/vrfv2plus_reverting_example/vrfv2plus_reverting_example.go @@ -32,7 +32,7 @@ var ( var VRFV2PlusRevertingExampleMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"vrfCoordinator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"}],\"name\":\"OnlyOwnerOrCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"vrfCoordinator\",\"type\":\"address\"}],\"name\":\"CoordinatorSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"createSubscriptionAndFund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"minReqConfs\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"}],\"name\":\"requestRandomness\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_gasAvailable\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_randomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_subId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_vrfCoordinator\",\"outputs\":[{\"internalType\":\"contractIVRFCoordinatorV2Plus\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"name\":\"setCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"topUpSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"}],\"name\":\"updateSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60806040523480156200001157600080fd5b5060405162001247380380620012478339810160408190526200003491620001c2565b8133806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf81620000f9565b5050600280546001600160a01b039384166001600160a01b0319918216179091556005805494909316931692909217905550620001fa9050565b6001600160a01b038116331415620001545760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001bd57600080fd5b919050565b60008060408385031215620001d657600080fd5b620001e183620001a5565b9150620001f160208401620001a5565b90509250929050565b61103d806200020a6000396000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c80638ea981171161008c578063e89e106a11610066578063e89e106a146101e6578063f08c5daa146101ef578063f2fde38b146101f8578063f6eaffc81461020b57600080fd5b80638ea98117146101a05780639eccacf6146101b3578063cf62c8ab146101d357600080fd5b806336bfffed116100c857806336bfffed1461013d578063706da1ca1461015057806379ba5097146101595780638da5cb5b1461016157600080fd5b80631fe543e3146100ef5780632e75964e146101045780632fa4e4421461012a575b600080fd5b6101026100fd366004610d11565b61021e565b005b610117610112366004610c7f565b6102a4565b6040519081526020015b60405180910390f35b610102610138366004610db5565b6103a1565b61010261014b366004610bb9565b6104c3565b61011760065481565b6101026105fb565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610121565b6101026101ae366004610b97565b6106f8565b60025461017b9073ffffffffffffffffffffffffffffffffffffffff1681565b6101026101e1366004610db5565b610835565b61011760045481565b61011760075481565b610102610206366004610b97565b6109ac565b610117610219366004610cdf565b6109c0565b60025473ffffffffffffffffffffffffffffffffffffffff163314610296576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff90911660248201526044015b60405180910390fd5b6102a08282600080fd5b5050565b6040805160c081018252868152602080820187905261ffff86168284015263ffffffff80861660608401528416608083015282519081018352600080825260a083019190915260025492517f9b1c385e000000000000000000000000000000000000000000000000000000008152909273ffffffffffffffffffffffffffffffffffffffff1690639b1c385e9061033f908490600401610e9a565b602060405180830381600087803b15801561035957600080fd5b505af115801561036d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103919190610cf8565b6004819055979650505050505050565b60065461040a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f737562206e6f7420736574000000000000000000000000000000000000000000604482015260640161028d565b60055460025460065460408051602081019290925273ffffffffffffffffffffffffffffffffffffffff93841693634000aea09316918591015b6040516020818303038152906040526040518463ffffffff1660e01b815260040161047193929190610e4e565b602060405180830381600087803b15801561048b57600080fd5b505af115801561049f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102a09190610c5d565b60065461052c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f7375624944206e6f742073657400000000000000000000000000000000000000604482015260640161028d565b60005b81518110156102a057600254600654835173ffffffffffffffffffffffffffffffffffffffff9092169163bec4c08c919085908590811061057257610572610fd2565b60200260200101516040518363ffffffff1660e01b81526004016105b692919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b1580156105d057600080fd5b505af11580156105e4573d6000803e3d6000fd5b5050505080806105f390610f72565b91505061052f565b60015473ffffffffffffffffffffffffffffffffffffffff16331461067c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161028d565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590610738575060025473ffffffffffffffffffffffffffffffffffffffff163314155b156107bc573361075d60005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9384166004820152918316602483015291909116604482015260640161028d565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fd1a6a14209a385a964d036e404cb5cfb71f4000cdb03c9366292430787261be69060200160405180910390a150565b60065461040a57600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a21a23e46040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156108a657600080fd5b505af11580156108ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108de9190610cf8565b60068190556002546040517fbec4c08c000000000000000000000000000000000000000000000000000000008152600481019290925230602483015273ffffffffffffffffffffffffffffffffffffffff169063bec4c08c90604401600060405180830381600087803b15801561095457600080fd5b505af1158015610968573d6000803e3d6000fd5b5050505060055460025460065460405173ffffffffffffffffffffffffffffffffffffffff93841693634000aea09316918591610444919060200190815260200190565b6109b46109e1565b6109bd81610a64565b50565b600381815481106109d057600080fd5b600091825260209091200154905081565b60005473ffffffffffffffffffffffffffffffffffffffff163314610a62576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161028d565b565b73ffffffffffffffffffffffffffffffffffffffff8116331415610ae4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161028d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b803573ffffffffffffffffffffffffffffffffffffffff81168114610b7e57600080fd5b919050565b803563ffffffff81168114610b7e57600080fd5b600060208284031215610ba957600080fd5b610bb282610b5a565b9392505050565b60006020808385031215610bcc57600080fd5b823567ffffffffffffffff811115610be357600080fd5b8301601f81018513610bf457600080fd5b8035610c07610c0282610f4e565b610eff565b80828252848201915084840188868560051b8701011115610c2757600080fd5b600094505b83851015610c5157610c3d81610b5a565b835260019490940193918501918501610c2c565b50979650505050505050565b600060208284031215610c6f57600080fd5b81518015158114610bb257600080fd5b600080600080600060a08688031215610c9757600080fd5b8535945060208601359350604086013561ffff81168114610cb757600080fd5b9250610cc560608701610b83565b9150610cd360808701610b83565b90509295509295909350565b600060208284031215610cf157600080fd5b5035919050565b600060208284031215610d0a57600080fd5b5051919050565b60008060408385031215610d2457600080fd5b8235915060208084013567ffffffffffffffff811115610d4357600080fd5b8401601f81018613610d5457600080fd5b8035610d62610c0282610f4e565b80828252848201915084840189868560051b8701011115610d8257600080fd5b600094505b83851015610da5578035835260019490940193918501918501610d87565b5080955050505050509250929050565b600060208284031215610dc757600080fd5b81356bffffffffffffffffffffffff81168114610bb257600080fd5b6000815180845260005b81811015610e0957602081850181015186830182015201610ded565b81811115610e1b576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff841681526bffffffffffffffffffffffff83166020820152606060408201526000610e916060830184610de3565b95945050505050565b60208152815160208201526020820151604082015261ffff60408301511660608201526000606083015163ffffffff80821660808501528060808601511660a0850152505060a083015160c080840152610ef760e0840182610de3565b949350505050565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610f4657610f46611001565b604052919050565b600067ffffffffffffffff821115610f6857610f68611001565b5060051b60200190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610fcb577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + Bin: "0x60806040523480156200001157600080fd5b506040516200127d3803806200127d8339810160408190526200003491620001e8565b8133806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf8162000120565b5050506001600160a01b038116620000ea5760405163d92e233d60e01b815260040160405180910390fd5b600280546001600160a01b039283166001600160a01b031991821617909155600580549390921692169190911790555062000220565b336001600160a01b038216036200017a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001e357600080fd5b919050565b60008060408385031215620001fc57600080fd5b6200020783620001cb565b91506200021760208401620001cb565b90509250929050565b61104d80620002306000396000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c80638ea981171161008c578063e89e106a11610066578063e89e106a146101e6578063f08c5daa146101ef578063f2fde38b146101f8578063f6eaffc81461020b57600080fd5b80638ea98117146101a05780639eccacf6146101b3578063cf62c8ab146101d357600080fd5b806336bfffed116100c857806336bfffed1461013d578063706da1ca1461015057806379ba5097146101595780638da5cb5b1461016157600080fd5b80631fe543e3146100ef5780632e75964e146101045780632fa4e4421461012a575b600080fd5b6101026100fd366004610c22565b61021e565b005b610117610112366004610cdd565b6102a2565b6040519081526020015b60405180910390f35b610102610138366004610d3d565b610390565b61010261014b366004610d96565b6104a6565b61011760065481565b6101026105e1565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610121565b6101026101ae366004610e2e565b6106de565b60025461017b9073ffffffffffffffffffffffffffffffffffffffff1681565b6101026101e1366004610d3d565b610868565b61011760045481565b61011760075481565b610102610206366004610e2e565b6109d3565b610117610219366004610e49565b6109e7565b60025473ffffffffffffffffffffffffffffffffffffffff163314610296576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff90911660248201526044015b60405180910390fd5b61029e600080fd5b5050565b6040805160c081018252868152602080820187905261ffff86168284015263ffffffff80861660608401528416608083015282519081018352600080825260a083019190915260025492517f9b1c385e000000000000000000000000000000000000000000000000000000008152909273ffffffffffffffffffffffffffffffffffffffff1690639b1c385e9061033d908490600401610ec6565b6020604051808303816000875af115801561035c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103809190610f2b565b6004819055979650505050505050565b6006546000036103fc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f737562206e6f7420736574000000000000000000000000000000000000000000604482015260640161028d565b60055460025460065460408051602081019290925273ffffffffffffffffffffffffffffffffffffffff93841693634000aea09316918591015b6040516020818303038152906040526040518463ffffffff1660e01b815260040161046393929190610f44565b6020604051808303816000875af1158015610482573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061029e9190610f90565b600654600003610512576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f7375624944206e6f742073657400000000000000000000000000000000000000604482015260640161028d565b60005b815181101561029e57600254600654835173ffffffffffffffffffffffffffffffffffffffff9092169163bec4c08c919085908590811061055857610558610fb2565b60200260200101516040518363ffffffff1660e01b815260040161059c92919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b1580156105b657600080fd5b505af11580156105ca573d6000803e3d6000fd5b5050505080806105d990610fe1565b915050610515565b60015473ffffffffffffffffffffffffffffffffffffffff163314610662576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161028d565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff16331480159061071e575060025473ffffffffffffffffffffffffffffffffffffffff163314155b156107a2573361074360005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9384166004820152918316602483015291909116604482015260640161028d565b73ffffffffffffffffffffffffffffffffffffffff81166107ef576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fd1a6a14209a385a964d036e404cb5cfb71f4000cdb03c9366292430787261be69060200160405180910390a150565b6006546000036103fc57600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a21a23e46040518163ffffffff1660e01b81526004016020604051808303816000875af11580156108e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109059190610f2b565b60068190556002546040517fbec4c08c000000000000000000000000000000000000000000000000000000008152600481019290925230602483015273ffffffffffffffffffffffffffffffffffffffff169063bec4c08c90604401600060405180830381600087803b15801561097b57600080fd5b505af115801561098f573d6000803e3d6000fd5b5050505060055460025460065460405173ffffffffffffffffffffffffffffffffffffffff93841693634000aea09316918591610436919060200190815260200190565b6109db610a08565b6109e481610a8b565b50565b600381815481106109f757600080fd5b600091825260209091200154905081565b60005473ffffffffffffffffffffffffffffffffffffffff163314610a89576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161028d565b565b3373ffffffffffffffffffffffffffffffffffffffff821603610b0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161028d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610bf657610bf6610b80565b604052919050565b600067ffffffffffffffff821115610c1857610c18610b80565b5060051b60200190565b60008060408385031215610c3557600080fd5b8235915060208084013567ffffffffffffffff811115610c5457600080fd5b8401601f81018613610c6557600080fd5b8035610c78610c7382610bfe565b610baf565b81815260059190911b82018301908381019088831115610c9757600080fd5b928401925b82841015610cb557833582529284019290840190610c9c565b80955050505050509250929050565b803563ffffffff81168114610cd857600080fd5b919050565b600080600080600060a08688031215610cf557600080fd5b8535945060208601359350604086013561ffff81168114610d1557600080fd5b9250610d2360608701610cc4565b9150610d3160808701610cc4565b90509295509295909350565b600060208284031215610d4f57600080fd5b81356bffffffffffffffffffffffff81168114610d6b57600080fd5b9392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610cd857600080fd5b60006020808385031215610da957600080fd5b823567ffffffffffffffff811115610dc057600080fd5b8301601f81018513610dd157600080fd5b8035610ddf610c7382610bfe565b81815260059190911b82018301908381019087831115610dfe57600080fd5b928401925b82841015610e2357610e1484610d72565b82529284019290840190610e03565b979650505050505050565b600060208284031215610e4057600080fd5b610d6b82610d72565b600060208284031215610e5b57600080fd5b5035919050565b6000815180845260005b81811015610e8857602081850181015186830182015201610e6c565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152815160208201526020820151604082015261ffff60408301511660608201526000606083015163ffffffff80821660808501528060808601511660a0850152505060a083015160c080840152610f2360e0840182610e62565b949350505050565b600060208284031215610f3d57600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff841681526bffffffffffffffffffffffff83166020820152606060408201526000610f876060830184610e62565b95945050505050565b600060208284031215610fa257600080fd5b81518015158114610d6b57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611039577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b506001019056fea164736f6c6343000813000a", } var VRFV2PlusRevertingExampleABI = VRFV2PlusRevertingExampleMetaData.ABI diff --git a/core/gethwrappers/generated/vrfv2plus_wrapper/vrfv2plus_wrapper.go b/core/gethwrappers/generated/vrfv2plus_wrapper/vrfv2plus_wrapper.go index dc875deff18..7d358d5b03b 100644 --- a/core/gethwrappers/generated/vrfv2plus_wrapper/vrfv2plus_wrapper.go +++ b/core/gethwrappers/generated/vrfv2plus_wrapper/vrfv2plus_wrapper.go @@ -31,15 +31,15 @@ var ( ) var VRFV2PlusWrapperMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_linkNativeFeed\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_coordinator\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"FailedToTransferLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"expectedMinimumLength\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"actualLength\",\"type\":\"uint16\"}],\"name\":\"IncorrectExtraArgsLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LINKPaymentInRequestRandomWordsInNative\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkAlreadySet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativePaymentInOnTokenTransfer\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"}],\"name\":\"OnlyOwnerOrCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"wrapperGasOverhead\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"coordinatorGasOverhead\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"wrapperPremiumPercentage\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"maxNumWords\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"vrfCoordinator\",\"type\":\"address\"}],\"name\":\"CoordinatorSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"Disabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"Enabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"}],\"name\":\"FallbackWeiPerUnitLinkUsed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"size\",\"type\":\"uint32\"}],\"name\":\"FulfillmentTxSizeSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"linkNativeFeed\",\"type\":\"address\"}],\"name\":\"LinkAndLinkNativeFeedSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"NativeWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"WrapperFulfillmentFailed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"SUBSCRIPTION_ID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"}],\"name\":\"calculateRequestPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"}],\"name\":\"calculateRequestPriceNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"},{\"internalType\":\"bool\",\"name\":\"isLinkMode\",\"type\":\"bool\"}],\"name\":\"checkPaymentMode\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"disable\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"enable\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"_requestGasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateRequestPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"_requestGasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateRequestPriceNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"wrapperGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"coordinatorGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"wrapperPremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"maxNumWords\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"}],\"name\":\"migrate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"name\":\"requestRandomWordsInNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_callbacks\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"callbackAddress\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"requestGasPrice\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_configured\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_disabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fulfillmentTxSizeBytes\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_link\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_linkNativeFeed\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_vrfCoordinator\",\"outputs\":[{\"internalType\":\"contractIVRFCoordinatorV2Plus\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_wrapperGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_coordinatorGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"_wrapperPremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"_keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"_maxNumWords\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"_stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"int256\",\"name\":\"_fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"internalType\":\"uint32\",\"name\":\"_fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"name\":\"setCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"size\",\"type\":\"uint32\"}],\"name\":\"setFulfillmentTxSize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkNativeFeed\",\"type\":\"address\"}],\"name\":\"setLinkAndLinkNativeFeed\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"}],\"name\":\"withdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040526007805463ffffffff60201b1916650244000000001790553480156200002957600080fd5b5060405162003957380380620039578339810160408190526200004c9162000323565b803380600081620000a45760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000d757620000d7816200025a565b5050600280546001600160a01b0319166001600160a01b03938416179055508316156200012857600680546001600160601b03166c010000000000000000000000006001600160a01b038616021790555b6001600160a01b038216156200016257600780546001600160601b03166c010000000000000000000000006001600160a01b038516021790555b6002546040805163288688f960e21b815290516000926001600160a01b03169163a21a23e491600480830192602092919082900301818787803b158015620001a957600080fd5b505af1158015620001be573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001e491906200036d565b6080819052600254604051632fb1302360e21b8152600481018390523060248201529192506001600160a01b03169063bec4c08c90604401600060405180830381600087803b1580156200023757600080fd5b505af11580156200024c573d6000803e3d6000fd5b505050505050505062000387565b6001600160a01b038116331415620002b55760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200009b565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200031e57600080fd5b919050565b6000806000606084860312156200033957600080fd5b620003448462000306565b9250620003546020850162000306565b9150620003646040850162000306565b90509250925092565b6000602082840312156200038057600080fd5b5051919050565b60805161359f620003b8600039600081816101ef015281816114ae01528181611a000152611ee0015261359f6000f3fe6080604052600436106101d85760003560e01c80638ea9811711610102578063c3f909d411610095578063f254bdc711610064578063f254bdc714610701578063f2fde38b1461073e578063fb8f80101461075e578063fc2a88c31461077e57600080fd5b8063c3f909d4146105d1578063cdd8d8851461066a578063ce5494bb146106a4578063da4f5e6d146106c457600080fd5b8063a4c0ed36116100d1578063a4c0ed3614610552578063a608a1e114610572578063bed41a9314610591578063bf17e559146105b157600080fd5b80638ea98117146104dd5780639cfc058e146104fd5780639eccacf614610510578063a3907d711461053d57600080fd5b80634306d3541161017a57806357a8070a1161014957806357a8070a1461043257806379ba50971461045c5780637fb5d19d146104715780638da5cb5b1461049157600080fd5b80634306d3541461030757806348baa1c5146103275780634b160935146103f257806351cff8d91461041257600080fd5b80631fe543e3116101b65780631fe543e3146102925780632f2770db146102b25780632f622e6b146102c75780633255c456146102e757600080fd5b8063030932bb146101dd578063181f5a771461022457806318b6f4c814610270575b600080fd5b3480156101e957600080fd5b506102117f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b34801561023057600080fd5b50604080518082018252601281527f56524656325772617070657220312e302e3000000000000000000000000000006020820152905161021b91906131a4565b34801561027c57600080fd5b5061029061028b366004612d9e565b610794565b005b34801561029e57600080fd5b506102906102ad366004612e22565b610919565b3480156102be57600080fd5b50610290610996565b3480156102d357600080fd5b506102906102e2366004612cd2565b6109f5565b3480156102f357600080fd5b50610211610302366004613025565b610b1c565b34801561031357600080fd5b50610211610322366004612f25565b610c16565b34801561033357600080fd5b506103b1610342366004612df0565b60096020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff81169074010000000000000000000000000000000000000000810463ffffffff16907801000000000000000000000000000000000000000000000000900467ffffffffffffffff1683565b6040805173ffffffffffffffffffffffffffffffffffffffff909416845263ffffffff909216602084015267ffffffffffffffff169082015260600161021b565b3480156103fe57600080fd5b5061021161040d366004612f25565b610d1e565b34801561041e57600080fd5b5061029061042d366004612cd2565b610e0f565b34801561043e57600080fd5b5060085461044c9060ff1681565b604051901515815260200161021b565b34801561046857600080fd5b50610290611013565b34801561047d57600080fd5b5061021161048c366004613025565b611110565b34801561049d57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161021b565b3480156104e957600080fd5b506102906104f8366004612cd2565b611217565b61021161050b366004612f40565b611355565b34801561051c57600080fd5b506002546104b89073ffffffffffffffffffffffffffffffffffffffff1681565b34801561054957600080fd5b506102906116ea565b34801561055e57600080fd5b5061029061056d366004612d20565b611745565b34801561057e57600080fd5b5060085461044c90610100900460ff1681565b34801561059d57600080fd5b506102906105ac36600461304f565b611c6d565b3480156105bd57600080fd5b506102906105cc366004612f25565b611e38565b3480156105dd57600080fd5b506005546006546007546008546003546040805195865263ffffffff8086166020880152640100000000860481169187019190915268010000000000000000948590048116606087015280841660808701529390920490921660a084015260ff620100008304811660c085015260e08401919091526301000000909104166101008201526101200161021b565b34801561067657600080fd5b5060075461068f90640100000000900463ffffffff1681565b60405163ffffffff909116815260200161021b565b3480156106b057600080fd5b506102906106bf366004612cd2565b611ead565b3480156106d057600080fd5b506006546104b8906c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1681565b34801561070d57600080fd5b506007546104b8906c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1681565b34801561074a57600080fd5b50610290610759366004612cd2565b611f63565b34801561076a57600080fd5b50610290610779366004612ced565b611f77565b34801561078a57600080fd5b5061021160045481565b81516107d557806107d1576040517f6b81746e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b81516024111561082f5781516040517f51200dce0000000000000000000000000000000000000000000000000000000081526108269160249160040161ffff92831681529116602082015260400190565b60405180910390fd5b60008260238151811061084457610844613526565b6020910101517fff00000000000000000000000000000000000000000000000000000000000000167f010000000000000000000000000000000000000000000000000000000000000014905080801561089a5750815b156108d1576040517f6048aa6800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b801580156108dd575081155b15610914576040517f6b81746e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b60025473ffffffffffffffffffffffffffffffffffffffff16331461098c576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091166024820152604401610826565b6107d1828261208f565b61099e612277565b600880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790556040517f75884cdadc4a89e8b545db800057f06ec7f5338a08183c7ba515f2bfdd9fe1e190600090a1565b6109fd612277565b604051479060009073ffffffffffffffffffffffffffffffffffffffff84169083908381818185875af1925050503d8060008114610a57576040519150601f19603f3d011682016040523d82523d6000602084013e610a5c565b606091505b5050905080610ac7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f6661696c656420746f207769746864726177206e6174697665000000000000006044820152606401610826565b8273ffffffffffffffffffffffffffffffffffffffff167fc303ca808382409472acbbf899c316cf439f409f6584aae22df86dfa3c9ed50483604051610b0f91815260200190565b60405180910390a2505050565b60085460009060ff16610b8b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e66696775726564000000000000006044820152606401610826565b600854610100900460ff1615610bfd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c6564000000000000000000000000006044820152606401610826565b610c0d8363ffffffff16836122fa565b90505b92915050565b60085460009060ff16610c85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e66696775726564000000000000006044820152606401610826565b600854610100900460ff1615610cf7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c6564000000000000000000000000006044820152606401610826565b6000610d016123d0565b509050610d158363ffffffff163a83612537565b9150505b919050565b60085460009060ff16610d8d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e66696775726564000000000000006044820152606401610826565b600854610100900460ff1615610dff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c6564000000000000000000000000006044820152606401610826565b610c108263ffffffff163a6122fa565b610e17612277565b6006546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000916c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b158015610e9157600080fd5b505afa158015610ea5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ec99190612e09565b6006546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152602482018490529293506c010000000000000000000000009091049091169063a9059cbb90604401602060405180830381600087803b158015610f5157600080fd5b505af1158015610f65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f899190612d7a565b610fbf576040517f7c07fc4c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff167f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d58260405161100791815260200190565b60405180910390a25050565b60015473ffffffffffffffffffffffffffffffffffffffff163314611094576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610826565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60085460009060ff1661117f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e66696775726564000000000000006044820152606401610826565b600854610100900460ff16156111f1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c6564000000000000000000000000006044820152606401610826565b60006111fb6123d0565b50905061120f8463ffffffff168483612537565b949350505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590611257575060025473ffffffffffffffffffffffffffffffffffffffff163314155b156112db573361127c60005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff93841660048201529183166024830152919091166044820152606401610826565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fd1a6a14209a385a964d036e404cb5cfb71f4000cdb03c9366292430787261be6906020015b60405180910390a150565b600061139683838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509250610794915050565b60006113a187612629565b905060006113b58863ffffffff163a6122fa565b905080341015611421576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f66656520746f6f206c6f770000000000000000000000000000000000000000006044820152606401610826565b6008546301000000900460ff1663ffffffff8716111561149d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f6e756d576f72647320746f6f20686967680000000000000000000000000000006044820152606401610826565b6040805160c08101825260035481527f0000000000000000000000000000000000000000000000000000000000000000602082015261ffff89169181019190915260075460009190606082019063ffffffff166114fa868d6132c9565b61150491906132c9565b63ffffffff1681526020018863ffffffff16815260200187878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506002546040517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690639b1c385e906115aa9084906004016131b7565b602060405180830381600087803b1580156115c457600080fd5b505af11580156115d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115fc9190612e09565b6040805160608101825233815263ffffffff808d16602080840191825267ffffffffffffffff3a81168587019081526000888152600990935295909120935184549251955190911678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff9590931674010000000000000000000000000000000000000000027fffffffffffffffff00000000000000000000000000000000000000000000000090921673ffffffffffffffffffffffffffffffffffffffff91909116171792909216919091179055935050505095945050505050565b6116f2612277565b600880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690556040517fc0f961051f97b04c496472d11cb6170d844e4b2c9dfd3b602a4fa0139712d48490600090a1565b60085460ff166117b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e66696775726564000000000000006044820152606401610826565b600854610100900460ff1615611823576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c6564000000000000000000000000006044820152606401610826565b6006546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1633146118b4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f6f6e6c792063616c6c61626c652066726f6d204c494e4b0000000000000000006044820152606401610826565b60008080806118c585870187612fb6565b93509350935093506118d8816001610794565b60006118e385612629565b90506000806118f06123d0565b9150915060006119078863ffffffff163a85612537565b9050808b1015611973576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f66656520746f6f206c6f770000000000000000000000000000000000000000006044820152606401610826565b6008546301000000900460ff1663ffffffff871611156119ef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f6e756d576f72647320746f6f20686967680000000000000000000000000000006044820152606401610826565b6040805160c08101825260035481527f0000000000000000000000000000000000000000000000000000000000000000602082015261ffff89169181019190915260075460009190606082019063ffffffff16611a4c888d6132c9565b611a5691906132c9565b63ffffffff908116825289166020820152604090810188905260025490517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925060009173ffffffffffffffffffffffffffffffffffffffff90911690639b1c385e90611aca9085906004016131b7565b602060405180830381600087803b158015611ae457600080fd5b505af1158015611af8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b1c9190612e09565b905060405180606001604052808f73ffffffffffffffffffffffffffffffffffffffff1681526020018b63ffffffff1681526020013a67ffffffffffffffff168152506009600083815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160186101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550905050806004819055508315611c5d576005546040805183815260208101929092527f6ca648a381f22ead7e37773d934e64885dcf861fbfbb26c40354cbf0c4662d1a910160405180910390a15b5050505050505050505050505050565b611c75612277565b6007805463ffffffff8b81167fffffffffffffffffffffffffffffffffffffffff00000000ffffffff000000009092168217680100000000000000008c8316818102929092179094556008805460038c90557fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffff166201000060ff8e81169182027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff16929092176301000000928d16928302177fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179092556006805460058b90557fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff8c87167fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000090921682176401000000008c89169081029190911791909116968a169889029690961790915560408051968752602087019490945292850191909152606084018b9052608084015260a083015260c0820186905260e08201526101008101919091527f671302dfb4fd6e0b074fffc969890821e7a72a82802194d68cbb6a70a75934fb906101200160405180910390a1505050505050505050565b611e40612277565b600780547fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff1664010000000063ffffffff8416908102919091179091556040519081527f697b48b8b76cebb09a54ec4ff810e8a181c96f65395d51c744db09c115d1d5d09060200161134a565b611eb5612277565b6002546040517f405b84fa0000000000000000000000000000000000000000000000000000000081527f0000000000000000000000000000000000000000000000000000000000000000600482015273ffffffffffffffffffffffffffffffffffffffff83811660248301529091169063405b84fa90604401600060405180830381600087803b158015611f4857600080fd5b505af1158015611f5c573d6000803e3d6000fd5b5050505050565b611f6b612277565b611f7481612641565b50565b611f7f612277565b6006546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1615611fdf576040517f2d118a6e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006805473ffffffffffffffffffffffffffffffffffffffff8085166c010000000000000000000000009081026bffffffffffffffffffffffff938416179093556007805491851690930291161790556040517ffe255131c483b5b74cae4b315eb2c6cd06c1ae4b17b11a61ed4348dfd54e338590612083908490849073ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b60405180910390a15050565b60008281526009602081815260408084208151606081018352815473ffffffffffffffffffffffffffffffffffffffff808216835274010000000000000000000000000000000000000000820463ffffffff1683870152780100000000000000000000000000000000000000000000000090910467ffffffffffffffff1693820193909352878652939092529290558051909116612189576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e640000000000000000000000000000006044820152606401610826565b600080631fe543e360e01b85856040516024016121a7929190613214565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506000612221846020015163ffffffff16856000015184612737565b90508061226f57835160405173ffffffffffffffffffffffffffffffffffffffff9091169087907fc551b83c151f2d1c7eeb938ac59008e0409f1c1dc1e2f112449d4d79b458902290600090a35b505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146122f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610826565b565b600754600090819061231990640100000000900463ffffffff16612783565b60075463ffffffff68010000000000000000820481169161233b9116876132b1565b61234591906132b1565b61234f9085613474565b61235991906132b1565b600854909150819060009060649061237a9062010000900460ff16826132f1565b6123879060ff1684613474565b6123919190613316565b6006549091506000906123bb9068010000000000000000900463ffffffff1664e8d4a51000613474565b6123c590836132b1565b979650505050505050565b6000806000600660009054906101000a900463ffffffff16905060006007600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b15801561245457600080fd5b505afa158015612468573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061248c91906130e9565b50919650909250505063ffffffff8216158015906124b857506124af81426134b1565b8263ffffffff16105b925082156124c65760055493505b6000841215612531576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c6964204c494e4b20776569207072696365000000000000000000006044820152606401610826565b50509091565b600754600090819061255690640100000000900463ffffffff16612783565b60075463ffffffff6801000000000000000082048116916125789116886132b1565b61258291906132b1565b61258c9086613474565b61259691906132b1565b90506000836125ad83670de0b6b3a7640000613474565b6125b79190613316565b6008549091506000906064906125d69062010000900460ff16826132f1565b6125e39060ff1684613474565b6125ed9190613316565b60065490915060009061261390640100000000900463ffffffff1664e8d4a51000613474565b61261d90836132b1565b98975050505050505050565b6000612636603f8361332a565b610c109060016132c9565b73ffffffffffffffffffffffffffffffffffffffff81163314156126c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610826565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60005a61138881101561274957600080fd5b61138881039050846040820482031161276157600080fd5b50823b61276d57600080fd5b60008083516020850160008789f1949350505050565b60004661278f81612853565b15612833576000606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c06040518083038186803b1580156127dd57600080fd5b505afa1580156127f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128159190612edb565b5050505091505083608c61282991906132b1565b61120f9082613474565b61283c81612876565b1561284a57610d15836128b0565b50600092915050565b600061a4b1821480612867575062066eed82145b80610c1057505062066eee1490565b6000600a82148061288857506101a482145b80612895575062aa37dc82145b806128a1575061210582145b80610c1057505062014a331490565b60008073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff1663519b4bd36040518163ffffffff1660e01b815260040160206040518083038186803b15801561290d57600080fd5b505afa158015612921573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129459190612e09565b905060008061295481866134b1565b90506000612963826010613474565b61296e846004613474565b61297891906132b1565b9050600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff16630c18c1626040518163ffffffff1660e01b815260040160206040518083038186803b1580156129d657600080fd5b505afa1580156129ea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a0e9190612e09565b9050600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff1663f45e65d86040518163ffffffff1660e01b815260040160206040518083038186803b158015612a6c57600080fd5b505afa158015612a80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aa49190612e09565b9050600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015612b0257600080fd5b505afa158015612b16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b3a9190612e09565b90506000612b4982600a6133ae565b905060008184612b5987896132b1565b612b63908c613474565b612b6d9190613474565b612b779190613316565b9b9a5050505050505050505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610d1957600080fd5b60008083601f840112612bbc57600080fd5b50813567ffffffffffffffff811115612bd457600080fd5b602083019150836020828501011115612bec57600080fd5b9250929050565b600082601f830112612c0457600080fd5b813567ffffffffffffffff811115612c1e57612c1e613555565b612c4f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613262565b818152846020838601011115612c6457600080fd5b816020850160208301376000918101602001919091529392505050565b803561ffff81168114610d1957600080fd5b803563ffffffff81168114610d1957600080fd5b803560ff81168114610d1957600080fd5b805169ffffffffffffffffffff81168114610d1957600080fd5b600060208284031215612ce457600080fd5b610c0d82612b86565b60008060408385031215612d0057600080fd5b612d0983612b86565b9150612d1760208401612b86565b90509250929050565b60008060008060608587031215612d3657600080fd5b612d3f85612b86565b935060208501359250604085013567ffffffffffffffff811115612d6257600080fd5b612d6e87828801612baa565b95989497509550505050565b600060208284031215612d8c57600080fd5b8151612d9781613584565b9392505050565b60008060408385031215612db157600080fd5b823567ffffffffffffffff811115612dc857600080fd5b612dd485828601612bf3565b9250506020830135612de581613584565b809150509250929050565b600060208284031215612e0257600080fd5b5035919050565b600060208284031215612e1b57600080fd5b5051919050565b60008060408385031215612e3557600080fd5b8235915060208084013567ffffffffffffffff80821115612e5557600080fd5b818601915086601f830112612e6957600080fd5b813581811115612e7b57612e7b613555565b8060051b9150612e8c848301613262565b8181528481019084860184860187018b1015612ea757600080fd5b600095505b83861015612eca578035835260019590950194918601918601612eac565b508096505050505050509250929050565b60008060008060008060c08789031215612ef457600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b600060208284031215612f3757600080fd5b610c0d82612c93565b600080600080600060808688031215612f5857600080fd5b612f6186612c93565b9450612f6f60208701612c81565b9350612f7d60408701612c93565b9250606086013567ffffffffffffffff811115612f9957600080fd5b612fa588828901612baa565b969995985093965092949392505050565b60008060008060808587031215612fcc57600080fd5b612fd585612c93565b9350612fe360208601612c81565b9250612ff160408601612c93565b9150606085013567ffffffffffffffff81111561300d57600080fd5b61301987828801612bf3565b91505092959194509250565b6000806040838503121561303857600080fd5b61304183612c93565b946020939093013593505050565b60008060008060008060008060006101208a8c03121561306e57600080fd5b6130778a612c93565b985061308560208b01612c93565b975061309360408b01612ca7565b965060608a013595506130a860808b01612ca7565b94506130b660a08b01612c93565b935060c08a013592506130cb60e08b01612c93565b91506130da6101008b01612c93565b90509295985092959850929598565b600080600080600060a0868803121561310157600080fd5b61310a86612cb8565b945060208601519350604086015192506060860151915061312d60808701612cb8565b90509295509295909350565b6000815180845260005b8181101561315f57602081850181015186830182015201613143565b81811115613171576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610c0d6020830184613139565b60208152815160208201526020820151604082015261ffff60408301511660608201526000606083015163ffffffff80821660808501528060808601511660a0850152505060a083015160c08084015261120f60e0840182613139565b6000604082018483526020604081850152818551808452606086019150828701935060005b8181101561325557845183529383019391830191600101613239565b5090979650505050505050565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156132a9576132a9613555565b604052919050565b600082198211156132c4576132c46134c8565b500190565b600063ffffffff8083168185168083038211156132e8576132e86134c8565b01949350505050565b600060ff821660ff84168060ff0382111561330e5761330e6134c8565b019392505050565b600082613325576133256134f7565b500490565b600063ffffffff80841680613341576133416134f7565b92169190910492915050565b600181815b808511156133a657817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561338c5761338c6134c8565b8085161561339957918102915b93841c9390800290613352565b509250929050565b6000610c0d83836000826133c457506001610c10565b816133d157506000610c10565b81600181146133e757600281146133f15761340d565b6001915050610c10565b60ff841115613402576134026134c8565b50506001821b610c10565b5060208310610133831016604e8410600b8410161715613430575081810a610c10565b61343a838361334d565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561346c5761346c6134c8565b029392505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156134ac576134ac6134c8565b500290565b6000828210156134c3576134c36134c8565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b8015158114611f7457600080fdfea164736f6c6343000806000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_linkNativeFeed\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_coordinator\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_subId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"FailedToTransferLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"expectedMinimumLength\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"actualLength\",\"type\":\"uint16\"}],\"name\":\"IncorrectExtraArgsLength\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"premiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"max\",\"type\":\"uint8\"}],\"name\":\"InvalidPremiumPercentage\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LINKPaymentInRequestRandomWordsInNative\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkAlreadySet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"flatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeNativePPM\",\"type\":\"uint32\"}],\"name\":\"LinkDiscountTooHigh\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativePaymentInOnTokenTransfer\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"}],\"name\":\"OnlyOwnerOrCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SubscriptionIdMissing\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"wrapperGasOverhead\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"coordinatorGasOverhead\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"coordinatorNativePremiumPercentage\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"coordinatorLinkPremiumPercentage\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"maxNumWords\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"vrfCoordinator\",\"type\":\"address\"}],\"name\":\"CoordinatorSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"Disabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"Enabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"}],\"name\":\"FallbackWeiPerUnitLinkUsed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"size\",\"type\":\"uint32\"}],\"name\":\"FulfillmentTxSizeSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"NativeWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"WrapperFulfillmentFailed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"SUBSCRIPTION_ID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"}],\"name\":\"calculateRequestPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"}],\"name\":\"calculateRequestPriceNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"},{\"internalType\":\"bool\",\"name\":\"isLinkMode\",\"type\":\"bool\"}],\"name\":\"checkPaymentMode\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"disable\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"enable\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"_requestGasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateRequestPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"_requestGasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateRequestPriceNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"wrapperGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"coordinatorGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"wrapperNativePremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"wrapperLinkPremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"maxNumWords\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"link\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkNativeFeed\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"name\":\"requestRandomWordsInNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_callbacks\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"callbackAddress\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"requestGasPrice\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_configured\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_disabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fulfillmentTxSizeBytes\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_vrfCoordinator\",\"outputs\":[{\"internalType\":\"contractIVRFCoordinatorV2Plus\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_wrapperGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_coordinatorGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"_coordinatorNativePremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"_coordinatorLinkPremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"_keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"_maxNumWords\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"_stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"int256\",\"name\":\"_fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"internalType\":\"uint32\",\"name\":\"_fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_fulfillmentFlatFeeLinkDiscountPPM\",\"type\":\"uint32\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"name\":\"setCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"size\",\"type\":\"uint32\"}],\"name\":\"setFulfillmentTxSize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"}],\"name\":\"withdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60e06040526006805463ffffffff60401b191669024400000000000000001790553480156200002d57600080fd5b5060405162003c1c38038062003c1c8339810160408190526200005091620002a1565b813380600081620000a85760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000db57620000db81620001d9565b5050506001600160a01b038116620001065760405163d92e233d60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0392831617905584811660a052831660c0526000819003620001505760405163a81c0bef60e01b815260040160405180910390fd5b60025460405163dc311dd360e01b8152600481018390526001600160a01b039091169063dc311dd390602401600060405180830381865afa1580156200019a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620001c4919081019062000321565b505050608092909252506200044a9350505050565b336001600160a01b03821603620002335760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200009f565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200029c57600080fd5b919050565b60008060008060808587031215620002b857600080fd5b620002c38562000284565b9350620002d36020860162000284565b9250620002e36040860162000284565b6060959095015193969295505050565b80516001600160601b03811681146200029c57600080fd5b634e487b7160e01b600052604160045260246000fd5b600080600080600060a086880312156200033a57600080fd5b6200034586620002f3565b9450602062000356818801620002f3565b60408801519095506001600160401b0380821682146200037557600080fd5b8195506200038660608a0162000284565b945060808901519150808211156200039d57600080fd5b818901915089601f830112620003b257600080fd5b815181811115620003c757620003c76200030b565b8060051b604051601f19603f83011681018181108582111715620003ef57620003ef6200030b565b60405291825284820192508381018501918c8311156200040e57600080fd5b938501935b828510156200043757620004278562000284565b8452938501939285019262000413565b8096505050505050509295509295909350565b60805160a05160c051613778620004a4600039600081816102ff015261260601526000818161028b01528181610f1b01528181610fea0152611ac60152600081816101d90152818161171b0152611cb201526137786000f3fe6080604052600436106101c25760003560e01c806379ba5097116100f7578063a4c0ed3611610095578063cdd8d88511610064578063cdd8d88514610738578063f2fde38b14610776578063fc2a88c314610796578063fc2dbebc146107ac57600080fd5b8063a4c0ed36146105ba578063a608a1e1146105da578063bf17e5591461060d578063c3f909d41461062d57600080fd5b80638ea98117116100d15780638ea98117146105455780639cfc058e146105655780639eccacf614610578578063a3907d71146105a557600080fd5b806379ba5097146104e55780637fb5d19d146104fa5780638da5cb5b1461051a57600080fd5b80632f622e6b1161016457806348baa1c51161013e57806348baa1c5146103985780634b1609351461046357806351cff8d91461048357806357a8070a146104a357600080fd5b80632f622e6b146103385780633255c456146103585780634306d3541461037857600080fd5b80631c4695f4116101a05780631c4695f41461027c5780631fe543e3146102d05780632808e6c8146102f05780632f2770db1461032357600080fd5b8063030932bb146101c7578063181f5a771461020e57806318b6f4c81461025a575b600080fd5b3480156101d357600080fd5b506101fb7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b34801561021a57600080fd5b50604080518082018252601681527f5652465632506c75735772617070657220312e302e3000000000000000000000602082015290516102059190612e0f565b34801561026657600080fd5b5061027a610275366004612f3c565b6107cc565b005b34801561028857600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610205565b3480156102dc57600080fd5b5061027a6102eb366004612f8e565b610954565b3480156102fc57600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006102ab565b34801561032f57600080fd5b5061027a6109d1565b34801561034457600080fd5b5061027a610353366004613064565b610a44565b34801561036457600080fd5b506101fb610373366004613093565b610b6b565b34801561038457600080fd5b506101fb6103933660046130bd565b610c91565b3480156103a457600080fd5b506104226103b33660046130d8565b60076020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff81169074010000000000000000000000000000000000000000810463ffffffff16907801000000000000000000000000000000000000000000000000900467ffffffffffffffff1683565b6040805173ffffffffffffffffffffffffffffffffffffffff909416845263ffffffff909216602084015267ffffffffffffffff1690820152606001610205565b34801561046f57600080fd5b506101fb61047e3660046130bd565b610dc5565b34801561048f57600080fd5b5061027a61049e366004613064565b610ee2565b3480156104af57600080fd5b506002546104d59074010000000000000000000000000000000000000000900460ff1681565b6040519015158152602001610205565b3480156104f157600080fd5b5061027a6110e3565b34801561050657600080fd5b506101fb610515366004613093565b6111e0565b34801561052657600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166102ab565b34801561055157600080fd5b5061027a610560366004613064565b611313565b6101fb61057336600461314c565b61149e565b34801561058457600080fd5b506002546102ab9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105b157600080fd5b5061027a611949565b3480156105c657600080fd5b5061027a6105d53660046131c2565b6119a4565b3480156105e657600080fd5b506002546104d5907501000000000000000000000000000000000000000000900460ff1681565b34801561061957600080fd5b5061027a6106283660046130bd565b611f11565b34801561063957600080fd5b506005546006546003546002546040805194855263ffffffff80851660208701527001000000000000000000000000000000008504811691860191909152740100000000000000000000000000000000000000008404811660608601526401000000008404811660808601526c0100000000000000000000000084041660a085015260ff78010000000000000000000000000000000000000000000000008404811660c0860152790100000000000000000000000000000000000000000000000000909304831660e085015261010084019190915276010000000000000000000000000000000000000000000090041661012082015261014001610205565b34801561074457600080fd5b506006546107619068010000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610205565b34801561078257600080fd5b5061027a610791366004613064565b611f8a565b3480156107a257600080fd5b506101fb60045481565b3480156107b857600080fd5b5061027a6107c736600461322d565b611f9e565b8151600003610810578061080c576040517f6b81746e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b81516024111561086a5781516040517f51200dce0000000000000000000000000000000000000000000000000000000081526108619160249160040161ffff92831681529116602082015260400190565b60405180910390fd5b60008260238151811061087f5761087f6132d9565b6020910101517fff00000000000000000000000000000000000000000000000000000000000000167f01000000000000000000000000000000000000000000000000000000000000001490508080156108d55750815b1561090c576040517f6048aa6800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80158015610918575081155b1561094f576040517f6b81746e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b60025473ffffffffffffffffffffffffffffffffffffffff1633146109c7576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091166024820152604401610861565b61080c828261226f565b6109d9612452565b600280547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1675010000000000000000000000000000000000000000001790556040517f75884cdadc4a89e8b545db800057f06ec7f5338a08183c7ba515f2bfdd9fe1e190600090a1565b610a4c612452565b604051479060009073ffffffffffffffffffffffffffffffffffffffff84169083908381818185875af1925050503d8060008114610aa6576040519150601f19603f3d011682016040523d82523d6000602084013e610aab565b606091505b5050905080610b16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f6661696c656420746f207769746864726177206e6174697665000000000000006044820152606401610861565b8273ffffffffffffffffffffffffffffffffffffffff167fc303ca808382409472acbbf899c316cf439f409f6584aae22df86dfa3c9ed50483604051610b5e91815260200190565b60405180910390a2505050565b60025460009074010000000000000000000000000000000000000000900460ff16610bf2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e66696775726564000000000000006044820152606401610861565b6002547501000000000000000000000000000000000000000000900460ff1615610c78576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c6564000000000000000000000000006044820152606401610861565b610c888363ffffffff16836124d5565b90505b92915050565b60025460009074010000000000000000000000000000000000000000900460ff16610d18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e66696775726564000000000000006044820152606401610861565b6002547501000000000000000000000000000000000000000000900460ff1615610d9e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c6564000000000000000000000000006044820152606401610861565b6000610da86125e8565b509050610dbc8363ffffffff163a8361273e565b9150505b919050565b60025460009074010000000000000000000000000000000000000000900460ff16610e4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e66696775726564000000000000006044820152606401610861565b6002547501000000000000000000000000000000000000000000900460ff1615610ed2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c6564000000000000000000000000006044820152606401610861565b610c8b8263ffffffff163a6124d5565b610eea612452565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610f77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f9b9190613308565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018390529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af1158015611035573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110599190613321565b61108f576040517f7c07fc4c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff167f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5826040516110d791815260200190565b60405180910390a25050565b60015473ffffffffffffffffffffffffffffffffffffffff163314611164576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610861565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60025460009074010000000000000000000000000000000000000000900460ff16611267576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e66696775726564000000000000006044820152606401610861565b6002547501000000000000000000000000000000000000000000900460ff16156112ed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c6564000000000000000000000000006044820152606401610861565b60006112f76125e8565b50905061130b8463ffffffff16848361273e565b949350505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590611353575060025473ffffffffffffffffffffffffffffffffffffffff163314155b156113d7573361137860005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff93841660048201529183166024830152919091166044820152606401610861565b73ffffffffffffffffffffffffffffffffffffffff8116611424576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fd1a6a14209a385a964d036e404cb5cfb71f4000cdb03c9366292430787261be6906020015b60405180910390a150565b60025460009074010000000000000000000000000000000000000000900460ff16611525576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e66696775726564000000000000006044820152606401610861565b6002547501000000000000000000000000000000000000000000900460ff16156115ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c6564000000000000000000000000006044820152606401610861565b6115ea83838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525092506107cc915050565b60006115f58761289a565b905060006116098863ffffffff163a6124d5565b905080341015611675576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f66656520746f6f206c6f770000000000000000000000000000000000000000006044820152606401610861565b600254760100000000000000000000000000000000000000000000900460ff1663ffffffff87161115611704576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f6e756d576f72647320746f6f20686967680000000000000000000000000000006044820152606401610861565b60006040518060c0016040528060035481526020017f000000000000000000000000000000000000000000000000000000000000000081526020018961ffff168152602001600660049054906101000a900463ffffffff16858c6117689190613374565b6117729190613374565b63ffffffff1681526020018863ffffffff16815260200187878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506002546040517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690639b1c385e90611818908490600401613398565b6020604051808303816000875af1158015611837573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185b9190613308565b6040805160608101825233815263ffffffff808d16602080840191825267ffffffffffffffff3a81168587019081526000888152600790935295909120935184549251955190911678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff9590931674010000000000000000000000000000000000000000027fffffffffffffffff00000000000000000000000000000000000000000000000090921673ffffffffffffffffffffffffffffffffffffffff91909116171792909216919091179055935050505095945050505050565b611951612452565b600280547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1690556040517fc0f961051f97b04c496472d11cb6170d844e4b2c9dfd3b602a4fa0139712d48490600090a1565b60025474010000000000000000000000000000000000000000900460ff16611a28576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e66696775726564000000000000006044820152606401610861565b6002547501000000000000000000000000000000000000000000900460ff1615611aae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c6564000000000000000000000000006044820152606401610861565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611b4d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f6f6e6c792063616c6c61626c652066726f6d204c494e4b0000000000000000006044820152606401610861565b6000808080611b5e858701876133f5565b9350935093509350611b718160016107cc565b6000611b7c8561289a565b9050600080611b896125e8565b915091506000611ba08863ffffffff163a8561273e565b9050808b1015611c0c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f66656520746f6f206c6f770000000000000000000000000000000000000000006044820152606401610861565b600254760100000000000000000000000000000000000000000000900460ff1663ffffffff87161115611c9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f6e756d576f72647320746f6f20686967680000000000000000000000000000006044820152606401610861565b60006040518060c0016040528060035481526020017f000000000000000000000000000000000000000000000000000000000000000081526020018961ffff168152602001600660049054906101000a900463ffffffff16878c611cff9190613374565b611d099190613374565b63ffffffff908116825289166020820152604090810188905260025490517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925060009173ffffffffffffffffffffffffffffffffffffffff90911690639b1c385e90611d7d908590600401613398565b6020604051808303816000875af1158015611d9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dc09190613308565b905060405180606001604052808f73ffffffffffffffffffffffffffffffffffffffff1681526020018b63ffffffff1681526020013a67ffffffffffffffff168152506007600083815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160186101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550905050806004819055508315611f01576005546040805183815260208101929092527f6ca648a381f22ead7e37773d934e64885dcf861fbfbb26c40354cbf0c4662d1a910160405180910390a15b5050505050505050505050505050565b611f19612452565b600680547fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff166801000000000000000063ffffffff8416908102919091179091556040519081527f697b48b8b76cebb09a54ec4ff810e8a181c96f65395d51c744db09c115d1d5d090602001611493565b611f92612452565b611f9b816128b2565b50565b611fa6612452565b8163ffffffff168163ffffffff161115611ffc576040517f2780dcb200000000000000000000000000000000000000000000000000000000815263ffffffff808316600483015283166024820152604401610861565b609b60ff89161115612046576040517f3acc511a00000000000000000000000000000000000000000000000000000000815260ff89166004820152609b6024820152604401610861565b609b60ff88161115612090576040517f3acc511a00000000000000000000000000000000000000000000000000000000815260ff88166004820152609b6024820152604401610861565b89600660046101000a81548163ffffffff021916908363ffffffff160217905550886006600c6101000a81548163ffffffff021916908363ffffffff16021790555087600660186101000a81548160ff021916908360ff16021790555086600660196101000a81548160ff021916908360ff1602179055508560038190555084600260166101000a81548160ff021916908360ff1602179055506001600260146101000a81548160ff02191690831515021790555083600660006101000a81548163ffffffff021916908363ffffffff1602179055508260058190555081600660106101000a81548163ffffffff021916908363ffffffff16021790555080600660146101000a81548163ffffffff021916908363ffffffff1602179055507fb18fd84519589131d50ae195b0aea1b042c3c0b25a53bb894d9d81c78980c20f8a8a8a8a8a8a8a8a8a600660149054906101000a900463ffffffff1660405161225b9a9998979695949392919063ffffffff9a8b168152988a1660208a015260ff97881660408a0152958716606089015260808801949094529190941660a086015292851660c085015260e08401929092529083166101008301529091166101208201526101400190565b60405180910390a150505050505050505050565b60008281526007602081815260408084208151606081018352815473ffffffffffffffffffffffffffffffffffffffff808216835274010000000000000000000000000000000000000000820463ffffffff1683870152780100000000000000000000000000000000000000000000000090910467ffffffffffffffff16938201939093528786529390925292905580519091811661236a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e640000000000000000000000000000006044820152606401610861565b600080631fe543e360e01b8686604051602401612388929190613464565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006123fe856020015163ffffffff1685846129a7565b9050806124495760405173ffffffffffffffffffffffffffffffffffffffff85169088907fc551b83c151f2d1c7eeb938ac59008e0409f1c1dc1e2f112449d4d79b458902290600090a35b50505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146124d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610861565b565b60065460009081906124f590640100000000900463ffffffff16846134b2565b6006549091506000906125199068010000000000000000900463ffffffff166129f3565b60065461253c906c01000000000000000000000000900463ffffffff16876134c9565b61254690866134b2565b61255091906134c9565b60065490915060009061258290700100000000000000000000000000000000900463ffffffff1664e8d4a510006134b2565b6006546064906125b1907801000000000000000000000000000000000000000000000000900460ff16826134dc565b6125be9060ff16856134b2565b6125c89190613524565b6125d291906134c9565b90506125de81846134c9565b9695505050505050565b6000806000600660009054906101000a900463ffffffff16905060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801561266f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126939190613552565b50919650909250505063ffffffff8216158015906126bf57506126b681426135a2565b8263ffffffff16105b925082156126cd5760055493505b6000841215612738576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c6964204c494e4b20776569207072696365000000000000000000006044820152606401610861565b50509091565b600654600090819061275e90640100000000900463ffffffff16856134b2565b6006549091506000906127829068010000000000000000900463ffffffff166129f3565b6006546127a5906c01000000000000000000000000900463ffffffff16886134c9565b6127af90876134b2565b6127b991906134c9565b6006549091506000906128009063ffffffff7401000000000000000000000000000000000000000082048116917001000000000000000000000000000000009004166135b5565b6128159063ffffffff1664e8d4a510006134b2565b60065460649061284590790100000000000000000000000000000000000000000000000000900460ff16826134dc565b6128529060ff16856134b2565b61285c9190613524565b61286691906134c9565b90508461287382856134c9565b61288590670de0b6b3a76400006134b2565b61288f9190613524565b979650505050505050565b60006128a7603f836135d2565b610c8b906001613374565b3373ffffffffffffffffffffffffffffffffffffffff821603612931576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610861565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60005a6113888110156129b957600080fd5b6113888103905084604082048203116129d157600080fd5b50823b6129dd57600080fd5b60008083516020850160008789f1949350505050565b6000466129ff81612ab4565b15612a94576000606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c060405180830381865afa158015612a52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a7691906135f5565b5050505091505083608c612a8a91906134c9565b61130b90826134b2565b612a9d81612ad7565b15612aab57610dbc83612b11565b50600092915050565b600061a4b1821480612ac8575062066eed82145b80610c8b57505062066eee1490565b6000600a821480612ae957506101a482145b80612af6575062aa37dc82145b80612b02575061210582145b80610c8b57505062014a331490565b60008073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff1663519b4bd36040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b979190613308565b9050600080612ba681866135a2565b90506000612bb58260106134b2565b612bc08460046134b2565b612bca91906134c9565b9050600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff16630c18c1626040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c519190613308565b9050600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff1663f45e65d86040518163ffffffff1660e01b8152600401602060405180830381865afa158015612cb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cd89190613308565b9050600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d5f9190613308565b90506000612d6e82600a61375f565b905060008184612d7e87896134c9565b612d88908c6134b2565b612d9291906134b2565b612d9c9190613524565b9b9a5050505050505050505050565b6000815180845260005b81811015612dd157602081850181015186830182015201612db5565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000610c886020830184612dab565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715612e9857612e98612e22565b604052919050565b600082601f830112612eb157600080fd5b813567ffffffffffffffff811115612ecb57612ecb612e22565b612efc60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601612e51565b818152846020838601011115612f1157600080fd5b816020850160208301376000918101602001919091529392505050565b8015158114611f9b57600080fd5b60008060408385031215612f4f57600080fd5b823567ffffffffffffffff811115612f6657600080fd5b612f7285828601612ea0565b9250506020830135612f8381612f2e565b809150509250929050565b60008060408385031215612fa157600080fd5b8235915060208084013567ffffffffffffffff80821115612fc157600080fd5b818601915086601f830112612fd557600080fd5b813581811115612fe757612fe7612e22565b8060051b9150612ff8848301612e51565b818152918301840191848101908984111561301257600080fd5b938501935b8385101561303057843582529385019390850190613017565b8096505050505050509250929050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610dc057600080fd5b60006020828403121561307657600080fd5b610c8882613040565b803563ffffffff81168114610dc057600080fd5b600080604083850312156130a657600080fd5b6130af8361307f565b946020939093013593505050565b6000602082840312156130cf57600080fd5b610c888261307f565b6000602082840312156130ea57600080fd5b5035919050565b803561ffff81168114610dc057600080fd5b60008083601f84011261311557600080fd5b50813567ffffffffffffffff81111561312d57600080fd5b60208301915083602082850101111561314557600080fd5b9250929050565b60008060008060006080868803121561316457600080fd5b61316d8661307f565b945061317b602087016130f1565b93506131896040870161307f565b9250606086013567ffffffffffffffff8111156131a557600080fd5b6131b188828901613103565b969995985093965092949392505050565b600080600080606085870312156131d857600080fd5b6131e185613040565b935060208501359250604085013567ffffffffffffffff81111561320457600080fd5b61321087828801613103565b95989497509550505050565b803560ff81168114610dc057600080fd5b6000806000806000806000806000806101408b8d03121561324d57600080fd5b6132568b61307f565b995061326460208c0161307f565b985061327260408c0161321c565b975061328060608c0161321c565b965060808b0135955061329560a08c0161321c565b94506132a360c08c0161307f565b935060e08b013592506132b96101008c0161307f565b91506132c86101208c0161307f565b90509295989b9194979a5092959850565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561331a57600080fd5b5051919050565b60006020828403121561333357600080fd5b815161333e81612f2e565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b63ffffffff81811683821601908082111561339157613391613345565b5092915050565b60208152815160208201526020820151604082015261ffff60408301511660608201526000606083015163ffffffff80821660808501528060808601511660a0850152505060a083015160c08084015261130b60e0840182612dab565b6000806000806080858703121561340b57600080fd5b6134148561307f565b9350613422602086016130f1565b92506134306040860161307f565b9150606085013567ffffffffffffffff81111561344c57600080fd5b61345887828801612ea0565b91505092959194509250565b6000604082018483526020604081850152818551808452606086019150828701935060005b818110156134a557845183529383019391830191600101613489565b5090979650505050505050565b8082028115828204841417610c8b57610c8b613345565b80820180821115610c8b57610c8b613345565b60ff8181168382160190811115610c8b57610c8b613345565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082613533576135336134f5565b500490565b805169ffffffffffffffffffff81168114610dc057600080fd5b600080600080600060a0868803121561356a57600080fd5b61357386613538565b945060208601519350604086015192506060860151915061359660808701613538565b90509295509295909350565b81810381811115610c8b57610c8b613345565b63ffffffff82811682821603908082111561339157613391613345565b600063ffffffff808416806135e9576135e96134f5565b92169190910492915050565b60008060008060008060c0878903121561360e57600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b600181815b8085111561369857817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561367e5761367e613345565b8085161561368b57918102915b93841c9390800290613644565b509250929050565b6000826136af57506001610c8b565b816136bc57506000610c8b565b81600181146136d257600281146136dc576136f8565b6001915050610c8b565b60ff8411156136ed576136ed613345565b50506001821b610c8b565b5060208310610133831016604e8410600b841016171561371b575081810a610c8b565b613725838361363f565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561375757613757613345565b029392505050565b6000610c8883836136a056fea164736f6c6343000813000a", } var VRFV2PlusWrapperABI = VRFV2PlusWrapperMetaData.ABI var VRFV2PlusWrapperBin = VRFV2PlusWrapperMetaData.Bin -func DeployVRFV2PlusWrapper(auth *bind.TransactOpts, backend bind.ContractBackend, _link common.Address, _linkNativeFeed common.Address, _coordinator common.Address) (common.Address, *types.Transaction, *VRFV2PlusWrapper, error) { +func DeployVRFV2PlusWrapper(auth *bind.TransactOpts, backend bind.ContractBackend, _link common.Address, _linkNativeFeed common.Address, _coordinator common.Address, _subId *big.Int) (common.Address, *types.Transaction, *VRFV2PlusWrapper, error) { parsed, err := VRFV2PlusWrapperMetaData.GetAbi() if err != nil { return common.Address{}, nil, nil, err @@ -48,7 +48,7 @@ func DeployVRFV2PlusWrapper(auth *bind.TransactOpts, backend bind.ContractBacken return common.Address{}, nil, nil, errors.New("GetABI returned nil") } - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(VRFV2PlusWrapperBin), backend, _link, _linkNativeFeed, _coordinator) + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(VRFV2PlusWrapperBin), backend, _link, _linkNativeFeed, _coordinator, _subId) if err != nil { return common.Address{}, nil, nil, err } @@ -314,13 +314,14 @@ func (_VRFV2PlusWrapper *VRFV2PlusWrapperCaller) GetConfig(opts *bind.CallOpts) outstruct.FallbackWeiPerUnitLink = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) outstruct.StalenessSeconds = *abi.ConvertType(out[1], new(uint32)).(*uint32) - outstruct.FulfillmentFlatFeeLinkPPM = *abi.ConvertType(out[2], new(uint32)).(*uint32) - outstruct.FulfillmentFlatFeeNativePPM = *abi.ConvertType(out[3], new(uint32)).(*uint32) + outstruct.FulfillmentFlatFeeNativePPM = *abi.ConvertType(out[2], new(uint32)).(*uint32) + outstruct.FulfillmentFlatFeeLinkDiscountPPM = *abi.ConvertType(out[3], new(uint32)).(*uint32) outstruct.WrapperGasOverhead = *abi.ConvertType(out[4], new(uint32)).(*uint32) outstruct.CoordinatorGasOverhead = *abi.ConvertType(out[5], new(uint32)).(*uint32) - outstruct.WrapperPremiumPercentage = *abi.ConvertType(out[6], new(uint8)).(*uint8) - outstruct.KeyHash = *abi.ConvertType(out[7], new([32]byte)).(*[32]byte) - outstruct.MaxNumWords = *abi.ConvertType(out[8], new(uint8)).(*uint8) + outstruct.WrapperNativePremiumPercentage = *abi.ConvertType(out[6], new(uint8)).(*uint8) + outstruct.WrapperLinkPremiumPercentage = *abi.ConvertType(out[7], new(uint8)).(*uint8) + outstruct.KeyHash = *abi.ConvertType(out[8], new([32]byte)).(*[32]byte) + outstruct.MaxNumWords = *abi.ConvertType(out[9], new(uint8)).(*uint8) return *outstruct, err @@ -360,6 +361,50 @@ func (_VRFV2PlusWrapper *VRFV2PlusWrapperCallerSession) LastRequestId() (*big.In return _VRFV2PlusWrapper.Contract.LastRequestId(&_VRFV2PlusWrapper.CallOpts) } +func (_VRFV2PlusWrapper *VRFV2PlusWrapperCaller) Link(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VRFV2PlusWrapper.contract.Call(opts, &out, "link") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_VRFV2PlusWrapper *VRFV2PlusWrapperSession) Link() (common.Address, error) { + return _VRFV2PlusWrapper.Contract.Link(&_VRFV2PlusWrapper.CallOpts) +} + +func (_VRFV2PlusWrapper *VRFV2PlusWrapperCallerSession) Link() (common.Address, error) { + return _VRFV2PlusWrapper.Contract.Link(&_VRFV2PlusWrapper.CallOpts) +} + +func (_VRFV2PlusWrapper *VRFV2PlusWrapperCaller) LinkNativeFeed(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VRFV2PlusWrapper.contract.Call(opts, &out, "linkNativeFeed") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_VRFV2PlusWrapper *VRFV2PlusWrapperSession) LinkNativeFeed() (common.Address, error) { + return _VRFV2PlusWrapper.Contract.LinkNativeFeed(&_VRFV2PlusWrapper.CallOpts) +} + +func (_VRFV2PlusWrapper *VRFV2PlusWrapperCallerSession) LinkNativeFeed() (common.Address, error) { + return _VRFV2PlusWrapper.Contract.LinkNativeFeed(&_VRFV2PlusWrapper.CallOpts) +} + func (_VRFV2PlusWrapper *VRFV2PlusWrapperCaller) Owner(opts *bind.CallOpts) (common.Address, error) { var out []interface{} err := _VRFV2PlusWrapper.contract.Call(opts, &out, "owner") @@ -479,50 +524,6 @@ func (_VRFV2PlusWrapper *VRFV2PlusWrapperCallerSession) SFulfillmentTxSizeBytes( return _VRFV2PlusWrapper.Contract.SFulfillmentTxSizeBytes(&_VRFV2PlusWrapper.CallOpts) } -func (_VRFV2PlusWrapper *VRFV2PlusWrapperCaller) SLink(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _VRFV2PlusWrapper.contract.Call(opts, &out, "s_link") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -func (_VRFV2PlusWrapper *VRFV2PlusWrapperSession) SLink() (common.Address, error) { - return _VRFV2PlusWrapper.Contract.SLink(&_VRFV2PlusWrapper.CallOpts) -} - -func (_VRFV2PlusWrapper *VRFV2PlusWrapperCallerSession) SLink() (common.Address, error) { - return _VRFV2PlusWrapper.Contract.SLink(&_VRFV2PlusWrapper.CallOpts) -} - -func (_VRFV2PlusWrapper *VRFV2PlusWrapperCaller) SLinkNativeFeed(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _VRFV2PlusWrapper.contract.Call(opts, &out, "s_linkNativeFeed") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -func (_VRFV2PlusWrapper *VRFV2PlusWrapperSession) SLinkNativeFeed() (common.Address, error) { - return _VRFV2PlusWrapper.Contract.SLinkNativeFeed(&_VRFV2PlusWrapper.CallOpts) -} - -func (_VRFV2PlusWrapper *VRFV2PlusWrapperCallerSession) SLinkNativeFeed() (common.Address, error) { - return _VRFV2PlusWrapper.Contract.SLinkNativeFeed(&_VRFV2PlusWrapper.CallOpts) -} - func (_VRFV2PlusWrapper *VRFV2PlusWrapperCaller) SVrfCoordinator(opts *bind.CallOpts) (common.Address, error) { var out []interface{} err := _VRFV2PlusWrapper.contract.Call(opts, &out, "s_vrfCoordinator") @@ -603,18 +604,6 @@ func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactorSession) Enable() (*types.Tra return _VRFV2PlusWrapper.Contract.Enable(&_VRFV2PlusWrapper.TransactOpts) } -func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactor) Migrate(opts *bind.TransactOpts, newCoordinator common.Address) (*types.Transaction, error) { - return _VRFV2PlusWrapper.contract.Transact(opts, "migrate", newCoordinator) -} - -func (_VRFV2PlusWrapper *VRFV2PlusWrapperSession) Migrate(newCoordinator common.Address) (*types.Transaction, error) { - return _VRFV2PlusWrapper.Contract.Migrate(&_VRFV2PlusWrapper.TransactOpts, newCoordinator) -} - -func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactorSession) Migrate(newCoordinator common.Address) (*types.Transaction, error) { - return _VRFV2PlusWrapper.Contract.Migrate(&_VRFV2PlusWrapper.TransactOpts, newCoordinator) -} - func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactor) OnTokenTransfer(opts *bind.TransactOpts, _sender common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) { return _VRFV2PlusWrapper.contract.Transact(opts, "onTokenTransfer", _sender, _amount, _data) } @@ -651,16 +640,16 @@ func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactorSession) RequestRandomWordsIn return _VRFV2PlusWrapper.Contract.RequestRandomWordsInNative(&_VRFV2PlusWrapper.TransactOpts, _callbackGasLimit, _requestConfirmations, _numWords, extraArgs) } -func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactor) SetConfig(opts *bind.TransactOpts, _wrapperGasOverhead uint32, _coordinatorGasOverhead uint32, _wrapperPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8, _stalenessSeconds uint32, _fallbackWeiPerUnitLink *big.Int, _fulfillmentFlatFeeLinkPPM uint32, _fulfillmentFlatFeeNativePPM uint32) (*types.Transaction, error) { - return _VRFV2PlusWrapper.contract.Transact(opts, "setConfig", _wrapperGasOverhead, _coordinatorGasOverhead, _wrapperPremiumPercentage, _keyHash, _maxNumWords, _stalenessSeconds, _fallbackWeiPerUnitLink, _fulfillmentFlatFeeLinkPPM, _fulfillmentFlatFeeNativePPM) +func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactor) SetConfig(opts *bind.TransactOpts, _wrapperGasOverhead uint32, _coordinatorGasOverhead uint32, _coordinatorNativePremiumPercentage uint8, _coordinatorLinkPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8, _stalenessSeconds uint32, _fallbackWeiPerUnitLink *big.Int, _fulfillmentFlatFeeNativePPM uint32, _fulfillmentFlatFeeLinkDiscountPPM uint32) (*types.Transaction, error) { + return _VRFV2PlusWrapper.contract.Transact(opts, "setConfig", _wrapperGasOverhead, _coordinatorGasOverhead, _coordinatorNativePremiumPercentage, _coordinatorLinkPremiumPercentage, _keyHash, _maxNumWords, _stalenessSeconds, _fallbackWeiPerUnitLink, _fulfillmentFlatFeeNativePPM, _fulfillmentFlatFeeLinkDiscountPPM) } -func (_VRFV2PlusWrapper *VRFV2PlusWrapperSession) SetConfig(_wrapperGasOverhead uint32, _coordinatorGasOverhead uint32, _wrapperPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8, _stalenessSeconds uint32, _fallbackWeiPerUnitLink *big.Int, _fulfillmentFlatFeeLinkPPM uint32, _fulfillmentFlatFeeNativePPM uint32) (*types.Transaction, error) { - return _VRFV2PlusWrapper.Contract.SetConfig(&_VRFV2PlusWrapper.TransactOpts, _wrapperGasOverhead, _coordinatorGasOverhead, _wrapperPremiumPercentage, _keyHash, _maxNumWords, _stalenessSeconds, _fallbackWeiPerUnitLink, _fulfillmentFlatFeeLinkPPM, _fulfillmentFlatFeeNativePPM) +func (_VRFV2PlusWrapper *VRFV2PlusWrapperSession) SetConfig(_wrapperGasOverhead uint32, _coordinatorGasOverhead uint32, _coordinatorNativePremiumPercentage uint8, _coordinatorLinkPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8, _stalenessSeconds uint32, _fallbackWeiPerUnitLink *big.Int, _fulfillmentFlatFeeNativePPM uint32, _fulfillmentFlatFeeLinkDiscountPPM uint32) (*types.Transaction, error) { + return _VRFV2PlusWrapper.Contract.SetConfig(&_VRFV2PlusWrapper.TransactOpts, _wrapperGasOverhead, _coordinatorGasOverhead, _coordinatorNativePremiumPercentage, _coordinatorLinkPremiumPercentage, _keyHash, _maxNumWords, _stalenessSeconds, _fallbackWeiPerUnitLink, _fulfillmentFlatFeeNativePPM, _fulfillmentFlatFeeLinkDiscountPPM) } -func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactorSession) SetConfig(_wrapperGasOverhead uint32, _coordinatorGasOverhead uint32, _wrapperPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8, _stalenessSeconds uint32, _fallbackWeiPerUnitLink *big.Int, _fulfillmentFlatFeeLinkPPM uint32, _fulfillmentFlatFeeNativePPM uint32) (*types.Transaction, error) { - return _VRFV2PlusWrapper.Contract.SetConfig(&_VRFV2PlusWrapper.TransactOpts, _wrapperGasOverhead, _coordinatorGasOverhead, _wrapperPremiumPercentage, _keyHash, _maxNumWords, _stalenessSeconds, _fallbackWeiPerUnitLink, _fulfillmentFlatFeeLinkPPM, _fulfillmentFlatFeeNativePPM) +func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactorSession) SetConfig(_wrapperGasOverhead uint32, _coordinatorGasOverhead uint32, _coordinatorNativePremiumPercentage uint8, _coordinatorLinkPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8, _stalenessSeconds uint32, _fallbackWeiPerUnitLink *big.Int, _fulfillmentFlatFeeNativePPM uint32, _fulfillmentFlatFeeLinkDiscountPPM uint32) (*types.Transaction, error) { + return _VRFV2PlusWrapper.Contract.SetConfig(&_VRFV2PlusWrapper.TransactOpts, _wrapperGasOverhead, _coordinatorGasOverhead, _coordinatorNativePremiumPercentage, _coordinatorLinkPremiumPercentage, _keyHash, _maxNumWords, _stalenessSeconds, _fallbackWeiPerUnitLink, _fulfillmentFlatFeeNativePPM, _fulfillmentFlatFeeLinkDiscountPPM) } func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactor) SetCoordinator(opts *bind.TransactOpts, _vrfCoordinator common.Address) (*types.Transaction, error) { @@ -687,18 +676,6 @@ func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactorSession) SetFulfillmentTxSize return _VRFV2PlusWrapper.Contract.SetFulfillmentTxSize(&_VRFV2PlusWrapper.TransactOpts, size) } -func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactor) SetLinkAndLinkNativeFeed(opts *bind.TransactOpts, link common.Address, linkNativeFeed common.Address) (*types.Transaction, error) { - return _VRFV2PlusWrapper.contract.Transact(opts, "setLinkAndLinkNativeFeed", link, linkNativeFeed) -} - -func (_VRFV2PlusWrapper *VRFV2PlusWrapperSession) SetLinkAndLinkNativeFeed(link common.Address, linkNativeFeed common.Address) (*types.Transaction, error) { - return _VRFV2PlusWrapper.Contract.SetLinkAndLinkNativeFeed(&_VRFV2PlusWrapper.TransactOpts, link, linkNativeFeed) -} - -func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactorSession) SetLinkAndLinkNativeFeed(link common.Address, linkNativeFeed common.Address) (*types.Transaction, error) { - return _VRFV2PlusWrapper.Contract.SetLinkAndLinkNativeFeed(&_VRFV2PlusWrapper.TransactOpts, link, linkNativeFeed) -} - func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { return _VRFV2PlusWrapper.contract.Transact(opts, "transferOwnership", to) } @@ -796,16 +773,17 @@ func (it *VRFV2PlusWrapperConfigSetIterator) Close() error { } type VRFV2PlusWrapperConfigSet struct { - WrapperGasOverhead uint32 - CoordinatorGasOverhead uint32 - WrapperPremiumPercentage uint8 - KeyHash [32]byte - MaxNumWords uint8 - StalenessSeconds uint32 - FallbackWeiPerUnitLink *big.Int - FulfillmentFlatFeeLinkPPM uint32 - FulfillmentFlatFeeNativePPM uint32 - Raw types.Log + WrapperGasOverhead uint32 + CoordinatorGasOverhead uint32 + CoordinatorNativePremiumPercentage uint8 + CoordinatorLinkPremiumPercentage uint8 + KeyHash [32]byte + MaxNumWords uint8 + StalenessSeconds uint32 + FallbackWeiPerUnitLink *big.Int + FulfillmentFlatFeeNativePPM uint32 + FulfillmentFlatFeeLinkDiscountPPM uint32 + Raw types.Log } func (_VRFV2PlusWrapper *VRFV2PlusWrapperFilterer) FilterConfigSet(opts *bind.FilterOpts) (*VRFV2PlusWrapperConfigSetIterator, error) { @@ -1444,124 +1422,6 @@ func (_VRFV2PlusWrapper *VRFV2PlusWrapperFilterer) ParseFulfillmentTxSizeSet(log return event, nil } -type VRFV2PlusWrapperLinkAndLinkNativeFeedSetIterator struct { - Event *VRFV2PlusWrapperLinkAndLinkNativeFeedSet - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFV2PlusWrapperLinkAndLinkNativeFeedSetIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFV2PlusWrapperLinkAndLinkNativeFeedSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - - select { - case log := <-it.logs: - it.Event = new(VRFV2PlusWrapperLinkAndLinkNativeFeedSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -func (it *VRFV2PlusWrapperLinkAndLinkNativeFeedSetIterator) Error() error { - return it.fail -} - -func (it *VRFV2PlusWrapperLinkAndLinkNativeFeedSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFV2PlusWrapperLinkAndLinkNativeFeedSet struct { - Link common.Address - LinkNativeFeed common.Address - Raw types.Log -} - -func (_VRFV2PlusWrapper *VRFV2PlusWrapperFilterer) FilterLinkAndLinkNativeFeedSet(opts *bind.FilterOpts) (*VRFV2PlusWrapperLinkAndLinkNativeFeedSetIterator, error) { - - logs, sub, err := _VRFV2PlusWrapper.contract.FilterLogs(opts, "LinkAndLinkNativeFeedSet") - if err != nil { - return nil, err - } - return &VRFV2PlusWrapperLinkAndLinkNativeFeedSetIterator{contract: _VRFV2PlusWrapper.contract, event: "LinkAndLinkNativeFeedSet", logs: logs, sub: sub}, nil -} - -func (_VRFV2PlusWrapper *VRFV2PlusWrapperFilterer) WatchLinkAndLinkNativeFeedSet(opts *bind.WatchOpts, sink chan<- *VRFV2PlusWrapperLinkAndLinkNativeFeedSet) (event.Subscription, error) { - - logs, sub, err := _VRFV2PlusWrapper.contract.WatchLogs(opts, "LinkAndLinkNativeFeedSet") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFV2PlusWrapperLinkAndLinkNativeFeedSet) - if err := _VRFV2PlusWrapper.contract.UnpackLog(event, "LinkAndLinkNativeFeedSet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_VRFV2PlusWrapper *VRFV2PlusWrapperFilterer) ParseLinkAndLinkNativeFeedSet(log types.Log) (*VRFV2PlusWrapperLinkAndLinkNativeFeedSet, error) { - event := new(VRFV2PlusWrapperLinkAndLinkNativeFeedSet) - if err := _VRFV2PlusWrapper.contract.UnpackLog(event, "LinkAndLinkNativeFeedSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - type VRFV2PlusWrapperNativeWithdrawnIterator struct { Event *VRFV2PlusWrapperNativeWithdrawn @@ -2227,15 +2087,16 @@ func (_VRFV2PlusWrapper *VRFV2PlusWrapperFilterer) ParseWrapperFulfillmentFailed } type GetConfig struct { - FallbackWeiPerUnitLink *big.Int - StalenessSeconds uint32 - FulfillmentFlatFeeLinkPPM uint32 - FulfillmentFlatFeeNativePPM uint32 - WrapperGasOverhead uint32 - CoordinatorGasOverhead uint32 - WrapperPremiumPercentage uint8 - KeyHash [32]byte - MaxNumWords uint8 + FallbackWeiPerUnitLink *big.Int + StalenessSeconds uint32 + FulfillmentFlatFeeNativePPM uint32 + FulfillmentFlatFeeLinkDiscountPPM uint32 + WrapperGasOverhead uint32 + CoordinatorGasOverhead uint32 + WrapperNativePremiumPercentage uint8 + WrapperLinkPremiumPercentage uint8 + KeyHash [32]byte + MaxNumWords uint8 } type SCallbacks struct { CallbackAddress common.Address @@ -2257,8 +2118,6 @@ func (_VRFV2PlusWrapper *VRFV2PlusWrapper) ParseLog(log types.Log) (generated.Ab return _VRFV2PlusWrapper.ParseFallbackWeiPerUnitLinkUsed(log) case _VRFV2PlusWrapper.abi.Events["FulfillmentTxSizeSet"].ID: return _VRFV2PlusWrapper.ParseFulfillmentTxSizeSet(log) - case _VRFV2PlusWrapper.abi.Events["LinkAndLinkNativeFeedSet"].ID: - return _VRFV2PlusWrapper.ParseLinkAndLinkNativeFeedSet(log) case _VRFV2PlusWrapper.abi.Events["NativeWithdrawn"].ID: return _VRFV2PlusWrapper.ParseNativeWithdrawn(log) case _VRFV2PlusWrapper.abi.Events["OwnershipTransferRequested"].ID: @@ -2276,7 +2135,7 @@ func (_VRFV2PlusWrapper *VRFV2PlusWrapper) ParseLog(log types.Log) (generated.Ab } func (VRFV2PlusWrapperConfigSet) Topic() common.Hash { - return common.HexToHash("0x671302dfb4fd6e0b074fffc969890821e7a72a82802194d68cbb6a70a75934fb") + return common.HexToHash("0xb18fd84519589131d50ae195b0aea1b042c3c0b25a53bb894d9d81c78980c20f") } func (VRFV2PlusWrapperCoordinatorSet) Topic() common.Hash { @@ -2299,10 +2158,6 @@ func (VRFV2PlusWrapperFulfillmentTxSizeSet) Topic() common.Hash { return common.HexToHash("0x697b48b8b76cebb09a54ec4ff810e8a181c96f65395d51c744db09c115d1d5d0") } -func (VRFV2PlusWrapperLinkAndLinkNativeFeedSet) Topic() common.Hash { - return common.HexToHash("0xfe255131c483b5b74cae4b315eb2c6cd06c1ae4b17b11a61ed4348dfd54e3385") -} - func (VRFV2PlusWrapperNativeWithdrawn) Topic() common.Hash { return common.HexToHash("0xc303ca808382409472acbbf899c316cf439f409f6584aae22df86dfa3c9ed504") } @@ -2346,6 +2201,10 @@ type VRFV2PlusWrapperInterface interface { LastRequestId(opts *bind.CallOpts) (*big.Int, error) + Link(opts *bind.CallOpts) (common.Address, error) + + LinkNativeFeed(opts *bind.CallOpts) (common.Address, error) + Owner(opts *bind.CallOpts) (common.Address, error) SCallbacks(opts *bind.CallOpts, arg0 *big.Int) (SCallbacks, @@ -2358,10 +2217,6 @@ type VRFV2PlusWrapperInterface interface { SFulfillmentTxSizeBytes(opts *bind.CallOpts) (uint32, error) - SLink(opts *bind.CallOpts) (common.Address, error) - - SLinkNativeFeed(opts *bind.CallOpts) (common.Address, error) - SVrfCoordinator(opts *bind.CallOpts) (common.Address, error) TypeAndVersion(opts *bind.CallOpts) (string, error) @@ -2372,22 +2227,18 @@ type VRFV2PlusWrapperInterface interface { Enable(opts *bind.TransactOpts) (*types.Transaction, error) - Migrate(opts *bind.TransactOpts, newCoordinator common.Address) (*types.Transaction, error) - OnTokenTransfer(opts *bind.TransactOpts, _sender common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) RawFulfillRandomWords(opts *bind.TransactOpts, requestId *big.Int, randomWords []*big.Int) (*types.Transaction, error) RequestRandomWordsInNative(opts *bind.TransactOpts, _callbackGasLimit uint32, _requestConfirmations uint16, _numWords uint32, extraArgs []byte) (*types.Transaction, error) - SetConfig(opts *bind.TransactOpts, _wrapperGasOverhead uint32, _coordinatorGasOverhead uint32, _wrapperPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8, _stalenessSeconds uint32, _fallbackWeiPerUnitLink *big.Int, _fulfillmentFlatFeeLinkPPM uint32, _fulfillmentFlatFeeNativePPM uint32) (*types.Transaction, error) + SetConfig(opts *bind.TransactOpts, _wrapperGasOverhead uint32, _coordinatorGasOverhead uint32, _coordinatorNativePremiumPercentage uint8, _coordinatorLinkPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8, _stalenessSeconds uint32, _fallbackWeiPerUnitLink *big.Int, _fulfillmentFlatFeeNativePPM uint32, _fulfillmentFlatFeeLinkDiscountPPM uint32) (*types.Transaction, error) SetCoordinator(opts *bind.TransactOpts, _vrfCoordinator common.Address) (*types.Transaction, error) SetFulfillmentTxSize(opts *bind.TransactOpts, size uint32) (*types.Transaction, error) - SetLinkAndLinkNativeFeed(opts *bind.TransactOpts, link common.Address, linkNativeFeed common.Address) (*types.Transaction, error) - TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) Withdraw(opts *bind.TransactOpts, _recipient common.Address) (*types.Transaction, error) @@ -2430,12 +2281,6 @@ type VRFV2PlusWrapperInterface interface { ParseFulfillmentTxSizeSet(log types.Log) (*VRFV2PlusWrapperFulfillmentTxSizeSet, error) - FilterLinkAndLinkNativeFeedSet(opts *bind.FilterOpts) (*VRFV2PlusWrapperLinkAndLinkNativeFeedSetIterator, error) - - WatchLinkAndLinkNativeFeedSet(opts *bind.WatchOpts, sink chan<- *VRFV2PlusWrapperLinkAndLinkNativeFeedSet) (event.Subscription, error) - - ParseLinkAndLinkNativeFeedSet(log types.Log) (*VRFV2PlusWrapperLinkAndLinkNativeFeedSet, error) - FilterNativeWithdrawn(opts *bind.FilterOpts, to []common.Address) (*VRFV2PlusWrapperNativeWithdrawnIterator, error) WatchNativeWithdrawn(opts *bind.WatchOpts, sink chan<- *VRFV2PlusWrapperNativeWithdrawn, to []common.Address) (event.Subscription, error) diff --git a/core/gethwrappers/generated/vrfv2plus_wrapper_consumer_example/vrfv2plus_wrapper_consumer_example.go b/core/gethwrappers/generated/vrfv2plus_wrapper_consumer_example/vrfv2plus_wrapper_consumer_example.go index 3f90f873098..094d57a9adc 100644 --- a/core/gethwrappers/generated/vrfv2plus_wrapper_consumer_example/vrfv2plus_wrapper_consumer_example.go +++ b/core/gethwrappers/generated/vrfv2plus_wrapper_consumer_example/vrfv2plus_wrapper_consumer_example.go @@ -31,15 +31,15 @@ var ( ) var VRFV2PlusWrapperConsumerExampleMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_vrfV2Wrapper\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"LINKAlreadySet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyVRFWrapperCanFulfill\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"}],\"name\":\"LinkTokenSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"}],\"name\":\"WrappedRequestFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"}],\"name\":\"WrapperRequestMade\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLinkToken\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"getRequestStatus\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_vrfV2PlusWrapper\",\"outputs\":[{\"internalType\":\"contractIVRFV2PlusWrapper\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"}],\"name\":\"makeRequest\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"}],\"name\":\"makeRequestNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"_randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requests\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"native\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"}],\"name\":\"setLinkToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLink\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b5060405162001775380380620017758339810160408190526200003491620001db565b3380600084846001600160a01b038216156200006657600080546001600160a01b0319166001600160a01b0384161790555b60601b6001600160601b031916608052506001600160a01b038216620000d35760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b03848116919091179091558116156200010657620001068162000111565b505050505062000213565b6001600160a01b0381163314156200016c5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620000ca565b600280546001600160a01b0319166001600160a01b03838116918217909255600154604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b80516001600160a01b0381168114620001d657600080fd5b919050565b60008060408385031215620001ef57600080fd5b620001fa83620001be565b91506200020a60208401620001be565b90509250929050565b60805160601c6115196200025c600039600081816101c80152818161049701528181610ba201528181610c4401528181610cfc01528181610df10152610e6f01526115196000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c80638da5cb5b1161008c578063a168fa8911610066578063a168fa89146101ea578063d8a4676f1461023c578063e76d51681461025e578063f2fde38b1461027c57600080fd5b80638da5cb5b146101715780639c24ea40146101b05780639ed0868d146101c357600080fd5b80631fe543e3116100c85780631fe543e31461012e57806379ba5097146101435780637a8042bd1461014b57806384276d811461015e57600080fd5b80630c09b832146100ef57806312065fe0146101155780631e1a34991461011b575b600080fd5b6101026100fd366004611326565b61028f565b6040519081526020015b60405180910390f35b47610102565b610102610129366004611326565b6103cc565b61014161013c366004611237565b610495565b005b610141610537565b610141610159366004611205565b610638565b61014161016c366004611205565b610726565b60015473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161010c565b6101416101be3660046111a6565b610816565b61018b7f000000000000000000000000000000000000000000000000000000000000000081565b61021f6101f8366004611205565b600360208190526000918252604090912080546001820154919092015460ff918216911683565b60408051938452911515602084015215159082015260600161010c565b61024f61024a366004611205565b6108df565b60405161010c9392919061147f565b60005473ffffffffffffffffffffffffffffffffffffffff1661018b565b61014161028a3660046111a6565b610a01565b6000610299610a15565b60006102b5604051806020016040528060001515815250610a98565b905060006102c586868685610b54565b6040805160808101825282815260006020808301828152845183815280830186528486019081526060850184905287845260038352949092208351815591516001830180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055925180519598509395509093909261035492600285019291019061112d565b5060609190910151600390910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905560405181815283907f5f56b4c20db9f5b294cbf6f681368de4a992a27e2de2ee702dcf2cbbfa791ec49060200160405180910390a250509392505050565b60006103d6610a15565b60006103f2604051806020016040528060011515815250610a98565b9050600061040286868685610da3565b604080516080810182528281526000602080830182815284518381528083018652848601908152600160608601819052888552600384529590932084518155905194810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016951515959095179094559051805195985093955090939192610354926002850192919091019061112d565b7f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff821614610528576040517f8ba9316e00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff821660248201526044015b60405180910390fd5b6105328383610f1f565b505050565b60025473ffffffffffffffffffffffffffffffffffffffff1633146105b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161051f565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560028054909116905560405173ffffffffffffffffffffffffffffffffffffffff909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b610640610a15565b60005473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb61067d60015473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff909116600482015260248101849052604401602060405180830381600087803b1580156106ea57600080fd5b505af11580156106fe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061072291906111e3565b5050565b61072e610a15565b600061074f60015473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d80600081146107a6576040519150601f19603f3d011682016040523d82523d6000602084013e6107ab565b606091505b5050905080610722576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f77697468647261774e6174697665206661696c65640000000000000000000000604482015260640161051f565b60005473ffffffffffffffffffffffffffffffffffffffff1615610866576040517f64f778ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fc985b3c2e817dbd28c7ccd936e9b72c3de828a7bd504fa999ab8e02baeb59ca29060200160405180910390a150565b6000818152600360205260408120548190606090610959576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e64000000000000000000000000000000604482015260640161051f565b6000848152600360209081526040808320815160808101835281548152600182015460ff161515818501526002820180548451818702810187018652818152929593948601938301828280156109ce57602002820191906000526020600020905b8154815260200190600101908083116109ba575b50505091835250506003919091015460ff1615156020918201528151908201516040909201519097919650945092505050565b610a09610a15565b610a1281611036565b50565b60015473ffffffffffffffffffffffffffffffffffffffff163314610a96576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161051f565b565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401610ad191511515815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915292915050565b6040517f4306d35400000000000000000000000000000000000000000000000000000000815263ffffffff85166004820152600090819073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634306d3549060240160206040518083038186803b158015610be457600080fd5b505afa158015610bf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1c919061121e565b60005460405191925073ffffffffffffffffffffffffffffffffffffffff1690634000aea0907f0000000000000000000000000000000000000000000000000000000000000000908490610c7a908b908b908b908b906020016114a0565b6040516020818303038152906040526040518463ffffffff1660e01b8152600401610ca793929190611418565b602060405180830381600087803b158015610cc157600080fd5b505af1158015610cd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf991906111e3565b507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663fc2a88c36040518163ffffffff1660e01b815260040160206040518083038186803b158015610d6057600080fd5b505afa158015610d74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d98919061121e565b915094509492505050565b6040517f4b16093500000000000000000000000000000000000000000000000000000000815263ffffffff85166004820152600090819073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634b1609359060240160206040518083038186803b158015610e3357600080fd5b505afa158015610e47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e6b919061121e565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16639cfc058e82888888886040518663ffffffff1660e01b8152600401610ecd94939291906114a0565b6020604051808303818588803b158015610ee657600080fd5b505af1158015610efa573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610d98919061121e565b600082815260036020526040902054610f94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e64000000000000000000000000000000604482015260640161051f565b6000828152600360209081526040909120600181810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690911790558251610fe79260029092019184019061112d565b50600082815260036020526040908190205490517f6c84e12b4c188e61f1b4727024a5cf05c025fa58467e5eedf763c0744c89da7b9161102a9185918591611456565b60405180910390a15050565b73ffffffffffffffffffffffffffffffffffffffff81163314156110b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161051f565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600154604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b828054828255906000526020600020908101928215611168579160200282015b8281111561116857825182559160200191906001019061114d565b50611174929150611178565b5090565b5b808211156111745760008155600101611179565b803563ffffffff811681146111a157600080fd5b919050565b6000602082840312156111b857600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146111dc57600080fd5b9392505050565b6000602082840312156111f557600080fd5b815180151581146111dc57600080fd5b60006020828403121561121757600080fd5b5035919050565b60006020828403121561123057600080fd5b5051919050565b6000806040838503121561124a57600080fd5b8235915060208084013567ffffffffffffffff8082111561126a57600080fd5b818601915086601f83011261127e57600080fd5b813581811115611290576112906114dd565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f830116810181811085821117156112d3576112d36114dd565b604052828152858101935084860182860187018b10156112f257600080fd5b600095505b838610156113155780358552600195909501949386019386016112f7565b508096505050505050509250929050565b60008060006060848603121561133b57600080fd5b6113448461118d565b9250602084013561ffff8116811461135b57600080fd5b91506113696040850161118d565b90509250925092565b600081518084526020808501945080840160005b838110156113a257815187529582019590820190600101611386565b509495945050505050565b6000815180845260005b818110156113d3576020818501810151868301820152016113b7565b818111156113e5576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff8416815282602082015260606040820152600061144d60608301846113ad565b95945050505050565b83815260606020820152600061146f6060830185611372565b9050826040830152949350505050565b838152821515602082015260606040820152600061144d6060830184611372565b600063ffffffff808716835261ffff86166020840152808516604084015250608060608301526114d360808301846113ad565b9695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfV2Wrapper\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyVRFWrapperCanFulfill\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"}],\"name\":\"WrappedRequestFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"}],\"name\":\"WrapperRequestMade\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLinkToken\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"getRequestStatus\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_vrfV2PlusWrapper\",\"outputs\":[{\"internalType\":\"contractIVRFV2PlusWrapper\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"}],\"name\":\"makeRequest\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"}],\"name\":\"makeRequestNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"_randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requests\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"native\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLink\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60c06040523480156200001157600080fd5b5060405162001662380380620016628339810160408190526200003491620001f5565b33806000836000819050806001600160a01b0316631c4695f46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200007d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000a39190620001f5565b6001600160a01b0390811660805290811660a052831690506200010d5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620001405762000140816200014a565b5050505062000227565b336001600160a01b03821603620001a45760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000104565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200020857600080fd5b81516001600160a01b03811681146200022057600080fd5b9392505050565b60805160a0516113dd62000285600039600081816101aa0152818161047b01528181610aa801528181610b5301528181610bfd01528181610ce30152610d52015260008181610242015281816106220152610b1701526113dd6000f3fe608060405234801561001057600080fd5b50600436106100df5760003560e01c806384276d811161008c578063a168fa8911610066578063a168fa89146101cc578063d8a4676f1461021e578063e76d516814610240578063f2fde38b1461026657600080fd5b806384276d81146101535780638da5cb5b146101665780639ed0868d146101a557600080fd5b80631fe543e3116100bd5780631fe543e31461012357806379ba5097146101385780637a8042bd1461014057600080fd5b80630c09b832146100e457806312065fe01461010a5780631e1a349914610110575b600080fd5b6100f76100f2366004611078565b610279565b6040519081526020015b60405180910390f35b476100f7565b6100f761011e366004611078565b6103b4565b6101366101313660046110f3565b610479565b005b61013661051b565b61013661014e3660046111db565b610618565b6101366101613660046111db565b610715565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610101565b6101807f000000000000000000000000000000000000000000000000000000000000000081565b6102016101da3660046111db565b600260205260009081526040902080546001820154600390920154909160ff908116911683565b604080519384529115156020840152151590820152606001610101565b61023161022c3660046111db565b6107e7565b6040516101019392919061122f565b7f0000000000000000000000000000000000000000000000000000000000000000610180565b610136610274366004611259565b610907565b600061028361091b565b600061029f60405180602001604052806000151581525061099e565b905060006102af86868685610a5a565b604080516080810182528281526000602080830182815284518381528083018652848601908152606085018490528784526002808452959093208451815590516001820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055915180519699509496509194909361033c938501920190610fff565b5060609190910151600390910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905560405181815283907f5f56b4c20db9f5b294cbf6f681368de4a992a27e2de2ee702dcf2cbbfa791ec49060200160405180910390a250509392505050565b60006103be61091b565b60006103da60405180602001604052806001151581525061099e565b905060006103ea86868685610c95565b60408051608081018252828152600060208083018281528451838152808301865284860190815260016060860181905288855260028085529690942085518155915193820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001694151594909417909355915180519699509496509194909361033c938501920190610fff565b7f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff82161461050c576040517f8ba9316e00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff821660248201526044015b60405180910390fd5b6105168383610df3565b505050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461059c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610503565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b61062061091b565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb61067b60005473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602481018490526044016020604051808303816000875af11580156106ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107119190611296565b5050565b61071d61091b565b6000805460405173ffffffffffffffffffffffffffffffffffffffff9091169083908381818185875af1925050503d8060008114610777576040519150601f19603f3d011682016040523d82523d6000602084013e61077c565b606091505b5050905080610711576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f77697468647261774e6174697665206661696c656400000000000000000000006044820152606401610503565b6000818152600260205260408120548190606090610861576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e640000000000000000000000000000006044820152606401610503565b6000848152600260208181526040808420815160808101835281548152600182015460ff16151581850152938101805483518186028101860185528181529294938601938301828280156108d457602002820191906000526020600020905b8154815260200190600101908083116108c0575b50505091835250506003919091015460ff1615156020918201528151908201516040909201519097919650945092505050565b61090f61091b565b61091881610f0a565b50565b60005473ffffffffffffffffffffffffffffffffffffffff16331461099c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610503565b565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa826040516024016109d791511515815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915292915050565b6040517f4306d35400000000000000000000000000000000000000000000000000000000815263ffffffff85166004820152600090819073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634306d35490602401602060405180830381865afa158015610aef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b1391906112b8565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16634000aea07f00000000000000000000000000000000000000000000000000000000000000008389898989604051602001610b8a9493929190611335565b6040516020818303038152906040526040518463ffffffff1660e01b8152600401610bb793929190611372565b6020604051808303816000875af1158015610bd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bfa9190611296565b507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663fc2a88c36040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c8a91906112b8565b915094509492505050565b6040517f4b16093500000000000000000000000000000000000000000000000000000000815263ffffffff85166004820152600090819073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634b16093590602401602060405180830381865afa158015610d2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d4e91906112b8565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16639cfc058e82888888886040518663ffffffff1660e01b8152600401610db09493929190611335565b60206040518083038185885af1158015610dce573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610c8a91906112b8565b600082815260026020526040902054610e68576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e640000000000000000000000000000006044820152606401610503565b6000828152600260208181526040909220600181810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690911790558351610ebb93919092019190840190610fff565b50600082815260026020526040908190205490517f6c84e12b4c188e61f1b4727024a5cf05c025fa58467e5eedf763c0744c89da7b91610efe91859185916113a7565b60405180910390a15050565b3373ffffffffffffffffffffffffffffffffffffffff821603610f89576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610503565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b82805482825590600052602060002090810192821561103a579160200282015b8281111561103a57825182559160200191906001019061101f565b5061104692915061104a565b5090565b5b80821115611046576000815560010161104b565b803563ffffffff8116811461107357600080fd5b919050565b60008060006060848603121561108d57600080fd5b6110968461105f565b9250602084013561ffff811681146110ad57600080fd5b91506110bb6040850161105f565b90509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806040838503121561110657600080fd5b8235915060208084013567ffffffffffffffff8082111561112657600080fd5b818601915086601f83011261113a57600080fd5b81358181111561114c5761114c6110c4565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110858211171561118f5761118f6110c4565b6040529182528482019250838101850191898311156111ad57600080fd5b938501935b828510156111cb578435845293850193928501926111b2565b8096505050505050509250929050565b6000602082840312156111ed57600080fd5b5035919050565b600081518084526020808501945080840160005b8381101561122457815187529582019590820190600101611208565b509495945050505050565b838152821515602082015260606040820152600061125060608301846111f4565b95945050505050565b60006020828403121561126b57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461128f57600080fd5b9392505050565b6000602082840312156112a857600080fd5b8151801515811461128f57600080fd5b6000602082840312156112ca57600080fd5b5051919050565b6000815180845260005b818110156112f7576020818501810151868301820152016112db565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b600063ffffffff808716835261ffff861660208401528085166040840152506080606083015261136860808301846112d1565b9695505050505050565b73ffffffffffffffffffffffffffffffffffffffff8416815282602082015260606040820152600061125060608301846112d1565b8381526060602082015260006113c060608301856111f4565b905082604083015294935050505056fea164736f6c6343000813000a", } var VRFV2PlusWrapperConsumerExampleABI = VRFV2PlusWrapperConsumerExampleMetaData.ABI var VRFV2PlusWrapperConsumerExampleBin = VRFV2PlusWrapperConsumerExampleMetaData.Bin -func DeployVRFV2PlusWrapperConsumerExample(auth *bind.TransactOpts, backend bind.ContractBackend, _link common.Address, _vrfV2Wrapper common.Address) (common.Address, *types.Transaction, *VRFV2PlusWrapperConsumerExample, error) { +func DeployVRFV2PlusWrapperConsumerExample(auth *bind.TransactOpts, backend bind.ContractBackend, _vrfV2Wrapper common.Address) (common.Address, *types.Transaction, *VRFV2PlusWrapperConsumerExample, error) { parsed, err := VRFV2PlusWrapperConsumerExampleMetaData.GetAbi() if err != nil { return common.Address{}, nil, nil, err @@ -48,7 +48,7 @@ func DeployVRFV2PlusWrapperConsumerExample(auth *bind.TransactOpts, backend bind return common.Address{}, nil, nil, errors.New("GetABI returned nil") } - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(VRFV2PlusWrapperConsumerExampleBin), backend, _link, _vrfV2Wrapper) + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(VRFV2PlusWrapperConsumerExampleBin), backend, _vrfV2Wrapper) if err != nil { return common.Address{}, nil, nil, err } @@ -369,18 +369,6 @@ func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExampleTransacto return _VRFV2PlusWrapperConsumerExample.Contract.RawFulfillRandomWords(&_VRFV2PlusWrapperConsumerExample.TransactOpts, _requestId, _randomWords) } -func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExampleTransactor) SetLinkToken(opts *bind.TransactOpts, _link common.Address) (*types.Transaction, error) { - return _VRFV2PlusWrapperConsumerExample.contract.Transact(opts, "setLinkToken", _link) -} - -func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExampleSession) SetLinkToken(_link common.Address) (*types.Transaction, error) { - return _VRFV2PlusWrapperConsumerExample.Contract.SetLinkToken(&_VRFV2PlusWrapperConsumerExample.TransactOpts, _link) -} - -func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExampleTransactorSession) SetLinkToken(_link common.Address) (*types.Transaction, error) { - return _VRFV2PlusWrapperConsumerExample.Contract.SetLinkToken(&_VRFV2PlusWrapperConsumerExample.TransactOpts, _link) -} - func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExampleTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { return _VRFV2PlusWrapperConsumerExample.contract.Transact(opts, "transferOwnership", to) } @@ -417,123 +405,6 @@ func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExampleTransacto return _VRFV2PlusWrapperConsumerExample.Contract.WithdrawNative(&_VRFV2PlusWrapperConsumerExample.TransactOpts, amount) } -type VRFV2PlusWrapperConsumerExampleLinkTokenSetIterator struct { - Event *VRFV2PlusWrapperConsumerExampleLinkTokenSet - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFV2PlusWrapperConsumerExampleLinkTokenSetIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFV2PlusWrapperConsumerExampleLinkTokenSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - - select { - case log := <-it.logs: - it.Event = new(VRFV2PlusWrapperConsumerExampleLinkTokenSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -func (it *VRFV2PlusWrapperConsumerExampleLinkTokenSetIterator) Error() error { - return it.fail -} - -func (it *VRFV2PlusWrapperConsumerExampleLinkTokenSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFV2PlusWrapperConsumerExampleLinkTokenSet struct { - Link common.Address - Raw types.Log -} - -func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExampleFilterer) FilterLinkTokenSet(opts *bind.FilterOpts) (*VRFV2PlusWrapperConsumerExampleLinkTokenSetIterator, error) { - - logs, sub, err := _VRFV2PlusWrapperConsumerExample.contract.FilterLogs(opts, "LinkTokenSet") - if err != nil { - return nil, err - } - return &VRFV2PlusWrapperConsumerExampleLinkTokenSetIterator{contract: _VRFV2PlusWrapperConsumerExample.contract, event: "LinkTokenSet", logs: logs, sub: sub}, nil -} - -func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExampleFilterer) WatchLinkTokenSet(opts *bind.WatchOpts, sink chan<- *VRFV2PlusWrapperConsumerExampleLinkTokenSet) (event.Subscription, error) { - - logs, sub, err := _VRFV2PlusWrapperConsumerExample.contract.WatchLogs(opts, "LinkTokenSet") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFV2PlusWrapperConsumerExampleLinkTokenSet) - if err := _VRFV2PlusWrapperConsumerExample.contract.UnpackLog(event, "LinkTokenSet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExampleFilterer) ParseLinkTokenSet(log types.Log) (*VRFV2PlusWrapperConsumerExampleLinkTokenSet, error) { - event := new(VRFV2PlusWrapperConsumerExampleLinkTokenSet) - if err := _VRFV2PlusWrapperConsumerExample.contract.UnpackLog(event, "LinkTokenSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - type VRFV2PlusWrapperConsumerExampleOwnershipTransferRequestedIterator struct { Event *VRFV2PlusWrapperConsumerExampleOwnershipTransferRequested @@ -1066,8 +937,6 @@ type SRequests struct { func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExample) ParseLog(log types.Log) (generated.AbigenLog, error) { switch log.Topics[0] { - case _VRFV2PlusWrapperConsumerExample.abi.Events["LinkTokenSet"].ID: - return _VRFV2PlusWrapperConsumerExample.ParseLinkTokenSet(log) case _VRFV2PlusWrapperConsumerExample.abi.Events["OwnershipTransferRequested"].ID: return _VRFV2PlusWrapperConsumerExample.ParseOwnershipTransferRequested(log) case _VRFV2PlusWrapperConsumerExample.abi.Events["OwnershipTransferred"].ID: @@ -1082,10 +951,6 @@ func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExample) ParseLo } } -func (VRFV2PlusWrapperConsumerExampleLinkTokenSet) Topic() common.Hash { - return common.HexToHash("0xc985b3c2e817dbd28c7ccd936e9b72c3de828a7bd504fa999ab8e02baeb59ca2") -} - func (VRFV2PlusWrapperConsumerExampleOwnershipTransferRequested) Topic() common.Hash { return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") } @@ -1131,20 +996,12 @@ type VRFV2PlusWrapperConsumerExampleInterface interface { RawFulfillRandomWords(opts *bind.TransactOpts, _requestId *big.Int, _randomWords []*big.Int) (*types.Transaction, error) - SetLinkToken(opts *bind.TransactOpts, _link common.Address) (*types.Transaction, error) - TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) WithdrawLink(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) WithdrawNative(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) - FilterLinkTokenSet(opts *bind.FilterOpts) (*VRFV2PlusWrapperConsumerExampleLinkTokenSetIterator, error) - - WatchLinkTokenSet(opts *bind.WatchOpts, sink chan<- *VRFV2PlusWrapperConsumerExampleLinkTokenSet) (event.Subscription, error) - - ParseLinkTokenSet(log types.Log) (*VRFV2PlusWrapperConsumerExampleLinkTokenSet, error) - FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFV2PlusWrapperConsumerExampleOwnershipTransferRequestedIterator, error) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFV2PlusWrapperConsumerExampleOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) diff --git a/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer/vrfv2plus_wrapper_load_test_consumer.go b/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer/vrfv2plus_wrapper_load_test_consumer.go index f42561a449c..20936e51f07 100644 --- a/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer/vrfv2plus_wrapper_load_test_consumer.go +++ b/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer/vrfv2plus_wrapper_load_test_consumer.go @@ -31,15 +31,15 @@ var ( ) var VRFV2PlusWrapperLoadTestConsumerMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_vrfV2PlusWrapper\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"LINKAlreadySet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyVRFWrapperCanFulfill\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"}],\"name\":\"LinkTokenSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"}],\"name\":\"WrappedRequestFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"}],\"name\":\"WrapperRequestMade\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLinkToken\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"getRequestStatus\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_vrfV2PlusWrapper\",\"outputs\":[{\"internalType\":\"contractIVRFV2PlusWrapper\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestCount\",\"type\":\"uint16\"}],\"name\":\"makeRequests\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestCount\",\"type\":\"uint16\"}],\"name\":\"makeRequestsNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"_randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_averageFulfillmentInMillions\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fastestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requests\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"native\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_responseCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_slowestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"}],\"name\":\"setLinkToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLink\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", - Bin: "0x60a0604052600060055560006006556103e76007553480156200002157600080fd5b5060405162001eca38038062001eca8339810160408190526200004491620001eb565b3380600084846001600160a01b038216156200007657600080546001600160a01b0319166001600160a01b0384161790555b60601b6001600160601b031916608052506001600160a01b038216620000e35760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b03848116919091179091558116156200011657620001168162000121565b505050505062000223565b6001600160a01b0381163314156200017c5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620000da565b600280546001600160a01b0319166001600160a01b03838116918217909255600154604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b80516001600160a01b0381168114620001e657600080fd5b919050565b60008060408385031215620001ff57600080fd5b6200020a83620001ce565b91506200021a60208401620001ce565b90509250929050565b60805160601c611c5e6200026c600039600081816102e9015281816104b8015281816111c90152818161126b01528181611323015281816114b501526115330152611c5e6000f3fe60806040526004361061016e5760003560e01c80639c24ea40116100cb578063d826f88f1161007f578063e76d516811610059578063e76d51681461044b578063f176596214610476578063f2fde38b1461049657600080fd5b8063d826f88f146103d6578063d8a4676f14610402578063dc1670db1461043557600080fd5b8063a168fa89116100b0578063a168fa891461030b578063afacbf9c146103a0578063b1e21749146103c057600080fd5b80639c24ea40146102b75780639ed0868d146102d757600080fd5b806374dba124116101225780637a8042bd116101075780637a8042bd1461022b57806384276d811461024b5780638da5cb5b1461026b57600080fd5b806374dba1241461020057806379ba50971461021657600080fd5b80631fe543e3116101535780631fe543e3146101b2578063557d2e92146101d4578063737144bc146101ea57600080fd5b806312065fe01461017a5780631757f11c1461019c57600080fd5b3661017557005b600080fd5b34801561018657600080fd5b50475b6040519081526020015b60405180910390f35b3480156101a857600080fd5b5061018960065481565b3480156101be57600080fd5b506101d26101cd36600461181d565b6104b6565b005b3480156101e057600080fd5b5061018960045481565b3480156101f657600080fd5b5061018960055481565b34801561020c57600080fd5b5061018960075481565b34801561022257600080fd5b506101d2610558565b34801561023757600080fd5b506101d26102463660046117eb565b610659565b34801561025757600080fd5b506101d26102663660046117eb565b610747565b34801561027757600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610193565b3480156102c357600080fd5b506101d26102d236600461178c565b610837565b3480156102e357600080fd5b506102927f000000000000000000000000000000000000000000000000000000000000000081565b34801561031757600080fd5b506103696103263660046117eb565b600a602052600090815260409020805460018201546003830154600484015460058501546006860154600790960154949560ff9485169593949293919290911687565b604080519788529515156020880152948601939093526060850191909152608084015260a0830152151560c082015260e001610193565b3480156103ac57600080fd5b506101d26103bb36600461190c565b610900565b3480156103cc57600080fd5b5061018960085481565b3480156103e257600080fd5b506101d26000600581905560068190556103e76007556004819055600355565b34801561040e57600080fd5b5061042261041d3660046117eb565b610ae7565b6040516101939796959493929190611a6d565b34801561044157600080fd5b5061018960035481565b34801561045757600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610292565b34801561048257600080fd5b506101d261049136600461190c565b610c6a565b3480156104a257600080fd5b506101d26104b136600461178c565b610e49565b7f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff821614610549576040517f8ba9316e00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff821660248201526044015b60405180910390fd5b6105538383610e5d565b505050565b60025473ffffffffffffffffffffffffffffffffffffffff1633146105d9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610540565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560028054909116905560405173ffffffffffffffffffffffffffffffffffffffff909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b61066161103c565b60005473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb61069e60015473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff909116600482015260248101849052604401602060405180830381600087803b15801561070b57600080fd5b505af115801561071f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061074391906117c9565b5050565b61074f61103c565b600061077060015473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d80600081146107c7576040519150601f19603f3d011682016040523d82523d6000602084013e6107cc565b606091505b5050905080610743576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f77697468647261774e6174697665206661696c656400000000000000000000006044820152606401610540565b60005473ffffffffffffffffffffffffffffffffffffffff1615610887576040517f64f778ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fc985b3c2e817dbd28c7ccd936e9b72c3de828a7bd504fa999ab8e02baeb59ca29060200160405180910390a150565b61090861103c565b60005b8161ffff168161ffff161015610ae05760006109376040518060200160405280600015158152506110bf565b90506000806109488888888661117b565b60088290559092509050600061095c6113ca565b604080516101008101825284815260006020808301828152845183815280830186528486019081524260608601526080850184905260a0850187905260c0850184905260e08501849052898452600a8352949092208351815591516001830180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790559251805194955091939092610a04926002850192910190611701565b5060608201516003820155608082015160048083019190915560a0830151600583015560c0830151600683015560e090920151600790910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790558054906000610a7783611bba565b9091555050600083815260096020526040908190208290555183907f5f56b4c20db9f5b294cbf6f681368de4a992a27e2de2ee702dcf2cbbfa791ec490610ac19085815260200190565b60405180910390a2505050508080610ad890611b98565b91505061090b565b5050505050565b6000818152600a602052604081205481906060908290819081908190610b69576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e640000000000000000000000000000006044820152606401610540565b6000888152600a6020908152604080832081516101008101835281548152600182015460ff16151581850152600282018054845181870281018701865281815292959394860193830182828015610bdf57602002820191906000526020600020905b815481526020019060010190808311610bcb575b50505050508152602001600382015481526020016004820154815260200160058201548152602001600682015481526020016007820160009054906101000a900460ff1615151515815250509050806000015181602001518260400151836060015184608001518560a001518660c00151975097509750975097509750975050919395979092949650565b610c7261103c565b60005b8161ffff168161ffff161015610ae0576000610ca16040518060200160405280600115158152506110bf565b9050600080610cb288888886611467565b600882905590925090506000610cc66113ca565b604080516101008101825284815260006020808301828152845183815280830186528486019081524260608601526080850184905260a0850187905260c08501849052600160e086018190528a8552600a84529590932084518155905194810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001695151595909517909455905180519495509193610d6d9260028501920190611701565b5060608201516003820155608082015160048083019190915560a0830151600583015560c0830151600683015560e090920151600790910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790558054906000610de083611bba565b9091555050600083815260096020526040908190208290555183907f5f56b4c20db9f5b294cbf6f681368de4a992a27e2de2ee702dcf2cbbfa791ec490610e2a9085815260200190565b60405180910390a2505050508080610e4190611b98565b915050610c75565b610e5161103c565b610e5a816115e3565b50565b6000828152600a6020526040902054610ed2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e640000000000000000000000000000006044820152606401610540565b6000610edc6113ca565b60008481526009602052604081205491925090610ef99083611b81565b90506000610f0a82620f4240611b44565b9050600654821115610f1c5760068290555b6007548210610f2d57600754610f2f565b815b600755600354610f3f5780610f72565b600354610f4d906001611af1565b81600354600554610f5e9190611b44565b610f689190611af1565b610f729190611b09565b60055560038054906000610f8583611bba565b90915550506000858152600a60209081526040909120600181810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690911790558551610fdd92600290920191870190611701565b506000858152600a602052604090819020426004820155600681018590555490517f6c84e12b4c188e61f1b4727024a5cf05c025fa58467e5eedf763c0744c89da7b9161102d9188918891611a44565b60405180910390a15050505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146110bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610540565b565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa826040516024016110f891511515815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915292915050565b6040517f4306d35400000000000000000000000000000000000000000000000000000000815263ffffffff85166004820152600090819073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634306d3549060240160206040518083038186803b15801561120b57600080fd5b505afa15801561121f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112439190611804565b60005460405191925073ffffffffffffffffffffffffffffffffffffffff1690634000aea0907f00000000000000000000000000000000000000000000000000000000000000009084906112a1908b908b908b908b90602001611ab4565b6040516020818303038152906040526040518463ffffffff1660e01b81526004016112ce93929190611a06565b602060405180830381600087803b1580156112e857600080fd5b505af11580156112fc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061132091906117c9565b507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663fc2a88c36040518163ffffffff1660e01b815260040160206040518083038186803b15801561138757600080fd5b505afa15801561139b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113bf9190611804565b915094509492505050565b6000466113d6816116da565b1561146057606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561142257600080fd5b505afa158015611436573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061145a9190611804565b91505090565b4391505090565b6040517f4b16093500000000000000000000000000000000000000000000000000000000815263ffffffff85166004820152600090819073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634b1609359060240160206040518083038186803b1580156114f757600080fd5b505afa15801561150b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061152f9190611804565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16639cfc058e82888888886040518663ffffffff1660e01b81526004016115919493929190611ab4565b6020604051808303818588803b1580156115aa57600080fd5b505af11580156115be573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906113bf9190611804565b73ffffffffffffffffffffffffffffffffffffffff8116331415611663576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610540565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600154604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b600061a4b18214806116ee575062066eed82145b806116fb575062066eee82145b92915050565b82805482825590600052602060002090810192821561173c579160200282015b8281111561173c578251825591602001919060010190611721565b5061174892915061174c565b5090565b5b80821115611748576000815560010161174d565b803561ffff8116811461177357600080fd5b919050565b803563ffffffff8116811461177357600080fd5b60006020828403121561179e57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146117c257600080fd5b9392505050565b6000602082840312156117db57600080fd5b815180151581146117c257600080fd5b6000602082840312156117fd57600080fd5b5035919050565b60006020828403121561181657600080fd5b5051919050565b6000806040838503121561183057600080fd5b8235915060208084013567ffffffffffffffff8082111561185057600080fd5b818601915086601f83011261186457600080fd5b81358181111561187657611876611c22565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f830116810181811085821117156118b9576118b9611c22565b604052828152858101935084860182860187018b10156118d857600080fd5b600095505b838610156118fb5780358552600195909501949386019386016118dd565b508096505050505050509250929050565b6000806000806080858703121561192257600080fd5b61192b85611778565b935061193960208601611761565b925061194760408601611778565b915061195560608601611761565b905092959194509250565b600081518084526020808501945080840160005b8381101561199057815187529582019590820190600101611974565b509495945050505050565b6000815180845260005b818110156119c1576020818501810151868301820152016119a5565b818111156119d3576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201526000611a3b606083018461199b565b95945050505050565b838152606060208201526000611a5d6060830185611960565b9050826040830152949350505050565b878152861515602082015260e060408201526000611a8e60e0830188611960565b90508560608301528460808301528360a08301528260c083015298975050505050505050565b600063ffffffff808716835261ffff8616602084015280851660408401525060806060830152611ae7608083018461199b565b9695505050505050565b60008219821115611b0457611b04611bf3565b500190565b600082611b3f577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611b7c57611b7c611bf3565b500290565b600082821015611b9357611b93611bf3565b500390565b600061ffff80831681811415611bb057611bb0611bf3565b6001019392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415611bec57611bec611bf3565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfV2PlusWrapper\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyVRFWrapperCanFulfill\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"}],\"name\":\"WrappedRequestFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"}],\"name\":\"WrapperRequestMade\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLinkToken\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"offset\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"quantity\",\"type\":\"uint256\"}],\"name\":\"getRequestBlockTimes\",\"outputs\":[{\"internalType\":\"uint32[]\",\"name\":\"\",\"type\":\"uint32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"getRequestStatus\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_vrfV2PlusWrapper\",\"outputs\":[{\"internalType\":\"contractIVRFV2PlusWrapper\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestCount\",\"type\":\"uint16\"}],\"name\":\"makeRequests\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestCount\",\"type\":\"uint16\"}],\"name\":\"makeRequestsNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"_randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_averageFulfillmentInMillions\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fastestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requestBlockTimes\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requests\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"native\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_responseCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_slowestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLink\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", + Bin: "0x60c0604052600060045560006005556103e76006553480156200002157600080fd5b506040516200204638038062002046833981016040819052620000449162000205565b33806000836000819050806001600160a01b0316631c4695f46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200008d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000b3919062000205565b6001600160a01b0390811660805290811660a052831690506200011d5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620001505762000150816200015a565b5050505062000237565b336001600160a01b03821603620001b45760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000114565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200021857600080fd5b81516001600160a01b03811681146200023057600080fd5b9392505050565b60805160a051611db1620002956000396000818161033a015281816105f8015281816112e6015281816113910152818161143b015281816115af015261161e0152600081816104940152818161079f01526113550152611db16000f3fe6080604052600436106101795760003560e01c8063958cccb7116100cb578063d826f88f1161007f578063e76d516811610059578063e76d516814610485578063f1765962146104b8578063f2fde38b146104d857600080fd5b8063d826f88f14610427578063d8a4676f1461043c578063dc1670db1461046f57600080fd5b8063a168fa89116100b0578063a168fa891461035c578063afacbf9c146103f1578063b1e217491461041157600080fd5b8063958cccb7146102f35780639ed0868d1461032857600080fd5b8063737144bc1161012d5780637a8042bd116101075780637a8042bd1461026757806384276d81146102875780638da5cb5b146102a757600080fd5b8063737144bc1461022657806374dba1241461023c57806379ba50971461025257600080fd5b80631757f11c1161015e5780631757f11c146101d85780631fe543e3146101ee578063557d2e921461021057600080fd5b80630b2634861461018557806312065fe0146101bb57600080fd5b3661018057005b600080fd5b34801561019157600080fd5b506101a56101a0366004611858565b6104f8565b6040516101b2919061187a565b60405180910390f35b3480156101c757600080fd5b50475b6040519081526020016101b2565b3480156101e457600080fd5b506101ca60055481565b3480156101fa57600080fd5b5061020e6102093660046118f3565b6105f6565b005b34801561021c57600080fd5b506101ca60035481565b34801561023257600080fd5b506101ca60045481565b34801561024857600080fd5b506101ca60065481565b34801561025e57600080fd5b5061020e610698565b34801561027357600080fd5b5061020e6102823660046119db565b610795565b34801561029357600080fd5b5061020e6102a23660046119db565b610892565b3480156102b357600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101b2565b3480156102ff57600080fd5b5061031361030e3660046119db565b610964565b60405163ffffffff90911681526020016101b2565b34801561033457600080fd5b506102ce7f000000000000000000000000000000000000000000000000000000000000000081565b34801561036857600080fd5b506103ba6103773660046119db565b600a602052600090815260409020805460018201546003830154600484015460058501546006860154600790960154949560ff9485169593949293919290911687565b604080519788529515156020880152948601939093526060850191909152608084015260a0830152151560c082015260e0016101b2565b3480156103fd57600080fd5b5061020e61040c366004611a1f565b61099e565b34801561041d57600080fd5b506101ca60075481565b34801561043357600080fd5b5061020e610b85565b34801561044857600080fd5b5061045c6104573660046119db565b610baf565b6040516101b29796959493929190611aae565b34801561047b57600080fd5b506101ca60025481565b34801561049157600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006102ce565b3480156104c457600080fd5b5061020e6104d3366004611a1f565b610d32565b3480156104e457600080fd5b5061020e6104f3366004611af5565b610f11565b606060006105068385611b61565b60085490915081111561051857506008545b60006105248583611b74565b67ffffffffffffffff81111561053c5761053c6118c4565b604051908082528060200260200182016040528015610565578160200160208202803683370190505b509050845b828110156105eb576008818154811061058557610585611b87565b6000918252602090912060088204015460079091166004026101000a900463ffffffff16826105b48884611b74565b815181106105c4576105c4611b87565b63ffffffff90921660209283029190910190910152806105e381611bb6565b91505061056a565b509150505b92915050565b7f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff821614610689576040517f8ba9316e00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff821660248201526044015b60405180910390fd5b6106938383610f25565b505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610719576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610680565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b61079d61115b565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb6107f860005473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602481018490526044016020604051808303816000875af115801561086a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061088e9190611bee565b5050565b61089a61115b565b6000805460405173ffffffffffffffffffffffffffffffffffffffff9091169083908381818185875af1925050503d80600081146108f4576040519150601f19603f3d011682016040523d82523d6000602084013e6108f9565b606091505b505090508061088e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f77697468647261774e6174697665206661696c656400000000000000000000006044820152606401610680565b6008818154811061097457600080fd5b9060005260206000209060089182820401919006600402915054906101000a900463ffffffff1681565b6109a661115b565b60005b8161ffff168161ffff161015610b7e5760006109d56040518060200160405280600015158152506111dc565b90506000806109e688888886611298565b6007829055909250905060006109fa6114d3565b604080516101008101825284815260006020808301828152845183815280830186528486019081524260608601526080850184905260a0850187905260c0850184905260e08501849052898452600a8352949092208351815591516001830180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790559251805194955091939092610aa29260028501929101906117d7565b5060608201516003828101919091556080830151600483015560a0830151600583015560c0830151600683015560e090920151600790910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790558054906000610b1583611bb6565b9091555050600083815260096020526040908190208290555183907f5f56b4c20db9f5b294cbf6f681368de4a992a27e2de2ee702dcf2cbbfa791ec490610b5f9085815260200190565b60405180910390a2505050508080610b7690611c10565b9150506109a9565b5050505050565b6000600481905560058190556103e760065560038190556002819055610bad90600890611822565b565b6000818152600a602052604081205481906060908290819081908190610c31576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e640000000000000000000000000000006044820152606401610680565b6000888152600a6020908152604080832081516101008101835281548152600182015460ff16151581850152600282018054845181870281018701865281815292959394860193830182828015610ca757602002820191906000526020600020905b815481526020019060010190808311610c93575b50505050508152602001600382015481526020016004820154815260200160058201548152602001600682015481526020016007820160009054906101000a900460ff1615151515815250509050806000015181602001518260400151836060015184608001518560a001518660c00151975097509750975097509750975050919395979092949650565b610d3a61115b565b60005b8161ffff168161ffff161015610b7e576000610d696040518060200160405280600115158152506111dc565b9050600080610d7a88888886611561565b600782905590925090506000610d8e6114d3565b604080516101008101825284815260006020808301828152845183815280830186528486019081524260608601526080850184905260a0850187905260c08501849052600160e086018190528a8552600a84529590932084518155905194810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001695151595909517909455905180519495509193610e3592600285019201906117d7565b5060608201516003828101919091556080830151600483015560a0830151600583015560c0830151600683015560e090920151600790910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790558054906000610ea883611bb6565b9091555050600083815260096020526040908190208290555183907f5f56b4c20db9f5b294cbf6f681368de4a992a27e2de2ee702dcf2cbbfa791ec490610ef29085815260200190565b60405180910390a2505050508080610f0990611c10565b915050610d3d565b610f1961115b565b610f22816116bf565b50565b6000828152600a6020526040902054610f9a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e640000000000000000000000000000006044820152606401610680565b6000610fa46114d3565b60008481526009602052604081205491925090610fc19083611b74565b90506000610fd282620f4240611c31565b9050600554821115610fe45760058290555b6006548210610ff557600654610ff7565b815b600655600254611007578061103a565b600254611015906001611b61565b816002546004546110269190611c31565b6110309190611b61565b61103a9190611c48565b6004556002805490600061104d83611bb6565b90915550506000858152600a60209081526040909120600181810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016909117905585516110a5926002909201918701906117d7565b506000858152600a6020526040908190204260048083019190915560068201869055600880546001810182557ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee391810491909101805460079092169092026101000a63ffffffff81810219909216918716021790555490517f6c84e12b4c188e61f1b4727024a5cf05c025fa58467e5eedf763c0744c89da7b9161114c9188918891611c83565b60405180910390a15050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610bad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610680565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa8260405160240161121591511515815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915292915050565b6040517f4306d35400000000000000000000000000000000000000000000000000000000815263ffffffff85166004820152600090819073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634306d35490602401602060405180830381865afa15801561132d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113519190611cac565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16634000aea07f000000000000000000000000000000000000000000000000000000000000000083898989896040516020016113c89493929190611d29565b6040516020818303038152906040526040518463ffffffff1660e01b81526004016113f593929190611d66565b6020604051808303816000875af1158015611414573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114389190611bee565b507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663fc2a88c36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c89190611cac565b915094509492505050565b6000466114df816117b4565b1561155a57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611530573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115549190611cac565b91505090565b4391505090565b6040517f4b16093500000000000000000000000000000000000000000000000000000000815263ffffffff85166004820152600090819073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634b16093590602401602060405180830381865afa1580156115f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061161a9190611cac565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16639cfc058e82888888886040518663ffffffff1660e01b815260040161167c9493929190611d29565b60206040518083038185885af115801561169a573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906114c89190611cac565b3373ffffffffffffffffffffffffffffffffffffffff82160361173e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610680565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600061a4b18214806117c8575062066eed82145b806105f057505062066eee1490565b828054828255906000526020600020908101928215611812579160200282015b828111156118125782518255916020019190600101906117f7565b5061181e929150611843565b5090565b508054600082556007016008900490600052602060002090810190610f2291905b5b8082111561181e5760008155600101611844565b6000806040838503121561186b57600080fd5b50508035926020909101359150565b6020808252825182820181905260009190848201906040850190845b818110156118b857835163ffffffff1683529284019291840191600101611896565b50909695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806040838503121561190657600080fd5b8235915060208084013567ffffffffffffffff8082111561192657600080fd5b818601915086601f83011261193a57600080fd5b81358181111561194c5761194c6118c4565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110858211171561198f5761198f6118c4565b6040529182528482019250838101850191898311156119ad57600080fd5b938501935b828510156119cb578435845293850193928501926119b2565b8096505050505050509250929050565b6000602082840312156119ed57600080fd5b5035919050565b803563ffffffff81168114611a0857600080fd5b919050565b803561ffff81168114611a0857600080fd5b60008060008060808587031215611a3557600080fd5b611a3e856119f4565b9350611a4c60208601611a0d565b9250611a5a604086016119f4565b9150611a6860608601611a0d565b905092959194509250565b600081518084526020808501945080840160005b83811015611aa357815187529582019590820190600101611a87565b509495945050505050565b878152861515602082015260e060408201526000611acf60e0830188611a73565b90508560608301528460808301528360a08301528260c083015298975050505050505050565b600060208284031215611b0757600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114611b2b57600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156105f0576105f0611b32565b818103818111156105f0576105f0611b32565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611be757611be7611b32565b5060010190565b600060208284031215611c0057600080fd5b81518015158114611b2b57600080fd5b600061ffff808316818103611c2757611c27611b32565b6001019392505050565b80820281158282048414176105f0576105f0611b32565b600082611c7e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b838152606060208201526000611c9c6060830185611a73565b9050826040830152949350505050565b600060208284031215611cbe57600080fd5b5051919050565b6000815180845260005b81811015611ceb57602081850181015186830182015201611ccf565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b600063ffffffff808716835261ffff8616602084015280851660408401525060806060830152611d5c6080830184611cc5565b9695505050505050565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201526000611d9b6060830184611cc5565b9594505050505056fea164736f6c6343000813000a", } var VRFV2PlusWrapperLoadTestConsumerABI = VRFV2PlusWrapperLoadTestConsumerMetaData.ABI var VRFV2PlusWrapperLoadTestConsumerBin = VRFV2PlusWrapperLoadTestConsumerMetaData.Bin -func DeployVRFV2PlusWrapperLoadTestConsumer(auth *bind.TransactOpts, backend bind.ContractBackend, _link common.Address, _vrfV2PlusWrapper common.Address) (common.Address, *types.Transaction, *VRFV2PlusWrapperLoadTestConsumer, error) { +func DeployVRFV2PlusWrapperLoadTestConsumer(auth *bind.TransactOpts, backend bind.ContractBackend, _vrfV2PlusWrapper common.Address) (common.Address, *types.Transaction, *VRFV2PlusWrapperLoadTestConsumer, error) { parsed, err := VRFV2PlusWrapperLoadTestConsumerMetaData.GetAbi() if err != nil { return common.Address{}, nil, nil, err @@ -48,7 +48,7 @@ func DeployVRFV2PlusWrapperLoadTestConsumer(auth *bind.TransactOpts, backend bin return common.Address{}, nil, nil, errors.New("GetABI returned nil") } - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(VRFV2PlusWrapperLoadTestConsumerBin), backend, _link, _vrfV2PlusWrapper) + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(VRFV2PlusWrapperLoadTestConsumerBin), backend, _vrfV2PlusWrapper) if err != nil { return common.Address{}, nil, nil, err } @@ -215,6 +215,28 @@ func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerCallerS return _VRFV2PlusWrapperLoadTestConsumer.Contract.GetLinkToken(&_VRFV2PlusWrapperLoadTestConsumer.CallOpts) } +func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerCaller) GetRequestBlockTimes(opts *bind.CallOpts, offset *big.Int, quantity *big.Int) ([]uint32, error) { + var out []interface{} + err := _VRFV2PlusWrapperLoadTestConsumer.contract.Call(opts, &out, "getRequestBlockTimes", offset, quantity) + + if err != nil { + return *new([]uint32), err + } + + out0 := *abi.ConvertType(out[0], new([]uint32)).(*[]uint32) + + return out0, err + +} + +func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerSession) GetRequestBlockTimes(offset *big.Int, quantity *big.Int) ([]uint32, error) { + return _VRFV2PlusWrapperLoadTestConsumer.Contract.GetRequestBlockTimes(&_VRFV2PlusWrapperLoadTestConsumer.CallOpts, offset, quantity) +} + +func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerCallerSession) GetRequestBlockTimes(offset *big.Int, quantity *big.Int) ([]uint32, error) { + return _VRFV2PlusWrapperLoadTestConsumer.Contract.GetRequestBlockTimes(&_VRFV2PlusWrapperLoadTestConsumer.CallOpts, offset, quantity) +} + func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerCaller) GetRequestStatus(opts *bind.CallOpts, _requestId *big.Int) (GetRequestStatus, error) { @@ -360,6 +382,28 @@ func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerCallerS return _VRFV2PlusWrapperLoadTestConsumer.Contract.SLastRequestId(&_VRFV2PlusWrapperLoadTestConsumer.CallOpts) } +func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerCaller) SRequestBlockTimes(opts *bind.CallOpts, arg0 *big.Int) (uint32, error) { + var out []interface{} + err := _VRFV2PlusWrapperLoadTestConsumer.contract.Call(opts, &out, "s_requestBlockTimes", arg0) + + if err != nil { + return *new(uint32), err + } + + out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32) + + return out0, err + +} + +func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerSession) SRequestBlockTimes(arg0 *big.Int) (uint32, error) { + return _VRFV2PlusWrapperLoadTestConsumer.Contract.SRequestBlockTimes(&_VRFV2PlusWrapperLoadTestConsumer.CallOpts, arg0) +} + +func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerCallerSession) SRequestBlockTimes(arg0 *big.Int) (uint32, error) { + return _VRFV2PlusWrapperLoadTestConsumer.Contract.SRequestBlockTimes(&_VRFV2PlusWrapperLoadTestConsumer.CallOpts, arg0) +} + func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerCaller) SRequestCount(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _VRFV2PlusWrapperLoadTestConsumer.contract.Call(opts, &out, "s_requestCount") @@ -521,18 +565,6 @@ func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerTransac return _VRFV2PlusWrapperLoadTestConsumer.Contract.Reset(&_VRFV2PlusWrapperLoadTestConsumer.TransactOpts) } -func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerTransactor) SetLinkToken(opts *bind.TransactOpts, _link common.Address) (*types.Transaction, error) { - return _VRFV2PlusWrapperLoadTestConsumer.contract.Transact(opts, "setLinkToken", _link) -} - -func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerSession) SetLinkToken(_link common.Address) (*types.Transaction, error) { - return _VRFV2PlusWrapperLoadTestConsumer.Contract.SetLinkToken(&_VRFV2PlusWrapperLoadTestConsumer.TransactOpts, _link) -} - -func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerTransactorSession) SetLinkToken(_link common.Address) (*types.Transaction, error) { - return _VRFV2PlusWrapperLoadTestConsumer.Contract.SetLinkToken(&_VRFV2PlusWrapperLoadTestConsumer.TransactOpts, _link) -} - func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { return _VRFV2PlusWrapperLoadTestConsumer.contract.Transact(opts, "transferOwnership", to) } @@ -581,123 +613,6 @@ func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerTransac return _VRFV2PlusWrapperLoadTestConsumer.Contract.Receive(&_VRFV2PlusWrapperLoadTestConsumer.TransactOpts) } -type VRFV2PlusWrapperLoadTestConsumerLinkTokenSetIterator struct { - Event *VRFV2PlusWrapperLoadTestConsumerLinkTokenSet - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error -} - -func (it *VRFV2PlusWrapperLoadTestConsumerLinkTokenSetIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFV2PlusWrapperLoadTestConsumerLinkTokenSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - - select { - case log := <-it.logs: - it.Event = new(VRFV2PlusWrapperLoadTestConsumerLinkTokenSet) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -func (it *VRFV2PlusWrapperLoadTestConsumerLinkTokenSetIterator) Error() error { - return it.fail -} - -func (it *VRFV2PlusWrapperLoadTestConsumerLinkTokenSetIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -type VRFV2PlusWrapperLoadTestConsumerLinkTokenSet struct { - Link common.Address - Raw types.Log -} - -func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerFilterer) FilterLinkTokenSet(opts *bind.FilterOpts) (*VRFV2PlusWrapperLoadTestConsumerLinkTokenSetIterator, error) { - - logs, sub, err := _VRFV2PlusWrapperLoadTestConsumer.contract.FilterLogs(opts, "LinkTokenSet") - if err != nil { - return nil, err - } - return &VRFV2PlusWrapperLoadTestConsumerLinkTokenSetIterator{contract: _VRFV2PlusWrapperLoadTestConsumer.contract, event: "LinkTokenSet", logs: logs, sub: sub}, nil -} - -func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerFilterer) WatchLinkTokenSet(opts *bind.WatchOpts, sink chan<- *VRFV2PlusWrapperLoadTestConsumerLinkTokenSet) (event.Subscription, error) { - - logs, sub, err := _VRFV2PlusWrapperLoadTestConsumer.contract.WatchLogs(opts, "LinkTokenSet") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - - event := new(VRFV2PlusWrapperLoadTestConsumerLinkTokenSet) - if err := _VRFV2PlusWrapperLoadTestConsumer.contract.UnpackLog(event, "LinkTokenSet", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerFilterer) ParseLinkTokenSet(log types.Log) (*VRFV2PlusWrapperLoadTestConsumerLinkTokenSet, error) { - event := new(VRFV2PlusWrapperLoadTestConsumerLinkTokenSet) - if err := _VRFV2PlusWrapperLoadTestConsumer.contract.UnpackLog(event, "LinkTokenSet", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - type VRFV2PlusWrapperLoadTestConsumerOwnershipTransferRequestedIterator struct { Event *VRFV2PlusWrapperLoadTestConsumerOwnershipTransferRequested @@ -1238,8 +1153,6 @@ type SRequests struct { func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumer) ParseLog(log types.Log) (generated.AbigenLog, error) { switch log.Topics[0] { - case _VRFV2PlusWrapperLoadTestConsumer.abi.Events["LinkTokenSet"].ID: - return _VRFV2PlusWrapperLoadTestConsumer.ParseLinkTokenSet(log) case _VRFV2PlusWrapperLoadTestConsumer.abi.Events["OwnershipTransferRequested"].ID: return _VRFV2PlusWrapperLoadTestConsumer.ParseOwnershipTransferRequested(log) case _VRFV2PlusWrapperLoadTestConsumer.abi.Events["OwnershipTransferred"].ID: @@ -1254,10 +1167,6 @@ func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumer) Parse } } -func (VRFV2PlusWrapperLoadTestConsumerLinkTokenSet) Topic() common.Hash { - return common.HexToHash("0xc985b3c2e817dbd28c7ccd936e9b72c3de828a7bd504fa999ab8e02baeb59ca2") -} - func (VRFV2PlusWrapperLoadTestConsumerOwnershipTransferRequested) Topic() common.Hash { return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") } @@ -1283,6 +1192,8 @@ type VRFV2PlusWrapperLoadTestConsumerInterface interface { GetLinkToken(opts *bind.CallOpts) (common.Address, error) + GetRequestBlockTimes(opts *bind.CallOpts, offset *big.Int, quantity *big.Int) ([]uint32, error) + GetRequestStatus(opts *bind.CallOpts, _requestId *big.Int) (GetRequestStatus, error) @@ -1297,6 +1208,8 @@ type VRFV2PlusWrapperLoadTestConsumerInterface interface { SLastRequestId(opts *bind.CallOpts) (*big.Int, error) + SRequestBlockTimes(opts *bind.CallOpts, arg0 *big.Int) (uint32, error) + SRequestCount(opts *bind.CallOpts) (*big.Int, error) SRequests(opts *bind.CallOpts, arg0 *big.Int) (SRequests, @@ -1317,8 +1230,6 @@ type VRFV2PlusWrapperLoadTestConsumerInterface interface { Reset(opts *bind.TransactOpts) (*types.Transaction, error) - SetLinkToken(opts *bind.TransactOpts, _link common.Address) (*types.Transaction, error) - TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) WithdrawLink(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) @@ -1327,12 +1238,6 @@ type VRFV2PlusWrapperLoadTestConsumerInterface interface { Receive(opts *bind.TransactOpts) (*types.Transaction, error) - FilterLinkTokenSet(opts *bind.FilterOpts) (*VRFV2PlusWrapperLoadTestConsumerLinkTokenSetIterator, error) - - WatchLinkTokenSet(opts *bind.WatchOpts, sink chan<- *VRFV2PlusWrapperLoadTestConsumerLinkTokenSet) (event.Subscription, error) - - ParseLinkTokenSet(log types.Log) (*VRFV2PlusWrapperLoadTestConsumerLinkTokenSet, error) - FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFV2PlusWrapperLoadTestConsumerOwnershipTransferRequestedIterator, error) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFV2PlusWrapperLoadTestConsumerOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) diff --git a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 9e6719db955..1d136712c10 100644 --- a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -8,33 +8,30 @@ automation_compatible_utils: ../../contracts/solc/v0.8.19/AutomationCompatibleUt automation_consumer_benchmark: ../../contracts/solc/v0.8.16/AutomationConsumerBenchmark/AutomationConsumerBenchmark.abi ../../contracts/solc/v0.8.16/AutomationConsumerBenchmark/AutomationConsumerBenchmark.bin f52c76f1aaed4be541d82d97189d70f5aa027fc9838037dd7a7d21910c8c488e automation_forwarder_logic: ../../contracts/solc/v0.8.16/AutomationForwarderLogic/AutomationForwarderLogic.abi ../../contracts/solc/v0.8.16/AutomationForwarderLogic/AutomationForwarderLogic.bin 15ae0c367297955fdab4b552dbb10e1f2be80a8fde0efec4a4d398693e9d72b5 automation_registrar_wrapper2_1: ../../contracts/solc/v0.8.16/AutomationRegistrar2_1/AutomationRegistrar2_1.abi ../../contracts/solc/v0.8.16/AutomationRegistrar2_1/AutomationRegistrar2_1.bin eb06d853aab39d3196c593b03e555851cbe8386e0fe54a74c2479f62d14b3c42 -automation_registrar_wrapper2_3: ../../contracts/solc/v0.8.19/AutomationRegistrar2_3/AutomationRegistrar2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistrar2_3/AutomationRegistrar2_3.bin 8e18d447009546ac8ad15d0d516ad4d663d0e1ca5f723300acb604b5571b63bf -automation_registry_logic_a_wrapper_2_2: ../../contracts/solc/v0.8.19/AutomationRegistryLogicA2_2/AutomationRegistryLogicA2_2.abi ../../contracts/solc/v0.8.19/AutomationRegistryLogicA2_2/AutomationRegistryLogicA2_2.bin 58d09c16be20a6d3f70be6d06299ed61415b7796c71f176d87ce015e1294e029 -automation_registry_logic_a_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistryLogicA2_3/AutomationRegistryLogicA2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistryLogicA2_3/AutomationRegistryLogicA2_3.bin 814408fe3f1c80c709c91341a303a18c5bf758060ca4fae2686194ffa5ee5ffc +automation_registrar_wrapper2_3: ../../contracts/solc/v0.8.19/AutomationRegistrar2_3/AutomationRegistrar2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistrar2_3/AutomationRegistrar2_3.bin 20fac1208261e866caa1f3ffc71030f682a96761bebe79e5ecd71186fce86c60 +automation_registry_logic_a_wrapper_2_2: ../../contracts/solc/v0.8.19/AutomationRegistryLogicA2_2/AutomationRegistryLogicA2_2.abi ../../contracts/solc/v0.8.19/AutomationRegistryLogicA2_2/AutomationRegistryLogicA2_2.bin 2f267fb8467a15c587ce4586ac56069f7229344ad3936430d7c7624c0528a171 +automation_registry_logic_a_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistryLogicA2_3/AutomationRegistryLogicA2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistryLogicA2_3/AutomationRegistryLogicA2_3.bin 71e1f5b676306de9e2d7edc4f44e87cb18e542337a8c4756f554c4e47d213e5a automation_registry_logic_b_wrapper_2_2: ../../contracts/solc/v0.8.19/AutomationRegistryLogicB2_2/AutomationRegistryLogicB2_2.abi ../../contracts/solc/v0.8.19/AutomationRegistryLogicB2_2/AutomationRegistryLogicB2_2.bin a6d33dfbbfb0ff253eb59a51f4f6d6d4c22ea5ec95aae52d25d49a312b37a22f -automation_registry_logic_b_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistryLogicB2_3/AutomationRegistryLogicB2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistryLogicB2_3/AutomationRegistryLogicB2_3.bin a6d3aa3dd5aa64887e1f73d03cc35dbb6c3e2f3e311d81ae5496ef96cfd01bda -automation_registry_wrapper_2_2: ../../contracts/solc/v0.8.19/AutomationRegistry2_2/AutomationRegistry2_2.abi ../../contracts/solc/v0.8.19/AutomationRegistry2_2/AutomationRegistry2_2.bin eca1187a878b622ef3fced041a28a4229d45dd797d95630838ff6351b6afc437 -automation_registry_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistry2_3/AutomationRegistry2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistry2_3/AutomationRegistry2_3.bin 6127aa4541dbecc98e01486f43fa8bc6934f56037a376e2f9a97dac2870165fe +automation_registry_logic_b_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistryLogicB2_3/AutomationRegistryLogicB2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistryLogicB2_3/AutomationRegistryLogicB2_3.bin 47e52b9cba609322c6996293ff5de64cf3b1c1f2e983ff0fe342beaeabfc7ea4 +automation_registry_wrapper_2_2: ../../contracts/solc/v0.8.19/AutomationRegistry2_2/AutomationRegistry2_2.abi ../../contracts/solc/v0.8.19/AutomationRegistry2_2/AutomationRegistry2_2.bin de60f69878e9b32a291a001c91fc8636544c2cfbd9b507c8c1a4873b602bfb62 +automation_registry_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistry2_3/AutomationRegistry2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistry2_3/AutomationRegistry2_3.bin 172ca6c3a5b3e8f43443ae21435efb98dcb0651b0bb8e7ef25761d4761abe12a automation_utils_2_1: ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.abi ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.bin 815b17b63f15d26a0274b962eefad98cdee4ec897ead58688bbb8e2470e585f5 automation_utils_2_2: ../../contracts/solc/v0.8.19/AutomationUtils2_2/AutomationUtils2_2.abi ../../contracts/solc/v0.8.19/AutomationUtils2_2/AutomationUtils2_2.bin 8743f6231aaefa3f2a0b2d484258070d506e2d0860690e66890dccc3949edb2e -automation_utils_2_3: ../../contracts/solc/v0.8.19/AutomationUtils2_3/AutomationUtils2_3.abi ../../contracts/solc/v0.8.19/AutomationUtils2_3/AutomationUtils2_3.bin 6c774a1924c04f545b1dd8e7b2463293cdaeeced43e8ef7f34effc490cbe7f4a -batch_blockhash_store: ../../contracts/solc/v0.8.6/BatchBlockhashStore/BatchBlockhashStore.abi ../../contracts/solc/v0.8.6/BatchBlockhashStore/BatchBlockhashStore.bin 14356c48ef70f66ef74f22f644450dbf3b2a147c1b68deaa7e7d1eb8ffab15db +automation_utils_2_3: ../../contracts/solc/v0.8.19/AutomationUtils2_3/AutomationUtils2_3.abi ../../contracts/solc/v0.8.19/AutomationUtils2_3/AutomationUtils2_3.bin 11e2b481dc9a4d936e3443345d45d2cc571164459d214917b42a8054b295393b +batch_blockhash_store: ../../contracts/solc/v0.8.19/BatchBlockhashStore/BatchBlockhashStore.abi ../../contracts/solc/v0.8.19/BatchBlockhashStore/BatchBlockhashStore.bin 6a7444e5e3e95c370de2442ff53740e535d81ec9c6fb84e8b3c53742e4aaa38e batch_vrf_coordinator_v2: ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2/BatchVRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2/BatchVRFCoordinatorV2.bin d0a54963260d8c1f1bbd984b758285e6027cfb5a7e42701bcb562ab123219332 -batch_vrf_coordinator_v2plus: ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.bin 73cb626b5cb2c3464655b61b8ac42fe7a1963fe25e6a5eea40b8e4d5bff3de36 -blockhash_store: ../../contracts/solc/v0.8.6/BlockhashStore/BlockhashStore.abi ../../contracts/solc/v0.8.6/BlockhashStore/BlockhashStore.bin 12b0662f1636a341c8863bdec7a20f2ddd97c3a4fd1a7ae353fe316609face4e +batch_vrf_coordinator_v2plus: ../../contracts/solc/v0.8.19/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.19/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.bin ace5851ac0b419ee93f3c716ee13e77c530531248119f3970657f84dfcd73c6e +blockhash_store: ../../contracts/solc/v0.8.19/BlockhashStore/BlockhashStore.abi ../../contracts/solc/v0.8.19/BlockhashStore/BlockhashStore.bin 31b118f9577240c8834c35f8b5a1440e82a6ca8aea702970de2601824b6ab0e1 chain_module_base: ../../contracts/solc/v0.8.19/ChainModuleBase/ChainModuleBase.abi ../../contracts/solc/v0.8.19/ChainModuleBase/ChainModuleBase.bin 39dfce79330e921e5c169051b11c6e5ea15cd4db5a7b09c06aabbe9658148915 chain_reader_example: ../../contracts/solc/v0.8.19/ChainReaderTestContract/LatestValueHolder.abi ../../contracts/solc/v0.8.19/ChainReaderTestContract/LatestValueHolder.bin de88c7e68de36b96aa2bec844bdc96fcd7c9017b38e25062b3b9f9cec42c814f chain_specific_util_helper: ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper/ChainSpecificUtilHelper.abi ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper/ChainSpecificUtilHelper.bin 5f10664e31abc768f4a37901cae7a3bef90146180f97303e5a1bde5a08d84595 -consumer_wrapper: ../../contracts/solc/v0.7/Consumer/Consumer.abi ../../contracts/solc/v0.7/Consumer/Consumer.bin 894d1cbd920dccbd36d92918c1037c6ded34f66f417ccb18ec3f33c64ef83ec5 cron_upkeep_factory_wrapper: ../../contracts/solc/v0.8.6/CronUpkeepFactory/CronUpkeepFactory.abi - dacb0f8cdf54ae9d2781c5e720fc314b32ed5e58eddccff512c75d6067292cd7 cron_upkeep_wrapper: ../../contracts/solc/v0.8.6/CronUpkeepFactory/CronUpkeep.abi - 362fcfcf30a6ab3acff83095ea4b2b9056dd5e9dcb94bc5411aae58995d22709 dummy_protocol_wrapper: ../../contracts/solc/v0.8.16/DummyProtocol/DummyProtocol.abi ../../contracts/solc/v0.8.16/DummyProtocol/DummyProtocol.bin 583a448170b13abf7ed64e406e8177d78c9e55ab44efd141eee60de23a71ee3b -flags_wrapper: ../../contracts/solc/v0.6/Flags/Flags.abi ../../contracts/solc/v0.6/Flags/Flags.bin 2034d1b562ca37a63068851915e3703980276e8d5f7db6db8a3351a49d69fc4a -flux_aggregator_wrapper: ../../contracts/solc/v0.6/FluxAggregator/FluxAggregator.abi ../../contracts/solc/v0.6/FluxAggregator/FluxAggregator.bin a3b0a6396c4aa3b5ee39b3c4bd45efc89789d4859379a8a92caca3a0496c5794 gas_wrapper: ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2/KeeperRegistryCheckUpkeepGasUsageWrapper1_2.abi ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2/KeeperRegistryCheckUpkeepGasUsageWrapper1_2.bin 4a5dcdac486d18fcd58e3488c15c1710ae76b977556a3f3191bd269a4bc75723 gas_wrapper_mock: ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.abi ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.bin a9b08f18da59125c6fc305855710241f3d35161b8b9f3e3f635a7b1d5c6da9c8 i_automation_registry_master_wrapper_2_2: ../../contracts/solc/v0.8.19/IAutomationRegistryMaster/IAutomationRegistryMaster.abi ../../contracts/solc/v0.8.19/IAutomationRegistryMaster/IAutomationRegistryMaster.bin 9ff7087179f89f9b05964ebc3e71332fce11f1b8e85058f7b16b3bc0dd6fb96b -i_automation_registry_master_wrapper_2_3: ../../contracts/solc/v0.8.19/IAutomationRegistryMaster2_3/IAutomationRegistryMaster2_3.abi ../../contracts/solc/v0.8.19/IAutomationRegistryMaster2_3/IAutomationRegistryMaster2_3.bin 990075f64a47104706bf9a41f099b4cb09285884689269274870ab527fcb1f14 +i_automation_registry_master_wrapper_2_3: ../../contracts/solc/v0.8.19/IAutomationRegistryMaster2_3/IAutomationRegistryMaster2_3.abi ../../contracts/solc/v0.8.19/IAutomationRegistryMaster2_3/IAutomationRegistryMaster2_3.bin 16b346a64126554bad0929f49ce020d886cc7203d03ca52c4537daf273b4c369 i_automation_v21_plus_common: ../../contracts/solc/v0.8.19/IAutomationV21PlusCommon/IAutomationV21PlusCommon.abi ../../contracts/solc/v0.8.19/IAutomationV21PlusCommon/IAutomationV21PlusCommon.bin e8a601ec382c0a2e83c49759de13b0622b5e04e6b95901e96a1e9504329e594c i_chain_module: ../../contracts/solc/v0.8.19/IChainModule/IChainModule.abi ../../contracts/solc/v0.8.19/IChainModule/IChainModule.bin 383611981c86c70522f41b8750719faacc7d7933a22849d5004799ebef3371fa i_keeper_registry_master_wrapper_2_1: ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.abi ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.bin ee0f150b3afbab2df3d24ff3f4c87851efa635da30db04cd1f70cb4e185a1781 @@ -46,42 +43,30 @@ keeper_registrar_wrapper1_2_mock: ../../contracts/solc/v0.8.6/KeeperRegistrar1_2 keeper_registrar_wrapper2_0: ../../contracts/solc/v0.8.6/KeeperRegistrar2_0/KeeperRegistrar2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistrar2_0/KeeperRegistrar2_0.bin 647f125c2f0dafabcdc545cb77b15dc2ec3ea9429357806813179b1fd555c2d2 keeper_registry_logic1_3: ../../contracts/solc/v0.8.6/KeeperRegistryLogic1_3/KeeperRegistryLogic1_3.abi ../../contracts/solc/v0.8.6/KeeperRegistryLogic1_3/KeeperRegistryLogic1_3.bin 903f8b9c8e25425ca6d0b81b89e339d695a83630bfbfa24a6f3b38869676bc5a keeper_registry_logic2_0: ../../contracts/solc/v0.8.6/KeeperRegistryLogic2_0/KeeperRegistryLogic2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistryLogic2_0/KeeperRegistryLogic2_0.bin d69d2bc8e4844293dbc2d45abcddc50b84c88554ecccfa4fa77c0ca45ec80871 -keeper_registry_logic_a_wrapper_2_1: ../../contracts/solc/v0.8.16/KeeperRegistryLogicA2_1/KeeperRegistryLogicA2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistryLogicA2_1/KeeperRegistryLogicA2_1.bin 77481ab75c9aa86a62a7b2a708599b5ea1a6346ed1c0def6d4826e7ae523f1ee +keeper_registry_logic_a_wrapper_2_1: ../../contracts/solc/v0.8.16/KeeperRegistryLogicA2_1/KeeperRegistryLogicA2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistryLogicA2_1/KeeperRegistryLogicA2_1.bin a2327779e652a2bbd2ed2f4a7b904b696dbefd5b16e73d39be87188bde654d61 keeper_registry_logic_b_wrapper_2_1: ../../contracts/solc/v0.8.16/KeeperRegistryLogicB2_1/KeeperRegistryLogicB2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistryLogicB2_1/KeeperRegistryLogicB2_1.bin 83b0cc20c6aa437b824f424b3e16ddcb18ab08bfa64398f143dbbf78f953dfef -keeper_registry_wrapper1_1: ../../contracts/solc/v0.7/KeeperRegistry1_1/KeeperRegistry1_1.abi ../../contracts/solc/v0.7/KeeperRegistry1_1/KeeperRegistry1_1.bin 6ce079f2738f015f7374673a2816e8e9787143d00b780ea7652c8aa9ad9e1e20 -keeper_registry_wrapper1_1_mock: ../../contracts/solc/v0.7/KeeperRegistry1_1Mock/KeeperRegistry1_1Mock.abi ../../contracts/solc/v0.7/KeeperRegistry1_1Mock/KeeperRegistry1_1Mock.bin 98ddb3680e86359de3b5d17e648253ba29a84703f087a1b52237824003a8c6df keeper_registry_wrapper1_2: ../../contracts/solc/v0.8.6/KeeperRegistry1_2/KeeperRegistry1_2.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_2/KeeperRegistry1_2.bin f6f48cc6a4e03ffc987a017041417a1db78566275ec8ed7673fbfc9052ce0215 keeper_registry_wrapper1_3: ../../contracts/solc/v0.8.6/KeeperRegistry1_3/KeeperRegistry1_3.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_3/KeeperRegistry1_3.bin d4dc760b767ae274ee25c4a604ea371e1fa603a7b6421b69efb2088ad9e8abb3 keeper_registry_wrapper2_0: ../../contracts/solc/v0.8.6/KeeperRegistry2_0/KeeperRegistry2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistry2_0/KeeperRegistry2_0.bin c32dea7d5ef66b7c58ddc84ddf69aa44df1b3ae8601fbc271c95be4ff5853056 -keeper_registry_wrapper_2_1: ../../contracts/solc/v0.8.16/KeeperRegistry2_1/KeeperRegistry2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistry2_1/KeeperRegistry2_1.bin 3043b862a9c3d30b683f646739e42b41a09ad4922f6ea502bfef7c9c12fbfb5e +keeper_registry_wrapper_2_1: ../../contracts/solc/v0.8.16/KeeperRegistry2_1/KeeperRegistry2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistry2_1/KeeperRegistry2_1.bin 11d36cb9eab0e136a2c3224709f7df17711756a126127e8c82326ce0a2e2b4f4 keepers_vrf_consumer: ../../contracts/solc/v0.8.6/KeepersVRFConsumer/KeepersVRFConsumer.abi ../../contracts/solc/v0.8.6/KeepersVRFConsumer/KeepersVRFConsumer.bin fa75572e689c9e84705c63e8dbe1b7b8aa1a8fe82d66356c4873d024bb9166e8 log_emitter: ../../contracts/solc/v0.8.19/LogEmitter/LogEmitter.abi ../../contracts/solc/v0.8.19/LogEmitter/LogEmitter.bin 4b129ab93432c95ff9143f0631323e189887668889e0b36ccccf18a571e41ccf log_triggered_streams_lookup_wrapper: ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup/LogTriggeredStreamsLookup.abi ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup/LogTriggeredStreamsLookup.bin 920fff3b662909f12ed11b47d168036ffa74ad52070a94e2fa26cdad5e428b4e log_upkeep_counter_wrapper: ../../contracts/solc/v0.8.6/LogUpkeepCounter/LogUpkeepCounter.abi ../../contracts/solc/v0.8.6/LogUpkeepCounter/LogUpkeepCounter.bin 42426bbb83f96dfbe55fc576d6c65020eaeed690e2289cf99b0c4aa810a5f4ec mock_aggregator_proxy: ../../contracts/solc/v0.8.6/MockAggregatorProxy/MockAggregatorProxy.abi ../../contracts/solc/v0.8.6/MockAggregatorProxy/MockAggregatorProxy.bin b16c108f3dd384c342ddff5e94da7c0a8d39d1be5e3d8f2cf61ecc7f0e50ff42 -mock_ethlink_aggregator_wrapper: ../../contracts/solc/v0.6/MockETHLINKAggregator/MockETHLINKAggregator.abi ../../contracts/solc/v0.6/MockETHLINKAggregator/MockETHLINKAggregator.bin 1c52c24f797b8482aa12b8251dcea1c072827bd5b3426b822621261944b99ca0 -mock_gas_aggregator_wrapper: ../../contracts/solc/v0.6/MockGASAggregator/MockGASAggregator.abi ../../contracts/solc/v0.6/MockGASAggregator/MockGASAggregator.bin bacbb1ea4dc6beac0db8a13ca5c75e2fd61b903d70feea9b3b1c8b10fe8df4f3 -multiwordconsumer_wrapper: ../../contracts/solc/v0.7/MultiWordConsumer/MultiWordConsumer.abi ../../contracts/solc/v0.7/MultiWordConsumer/MultiWordConsumer.bin 6e68abdf614e3ed0f5066c1b5f9d7c1199f1e7c5c5251fe8a471344a59afc6ba offchain_aggregator_wrapper: OffchainAggregator/OffchainAggregator.abi - 5c8d6562e94166d4790f1ee6e4321d359d9f7262e6c5452a712b1f1c896f45cf -operator_factory: ../../contracts/solc/v0.8.19/OperatorFactory/OperatorFactory.abi ../../contracts/solc/v0.8.19/OperatorFactory/OperatorFactory.bin 357203fabe3df436eb015e2d5094374c6967a9fc922ac8edc265b27aac4d67cf -operator_wrapper: ../../contracts/solc/v0.8.19/Operator/Operator.abi ../../contracts/solc/v0.8.19/Operator/Operator.bin c5e1db81070d940a82ef100b0bce38e055593cbeebbc73abf9d45c30d6020cd2 +operator_factory: ../../contracts/solc/v0.8.19/OperatorFactory/OperatorFactory.abi ../../contracts/solc/v0.8.19/OperatorFactory/OperatorFactory.bin b387ab42b7b5dd7d65d45a6d07e9ff7a36f7b46749c4e2596f8f3635d35a8e4e +operator_wrapper: ../../contracts/solc/v0.8.19/Operator/Operator.abi ../../contracts/solc/v0.8.19/Operator/Operator.bin 038a19aad41125dc6c67b920e0d2b349b6b07c4106db19df5f5109170aabfa07 optimism_module: ../../contracts/solc/v0.8.19/OptimismModule/OptimismModule.abi ../../contracts/solc/v0.8.19/OptimismModule/OptimismModule.bin a1f8ee97e12b1b2311db03b94dc52b91f3c2e9a2f8d554031a9c7b41e4432280 -oracle_wrapper: ../../contracts/solc/v0.6/Oracle/Oracle.abi ../../contracts/solc/v0.6/Oracle/Oracle.bin 7af2fbac22a6e8c2847e8e685a5400cac5101d72ddf5365213beb79e4dede43a perform_data_checker_wrapper: ../../contracts/solc/v0.8.16/PerformDataChecker/PerformDataChecker.abi ../../contracts/solc/v0.8.16/PerformDataChecker/PerformDataChecker.bin 48d8309c2117c29a24e1155917ab0b780956b2cd6a8a39ef06ae66a7f6d94f73 scroll_module: ../../contracts/solc/v0.8.19/ScrollModule/ScrollModule.abi ../../contracts/solc/v0.8.19/ScrollModule/ScrollModule.bin 8de157cb7e5bc78146548212803d60926c8483aca7e912d802b7c66dc5d2ab11 -simple_log_upkeep_counter_wrapper: ../../contracts/solc/v0.8.6/SimpleLogUpkeepCounter/SimpleLogUpkeepCounter.abi ../../contracts/solc/v0.8.6/SimpleLogUpkeepCounter/SimpleLogUpkeepCounter.bin a2532ca73e227f846be39b52fa63cfa9d088116c3cfc311d972fe8db886fa915 -solidity_vrf_consumer_interface: ../../contracts/solc/v0.6/VRFConsumer/VRFConsumer.abi ../../contracts/solc/v0.6/VRFConsumer/VRFConsumer.bin ecc99378aa798014de9db42b2eb81320778b0663dbe208008dad75ccdc1d4366 +simple_log_upkeep_counter_wrapper: ../../contracts/solc/v0.8.6/SimpleLogUpkeepCounter/SimpleLogUpkeepCounter.abi ../../contracts/solc/v0.8.6/SimpleLogUpkeepCounter/SimpleLogUpkeepCounter.bin 7557d117a066cd8cf35f635bc085ee11795442073c18f8610ede9037b74fd814 solidity_vrf_consumer_interface_v08: ../../contracts/solc/v0.8.6/VRFConsumer/VRFConsumer.abi ../../contracts/solc/v0.8.6/VRFConsumer/VRFConsumer.bin b14f9136b15e3dc9d6154d5700f3ed4cf88ddc4f70f20c3bb57fc46050904c8f -solidity_vrf_coordinator_interface: ../../contracts/solc/v0.6/VRFCoordinator/VRFCoordinator.abi ../../contracts/solc/v0.6/VRFCoordinator/VRFCoordinator.bin a23d3c395156804788c7f6fbda2994e8f7184304c0f0c9f2c4ddeaf073d346d2 -solidity_vrf_request_id: ../../contracts/solc/v0.6/VRFRequestIDBaseTestHelper/VRFRequestIDBaseTestHelper.abi ../../contracts/solc/v0.6/VRFRequestIDBaseTestHelper/VRFRequestIDBaseTestHelper.bin 383b59e861732c1911ddb7b002c6158608496ce889979296527215fd0366b318 solidity_vrf_request_id_v08: ../../contracts/solc/v0.8.6/VRFRequestIDBaseTestHelper/VRFRequestIDBaseTestHelper.abi ../../contracts/solc/v0.8.6/VRFRequestIDBaseTestHelper/VRFRequestIDBaseTestHelper.bin f2559015d6f3e5d285c57b011be9b2300632e93dd6c4524e58202d6200f09edc solidity_vrf_v08_verifier_wrapper: ../../contracts/solc/v0.8.6/VRFTestHelper/VRFTestHelper.abi ../../contracts/solc/v0.8.6/VRFTestHelper/VRFTestHelper.bin f37f8b21a81c113085c6137835a2246db6ebda07da455c4f2b5c7ec60c725c3b -solidity_vrf_verifier_wrapper: ../../contracts/solc/v0.6/VRFTestHelper/VRFTestHelper.abi ../../contracts/solc/v0.6/VRFTestHelper/VRFTestHelper.bin 44c2b67d8d2990ab580453deb29d63508c6147a3dc49908a1db563bef06e6474 -solidity_vrf_wrapper: ../../contracts/solc/v0.6/VRF/VRF.abi ../../contracts/solc/v0.6/VRF/VRF.bin 04ede5b83c06ba5b76ef99c081c72928007d8a7aaefcf21449a46a07cbd4bfc2 streams_lookup_compatible_interface: ../../contracts/solc/v0.8.16/StreamsLookupCompatibleInterface/StreamsLookupCompatibleInterface.abi ../../contracts/solc/v0.8.16/StreamsLookupCompatibleInterface/StreamsLookupCompatibleInterface.bin 2861f553fb4731e89126b13319462df674727005a51982d1e617e2c2e44fa422 streams_lookup_upkeep_wrapper: ../../contracts/solc/v0.8.16/StreamsLookupUpkeep/StreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/StreamsLookupUpkeep/StreamsLookupUpkeep.bin 37e3a61091cc2a156539dd4aaff987e07577118aa02e97931a647df55705465e -test_api_consumer_wrapper: ../../contracts/solc/v0.6/TestAPIConsumer/TestAPIConsumer.abi ../../contracts/solc/v0.6/TestAPIConsumer/TestAPIConsumer.bin ed10893cb18894c18e275302329c955f14ea2de37ee044f84aa1e067ac5ea71e -trusted_blockhash_store: ../../contracts/solc/v0.8.6/TrustedBlockhashStore/TrustedBlockhashStore.abi ../../contracts/solc/v0.8.6/TrustedBlockhashStore/TrustedBlockhashStore.bin 98cb0dc06c15af5dcd3b53bdfc98e7ed2489edc96a42203294ac2fc0efdda02b +trusted_blockhash_store: ../../contracts/solc/v0.8.19/TrustedBlockhashStore/TrustedBlockhashStore.abi ../../contracts/solc/v0.8.19/TrustedBlockhashStore/TrustedBlockhashStore.bin 1570663ef6feabf8660a93e85d2427ad8e7dabcfa5b418d308c62132451c5662 type_and_version_interface_wrapper: ../../contracts/solc/v0.8.6/KeeperRegistry1_2/TypeAndVersionInterface.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_2/TypeAndVersionInterface.bin bc9c3a6e73e3ebd5b58754df0deeb3b33f4bb404d5709bb904aed51d32f4b45e upkeep_counter_wrapper: ../../contracts/solc/v0.8.16/UpkeepCounter/UpkeepCounter.abi ../../contracts/solc/v0.8.16/UpkeepCounter/UpkeepCounter.bin cef953186d12ac802e54d17c897d01605b60bbe0ce2df3b4cf2c31c5c3168b35 upkeep_perform_counter_restrictive_wrapper: ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive/UpkeepPerformCounterRestrictive.abi ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive/UpkeepPerformCounterRestrictive.bin 20955b21acceb58355fa287b29194a73edf5937067ba7140667301017cb2b24c @@ -90,31 +75,31 @@ verifiable_load_log_trigger_upkeep_wrapper: ../../contracts/solc/v0.8.16/Verifia verifiable_load_streams_lookup_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep/VerifiableLoadStreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep/VerifiableLoadStreamsLookupUpkeep.bin 58ef2b6d008d8247055ecb042bf88eff3ebee808fcb28179fb6b14684a159f3b verifiable_load_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadUpkeep/VerifiableLoadUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadUpkeep/VerifiableLoadUpkeep.bin ff2bf9a9a29557ebfbebc6c5abf9bff6932a50d1c71440feb513504cb3b2d055 vrf_consumer_v2: ../../contracts/solc/v0.8.6/VRFConsumerV2/VRFConsumerV2.abi ../../contracts/solc/v0.8.6/VRFConsumerV2/VRFConsumerV2.bin 9ef258bf8e9f8d880fd229ceb145593d91e24fc89366baa0bf19169c5787d15f -vrf_consumer_v2_plus_upgradeable_example: ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample/VRFConsumerV2PlusUpgradeableExample.abi ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample/VRFConsumerV2PlusUpgradeableExample.bin 3155c611e4d6882e9324b6e975033b31356776ea8b031ca63d63da37589d583b +vrf_consumer_v2_plus_upgradeable_example: ../../contracts/solc/v0.8.19/VRFConsumerV2PlusUpgradeableExample/VRFConsumerV2PlusUpgradeableExample.abi ../../contracts/solc/v0.8.19/VRFConsumerV2PlusUpgradeableExample/VRFConsumerV2PlusUpgradeableExample.bin 02a48cf194946ed680f4fa224bb8aebd95cc79cb4349ec382b9673605c079ac4 vrf_consumer_v2_upgradeable_example: ../../contracts/solc/v0.8.6/VRFConsumerV2UpgradeableExample/VRFConsumerV2UpgradeableExample.abi ../../contracts/solc/v0.8.6/VRFConsumerV2UpgradeableExample/VRFConsumerV2UpgradeableExample.bin f1790a9a2f2a04c730593e483459709cb89e897f8a19d7a3ac0cfe6a97265e6e vrf_coordinator_mock: ../../contracts/solc/v0.8.6/VRFCoordinatorMock/VRFCoordinatorMock.abi ../../contracts/solc/v0.8.6/VRFCoordinatorMock/VRFCoordinatorMock.bin 5c495cf8df1f46d8736b9150cdf174cce358cb8352f60f0d5bb9581e23920501 vrf_coordinator_test_v2: ../../contracts/solc/v0.8.6/VRFCoordinatorTestV2/VRFCoordinatorTestV2.abi ../../contracts/solc/v0.8.6/VRFCoordinatorTestV2/VRFCoordinatorTestV2.bin eaefd785c38bac67fb11a7fc2737ab2da68c988ca170e7db8ff235c80893e01c vrf_coordinator_v2: ../../contracts/solc/v0.8.6/VRFCoordinatorV2/VRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2/VRFCoordinatorV2.bin 295f35ce282060317dfd01f45959f5a2b05ba26913e422fbd4fb6bf90b107006 -vrf_coordinator_v2_5: ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5/VRFCoordinatorV2_5.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5/VRFCoordinatorV2_5.bin 6b4c50e8c8bbe877e5450d679e968dbde896f7c9043d29f3ecf79aefc28a0ef3 -vrf_coordinator_v2_plus_v2_example: ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example/VRFCoordinatorV2Plus_V2Example.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example/VRFCoordinatorV2Plus_V2Example.bin 4a5b86701983b1b65f0a8dfa116b3f6d75f8f706fa274004b57bdf5992e4cec3 -vrf_coordinator_v2plus_interface: ../../contracts/solc/v0.8.6/IVRFCoordinatorV2PlusInternal/IVRFCoordinatorV2PlusInternal.abi ../../contracts/solc/v0.8.6/IVRFCoordinatorV2PlusInternal/IVRFCoordinatorV2PlusInternal.bin 86b8e23aab28c5b98e3d2384dc4f702b093e382dc985c88101278e6e4bf6f7b8 +vrf_coordinator_v2_5: ../../contracts/solc/v0.8.19/VRFCoordinatorV2_5/VRFCoordinatorV2_5.abi ../../contracts/solc/v0.8.19/VRFCoordinatorV2_5/VRFCoordinatorV2_5.bin 91703cf40a54fecceed8cc706645e09b80a0f0dda93dec343addb699191d8cd4 +vrf_coordinator_v2_plus_v2_example: ../../contracts/solc/v0.8.19/VRFCoordinatorV2Plus_V2Example/VRFCoordinatorV2Plus_V2Example.abi ../../contracts/solc/v0.8.19/VRFCoordinatorV2Plus_V2Example/VRFCoordinatorV2Plus_V2Example.bin 75eddfee13481e4fa1031762a230cdb2db78fa80d48faa0db555dd1c202aa347 +vrf_coordinator_v2plus_interface: ../../contracts/solc/v0.8.19/IVRFCoordinatorV2PlusInternal/IVRFCoordinatorV2PlusInternal.abi ../../contracts/solc/v0.8.19/IVRFCoordinatorV2PlusInternal/IVRFCoordinatorV2PlusInternal.bin 86b8e23aab28c5b98e3d2384dc4f702b093e382dc985c88101278e6e4bf6f7b8 vrf_external_sub_owner_example: ../../contracts/solc/v0.8.6/VRFExternalSubOwnerExample/VRFExternalSubOwnerExample.abi ../../contracts/solc/v0.8.6/VRFExternalSubOwnerExample/VRFExternalSubOwnerExample.bin 14f888eb313930b50233a6f01ea31eba0206b7f41a41f6311670da8bb8a26963 vrf_load_test_external_sub_owner: ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner/VRFLoadTestExternalSubOwner.abi ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner/VRFLoadTestExternalSubOwner.bin 2097faa70265e420036cc8a3efb1f1e0836ad2d7323b295b9a26a125dbbe6c7d vrf_load_test_ownerless_consumer: ../../contracts/solc/v0.8.6/VRFLoadTestOwnerlessConsumer/VRFLoadTestOwnerlessConsumer.abi ../../contracts/solc/v0.8.6/VRFLoadTestOwnerlessConsumer/VRFLoadTestOwnerlessConsumer.bin 74f914843cbc70b9c3079c3e1c709382ce415225e8bb40113e7ac018bfcb0f5c vrf_load_test_with_metrics: ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics/VRFV2LoadTestWithMetrics.abi ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics/VRFV2LoadTestWithMetrics.bin c9621c52d216a090ff6bbe942f1b75d2bce8658a27323c3789e5e14b523277ee vrf_log_emitter: ../../contracts/solc/v0.8.19/VRFLogEmitter/VRFLogEmitter.abi ../../contracts/solc/v0.8.19/VRFLogEmitter/VRFLogEmitter.bin 15f491d445ac4d0c712d1cbe4e5054c759b080bf20de7d54bfe2a82cde4dcf06 vrf_malicious_consumer_v2: ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2/VRFMaliciousConsumerV2.abi ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2/VRFMaliciousConsumerV2.bin 9755fa8ffc7f5f0b337d5d413d77b0c9f6cd6f68c31727d49acdf9d4a51bc522 -vrf_malicious_consumer_v2_plus: ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus/VRFMaliciousConsumerV2Plus.abi ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus/VRFMaliciousConsumerV2Plus.bin 9acb4f7ac1e46ed7c3b2c4b377930a4531d2b0953fb09ed828464117c495edbd +vrf_malicious_consumer_v2_plus: ../../contracts/solc/v0.8.19/VRFMaliciousConsumerV2Plus/VRFMaliciousConsumerV2Plus.abi ../../contracts/solc/v0.8.19/VRFMaliciousConsumerV2Plus/VRFMaliciousConsumerV2Plus.bin 41e00ab611e1b62589130cbb54e8420bfd31c90d842847ec6d9f991a9fec4027 vrf_mock_ethlink_aggregator: ../../contracts/solc/v0.8.6/VRFMockETHLINKAggregator/VRFMockETHLINKAggregator.abi ../../contracts/solc/v0.8.6/VRFMockETHLINKAggregator/VRFMockETHLINKAggregator.bin 3657f8c552147eb55d7538fa7d8012c1a983d8c5184610de60600834a72e006b vrf_owner: ../../contracts/solc/v0.8.6/VRFOwner/VRFOwner.abi ../../contracts/solc/v0.8.6/VRFOwner/VRFOwner.bin eccfae5ee295b5850e22f61240c469f79752b8d9a3bac5d64aec7ac8def2f6cb vrf_owner_test_consumer: ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer/VRFV2OwnerTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer/VRFV2OwnerTestConsumer.bin 6969de242efe8f366ae4097fc279d9375c8e2d0307aaa322e31f2ce6b8c1909a vrf_ownerless_consumer_example: ../../contracts/solc/v0.8.6/VRFOwnerlessConsumerExample/VRFOwnerlessConsumerExample.abi ../../contracts/solc/v0.8.6/VRFOwnerlessConsumerExample/VRFOwnerlessConsumerExample.bin 9893b3805863273917fb282eed32274e32aa3d5c2a67a911510133e1218132be vrf_single_consumer_example: ../../contracts/solc/v0.8.6/VRFSingleConsumerExample/VRFSingleConsumerExample.abi ../../contracts/solc/v0.8.6/VRFSingleConsumerExample/VRFSingleConsumerExample.bin 892a5ed35da2e933f7fd7835cd6f7f70ef3aa63a9c03a22c5b1fd026711b0ece vrf_v2_consumer_wrapper: ../../contracts/solc/v0.8.6/VRFv2Consumer/VRFv2Consumer.abi ../../contracts/solc/v0.8.6/VRFv2Consumer/VRFv2Consumer.bin 12368b3b5e06392440143a13b94c0ea2f79c4c897becc3b060982559e10ace40 -vrf_v2plus_load_test_with_metrics: ../../contracts/solc/v0.8.6/VRFV2PlusLoadTestWithMetrics/VRFV2PlusLoadTestWithMetrics.abi ../../contracts/solc/v0.8.6/VRFV2PlusLoadTestWithMetrics/VRFV2PlusLoadTestWithMetrics.bin e8c6888df57e63e8b9a835b68e9e575631a2385feeb08c02c59732f699cc1f58 -vrf_v2plus_single_consumer: ../../contracts/solc/v0.8.6/VRFV2PlusSingleConsumerExample/VRFV2PlusSingleConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusSingleConsumerExample/VRFV2PlusSingleConsumerExample.bin 12b5d322db7dbf8af71955699e411109a4cc40811b606273ea0b5ecc8dbc639d -vrf_v2plus_sub_owner: ../../contracts/solc/v0.8.6/VRFV2PlusExternalSubOwnerExample/VRFV2PlusExternalSubOwnerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusExternalSubOwnerExample/VRFV2PlusExternalSubOwnerExample.bin 7b4f5ffe8fc293d2f4294d3d8348ed8dd480e909cef0743393095e5b20dc9c34 -vrf_v2plus_upgraded_version: ../../contracts/solc/v0.8.6/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.bin 1695b5f9990dfe1c7d71c6f47f4be3488be15d09def9d984ffbc1db0f207a08a +vrf_v2plus_load_test_with_metrics: ../../contracts/solc/v0.8.19/VRFV2PlusLoadTestWithMetrics/VRFV2PlusLoadTestWithMetrics.abi ../../contracts/solc/v0.8.19/VRFV2PlusLoadTestWithMetrics/VRFV2PlusLoadTestWithMetrics.bin af2452b489f4c252c69ffea48fbd601cd1bff69b2e1ce64b9b596380efaeb824 +vrf_v2plus_single_consumer: ../../contracts/solc/v0.8.19/VRFV2PlusSingleConsumerExample/VRFV2PlusSingleConsumerExample.abi ../../contracts/solc/v0.8.19/VRFV2PlusSingleConsumerExample/VRFV2PlusSingleConsumerExample.bin 1a6b101ee212da2fab7662dde918453ec6bae862568cff5151daea171583dfc9 +vrf_v2plus_sub_owner: ../../contracts/solc/v0.8.19/VRFV2PlusExternalSubOwnerExample/VRFV2PlusExternalSubOwnerExample.abi ../../contracts/solc/v0.8.19/VRFV2PlusExternalSubOwnerExample/VRFV2PlusExternalSubOwnerExample.bin fbe58337e8bc497a26deaec76d7177fe625c60691db89151d62076de0e6bbd75 +vrf_v2plus_upgraded_version: ../../contracts/solc/v0.8.19/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.abi ../../contracts/solc/v0.8.19/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.bin 4a7df5b066bc3944622009659828fae35bc39d15cf4d218c1560dbdf39b10de2 vrfv2_proxy_admin: ../../contracts/solc/v0.8.6/VRFV2ProxyAdmin/VRFV2ProxyAdmin.abi ../../contracts/solc/v0.8.6/VRFV2ProxyAdmin/VRFV2ProxyAdmin.bin 402b1103087ffe1aa598854a8f8b38f8cd3de2e3aaa86369e28017a9157f4980 vrfv2_reverting_example: ../../contracts/solc/v0.8.6/VRFV2RevertingExample/VRFV2RevertingExample.abi ../../contracts/solc/v0.8.6/VRFV2RevertingExample/VRFV2RevertingExample.bin 1ae46f80351d428bd85ba58b9041b2a608a1845300d79a8fed83edf96606de87 vrfv2_transparent_upgradeable_proxy: ../../contracts/solc/v0.8.6/VRFV2TransparentUpgradeableProxy/VRFV2TransparentUpgradeableProxy.abi ../../contracts/solc/v0.8.6/VRFV2TransparentUpgradeableProxy/VRFV2TransparentUpgradeableProxy.bin fe1a8e6852fbd06d91f64315c5cede86d340891f5b5cc981fb5b86563f7eac3f @@ -122,10 +107,10 @@ vrfv2_wrapper: ../../contracts/solc/v0.8.6/VRFV2Wrapper/VRFV2Wrapper.abi ../../c vrfv2_wrapper_consumer_example: ../../contracts/solc/v0.8.6/VRFV2WrapperConsumerExample/VRFV2WrapperConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2WrapperConsumerExample/VRFV2WrapperConsumerExample.bin 3c5c9f1c501e697a7e77e959b48767e2a0bb1372393fd7686f7aaef3eb794231 vrfv2_wrapper_interface: ../../contracts/solc/v0.8.6/VRFV2WrapperInterface/VRFV2WrapperInterface.abi ../../contracts/solc/v0.8.6/VRFV2WrapperInterface/VRFV2WrapperInterface.bin ff8560169de171a68b360b7438d13863682d07040d984fd0fb096b2379421003 vrfv2_wrapper_load_test_consumer: ../../contracts/solc/v0.8.6/VRFV2WrapperLoadTestConsumer/VRFV2WrapperLoadTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2WrapperLoadTestConsumer/VRFV2WrapperLoadTestConsumer.bin 664ca7fdf4dd65cc183bc25f20708c4b369c3401bba3ee12797a93bcd70138b6 -vrfv2plus_client: ../../contracts/solc/v0.8.6/VRFV2PlusClient/VRFV2PlusClient.abi ../../contracts/solc/v0.8.6/VRFV2PlusClient/VRFV2PlusClient.bin 3ffbfa4971a7e5f46051a26b1722613f265d89ea1867547ecec58500953a9501 -vrfv2plus_consumer_example: ../../contracts/solc/v0.8.6/VRFV2PlusConsumerExample/VRFV2PlusConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusConsumerExample/VRFV2PlusConsumerExample.bin f193fa1994f3dadf095c863ff2876cc638034df207e6bdca30efc02301ce3aa8 -vrfv2plus_malicious_migrator: ../../contracts/solc/v0.8.6/VRFV2PlusMaliciousMigrator/VRFV2PlusMaliciousMigrator.abi ../../contracts/solc/v0.8.6/VRFV2PlusMaliciousMigrator/VRFV2PlusMaliciousMigrator.bin 36df34af33acaacca03c646f64686ef8c693fd68299ee1b887cd4537e94fc76d -vrfv2plus_reverting_example: ../../contracts/solc/v0.8.6/VRFV2PlusRevertingExample/VRFV2PlusRevertingExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusRevertingExample/VRFV2PlusRevertingExample.bin 8e0e66cb6e6276a5cdf04c2292421eefe61069ab03d470964d7f0eb2a685af3e -vrfv2plus_wrapper: ../../contracts/solc/v0.8.6/VRFV2PlusWrapper/VRFV2PlusWrapper.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapper/VRFV2PlusWrapper.bin d8988ac33b21ff250984ee548a2f7149fec40f3b3ba5306aacec3eba1274c3f8 -vrfv2plus_wrapper_consumer_example: ../../contracts/solc/v0.8.6/VRFV2PlusWrapperConsumerExample/VRFV2PlusWrapperConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapperConsumerExample/VRFV2PlusWrapperConsumerExample.bin e55b806978c94d4d5073d4f227e7c4fe2ebb7340a3b12fce0f90bd3889075660 -vrfv2plus_wrapper_load_test_consumer: ../../contracts/solc/v0.8.6/VRFV2PlusWrapperLoadTestConsumer/VRFV2PlusWrapperLoadTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapperLoadTestConsumer/VRFV2PlusWrapperLoadTestConsumer.bin 75f97d0924cf6e1ff215f1a8860396d0747acabdeb40955ea4e5907c9c0ffe92 +vrfv2plus_client: ../../contracts/solc/v0.8.19/VRFV2PlusClient/VRFV2PlusClient.abi ../../contracts/solc/v0.8.19/VRFV2PlusClient/VRFV2PlusClient.bin 875d2c6f287babe5135cc7f67b6f1b1d8de746143ef6918fcadf044d1892dd2a +vrfv2plus_consumer_example: ../../contracts/solc/v0.8.19/VRFV2PlusConsumerExample/VRFV2PlusConsumerExample.abi ../../contracts/solc/v0.8.19/VRFV2PlusConsumerExample/VRFV2PlusConsumerExample.bin e25c1981638fb9ea8fdd21600d6954f999bf65b98ba4e4a3f8fb9f7858334e19 +vrfv2plus_malicious_migrator: ../../contracts/solc/v0.8.19/VRFV2PlusMaliciousMigrator/VRFV2PlusMaliciousMigrator.abi ../../contracts/solc/v0.8.19/VRFV2PlusMaliciousMigrator/VRFV2PlusMaliciousMigrator.bin 5dff20621fe6ed3bed75fe4b65381b0d4b1f6286ee3571553dbeb57213b53416 +vrfv2plus_reverting_example: ../../contracts/solc/v0.8.19/VRFV2PlusRevertingExample/VRFV2PlusRevertingExample.abi ../../contracts/solc/v0.8.19/VRFV2PlusRevertingExample/VRFV2PlusRevertingExample.bin ebc2e96af9bf3aaa8b9cb048f8ecfec9987ee8b90126b740722c6b6427ab128e +vrfv2plus_wrapper: ../../contracts/solc/v0.8.19/VRFV2PlusWrapper/VRFV2PlusWrapper.abi ../../contracts/solc/v0.8.19/VRFV2PlusWrapper/VRFV2PlusWrapper.bin 199af16342b22086fe4186c438857cd15b7dccbeb06e94f48b293b2237bb4278 +vrfv2plus_wrapper_consumer_example: ../../contracts/solc/v0.8.19/VRFV2PlusWrapperConsumerExample/VRFV2PlusWrapperConsumerExample.abi ../../contracts/solc/v0.8.19/VRFV2PlusWrapperConsumerExample/VRFV2PlusWrapperConsumerExample.bin 130217ffb341f19d1b3bda27f5c4a10567ac21ac3a49c9933bbdb068e8420177 +vrfv2plus_wrapper_load_test_consumer: ../../contracts/solc/v0.8.19/VRFV2PlusWrapperLoadTestConsumer/VRFV2PlusWrapperLoadTestConsumer.abi ../../contracts/solc/v0.8.19/VRFV2PlusWrapperLoadTestConsumer/VRFV2PlusWrapperLoadTestConsumer.bin f2880b0469b82ddd4a11aa81ac12916f2912555dfe64829416a583fd82ebf3ab diff --git a/core/gethwrappers/go_generate.go b/core/gethwrappers/go_generate.go index 52957905e11..e31f7feb833 100644 --- a/core/gethwrappers/go_generate.go +++ b/core/gethwrappers/go_generate.go @@ -5,20 +5,6 @@ package gethwrappers // Make sure solidity compiler artifacts are up-to-date. Only output stdout on failure. //go:generate ./generation/compile_contracts.sh -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/FluxAggregator/FluxAggregator.abi ../../contracts/solc/v0.6/FluxAggregator/FluxAggregator.bin FluxAggregator flux_aggregator_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/VRF/VRF.abi ../../contracts/solc/v0.6/VRF/VRF.bin VRF solidity_vrf_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/VRFTestHelper/VRFTestHelper.abi ../../contracts/solc/v0.6/VRFTestHelper/VRFTestHelper.bin VRFTestHelper solidity_vrf_verifier_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/VRFCoordinator/VRFCoordinator.abi ../../contracts/solc/v0.6/VRFCoordinator/VRFCoordinator.bin VRFCoordinator solidity_vrf_coordinator_interface -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/VRFConsumer/VRFConsumer.abi ../../contracts/solc/v0.6/VRFConsumer/VRFConsumer.bin VRFConsumer solidity_vrf_consumer_interface -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/VRFRequestIDBaseTestHelper/VRFRequestIDBaseTestHelper.abi ../../contracts/solc/v0.6/VRFRequestIDBaseTestHelper/VRFRequestIDBaseTestHelper.bin VRFRequestIDBaseTestHelper solidity_vrf_request_id -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/Flags/Flags.abi ../../contracts/solc/v0.6/Flags/Flags.bin Flags flags_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/Oracle/Oracle.abi ../../contracts/solc/v0.6/Oracle/Oracle.bin Oracle oracle_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/TestAPIConsumer/TestAPIConsumer.abi ../../contracts/solc/v0.6/TestAPIConsumer/TestAPIConsumer.bin TestAPIConsumer test_api_consumer_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/MockETHLINKAggregator/MockETHLINKAggregator.abi ../../contracts/solc/v0.6/MockETHLINKAggregator/MockETHLINKAggregator.bin MockETHLINKAggregator mock_ethlink_aggregator_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/MockGASAggregator/MockGASAggregator.abi ../../contracts/solc/v0.6/MockGASAggregator/MockGASAggregator.bin MockGASAggregator mock_gas_aggregator_wrapper - -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/Consumer/Consumer.abi ../../contracts/solc/v0.7/Consumer/Consumer.bin Consumer consumer_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/MultiWordConsumer/MultiWordConsumer.abi ../../contracts/solc/v0.7/MultiWordConsumer/MultiWordConsumer.bin MultiWordConsumer multiwordconsumer_wrapper //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/Operator/Operator.abi ../../contracts/solc/v0.8.19/Operator/Operator.bin Operator operator_wrapper //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/OperatorFactory/OperatorFactory.abi ../../contracts/solc/v0.8.19/OperatorFactory/OperatorFactory.bin OperatorFactory operator_factory //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/AuthorizedForwarder/AuthorizedForwarder.abi ../../contracts/solc/v0.8.19/AuthorizedForwarder/AuthorizedForwarder.bin AuthorizedForwarder authorized_forwarder @@ -26,10 +12,6 @@ package gethwrappers //go:generate go run ./generation/generate/wrap.go OffchainAggregator/OffchainAggregator.abi - OffchainAggregator offchain_aggregator_wrapper // Automation -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/KeeperRegistry1_1/KeeperRegistry1_1.abi ../../contracts/solc/v0.7/KeeperRegistry1_1/KeeperRegistry1_1.bin KeeperRegistry keeper_registry_wrapper1_1 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/KeeperRegistry1_1Mock/KeeperRegistry1_1Mock.abi ../../contracts/solc/v0.7/KeeperRegistry1_1Mock/KeeperRegistry1_1Mock.bin KeeperRegistryMock keeper_registry_wrapper1_1_mock -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/UpkeepPerformCounterRestrictive/UpkeepPerformCounterRestrictive.abi ../../contracts/solc/v0.7/UpkeepPerformCounterRestrictive/UpkeepPerformCounterRestrictive.bin UpkeepPerformCounterRestrictive upkeep_perform_counter_restrictive_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/UpkeepCounter/UpkeepCounter.abi ../../contracts/solc/v0.7/UpkeepCounter/UpkeepCounter.bin UpkeepCounter upkeep_counter_wrapper //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/CronUpkeepFactory/CronUpkeepFactory.abi - CronUpkeepFactory cron_upkeep_factory_wrapper //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/CronUpkeepFactory/CronUpkeep.abi - CronUpkeep cron_upkeep_wrapper //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeeperRegistrar1_2/KeeperRegistrar.abi ../../contracts/solc/v0.8.6/KeeperRegistrar1_2/KeeperRegistrar.bin KeeperRegistrar keeper_registrar_wrapper1_2 @@ -102,8 +84,6 @@ package gethwrappers //go:generate go run ./generation/generate_link/wrap_link.go // VRF V2 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/BlockhashStore/BlockhashStore.abi ../../contracts/solc/v0.8.6/BlockhashStore/BlockhashStore.bin BlockhashStore blockhash_store -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/BatchBlockhashStore/BatchBlockhashStore.abi ../../contracts/solc/v0.8.6/BatchBlockhashStore/BatchBlockhashStore.bin BatchBlockhashStore batch_blockhash_store //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2/BatchVRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2/BatchVRFCoordinatorV2.bin BatchVRFCoordinatorV2 batch_vrf_coordinator_v2 //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFOwner/VRFOwner.abi ../../contracts/solc/v0.8.6/VRFOwner/VRFOwner.bin VRFOwner vrf_owner //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFCoordinatorV2/VRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2/VRFCoordinatorV2.bin VRFCoordinatorV2 vrf_coordinator_v2 @@ -135,24 +115,26 @@ package gethwrappers //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeepersVRFConsumer/KeepersVRFConsumer.abi ../../contracts/solc/v0.8.6/KeepersVRFConsumer/KeepersVRFConsumer.bin KeepersVRFConsumer keepers_vrf_consumer // VRF V2Plus -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/IVRFCoordinatorV2PlusInternal/IVRFCoordinatorV2PlusInternal.abi ../../contracts/solc/v0.8.6/IVRFCoordinatorV2PlusInternal/IVRFCoordinatorV2PlusInternal.bin IVRFCoordinatorV2PlusInternal vrf_coordinator_v2plus_interface -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.bin BatchVRFCoordinatorV2Plus batch_vrf_coordinator_v2plus -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/TrustedBlockhashStore/TrustedBlockhashStore.abi ../../contracts/solc/v0.8.6/TrustedBlockhashStore/TrustedBlockhashStore.bin TrustedBlockhashStore trusted_blockhash_store -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusConsumerExample/VRFV2PlusConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusConsumerExample/VRFV2PlusConsumerExample.bin VRFV2PlusConsumerExample vrfv2plus_consumer_example -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5/VRFCoordinatorV2_5.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5/VRFCoordinatorV2_5.bin VRFCoordinatorV2_5 vrf_coordinator_v2_5 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusWrapper/VRFV2PlusWrapper.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapper/VRFV2PlusWrapper.bin VRFV2PlusWrapper vrfv2plus_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusWrapperConsumerExample/VRFV2PlusWrapperConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapperConsumerExample/VRFV2PlusWrapperConsumerExample.bin VRFV2PlusWrapperConsumerExample vrfv2plus_wrapper_consumer_example -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus/VRFMaliciousConsumerV2Plus.abi ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus/VRFMaliciousConsumerV2Plus.bin VRFMaliciousConsumerV2Plus vrf_malicious_consumer_v2_plus -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusSingleConsumerExample/VRFV2PlusSingleConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusSingleConsumerExample/VRFV2PlusSingleConsumerExample.bin VRFV2PlusSingleConsumerExample vrf_v2plus_single_consumer -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusExternalSubOwnerExample/VRFV2PlusExternalSubOwnerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusExternalSubOwnerExample/VRFV2PlusExternalSubOwnerExample.bin VRFV2PlusExternalSubOwnerExample vrf_v2plus_sub_owner -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusRevertingExample/VRFV2PlusRevertingExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusRevertingExample/VRFV2PlusRevertingExample.bin VRFV2PlusRevertingExample vrfv2plus_reverting_example -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample/VRFConsumerV2PlusUpgradeableExample.abi ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample/VRFConsumerV2PlusUpgradeableExample.bin VRFConsumerV2PlusUpgradeableExample vrf_consumer_v2_plus_upgradeable_example -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusClient/VRFV2PlusClient.abi ../../contracts/solc/v0.8.6/VRFV2PlusClient/VRFV2PlusClient.bin VRFV2PlusClient vrfv2plus_client -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example/VRFCoordinatorV2Plus_V2Example.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example/VRFCoordinatorV2Plus_V2Example.bin VRFCoordinatorV2Plus_V2Example vrf_coordinator_v2_plus_v2_example -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusMaliciousMigrator/VRFV2PlusMaliciousMigrator.abi ../../contracts/solc/v0.8.6/VRFV2PlusMaliciousMigrator/VRFV2PlusMaliciousMigrator.bin VRFV2PlusMaliciousMigrator vrfv2plus_malicious_migrator -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusLoadTestWithMetrics/VRFV2PlusLoadTestWithMetrics.abi ../../contracts/solc/v0.8.6/VRFV2PlusLoadTestWithMetrics/VRFV2PlusLoadTestWithMetrics.bin VRFV2PlusLoadTestWithMetrics vrf_v2plus_load_test_with_metrics -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.bin VRFCoordinatorV2PlusUpgradedVersion vrf_v2plus_upgraded_version -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusWrapperLoadTestConsumer/VRFV2PlusWrapperLoadTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapperLoadTestConsumer/VRFV2PlusWrapperLoadTestConsumer.bin VRFV2PlusWrapperLoadTestConsumer vrfv2plus_wrapper_load_test_consumer +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/IVRFCoordinatorV2PlusInternal/IVRFCoordinatorV2PlusInternal.abi ../../contracts/solc/v0.8.19/IVRFCoordinatorV2PlusInternal/IVRFCoordinatorV2PlusInternal.bin IVRFCoordinatorV2PlusInternal vrf_coordinator_v2plus_interface +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.19/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.bin BatchVRFCoordinatorV2Plus batch_vrf_coordinator_v2plus +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/TrustedBlockhashStore/TrustedBlockhashStore.abi ../../contracts/solc/v0.8.19/TrustedBlockhashStore/TrustedBlockhashStore.bin TrustedBlockhashStore trusted_blockhash_store +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFV2PlusConsumerExample/VRFV2PlusConsumerExample.abi ../../contracts/solc/v0.8.19/VRFV2PlusConsumerExample/VRFV2PlusConsumerExample.bin VRFV2PlusConsumerExample vrfv2plus_consumer_example +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFCoordinatorV2_5/VRFCoordinatorV2_5.abi ../../contracts/solc/v0.8.19/VRFCoordinatorV2_5/VRFCoordinatorV2_5.bin VRFCoordinatorV2_5 vrf_coordinator_v2_5 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFV2PlusWrapper/VRFV2PlusWrapper.abi ../../contracts/solc/v0.8.19/VRFV2PlusWrapper/VRFV2PlusWrapper.bin VRFV2PlusWrapper vrfv2plus_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFV2PlusWrapperConsumerExample/VRFV2PlusWrapperConsumerExample.abi ../../contracts/solc/v0.8.19/VRFV2PlusWrapperConsumerExample/VRFV2PlusWrapperConsumerExample.bin VRFV2PlusWrapperConsumerExample vrfv2plus_wrapper_consumer_example +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFMaliciousConsumerV2Plus/VRFMaliciousConsumerV2Plus.abi ../../contracts/solc/v0.8.19/VRFMaliciousConsumerV2Plus/VRFMaliciousConsumerV2Plus.bin VRFMaliciousConsumerV2Plus vrf_malicious_consumer_v2_plus +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFV2PlusSingleConsumerExample/VRFV2PlusSingleConsumerExample.abi ../../contracts/solc/v0.8.19/VRFV2PlusSingleConsumerExample/VRFV2PlusSingleConsumerExample.bin VRFV2PlusSingleConsumerExample vrf_v2plus_single_consumer +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFV2PlusExternalSubOwnerExample/VRFV2PlusExternalSubOwnerExample.abi ../../contracts/solc/v0.8.19/VRFV2PlusExternalSubOwnerExample/VRFV2PlusExternalSubOwnerExample.bin VRFV2PlusExternalSubOwnerExample vrf_v2plus_sub_owner +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFV2PlusRevertingExample/VRFV2PlusRevertingExample.abi ../../contracts/solc/v0.8.19/VRFV2PlusRevertingExample/VRFV2PlusRevertingExample.bin VRFV2PlusRevertingExample vrfv2plus_reverting_example +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFConsumerV2PlusUpgradeableExample/VRFConsumerV2PlusUpgradeableExample.abi ../../contracts/solc/v0.8.19/VRFConsumerV2PlusUpgradeableExample/VRFConsumerV2PlusUpgradeableExample.bin VRFConsumerV2PlusUpgradeableExample vrf_consumer_v2_plus_upgradeable_example +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFV2PlusClient/VRFV2PlusClient.abi ../../contracts/solc/v0.8.19/VRFV2PlusClient/VRFV2PlusClient.bin VRFV2PlusClient vrfv2plus_client +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFCoordinatorV2Plus_V2Example/VRFCoordinatorV2Plus_V2Example.abi ../../contracts/solc/v0.8.19/VRFCoordinatorV2Plus_V2Example/VRFCoordinatorV2Plus_V2Example.bin VRFCoordinatorV2Plus_V2Example vrf_coordinator_v2_plus_v2_example +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFV2PlusMaliciousMigrator/VRFV2PlusMaliciousMigrator.abi ../../contracts/solc/v0.8.19/VRFV2PlusMaliciousMigrator/VRFV2PlusMaliciousMigrator.bin VRFV2PlusMaliciousMigrator vrfv2plus_malicious_migrator +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFV2PlusLoadTestWithMetrics/VRFV2PlusLoadTestWithMetrics.abi ../../contracts/solc/v0.8.19/VRFV2PlusLoadTestWithMetrics/VRFV2PlusLoadTestWithMetrics.bin VRFV2PlusLoadTestWithMetrics vrf_v2plus_load_test_with_metrics +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.abi ../../contracts/solc/v0.8.19/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.bin VRFCoordinatorV2PlusUpgradedVersion vrf_v2plus_upgraded_version +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFV2PlusWrapperLoadTestConsumer/VRFV2PlusWrapperLoadTestConsumer.abi ../../contracts/solc/v0.8.19/VRFV2PlusWrapperLoadTestConsumer/VRFV2PlusWrapperLoadTestConsumer.bin VRFV2PlusWrapperLoadTestConsumer vrfv2plus_wrapper_load_test_consumer +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/BlockhashStore/BlockhashStore.abi ../../contracts/solc/v0.8.19/BlockhashStore/BlockhashStore.bin BlockhashStore blockhash_store +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/BatchBlockhashStore/BatchBlockhashStore.abi ../../contracts/solc/v0.8.19/BatchBlockhashStore/BatchBlockhashStore.bin BatchBlockhashStore batch_blockhash_store // Aggregators //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV2V3Interface.abi ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV2V3Interface.bin AggregatorV2V3Interface aggregator_v2v3_interface diff --git a/core/gethwrappers/go_generate_vrfv2plus.go b/core/gethwrappers/go_generate_vrfv2plus.go index b8002dd91c0..6a2059e00c4 100644 --- a/core/gethwrappers/go_generate_vrfv2plus.go +++ b/core/gethwrappers/go_generate_vrfv2plus.go @@ -1,22 +1,23 @@ package gethwrappers // VRF V2Plus -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/IVRFCoordinatorV2PlusInternal/IVRFCoordinatorV2PlusInternal.abi ../../contracts/solc/v0.8.6/IVRFCoordinatorV2PlusInternal/IVRFCoordinatorV2PlusInternal.bin IVRFCoordinatorV2PlusInternal vrf_coordinator_v2plus_interface -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.bin BatchVRFCoordinatorV2Plus batch_vrf_coordinator_v2plus -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/TrustedBlockhashStore/TrustedBlockhashStore.abi ../../contracts/solc/v0.8.6/TrustedBlockhashStore/TrustedBlockhashStore.bin TrustedBlockhashStore trusted_blockhash_store -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusConsumerExample/VRFV2PlusConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusConsumerExample/VRFV2PlusConsumerExample.bin VRFV2PlusConsumerExample vrfv2plus_consumer_example -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5/VRFCoordinatorV2_5.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5/VRFCoordinatorV2_5.bin VRFCoordinatorV2_5 vrf_coordinator_v2_5 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusWrapper/VRFV2PlusWrapper.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapper/VRFV2PlusWrapper.bin VRFV2PlusWrapper vrfv2plus_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusWrapperConsumerExample/VRFV2PlusWrapperConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapperConsumerExample/VRFV2PlusWrapperConsumerExample.bin VRFV2PlusWrapperConsumerExample vrfv2plus_wrapper_consumer_example -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus/VRFMaliciousConsumerV2Plus.abi ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus/VRFMaliciousConsumerV2Plus.bin VRFMaliciousConsumerV2Plus vrf_malicious_consumer_v2_plus -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusSingleConsumerExample/VRFV2PlusSingleConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusSingleConsumerExample/VRFV2PlusSingleConsumerExample.bin VRFV2PlusSingleConsumerExample vrf_v2plus_single_consumer -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusExternalSubOwnerExample/VRFV2PlusExternalSubOwnerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusExternalSubOwnerExample/VRFV2PlusExternalSubOwnerExample.bin VRFV2PlusExternalSubOwnerExample vrf_v2plus_sub_owner -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusRevertingExample/VRFV2PlusRevertingExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusRevertingExample/VRFV2PlusRevertingExample.bin VRFV2PlusRevertingExample vrfv2plus_reverting_example -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample/VRFConsumerV2PlusUpgradeableExample.abi ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample/VRFConsumerV2PlusUpgradeableExample.bin VRFConsumerV2PlusUpgradeableExample vrf_consumer_v2_plus_upgradeable_example -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusClient/VRFV2PlusClient.abi ../../contracts/solc/v0.8.6/VRFV2PlusClient/VRFV2PlusClient.bin VRFV2PlusClient vrfv2plus_client -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example/VRFCoordinatorV2Plus_V2Example.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example/VRFCoordinatorV2Plus_V2Example.bin VRFCoordinatorV2Plus_V2Example vrf_coordinator_v2_plus_v2_example -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusMaliciousMigrator/VRFV2PlusMaliciousMigrator.abi ../../contracts/solc/v0.8.6/VRFV2PlusMaliciousMigrator/VRFV2PlusMaliciousMigrator.bin VRFV2PlusMaliciousMigrator vrfv2plus_malicious_migrator -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusLoadTestWithMetrics/VRFV2PlusLoadTestWithMetrics.abi ../../contracts/solc/v0.8.6/VRFV2PlusLoadTestWithMetrics/VRFV2PlusLoadTestWithMetrics.bin VRFV2PlusLoadTestWithMetrics vrf_v2plus_load_test_with_metrics -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.bin VRFCoordinatorV2PlusUpgradedVersion vrf_v2plus_upgraded_version -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2PlusWrapperLoadTestConsumer/VRFV2PlusWrapperLoadTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapperLoadTestConsumer/VRFV2PlusWrapperLoadTestConsumer.bin VRFV2PlusWrapperLoadTestConsumer vrfv2plus_wrapper_load_test_consumer -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFMockETHLINKAggregator/VRFMockETHLINKAggregator.abi ../../contracts/solc/v0.8.6/VRFMockETHLINKAggregator/VRFMockETHLINKAggregator.bin VRFMockETHLINKAggregator vrf_mock_ethlink_aggregator +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/IVRFCoordinatorV2PlusInternal/IVRFCoordinatorV2PlusInternal.abi ../../contracts/solc/v0.8.19/IVRFCoordinatorV2PlusInternal/IVRFCoordinatorV2PlusInternal.bin IVRFCoordinatorV2PlusInternal vrf_coordinator_v2plus_interface +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.19/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.bin BatchVRFCoordinatorV2Plus batch_vrf_coordinator_v2plus +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/TrustedBlockhashStore/TrustedBlockhashStore.abi ../../contracts/solc/v0.8.19/TrustedBlockhashStore/TrustedBlockhashStore.bin TrustedBlockhashStore trusted_blockhash_store +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFV2PlusConsumerExample/VRFV2PlusConsumerExample.abi ../../contracts/solc/v0.8.19/VRFV2PlusConsumerExample/VRFV2PlusConsumerExample.bin VRFV2PlusConsumerExample vrfv2plus_consumer_example +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFCoordinatorV2_5/VRFCoordinatorV2_5.abi ../../contracts/solc/v0.8.19/VRFCoordinatorV2_5/VRFCoordinatorV2_5.bin VRFCoordinatorV2_5 vrf_coordinator_v2_5 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFV2PlusWrapper/VRFV2PlusWrapper.abi ../../contracts/solc/v0.8.19/VRFV2PlusWrapper/VRFV2PlusWrapper.bin VRFV2PlusWrapper vrfv2plus_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFV2PlusWrapperConsumerExample/VRFV2PlusWrapperConsumerExample.abi ../../contracts/solc/v0.8.19/VRFV2PlusWrapperConsumerExample/VRFV2PlusWrapperConsumerExample.bin VRFV2PlusWrapperConsumerExample vrfv2plus_wrapper_consumer_example +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFMaliciousConsumerV2Plus/VRFMaliciousConsumerV2Plus.abi ../../contracts/solc/v0.8.19/VRFMaliciousConsumerV2Plus/VRFMaliciousConsumerV2Plus.bin VRFMaliciousConsumerV2Plus vrf_malicious_consumer_v2_plus +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFV2PlusSingleConsumerExample/VRFV2PlusSingleConsumerExample.abi ../../contracts/solc/v0.8.19/VRFV2PlusSingleConsumerExample/VRFV2PlusSingleConsumerExample.bin VRFV2PlusSingleConsumerExample vrf_v2plus_single_consumer +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFV2PlusExternalSubOwnerExample/VRFV2PlusExternalSubOwnerExample.abi ../../contracts/solc/v0.8.19/VRFV2PlusExternalSubOwnerExample/VRFV2PlusExternalSubOwnerExample.bin VRFV2PlusExternalSubOwnerExample vrf_v2plus_sub_owner +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFV2PlusRevertingExample/VRFV2PlusRevertingExample.abi ../../contracts/solc/v0.8.19/VRFV2PlusRevertingExample/VRFV2PlusRevertingExample.bin VRFV2PlusRevertingExample vrfv2plus_reverting_example +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFConsumerV2PlusUpgradeableExample/VRFConsumerV2PlusUpgradeableExample.abi ../../contracts/solc/v0.8.19/VRFConsumerV2PlusUpgradeableExample/VRFConsumerV2PlusUpgradeableExample.bin VRFConsumerV2PlusUpgradeableExample vrf_consumer_v2_plus_upgradeable_example +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFV2PlusClient/VRFV2PlusClient.abi ../../contracts/solc/v0.8.19/VRFV2PlusClient/VRFV2PlusClient.bin VRFV2PlusClient vrfv2plus_client +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFCoordinatorV2Plus_V2Example/VRFCoordinatorV2Plus_V2Example.abi ../../contracts/solc/v0.8.19/VRFCoordinatorV2Plus_V2Example/VRFCoordinatorV2Plus_V2Example.bin VRFCoordinatorV2Plus_V2Example vrf_coordinator_v2_plus_v2_example +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFV2PlusMaliciousMigrator/VRFV2PlusMaliciousMigrator.abi ../../contracts/solc/v0.8.19/VRFV2PlusMaliciousMigrator/VRFV2PlusMaliciousMigrator.bin VRFV2PlusMaliciousMigrator vrfv2plus_malicious_migrator +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFV2PlusLoadTestWithMetrics/VRFV2PlusLoadTestWithMetrics.abi ../../contracts/solc/v0.8.19/VRFV2PlusLoadTestWithMetrics/VRFV2PlusLoadTestWithMetrics.bin VRFV2PlusLoadTestWithMetrics vrf_v2plus_load_test_with_metrics +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.abi ../../contracts/solc/v0.8.19/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.bin VRFCoordinatorV2PlusUpgradedVersion vrf_v2plus_upgraded_version +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFV2PlusWrapperLoadTestConsumer/VRFV2PlusWrapperLoadTestConsumer.abi ../../contracts/solc/v0.8.19/VRFV2PlusWrapperLoadTestConsumer/VRFV2PlusWrapperLoadTestConsumer.bin VRFV2PlusWrapperLoadTestConsumer vrfv2plus_wrapper_load_test_consumer +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/BlockhashStore/BlockhashStore.abi ../../contracts/solc/v0.8.19/BlockhashStore/BlockhashStore.bin BlockhashStore blockhash_store +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/BatchBlockhashStore/BatchBlockhashStore.abi ../../contracts/solc/v0.8.19/BatchBlockhashStore/BatchBlockhashStore.bin BatchBlockhashStore batch_blockhash_store diff --git a/core/gethwrappers/transmission/generated/entry_point/entry_point.go b/core/gethwrappers/transmission/generated/entry_point/entry_point.go index 09a3a94a7f4..5a22214cb0e 100644 --- a/core/gethwrappers/transmission/generated/entry_point/entry_point.go +++ b/core/gethwrappers/transmission/generated/entry_point/entry_point.go @@ -79,7 +79,7 @@ type UserOperation struct { var EntryPointMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"preOpGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"uint48\",\"name\":\"validAfter\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"validUntil\",\"type\":\"uint48\"},{\"internalType\":\"bool\",\"name\":\"targetSuccess\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"targetResult\",\"type\":\"bytes\"}],\"name\":\"ExecutionResult\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"opIndex\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"reason\",\"type\":\"string\"}],\"name\":\"FailedOp\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderAddressResult\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"aggregator\",\"type\":\"address\"}],\"name\":\"SignatureValidationFailed\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"preOpGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"prefund\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sigFailed\",\"type\":\"bool\"},{\"internalType\":\"uint48\",\"name\":\"validAfter\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"validUntil\",\"type\":\"uint48\"},{\"internalType\":\"bytes\",\"name\":\"paymasterContext\",\"type\":\"bytes\"}],\"internalType\":\"structIEntryPoint.ReturnInfo\",\"name\":\"returnInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"structIStakeManager.StakeInfo\",\"name\":\"senderInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"structIStakeManager.StakeInfo\",\"name\":\"factoryInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"structIStakeManager.StakeInfo\",\"name\":\"paymasterInfo\",\"type\":\"tuple\"}],\"name\":\"ValidationResult\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"preOpGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"prefund\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sigFailed\",\"type\":\"bool\"},{\"internalType\":\"uint48\",\"name\":\"validAfter\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"validUntil\",\"type\":\"uint48\"},{\"internalType\":\"bytes\",\"name\":\"paymasterContext\",\"type\":\"bytes\"}],\"internalType\":\"structIEntryPoint.ReturnInfo\",\"name\":\"returnInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"structIStakeManager.StakeInfo\",\"name\":\"senderInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"structIStakeManager.StakeInfo\",\"name\":\"factoryInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"structIStakeManager.StakeInfo\",\"name\":\"paymasterInfo\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"aggregator\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"internalType\":\"structIStakeManager.StakeInfo\",\"name\":\"stakeInfo\",\"type\":\"tuple\"}],\"internalType\":\"structIEntryPoint.AggregatorStakeInfo\",\"name\":\"aggregatorInfo\",\"type\":\"tuple\"}],\"name\":\"ValidationResultWithAggregation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"userOpHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"factory\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"paymaster\",\"type\":\"address\"}],\"name\":\"AccountDeployed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalDeposit\",\"type\":\"uint256\"}],\"name\":\"Deposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"aggregator\",\"type\":\"address\"}],\"name\":\"SignatureAggregatorChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalStaked\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"unstakeDelaySec\",\"type\":\"uint256\"}],\"name\":\"StakeLocked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"withdrawTime\",\"type\":\"uint256\"}],\"name\":\"StakeUnlocked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"withdrawAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"StakeWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"userOpHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"paymaster\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"actualGasCost\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"actualGasUsed\",\"type\":\"uint256\"}],\"name\":\"UserOperationEvent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"userOpHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"revertReason\",\"type\":\"bytes\"}],\"name\":\"UserOperationRevertReason\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"withdrawAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Withdrawn\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"SIG_VALIDATION_FAILED\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"}],\"name\":\"_validateSenderAndPaymaster\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"unstakeDelaySec\",\"type\":\"uint32\"}],\"name\":\"addStake\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"depositTo\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"deposits\",\"outputs\":[{\"internalType\":\"uint112\",\"name\":\"deposit\",\"type\":\"uint112\"},{\"internalType\":\"bool\",\"name\":\"staked\",\"type\":\"bool\"},{\"internalType\":\"uint112\",\"name\":\"stake\",\"type\":\"uint112\"},{\"internalType\":\"uint32\",\"name\":\"unstakeDelaySec\",\"type\":\"uint32\"},{\"internalType\":\"uint48\",\"name\":\"withdrawTime\",\"type\":\"uint48\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"getDepositInfo\",\"outputs\":[{\"components\":[{\"internalType\":\"uint112\",\"name\":\"deposit\",\"type\":\"uint112\"},{\"internalType\":\"bool\",\"name\":\"staked\",\"type\":\"bool\"},{\"internalType\":\"uint112\",\"name\":\"stake\",\"type\":\"uint112\"},{\"internalType\":\"uint32\",\"name\":\"unstakeDelaySec\",\"type\":\"uint32\"},{\"internalType\":\"uint48\",\"name\":\"withdrawTime\",\"type\":\"uint48\"}],\"internalType\":\"structIStakeManager.DepositInfo\",\"name\":\"info\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"}],\"name\":\"getSenderAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structUserOperation\",\"name\":\"userOp\",\"type\":\"tuple\"}],\"name\":\"getUserOpHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structUserOperation[]\",\"name\":\"userOps\",\"type\":\"tuple[]\"},{\"internalType\":\"contractIAggregator\",\"name\":\"aggregator\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structIEntryPoint.UserOpsPerAggregator[]\",\"name\":\"opsPerAggregator\",\"type\":\"tuple[]\"},{\"internalType\":\"addresspayable\",\"name\":\"beneficiary\",\"type\":\"address\"}],\"name\":\"handleAggregatedOps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structUserOperation[]\",\"name\":\"ops\",\"type\":\"tuple[]\"},{\"internalType\":\"addresspayable\",\"name\":\"beneficiary\",\"type\":\"address\"}],\"name\":\"handleOps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"paymaster\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"}],\"internalType\":\"structEntryPoint.MemoryUserOp\",\"name\":\"mUserOp\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"userOpHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"prefund\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"contextOffset\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preOpGas\",\"type\":\"uint256\"}],\"internalType\":\"structEntryPoint.UserOpInfo\",\"name\":\"opInfo\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"context\",\"type\":\"bytes\"}],\"name\":\"innerHandleOp\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"actualGasCost\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structUserOperation\",\"name\":\"op\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"targetCallData\",\"type\":\"bytes\"}],\"name\":\"simulateHandleOp\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structUserOperation\",\"name\":\"userOp\",\"type\":\"tuple\"}],\"name\":\"simulateValidation\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unlockStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"withdrawAddress\",\"type\":\"address\"}],\"name\":\"withdrawStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"withdrawAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"withdrawAmount\",\"type\":\"uint256\"}],\"name\":\"withdrawTo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", - Bin: "0x60a0604052604051620000129062000050565b604051809103906000f0801580156200002f573d6000803e3d6000fd5b506001600160a01b03166080523480156200004957600080fd5b506200005e565b61020a8062004b1883390190565b608051614a97620000816000396000818161146e015261363d0152614a976000f3fe6080604052600436106101125760003560e01c8063957122ab116100a5578063bb9fe6bf11610074578063d6383f9411610059578063d6383f941461042c578063ee2194231461044c578063fc7e286d1461046c57600080fd5b8063bb9fe6bf146103f7578063c23a5cea1461040c57600080fd5b8063957122ab146103845780639b249f69146103a4578063a6193531146103c4578063b760faf9146103e457600080fd5b80634b1d7cf5116100e15780634b1d7cf5146101ad5780635287ce12146101cd57806370a082311461031c5780638f41ec5a1461036f57600080fd5b80630396cb60146101275780631d7327561461013a5780631fad948c1461016d578063205c28781461018d57600080fd5b366101225761012033610546565b005b600080fd5b6101206101353660046139b0565b6105c1565b34801561014657600080fd5b5061015a610155366004613c27565b610944565b6040519081526020015b60405180910390f35b34801561017957600080fd5b50610120610188366004613d32565b610af7565b34801561019957600080fd5b506101206101a8366004613d89565b610c38565b3480156101b957600080fd5b506101206101c8366004613d32565b610e3a565b3480156101d957600080fd5b506102bd6101e8366004613db5565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091525073ffffffffffffffffffffffffffffffffffffffff1660009081526020818152604091829020825160a08101845281546dffffffffffffffffffffffffffff80821683526e010000000000000000000000000000820460ff161515948301949094526f0100000000000000000000000000000090049092169282019290925260019091015463ffffffff81166060830152640100000000900465ffffffffffff16608082015290565b6040805182516dffffffffffffffffffffffffffff908116825260208085015115159083015283830151169181019190915260608083015163ffffffff169082015260809182015165ffffffffffff169181019190915260a001610164565b34801561032857600080fd5b5061015a610337366004613db5565b73ffffffffffffffffffffffffffffffffffffffff166000908152602081905260409020546dffffffffffffffffffffffffffff1690565b34801561037b57600080fd5b5061015a600181565b34801561039057600080fd5b5061012061039f366004613dd2565b6112d9565b3480156103b057600080fd5b506101206103bf366004613e57565b611431565b3480156103d057600080fd5b5061015a6103df366004613eb2565b611533565b6101206103f2366004613db5565b610546565b34801561040357600080fd5b50610120611575565b34801561041857600080fd5b50610120610427366004613db5565b61172c565b34801561043857600080fd5b50610120610447366004613ee7565b611a2c565b34801561045857600080fd5b50610120610467366004613eb2565b611b5a565b34801561047857600080fd5b506104f9610487366004613db5565b600060208190529081526040902080546001909101546dffffffffffffffffffffffffffff808316926e010000000000000000000000000000810460ff16926f010000000000000000000000000000009091049091169063ffffffff811690640100000000900465ffffffffffff1685565b604080516dffffffffffffffffffffffffffff96871681529415156020860152929094169183019190915263ffffffff16606082015265ffffffffffff909116608082015260a001610164565b6105508134611ec2565b73ffffffffffffffffffffffffffffffffffffffff811660008181526020818152604091829020805492516dffffffffffffffffffffffffffff909316835292917f2da466a7b24304f47e87fa2e1e5a81b9831ce54fec19055ce277ca2f39ba42c491015b60405180910390a25050565b33600090815260208190526040902063ffffffff8216610642576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f6d757374207370656369667920756e7374616b652064656c617900000000000060448201526064015b60405180910390fd5b600181015463ffffffff90811690831610156106ba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f63616e6e6f7420646563726561736520756e7374616b652074696d65000000006044820152606401610639565b80546000906106ed9034906f0100000000000000000000000000000090046dffffffffffffffffffffffffffff16613f78565b905060008111610759576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6e6f207374616b652073706563696669656400000000000000000000000000006044820152606401610639565b6dffffffffffffffffffffffffffff8111156107d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f7374616b65206f766572666c6f770000000000000000000000000000000000006044820152606401610639565b6040805160a08101825283546dffffffffffffffffffffffffffff90811682526001602080840182815286841685870190815263ffffffff808b16606088019081526000608089018181523380835296829052908a9020985189549551945189166f01000000000000000000000000000000027fffffff0000000000000000000000000000ffffffffffffffffffffffffffffff9515156e010000000000000000000000000000027fffffffffffffffffffffffffffffffffff0000000000000000000000000000009097169190991617949094179290921695909517865551949092018054925165ffffffffffff16640100000000027fffffffffffffffffffffffffffffffffffffffffffff00000000000000000000909316949093169390931717905590517fa5ae833d0bb1dcd632d98a8b70973e8516812898e19bf27b70071ebc8dc52c0190610937908490879091825263ffffffff16602082015260400190565b60405180910390a2505050565b6000805a90503330146109b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4141393220696e7465726e616c2063616c6c206f6e6c790000000000000000006044820152606401610639565b8451604081015160608201518101611388015a10156109f6577fdeaddead0000000000000000000000000000000000000000000000000000000060005260206000fd5b875160009015610a97576000610a13846000015160008c86611fbf565b905080610a95576000610a27610800611fd7565b805190915015610a8f57846000015173ffffffffffffffffffffffffffffffffffffffff168a602001517f1c4fada7374c0a9ee8841fc38afe82932dc0f8e69012e927f061a8bae611a201876020015184604051610a86929190614006565b60405180910390a35b60019250505b505b600088608001515a8603019050610ae96000838b8b8b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250889250612003915050565b9a9950505050505050505050565b8160008167ffffffffffffffff811115610b1357610b136139d6565b604051908082528060200260200182016040528015610b4c57816020015b610b3961390c565b815260200190600190039081610b315790505b50905060005b82811015610bc5576000828281518110610b6e57610b6e61401f565b60200260200101519050600080610ba9848a8a87818110610b9157610b9161401f565b9050602002810190610ba3919061404e565b856123e1565b91509150610bba84838360006125a3565b505050600101610b52565b506000805b83811015610c2557610c1981888884818110610be857610be861401f565b9050602002810190610bfa919061404e565b858481518110610c0c57610c0c61401f565b60200260200101516127f8565b90910190600101610bca565b50610c30848261297d565b505050505050565b33600090815260208190526040902080546dffffffffffffffffffffffffffff16821115610cc2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f576974686472617720616d6f756e7420746f6f206c61726765000000000000006044820152606401610639565b8054610cdf9083906dffffffffffffffffffffffffffff1661408c565b81547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff919091161781556040805173ffffffffffffffffffffffffffffffffffffffff851681526020810184905233917fd1c19fbcd4551a5edfb66d43d2e337c04837afda3482b42bdf569a8fccdae5fb910160405180910390a260008373ffffffffffffffffffffffffffffffffffffffff168360405160006040518083038185875af1925050503d8060008114610dc4576040519150601f19603f3d011682016040523d82523d6000602084013e610dc9565b606091505b5050905080610e34576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6661696c656420746f20776974686472617700000000000000000000000000006044820152606401610639565b50505050565b816000805b828110156110335736868683818110610e5a57610e5a61401f565b9050602002810190610e6c91906140a3565b9050366000610e7b83806140d7565b90925090506000610e926040850160208601613db5565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff821601610f33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4141393620696e76616c69642061676772656761746f720000000000000000006044820152606401610639565b73ffffffffffffffffffffffffffffffffffffffff8116156110105773ffffffffffffffffffffffffffffffffffffffff811663e3563a4f8484610f7a604089018961413f565b6040518563ffffffff1660e01b8152600401610f999493929190614355565b60006040518083038186803b158015610fb157600080fd5b505afa925050508015610fc2575060015b611010576040517f86a9f75000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610639565b61101a8287613f78565b955050505050808061102b9061440c565b915050610e3f565b5060008167ffffffffffffffff81111561104f5761104f6139d6565b60405190808252806020026020018201604052801561108857816020015b61107561390c565b81526020019060019003908161106d5790505b5090506000805b8481101561117357368888838181106110aa576110aa61401f565b90506020028101906110bc91906140a3565b90503660006110cb83806140d7565b909250905060006110e26040850160208601613db5565b90508160005b8181101561115a5760008989815181106111045761110461401f565b602002602001015190506000806111278b898987818110610b9157610b9161401f565b91509150611137848383896125a3565b8a6111418161440c565b9b505050505080806111529061440c565b9150506110e8565b505050505050808061116b9061440c565b91505061108f565b50600080915060005b8581101561129957368989838181106111975761119761401f565b90506020028101906111a991906140a3565b90506111bb6040820160208301613db5565b73ffffffffffffffffffffffffffffffffffffffff167f575ff3acadd5ab348fe1855e217e0f3678f8d767d7494c9f9fefbee2e17cca4d60405160405180910390a236600061120a83806140d7565b90925090508060005b8181101561128157611255888585848181106112315761123161401f565b9050602002810190611243919061404e565b8b8b81518110610c0c57610c0c61401f565b61125f9088613f78565b96508761126b8161440c565b98505080806112799061440c565b915050611213565b505050505080806112919061440c565b91505061117c565b506040516000907f575ff3acadd5ab348fe1855e217e0f3678f8d767d7494c9f9fefbee2e17cca4d908290a26112cf868261297d565b5050505050505050565b831580156112fc575073ffffffffffffffffffffffffffffffffffffffff83163b155b15611363576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f41413230206163636f756e74206e6f74206465706c6f796564000000000000006044820152606401610639565b601481106113f557600061137a6014828486614444565b6113839161446e565b60601c9050803b6000036113f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f41413330207061796d6173746572206e6f74206465706c6f79656400000000006044820152606401610639565b505b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526020600482015260006024820152604401610639565b6040517f570e1a3600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063570e1a36906114a590859085906004016144b6565b6020604051808303816000875af11580156114c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e891906144ca565b6040517f6ca7b80600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610639565b600061153e82612ac9565b6040805160208101929092523090820152466060820152608001604051602081830303815290604052805190602001209050919050565b3360009081526020819052604081206001810154909163ffffffff90911690036115fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f6e6f74207374616b6564000000000000000000000000000000000000000000006044820152606401610639565b80546e010000000000000000000000000000900460ff16611678576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f616c726561647920756e7374616b696e670000000000000000000000000000006044820152606401610639565b60018101546000906116909063ffffffff16426144e7565b6001830180547fffffffffffffffffffffffffffffffffffffffffffff000000000000ffffffff1664010000000065ffffffffffff84169081029190911790915583547fffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffff16845560405190815290915033907ffa9b3c14cc825c412c9ed81b3ba365a5b459439403f18829e572ed53a4180f0a906020016105b5565b33600090815260208190526040902080546f0100000000000000000000000000000090046dffffffffffffffffffffffffffff16806117c7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4e6f207374616b6520746f2077697468647261770000000000000000000000006044820152606401610639565b6001820154640100000000900465ffffffffffff16611842576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6d7573742063616c6c20756e6c6f636b5374616b6528292066697273740000006044820152606401610639565b60018201544264010000000090910465ffffffffffff1611156118c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f5374616b65207769746864726177616c206973206e6f742064756500000000006044820152606401610639565b6001820180547fffffffffffffffffffffffffffffffffffffffffffff0000000000000000000016905581547fffffff0000000000000000000000000000ffffffffffffffffffffffffffffff1682556040805173ffffffffffffffffffffffffffffffffffffffff851681526020810183905233917fb7c918e0e249f999e965cafeb6c664271b3f4317d296461500e71da39f0cbda3910160405180910390a260008373ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d80600081146119bc576040519150601f19603f3d011682016040523d82523d6000602084013e6119c1565b606091505b5050905080610e34576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661696c656420746f207769746864726177207374616b6500000000000000006044820152606401610639565b611a3461390c565b611a3d85612ae2565b600080611a4c600088856123e1565b915091506000611a5c8383612bd5565b9050611a6743600052565b6000611a7560008a876127f8565b9050611a8043600052565b6000606073ffffffffffffffffffffffffffffffffffffffff8a1615611b10578973ffffffffffffffffffffffffffffffffffffffff168989604051611ac7929190614511565b6000604051808303816000865af19150503d8060008114611b04576040519150601f19603f3d011682016040523d82523d6000602084013e611b09565b606091505b5090925090505b8660800151838560200151866040015185856040517f8b7ac98000000000000000000000000000000000000000000000000000000000815260040161063996959493929190614521565b611b6261390c565b611b6b82612ae2565b600080611b7a600085856123e1565b845160a001516040805180820182526000808252602080830182815273ffffffffffffffffffffffffffffffffffffffff958616835282825284832080546dffffffffffffffffffffffffffff6f01000000000000000000000000000000918290048116875260019283015463ffffffff9081169094528d51518851808a018a5287815280870188815291909a16875286865288872080549390930490911689529101549091169052835180850190945281845283015293955091935090366000611c4860408a018a61413f565b909250905060006014821015611c5f576000611c7a565b611c6d601460008486614444565b611c769161446e565b60601c5b6040805180820182526000808252602080830182815273ffffffffffffffffffffffffffffffffffffffff861683529082905292902080546f0100000000000000000000000000000090046dffffffffffffffffffffffffffff1682526001015463ffffffff1690915290915093505050506000611cf88686612bd5565b90506000816000015190506000600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614905060006040518060c001604052808b6080015181526020018b6040015181526020018315158152602001856020015165ffffffffffff168152602001856040015165ffffffffffff168152602001611d8f8c6060015190565b9052905073ffffffffffffffffffffffffffffffffffffffff831615801590611dcf575073ffffffffffffffffffffffffffffffffffffffff8316600114155b15611e885760408051808201825273ffffffffffffffffffffffffffffffffffffffff851680825282518084018452600080825260208083018281529382528181529085902080546f0100000000000000000000000000000090046dffffffffffffffffffffffffffff1683526001015463ffffffff169092529082015290517ffaecb4e4000000000000000000000000000000000000000000000000000000008152610639908390899089908c9086906004016145c3565b808686896040517fe0cff05f0000000000000000000000000000000000000000000000000000000081526004016106399493929190614650565b73ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604081208054909190611f079084906dffffffffffffffffffffffffffff16613f78565b90506dffffffffffffffffffffffffffff811115611f81576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6465706f736974206f766572666c6f77000000000000000000000000000000006044820152606401610639565b81547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff919091161790555050565b6000806000845160208601878987f195945050505050565b60603d82811115611fe55750815b604051602082018101604052818152816000602083013e9392505050565b6000805a85519091506000908161201982612cbb565b60a083015190915073ffffffffffffffffffffffffffffffffffffffff81166120455782519350612293565b80935060008851111561229357868202955060028a600281111561206b5761206b6146a7565b146121035760608301516040517fa9a2340900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83169163a9a23409916120cb908e908d908c906004016146d6565b600060405180830381600088803b1580156120e557600080fd5b5087f11580156120f9573d6000803e3d6000fd5b5050505050612293565b60608301516040517fa9a2340900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83169163a9a234099161215e908e908d908c906004016146d6565b600060405180830381600088803b15801561217857600080fd5b5087f19350505050801561218a575060015b61229357612196614736565b806308c379a00361222657506121aa614752565b806121b55750612228565b8b816040516020016121c791906147fa565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f220266b60000000000000000000000000000000000000000000000000000000082526106399291600401614006565b505b8a6040517f220266b60000000000000000000000000000000000000000000000000000000081526004016106399181526040602082018190526012908201527f4141353020706f73744f70207265766572740000000000000000000000000000606082015260800190565b5a85038701965081870295508589604001511015612315578a6040517f220266b600000000000000000000000000000000000000000000000000000000815260040161063991815260406020808301829052908201527f414135312070726566756e642062656c6f772061637475616c476173436f7374606082015260800190565b60408901518690036123278582611ec2565b6000808c600281111561233c5761233c6146a7565b1490508460a0015173ffffffffffffffffffffffffffffffffffffffff16856000015173ffffffffffffffffffffffffffffffffffffffff168c602001517f49628fd1471006c1482da88028e9ce4dbb080b815c9b0344d39e5a8e6ec1419f8860200151858d8f6040516123c9949392919093845291151560208401526040830152606082015260800190565b60405180910390a45050505050505095945050505050565b60008060005a84519091506123f68682612ceb565b6123ff86611533565b6020860152604081015160608201516080830151171760e087013517610100870135176effffffffffffffffffffffffffffff81111561249b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f41413934206761732076616c756573206f766572666c6f7700000000000000006044820152606401610639565b6000806124a784612e0b565b90506124b58a8a8a84612e65565b975091506124c243600052565b60a084015160609073ffffffffffffffffffffffffffffffffffffffff16156124f7576124f28b8b8b858761317b565b975090505b60005a87039050808b60a001351015612575578b6040517f220266b6000000000000000000000000000000000000000000000000000000008152600401610639918152604060208201819052601e908201527f41413430206f76657220766572696669636174696f6e4761734c696d69740000606082015260800190565b60408a018390528160608b015260c08b01355a8803018a608001818152505050505050505050935093915050565b6000806125af8561343e565b915091508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161461265157856040517f220266b60000000000000000000000000000000000000000000000000000000081526004016106399181526040602082018190526014908201527f41413234207369676e6174757265206572726f72000000000000000000000000606082015260800190565b80156126c257856040517f220266b60000000000000000000000000000000000000000000000000000000081526004016106399181526040602082018190526017908201527f414132322065787069726564206f72206e6f7420647565000000000000000000606082015260800190565b60006126cd8561343e565b9250905073ffffffffffffffffffffffffffffffffffffffff81161561275857866040517f220266b60000000000000000000000000000000000000000000000000000000081526004016106399181526040602082018190526014908201527f41413334207369676e6174757265206572726f72000000000000000000000000606082015260800190565b81156127ef57866040517f220266b60000000000000000000000000000000000000000000000000000000081526004016106399181526040602082018190526021908201527f41413332207061796d61737465722065787069726564206f72206e6f7420647560608201527f6500000000000000000000000000000000000000000000000000000000000000608082015260a00190565b50505050505050565b6000805a9050600061280b846060015190565b905030631d732756612820606088018861413f565b87856040518563ffffffff1660e01b8152600401612841949392919061483f565b6020604051808303816000875af192505050801561289a575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261289791810190614900565b60015b61297157600060206000803e506000517f2152215300000000000000000000000000000000000000000000000000000000810161293c57866040517f220266b6000000000000000000000000000000000000000000000000000000008152600401610639918152604060208201819052600f908201527f41413935206f7574206f66206761730000000000000000000000000000000000606082015260800190565b600085608001515a61294e908661408c565b6129589190613f78565b9050612968886002888685612003565b94505050612974565b92505b50509392505050565b73ffffffffffffffffffffffffffffffffffffffff82166129fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4141393020696e76616c69642062656e656669636961727900000000000000006044820152606401610639565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114612a54576040519150601f19603f3d011682016040523d82523d6000602084013e612a59565b606091505b5050905080612ac4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f41413931206661696c65642073656e6420746f2062656e6566696369617279006044820152606401610639565b505050565b6000612ad482613491565b805190602001209050919050565b3063957122ab612af5604084018461413f565b612b026020860186613db5565b612b1061012087018761413f565b6040518663ffffffff1660e01b8152600401612b30959493929190614919565b60006040518083038186803b158015612b4857600080fd5b505afa925050508015612b59575060015b612bd257612b65614736565b806308c379a003612bc65750612b79614752565b80612b845750612bc8565b805115612bc2576000816040517f220266b6000000000000000000000000000000000000000000000000000000008152600401610639929190614006565b5050565b505b3d6000803e3d6000fd5b50565b6040805160608101825260008082526020820181905291810182905290612bfb846134d0565b90506000612c08846134d0565b825190915073ffffffffffffffffffffffffffffffffffffffff8116612c2c575080515b602080840151604080860151928501519085015191929165ffffffffffff8083169085161015612c5a578193505b8065ffffffffffff168365ffffffffffff161115612c76578092505b50506040805160608101825273ffffffffffffffffffffffffffffffffffffffff909416845265ffffffffffff92831660208501529116908201529250505092915050565b60c081015160e082015160009190808203612cd7575092915050565b612ce38248830161354e565b949350505050565b612cf86020830183613db5565b73ffffffffffffffffffffffffffffffffffffffff16815260208083013590820152608080830135604083015260a0830135606083015260c0808401359183019190915260e0808401359183019190915261010083013590820152366000612d6461012085018561413f565b90925090508015612dfe576014811015612dda576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f4141393320696e76616c6964207061796d6173746572416e64446174610000006044820152606401610639565b612de8601460008385614444565b612df19161446e565b60601c60a0840152610e34565b600060a084015250505050565b60a0810151600090819073ffffffffffffffffffffffffffffffffffffffff16612e36576001612e39565b60035b60ff16905060008360800151828560600151028560400151010190508360c00151810292505050919050565b60008060005a8551805191925090612e8a8988612e8560408c018c61413f565b613566565b60a0820151612e9843600052565b600073ffffffffffffffffffffffffffffffffffffffff8216612f015773ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260409020546dffffffffffffffffffffffffffff16888111612efa57808903612efd565b60005b9150505b606084015160208a01516040517f3a871cdd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff861692633a871cdd929091612f61918f91879060040161495c565b60206040518083038160008887f193505050508015612fbb575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252612fb891810190614900565b60015b61306557612fc7614736565b806308c379a003612ff85750612fdb614752565b80612fe65750612ffa565b8b816040516020016121c79190614981565b505b8a6040517f220266b60000000000000000000000000000000000000000000000000000000081526004016106399181526040602082018190526016908201527f4141323320726576657274656420286f72204f4f472900000000000000000000606082015260800190565b955073ffffffffffffffffffffffffffffffffffffffff82166131685773ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902080546dffffffffffffffffffffffffffff16808a111561312c578c6040517f220266b60000000000000000000000000000000000000000000000000000000081526004016106399181526040602082018190526017908201527f41413231206469646e2774207061792070726566756e64000000000000000000606082015260800190565b81547fffffffffffffffffffffffffffffffffffff000000000000000000000000000016908a90036dffffffffffffffffffffffffffff161790555b5a85039650505050505094509492505050565b825160608181015190916000918481116131f1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4141343120746f6f206c6974746c6520766572696669636174696f6e476173006044820152606401610639565b60a082015173ffffffffffffffffffffffffffffffffffffffff8116600090815260208190526040902080548784039291906dffffffffffffffffffffffffffff16898110156132a6578c6040517f220266b6000000000000000000000000000000000000000000000000000000008152600401610639918152604060208201819052601e908201527f41413331207061796d6173746572206465706f73697420746f6f206c6f770000606082015260800190565b8981038260000160006101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff1602179055508273ffffffffffffffffffffffffffffffffffffffff1663f465c77e858e8e602001518e6040518563ffffffff1660e01b81526004016133219392919061495c565b60006040518083038160008887f19350505050801561338057506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261337d91908101906149c6565b60015b61342a5761338c614736565b806308c379a0036133bd57506133a0614752565b806133ab57506133bf565b8d816040516020016121c79190614a52565b505b8c6040517f220266b60000000000000000000000000000000000000000000000000000000081526004016106399181526040602082018190526016908201527f4141333320726576657274656420286f72204f4f472900000000000000000000606082015260800190565b909e909d509b505050505050505050505050565b6000808260000361345457506000928392509050565b600061345f846134d0565b9050806040015165ffffffffffff164211806134865750806020015165ffffffffffff1642105b905194909350915050565b60603660006134a461014085018561413f565b915091508360208184030360405194506020810185016040528085528082602087013750505050919050565b60408051606081018252600080825260208201819052918101919091528160a081901c65ffffffffffff811660000361350c575065ffffffffffff5b6040805160608101825273ffffffffffffffffffffffffffffffffffffffff909316835260d09490941c602083015265ffffffffffff16928101929092525090565b600081831061355d578161355f565b825b9392505050565b8015610e345782515173ffffffffffffffffffffffffffffffffffffffff81163b156135f757846040517f220266b6000000000000000000000000000000000000000000000000000000008152600401610639918152604060208201819052601f908201527f414131302073656e64657220616c726561647920636f6e737472756374656400606082015260800190565b8351606001516040517f570e1a3600000000000000000000000000000000000000000000000000000000815260009173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169163570e1a36919061367590889088906004016144b6565b60206040518083038160008887f1158015613694573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906136b991906144ca565b905073ffffffffffffffffffffffffffffffffffffffff811661374157856040517f220266b6000000000000000000000000000000000000000000000000000000008152600401610639918152604060208201819052601b908201527f4141313320696e6974436f6465206661696c6564206f72204f4f470000000000606082015260800190565b8173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146137de57856040517f220266b600000000000000000000000000000000000000000000000000000000815260040161063991815260406020808301829052908201527f4141313420696e6974436f6465206d7573742072657475726e2073656e646572606082015260800190565b8073ffffffffffffffffffffffffffffffffffffffff163b60000361386757856040517f220266b600000000000000000000000000000000000000000000000000000000815260040161063991815260406020808301829052908201527f4141313520696e6974436f6465206d757374206372656174652073656e646572606082015260800190565b60006138766014828688614444565b61387f9161446e565b60601c90508273ffffffffffffffffffffffffffffffffffffffff1686602001517fd51a9c61267aa6196961883ecf5ff2da6619c37dac0fa92122513fb32c032d2d83896000015160a001516040516138fb92919073ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b60405180910390a350505050505050565b6040518060a0016040528061398b604051806101000160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081525090565b8152602001600080191681526020016000815260200160008152602001600081525090565b6000602082840312156139c257600080fd5b813563ffffffff8116811461355f57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60a0810181811067ffffffffffffffff82111715613a2557613a256139d6565b60405250565b610100810181811067ffffffffffffffff82111715613a2557613a256139d6565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116810181811067ffffffffffffffff82111715613a9057613a906139d6565b6040525050565b600067ffffffffffffffff821115613ab157613ab16139d6565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b73ffffffffffffffffffffffffffffffffffffffff81168114612bd257600080fd5b8035613b0a81613add565b919050565b6000818303610180811215613b2357600080fd5b604051613b2f81613a05565b80925061010080831215613b4257600080fd5b6040519250613b5083613a2b565b613b5985613aff565b835260208501356020840152604085013560408401526060850135606084015260808501356080840152613b8f60a08601613aff565b60a084015260c085013560c084015260e085013560e084015282825280850135602083015250610120840135604082015261014084013560608201526101608401356080820152505092915050565b60008083601f840112613bf057600080fd5b50813567ffffffffffffffff811115613c0857600080fd5b602083019150836020828501011115613c2057600080fd5b9250929050565b6000806000806101c08587031215613c3e57600080fd5b843567ffffffffffffffff80821115613c5657600080fd5b818701915087601f830112613c6a57600080fd5b8135613c7581613a97565b604051613c828282613a4c565b8281528a6020848701011115613c9757600080fd5b82602086016020830137600060208483010152809850505050613cbd8860208901613b0f565b94506101a0870135915080821115613cd457600080fd5b50613ce187828801613bde565b95989497509550505050565b60008083601f840112613cff57600080fd5b50813567ffffffffffffffff811115613d1757600080fd5b6020830191508360208260051b8501011115613c2057600080fd5b600080600060408486031215613d4757600080fd5b833567ffffffffffffffff811115613d5e57600080fd5b613d6a86828701613ced565b9094509250506020840135613d7e81613add565b809150509250925092565b60008060408385031215613d9c57600080fd5b8235613da781613add565b946020939093013593505050565b600060208284031215613dc757600080fd5b813561355f81613add565b600080600080600060608688031215613dea57600080fd5b853567ffffffffffffffff80821115613e0257600080fd5b613e0e89838a01613bde565b909750955060208801359150613e2382613add565b90935060408701359080821115613e3957600080fd5b50613e4688828901613bde565b969995985093965092949392505050565b60008060208385031215613e6a57600080fd5b823567ffffffffffffffff811115613e8157600080fd5b613e8d85828601613bde565b90969095509350505050565b60006101608284031215613eac57600080fd5b50919050565b600060208284031215613ec457600080fd5b813567ffffffffffffffff811115613edb57600080fd5b612ce384828501613e99565b60008060008060608587031215613efd57600080fd5b843567ffffffffffffffff80821115613f1557600080fd5b613f2188838901613e99565b955060208701359150613f3382613add565b90935060408601359080821115613cd457600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115613f8b57613f8b613f49565b500190565b60005b83811015613fab578181015183820152602001613f93565b83811115610e345750506000910152565b60008151808452613fd4816020860160208601613f90565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b828152604060208201526000612ce36040830184613fbc565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffea183360301811261408257600080fd5b9190910192915050565b60008282101561409e5761409e613f49565b500390565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa183360301811261408257600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261410c57600080fd5b83018035915067ffffffffffffffff82111561412757600080fd5b6020019150600581901b3603821315613c2057600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261417457600080fd5b83018035915067ffffffffffffffff82111561418f57600080fd5b602001915036819003821315613c2057600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126141d957600080fd5b830160208101925035905067ffffffffffffffff8111156141f957600080fd5b803603821315613c2057600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600061016061427d8461426385613aff565b73ffffffffffffffffffffffffffffffffffffffff169052565b6020830135602085015261429460408401846141a4565b8260408701526142a78387018284614208565b925050506142b860608401846141a4565b85830360608701526142cb838284614208565b925050506080830135608085015260a083013560a085015260c083013560c085015260e083013560e0850152610100808401358186015250610120614312818501856141a4565b86840383880152614324848284614208565b9350505050610140614338818501856141a4565b8684038388015261434a848284614208565b979650505050505050565b6040808252810184905260006060600586901b830181019083018783805b898110156143f5577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa087860301845282357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffea18c36030181126143d3578283fd5b6143df868d8301614251565b9550506020938401939290920191600101614373565b50505050828103602084015261434a818587614208565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361443d5761443d613f49565b5060010190565b6000808585111561445457600080fd5b8386111561446157600080fd5b5050820193919092039150565b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000081358181169160148510156144ae5780818660140360031b1b83161692505b505092915050565b602081526000612ce3602083018486614208565b6000602082840312156144dc57600080fd5b815161355f81613add565b600065ffffffffffff80831681851680830382111561450857614508613f49565b01949350505050565b8183823760009101908152919050565b868152856020820152600065ffffffffffff8087166040840152808616606084015250831515608083015260c060a083015261456060c0830184613fbc565b98975050505050505050565b80518252602081015160208301526040810151151560408301526000606082015165ffffffffffff8082166060860152806080850151166080860152505060a082015160c060a0850152612ce360c0850182613fbc565b60006101408083526145d78184018961456c565b9150506145f1602083018780518252602090810151910152565b845160608301526020948501516080830152835160a08301529284015160c0820152815173ffffffffffffffffffffffffffffffffffffffff1660e0820152908301518051610100830152909201516101209092019190915292915050565b60e08152600061466360e083018761456c565b905061467c602083018680518252602090810151910152565b8351606083015260208401516080830152825160a0830152602083015160c083015295945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60006003851061470f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b848252606060208301526147266060830185613fbc565b9050826040830152949350505050565b600060033d111561474f5760046000803e5060005160e01c5b90565b600060443d10156147605790565b6040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc803d016004833e81513d67ffffffffffffffff81602484011181841117156147ae57505050505090565b82850191508151818111156147c65750505050505090565b843d87010160208285010111156147e05750505050505090565b6147ef60208286010187613a4c565b509095945050505050565b7f4141353020706f73744f702072657665727465643a2000000000000000000000815260008251614832816016850160208701613f90565b9190910160160192915050565b60006101c08083526148548184018789614208565b9050845173ffffffffffffffffffffffffffffffffffffffff808251166020860152602082015160408601526040820151606086015260608201516080860152608082015160a08601528060a08301511660c08601525060c081015160e085015260e08101516101008501525060208501516101208401526040850151610140840152606085015161016084015260808501516101808401528281036101a084015261434a8185613fbc565b60006020828403121561491257600080fd5b5051919050565b60608152600061492d606083018789614208565b73ffffffffffffffffffffffffffffffffffffffff861660208401528281036040840152614560818587614208565b60608152600061496f6060830186614251565b60208301949094525060400152919050565b7f414132332072657665727465643a2000000000000000000000000000000000008152600082516149b981600f850160208701613f90565b91909101600f0192915050565b600080604083850312156149d957600080fd5b825167ffffffffffffffff8111156149f057600080fd5b8301601f81018513614a0157600080fd5b8051614a0c81613a97565b604051614a198282613a4c565b828152876020848601011115614a2e57600080fd5b614a3f836020830160208701613f90565b6020969096015195979596505050505050565b7f414133332072657665727465643a2000000000000000000000000000000000008152600082516149b981600f850160208701613f9056fea164736f6c634300080f000a608060405234801561001057600080fd5b506101ea806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063570e1a3614610030575b600080fd5b61004361003e3660046100f9565b61006c565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b60008061007c601482858761016b565b61008591610195565b60601c90506000610099846014818861016b565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525084519495509360209350849250905082850182875af190506000519350806100f057600093505b50505092915050565b6000806020838503121561010c57600080fd5b823567ffffffffffffffff8082111561012457600080fd5b818501915085601f83011261013857600080fd5b81358181111561014757600080fd5b86602082850101111561015957600080fd5b60209290920196919550909350505050565b6000808585111561017b57600080fd5b8386111561018857600080fd5b5050820193919092039150565b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000081358181169160148510156101d55780818660140360031b1b83161692505b50509291505056fea164736f6c634300080f000a", + Bin: "0x60a0604052604051620000129062000050565b604051809103906000f0801580156200002f573d6000803e3d6000fd5b506001600160a01b03166080523480156200004957600080fd5b506200005e565b61020a8062004b0483390190565b608051614a83620000816000396000818161146e015261363e0152614a836000f3fe6080604052600436106101125760003560e01c8063957122ab116100a5578063bb9fe6bf11610074578063d6383f9411610059578063d6383f941461042c578063ee2194231461044c578063fc7e286d1461046c57600080fd5b8063bb9fe6bf146103f7578063c23a5cea1461040c57600080fd5b8063957122ab146103845780639b249f69146103a4578063a6193531146103c4578063b760faf9146103e457600080fd5b80634b1d7cf5116100e15780634b1d7cf5146101ad5780635287ce12146101cd57806370a082311461031c5780638f41ec5a1461036f57600080fd5b80630396cb60146101275780631d7327561461013a5780631fad948c1461016d578063205c28781461018d57600080fd5b366101225761012033610546565b005b600080fd5b6101206101353660046139b1565b6105c1565b34801561014657600080fd5b5061015a610155366004613c28565b610944565b6040519081526020015b60405180910390f35b34801561017957600080fd5b50610120610188366004613d33565b610af7565b34801561019957600080fd5b506101206101a8366004613d8a565b610c38565b3480156101b957600080fd5b506101206101c8366004613d33565b610e3a565b3480156101d957600080fd5b506102bd6101e8366004613db6565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091525073ffffffffffffffffffffffffffffffffffffffff1660009081526020818152604091829020825160a08101845281546dffffffffffffffffffffffffffff80821683526e010000000000000000000000000000820460ff161515948301949094526f0100000000000000000000000000000090049092169282019290925260019091015463ffffffff81166060830152640100000000900465ffffffffffff16608082015290565b6040805182516dffffffffffffffffffffffffffff908116825260208085015115159083015283830151169181019190915260608083015163ffffffff169082015260809182015165ffffffffffff169181019190915260a001610164565b34801561032857600080fd5b5061015a610337366004613db6565b73ffffffffffffffffffffffffffffffffffffffff166000908152602081905260409020546dffffffffffffffffffffffffffff1690565b34801561037b57600080fd5b5061015a600181565b34801561039057600080fd5b5061012061039f366004613dd3565b6112d9565b3480156103b057600080fd5b506101206103bf366004613e58565b611431565b3480156103d057600080fd5b5061015a6103df366004613eb3565b611533565b6101206103f2366004613db6565b610546565b34801561040357600080fd5b50610120611575565b34801561041857600080fd5b50610120610427366004613db6565b61172c565b34801561043857600080fd5b50610120610447366004613ee8565b611a2c565b34801561045857600080fd5b50610120610467366004613eb3565b611b5a565b34801561047857600080fd5b506104f9610487366004613db6565b600060208190529081526040902080546001909101546dffffffffffffffffffffffffffff808316926e010000000000000000000000000000810460ff16926f010000000000000000000000000000009091049091169063ffffffff811690640100000000900465ffffffffffff1685565b604080516dffffffffffffffffffffffffffff96871681529415156020860152929094169183019190915263ffffffff16606082015265ffffffffffff909116608082015260a001610164565b6105508134611ec2565b73ffffffffffffffffffffffffffffffffffffffff811660008181526020818152604091829020805492516dffffffffffffffffffffffffffff909316835292917f2da466a7b24304f47e87fa2e1e5a81b9831ce54fec19055ce277ca2f39ba42c491015b60405180910390a25050565b33600090815260208190526040902063ffffffff8216610642576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f6d757374207370656369667920756e7374616b652064656c617900000000000060448201526064015b60405180910390fd5b600181015463ffffffff90811690831610156106ba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f63616e6e6f7420646563726561736520756e7374616b652074696d65000000006044820152606401610639565b80546000906106ed9034906f0100000000000000000000000000000090046dffffffffffffffffffffffffffff16613f79565b905060008111610759576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6e6f207374616b652073706563696669656400000000000000000000000000006044820152606401610639565b6dffffffffffffffffffffffffffff8111156107d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f7374616b65206f766572666c6f770000000000000000000000000000000000006044820152606401610639565b6040805160a08101825283546dffffffffffffffffffffffffffff90811682526001602080840182815286841685870190815263ffffffff808b16606088019081526000608089018181523380835296829052908a9020985189549551945189166f01000000000000000000000000000000027fffffff0000000000000000000000000000ffffffffffffffffffffffffffffff9515156e010000000000000000000000000000027fffffffffffffffffffffffffffffffffff0000000000000000000000000000009097169190991617949094179290921695909517865551949092018054925165ffffffffffff16640100000000027fffffffffffffffffffffffffffffffffffffffffffff00000000000000000000909316949093169390931717905590517fa5ae833d0bb1dcd632d98a8b70973e8516812898e19bf27b70071ebc8dc52c0190610937908490879091825263ffffffff16602082015260400190565b60405180910390a2505050565b6000805a90503330146109b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4141393220696e7465726e616c2063616c6c206f6e6c790000000000000000006044820152606401610639565b8451604081015160608201518101611388015a10156109f6577fdeaddead0000000000000000000000000000000000000000000000000000000060005260206000fd5b875160009015610a97576000610a13846000015160008c86611fbf565b905080610a95576000610a27610800611fd7565b805190915015610a8f57846000015173ffffffffffffffffffffffffffffffffffffffff168a602001517f1c4fada7374c0a9ee8841fc38afe82932dc0f8e69012e927f061a8bae611a201876020015184604051610a86929190613ffa565b60405180910390a35b60019250505b505b600088608001515a8603019050610ae96000838b8b8b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250889250612003915050565b9a9950505050505050505050565b8160008167ffffffffffffffff811115610b1357610b136139d7565b604051908082528060200260200182016040528015610b4c57816020015b610b3961390d565b815260200190600190039081610b315790505b50905060005b82811015610bc5576000828281518110610b6e57610b6e614013565b60200260200101519050600080610ba9848a8a87818110610b9157610b91614013565b9050602002810190610ba39190614042565b856123e1565b91509150610bba84838360006125a3565b505050600101610b52565b506000805b83811015610c2557610c1981888884818110610be857610be8614013565b9050602002810190610bfa9190614042565b858481518110610c0c57610c0c614013565b60200260200101516127f8565b90910190600101610bca565b50610c30848261297d565b505050505050565b33600090815260208190526040902080546dffffffffffffffffffffffffffff16821115610cc2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f576974686472617720616d6f756e7420746f6f206c61726765000000000000006044820152606401610639565b8054610cdf9083906dffffffffffffffffffffffffffff16614080565b81547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff919091161781556040805173ffffffffffffffffffffffffffffffffffffffff851681526020810184905233917fd1c19fbcd4551a5edfb66d43d2e337c04837afda3482b42bdf569a8fccdae5fb910160405180910390a260008373ffffffffffffffffffffffffffffffffffffffff168360405160006040518083038185875af1925050503d8060008114610dc4576040519150601f19603f3d011682016040523d82523d6000602084013e610dc9565b606091505b5050905080610e34576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6661696c656420746f20776974686472617700000000000000000000000000006044820152606401610639565b50505050565b816000805b828110156110335736868683818110610e5a57610e5a614013565b9050602002810190610e6c9190614093565b9050366000610e7b83806140c7565b90925090506000610e926040850160208601613db6565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff821601610f33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4141393620696e76616c69642061676772656761746f720000000000000000006044820152606401610639565b73ffffffffffffffffffffffffffffffffffffffff8116156110105773ffffffffffffffffffffffffffffffffffffffff811663e3563a4f8484610f7a604089018961412f565b6040518563ffffffff1660e01b8152600401610f999493929190614345565b60006040518083038186803b158015610fb157600080fd5b505afa925050508015610fc2575060015b611010576040517f86a9f75000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610639565b61101a8287613f79565b955050505050808061102b906143fc565b915050610e3f565b5060008167ffffffffffffffff81111561104f5761104f6139d7565b60405190808252806020026020018201604052801561108857816020015b61107561390d565b81526020019060019003908161106d5790505b5090506000805b8481101561117357368888838181106110aa576110aa614013565b90506020028101906110bc9190614093565b90503660006110cb83806140c7565b909250905060006110e26040850160208601613db6565b90508160005b8181101561115a57600089898151811061110457611104614013565b602002602001015190506000806111278b898987818110610b9157610b91614013565b91509150611137848383896125a3565b8a611141816143fc565b9b50505050508080611152906143fc565b9150506110e8565b505050505050808061116b906143fc565b91505061108f565b50600080915060005b85811015611299573689898381811061119757611197614013565b90506020028101906111a99190614093565b90506111bb6040820160208301613db6565b73ffffffffffffffffffffffffffffffffffffffff167f575ff3acadd5ab348fe1855e217e0f3678f8d767d7494c9f9fefbee2e17cca4d60405160405180910390a236600061120a83806140c7565b90925090508060005b81811015611281576112558885858481811061123157611231614013565b90506020028101906112439190614042565b8b8b81518110610c0c57610c0c614013565b61125f9088613f79565b96508761126b816143fc565b9850508080611279906143fc565b915050611213565b50505050508080611291906143fc565b91505061117c565b506040516000907f575ff3acadd5ab348fe1855e217e0f3678f8d767d7494c9f9fefbee2e17cca4d908290a26112cf868261297d565b5050505050505050565b831580156112fc575073ffffffffffffffffffffffffffffffffffffffff83163b155b15611363576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f41413230206163636f756e74206e6f74206465706c6f796564000000000000006044820152606401610639565b601481106113f557600061137a6014828486614434565b6113839161445e565b60601c9050803b6000036113f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f41413330207061796d6173746572206e6f74206465706c6f79656400000000006044820152606401610639565b505b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526020600482015260006024820152604401610639565b6040517f570e1a3600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063570e1a36906114a590859085906004016144a6565b6020604051808303816000875af11580156114c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e891906144ba565b6040517f6ca7b80600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610639565b600061153e82612ac9565b6040805160208101929092523090820152466060820152608001604051602081830303815290604052805190602001209050919050565b3360009081526020819052604081206001810154909163ffffffff90911690036115fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f6e6f74207374616b6564000000000000000000000000000000000000000000006044820152606401610639565b80546e010000000000000000000000000000900460ff16611678576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f616c726561647920756e7374616b696e670000000000000000000000000000006044820152606401610639565b60018101546000906116909063ffffffff16426144d7565b6001830180547fffffffffffffffffffffffffffffffffffffffffffff000000000000ffffffff1664010000000065ffffffffffff84169081029190911790915583547fffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffff16845560405190815290915033907ffa9b3c14cc825c412c9ed81b3ba365a5b459439403f18829e572ed53a4180f0a906020016105b5565b33600090815260208190526040902080546f0100000000000000000000000000000090046dffffffffffffffffffffffffffff16806117c7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4e6f207374616b6520746f2077697468647261770000000000000000000000006044820152606401610639565b6001820154640100000000900465ffffffffffff16611842576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6d7573742063616c6c20756e6c6f636b5374616b6528292066697273740000006044820152606401610639565b60018201544264010000000090910465ffffffffffff1611156118c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f5374616b65207769746864726177616c206973206e6f742064756500000000006044820152606401610639565b6001820180547fffffffffffffffffffffffffffffffffffffffffffff0000000000000000000016905581547fffffff0000000000000000000000000000ffffffffffffffffffffffffffffff1682556040805173ffffffffffffffffffffffffffffffffffffffff851681526020810183905233917fb7c918e0e249f999e965cafeb6c664271b3f4317d296461500e71da39f0cbda3910160405180910390a260008373ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d80600081146119bc576040519150601f19603f3d011682016040523d82523d6000602084013e6119c1565b606091505b5050905080610e34576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661696c656420746f207769746864726177207374616b6500000000000000006044820152606401610639565b611a3461390d565b611a3d85612ae2565b600080611a4c600088856123e1565b915091506000611a5c8383612bd5565b9050611a6743600052565b6000611a7560008a876127f8565b9050611a8043600052565b6000606073ffffffffffffffffffffffffffffffffffffffff8a1615611b10578973ffffffffffffffffffffffffffffffffffffffff168989604051611ac79291906144fd565b6000604051808303816000865af19150503d8060008114611b04576040519150601f19603f3d011682016040523d82523d6000602084013e611b09565b606091505b5090925090505b8660800151838560200151866040015185856040517f8b7ac9800000000000000000000000000000000000000000000000000000000081526004016106399695949392919061450d565b611b6261390d565b611b6b82612ae2565b600080611b7a600085856123e1565b845160a001516040805180820182526000808252602080830182815273ffffffffffffffffffffffffffffffffffffffff958616835282825284832080546dffffffffffffffffffffffffffff6f01000000000000000000000000000000918290048116875260019283015463ffffffff9081169094528d51518851808a018a5287815280870188815291909a16875286865288872080549390930490911689529101549091169052835180850190945281845283015293955091935090366000611c4860408a018a61412f565b909250905060006014821015611c5f576000611c7a565b611c6d601460008486614434565b611c769161445e565b60601c5b6040805180820182526000808252602080830182815273ffffffffffffffffffffffffffffffffffffffff861683529082905292902080546f0100000000000000000000000000000090046dffffffffffffffffffffffffffff1682526001015463ffffffff1690915290915093505050506000611cf88686612bd5565b90506000816000015190506000600173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614905060006040518060c001604052808b6080015181526020018b6040015181526020018315158152602001856020015165ffffffffffff168152602001856040015165ffffffffffff168152602001611d8f8c6060015190565b9052905073ffffffffffffffffffffffffffffffffffffffff831615801590611dcf575073ffffffffffffffffffffffffffffffffffffffff8316600114155b15611e885760408051808201825273ffffffffffffffffffffffffffffffffffffffff851680825282518084018452600080825260208083018281529382528181529085902080546f0100000000000000000000000000000090046dffffffffffffffffffffffffffff1683526001015463ffffffff169092529082015290517ffaecb4e4000000000000000000000000000000000000000000000000000000008152610639908390899089908c9086906004016145af565b808686896040517fe0cff05f000000000000000000000000000000000000000000000000000000008152600401610639949392919061463c565b73ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604081208054909190611f079084906dffffffffffffffffffffffffffff16613f79565b90506dffffffffffffffffffffffffffff811115611f81576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6465706f736974206f766572666c6f77000000000000000000000000000000006044820152606401610639565b81547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff919091161790555050565b6000806000845160208601878987f195945050505050565b60603d82811115611fe55750815b604051602082018101604052818152816000602083013e9392505050565b6000805a85519091506000908161201982612cbc565b60a083015190915073ffffffffffffffffffffffffffffffffffffffff81166120455782519350612293565b80935060008851111561229357868202955060028a600281111561206b5761206b614693565b146121035760608301516040517fa9a2340900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83169163a9a23409916120cb908e908d908c906004016146c2565b600060405180830381600088803b1580156120e557600080fd5b5087f11580156120f9573d6000803e3d6000fd5b5050505050612293565b60608301516040517fa9a2340900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83169163a9a234099161215e908e908d908c906004016146c2565b600060405180830381600088803b15801561217857600080fd5b5087f19350505050801561218a575060015b61229357612196614722565b806308c379a00361222657506121aa61473e565b806121b55750612228565b8b816040516020016121c791906147e6565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f220266b60000000000000000000000000000000000000000000000000000000082526106399291600401613ffa565b505b8a6040517f220266b60000000000000000000000000000000000000000000000000000000081526004016106399181526040602082018190526012908201527f4141353020706f73744f70207265766572740000000000000000000000000000606082015260800190565b5a85038701965081870295508589604001511015612315578a6040517f220266b600000000000000000000000000000000000000000000000000000000815260040161063991815260406020808301829052908201527f414135312070726566756e642062656c6f772061637475616c476173436f7374606082015260800190565b60408901518690036123278582611ec2565b6000808c600281111561233c5761233c614693565b1490508460a0015173ffffffffffffffffffffffffffffffffffffffff16856000015173ffffffffffffffffffffffffffffffffffffffff168c602001517f49628fd1471006c1482da88028e9ce4dbb080b815c9b0344d39e5a8e6ec1419f8860200151858d8f6040516123c9949392919093845291151560208401526040830152606082015260800190565b60405180910390a45050505050505095945050505050565b60008060005a84519091506123f68682612cec565b6123ff86611533565b6020860152604081015160608201516080830151171760e087013517610100870135176effffffffffffffffffffffffffffff81111561249b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f41413934206761732076616c756573206f766572666c6f7700000000000000006044820152606401610639565b6000806124a784612e0c565b90506124b58a8a8a84612e66565b975091506124c243600052565b60a084015160609073ffffffffffffffffffffffffffffffffffffffff16156124f7576124f28b8b8b858761317c565b975090505b60005a87039050808b60a001351015612575578b6040517f220266b6000000000000000000000000000000000000000000000000000000008152600401610639918152604060208201819052601e908201527f41413430206f76657220766572696669636174696f6e4761734c696d69740000606082015260800190565b60408a018390528160608b015260c08b01355a8803018a608001818152505050505050505050935093915050565b6000806125af8561343f565b915091508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161461265157856040517f220266b60000000000000000000000000000000000000000000000000000000081526004016106399181526040602082018190526014908201527f41413234207369676e6174757265206572726f72000000000000000000000000606082015260800190565b80156126c257856040517f220266b60000000000000000000000000000000000000000000000000000000081526004016106399181526040602082018190526017908201527f414132322065787069726564206f72206e6f7420647565000000000000000000606082015260800190565b60006126cd8561343f565b9250905073ffffffffffffffffffffffffffffffffffffffff81161561275857866040517f220266b60000000000000000000000000000000000000000000000000000000081526004016106399181526040602082018190526014908201527f41413334207369676e6174757265206572726f72000000000000000000000000606082015260800190565b81156127ef57866040517f220266b60000000000000000000000000000000000000000000000000000000081526004016106399181526040602082018190526021908201527f41413332207061796d61737465722065787069726564206f72206e6f7420647560608201527f6500000000000000000000000000000000000000000000000000000000000000608082015260a00190565b50505050505050565b6000805a9050600061280b846060015190565b905030631d732756612820606088018861412f565b87856040518563ffffffff1660e01b8152600401612841949392919061482b565b6020604051808303816000875af192505050801561289a575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252612897918101906148ec565b60015b61297157600060206000803e506000517f2152215300000000000000000000000000000000000000000000000000000000810161293c57866040517f220266b6000000000000000000000000000000000000000000000000000000008152600401610639918152604060208201819052600f908201527f41413935206f7574206f66206761730000000000000000000000000000000000606082015260800190565b600085608001515a61294e9086614080565b6129589190613f79565b9050612968886002888685612003565b94505050612974565b92505b50509392505050565b73ffffffffffffffffffffffffffffffffffffffff82166129fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4141393020696e76616c69642062656e656669636961727900000000000000006044820152606401610639565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114612a54576040519150601f19603f3d011682016040523d82523d6000602084013e612a59565b606091505b5050905080612ac4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f41413931206661696c65642073656e6420746f2062656e6566696369617279006044820152606401610639565b505050565b6000612ad482613492565b805190602001209050919050565b3063957122ab612af5604084018461412f565b612b026020860186613db6565b612b1061012087018761412f565b6040518663ffffffff1660e01b8152600401612b30959493929190614905565b60006040518083038186803b158015612b4857600080fd5b505afa925050508015612b59575060015b612bd257612b65614722565b806308c379a003612bc65750612b7961473e565b80612b845750612bc8565b805115612bc2576000816040517f220266b6000000000000000000000000000000000000000000000000000000008152600401610639929190613ffa565b5050565b505b3d6000803e3d6000fd5b50565b6040805160608101825260008082526020820181905291810182905290612bfb846134d1565b90506000612c08846134d1565b825190915073ffffffffffffffffffffffffffffffffffffffff8116612c2c575080515b602080840151604080860151928501519085015191929165ffffffffffff8083169085161015612c5a578193505b8065ffffffffffff168365ffffffffffff161115612c76578092505b50506040805160608101825273ffffffffffffffffffffffffffffffffffffffff909416845265ffffffffffff9283166020850152911690820152925050505b92915050565b60c081015160e082015160009190808203612cd8575092915050565b612ce48248830161354f565b949350505050565b612cf96020830183613db6565b73ffffffffffffffffffffffffffffffffffffffff16815260208083013590820152608080830135604083015260a0830135606083015260c0808401359183019190915260e0808401359183019190915261010083013590820152366000612d6561012085018561412f565b90925090508015612dff576014811015612ddb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f4141393320696e76616c6964207061796d6173746572416e64446174610000006044820152606401610639565b612de9601460008385614434565b612df29161445e565b60601c60a0840152610e34565b600060a084015250505050565b60a0810151600090819073ffffffffffffffffffffffffffffffffffffffff16612e37576001612e3a565b60035b60ff16905060008360800151828560600151028560400151010190508360c00151810292505050919050565b60008060005a8551805191925090612e8b8988612e8660408c018c61412f565b613567565b60a0820151612e9943600052565b600073ffffffffffffffffffffffffffffffffffffffff8216612f025773ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260409020546dffffffffffffffffffffffffffff16888111612efb57808903612efe565b60005b9150505b606084015160208a01516040517f3a871cdd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff861692633a871cdd929091612f62918f918790600401614948565b60206040518083038160008887f193505050508015612fbc575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252612fb9918101906148ec565b60015b61306657612fc8614722565b806308c379a003612ff95750612fdc61473e565b80612fe75750612ffb565b8b816040516020016121c7919061496d565b505b8a6040517f220266b60000000000000000000000000000000000000000000000000000000081526004016106399181526040602082018190526016908201527f4141323320726576657274656420286f72204f4f472900000000000000000000606082015260800190565b955073ffffffffffffffffffffffffffffffffffffffff82166131695773ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902080546dffffffffffffffffffffffffffff16808a111561312d578c6040517f220266b60000000000000000000000000000000000000000000000000000000081526004016106399181526040602082018190526017908201527f41413231206469646e2774207061792070726566756e64000000000000000000606082015260800190565b81547fffffffffffffffffffffffffffffffffffff000000000000000000000000000016908a90036dffffffffffffffffffffffffffff161790555b5a85039650505050505094509492505050565b825160608181015190916000918481116131f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4141343120746f6f206c6974746c6520766572696669636174696f6e476173006044820152606401610639565b60a082015173ffffffffffffffffffffffffffffffffffffffff8116600090815260208190526040902080548784039291906dffffffffffffffffffffffffffff16898110156132a7578c6040517f220266b6000000000000000000000000000000000000000000000000000000008152600401610639918152604060208201819052601e908201527f41413331207061796d6173746572206465706f73697420746f6f206c6f770000606082015260800190565b8981038260000160006101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff1602179055508273ffffffffffffffffffffffffffffffffffffffff1663f465c77e858e8e602001518e6040518563ffffffff1660e01b815260040161332293929190614948565b60006040518083038160008887f19350505050801561338157506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261337e91908101906149b2565b60015b61342b5761338d614722565b806308c379a0036133be57506133a161473e565b806133ac57506133c0565b8d816040516020016121c79190614a3e565b505b8c6040517f220266b60000000000000000000000000000000000000000000000000000000081526004016106399181526040602082018190526016908201527f4141333320726576657274656420286f72204f4f472900000000000000000000606082015260800190565b909e909d509b505050505050505050505050565b6000808260000361345557506000928392509050565b6000613460846134d1565b9050806040015165ffffffffffff164211806134875750806020015165ffffffffffff1642105b905194909350915050565b60603660006134a561014085018561412f565b915091508360208184030360405194506020810185016040528085528082602087013750505050919050565b60408051606081018252600080825260208201819052918101919091528160a081901c65ffffffffffff811660000361350d575065ffffffffffff5b6040805160608101825273ffffffffffffffffffffffffffffffffffffffff909316835260d09490941c602083015265ffffffffffff16928101929092525090565b600081831061355e5781613560565b825b9392505050565b8015610e345782515173ffffffffffffffffffffffffffffffffffffffff81163b156135f857846040517f220266b6000000000000000000000000000000000000000000000000000000008152600401610639918152604060208201819052601f908201527f414131302073656e64657220616c726561647920636f6e737472756374656400606082015260800190565b8351606001516040517f570e1a3600000000000000000000000000000000000000000000000000000000815260009173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169163570e1a36919061367690889088906004016144a6565b60206040518083038160008887f1158015613695573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906136ba91906144ba565b905073ffffffffffffffffffffffffffffffffffffffff811661374257856040517f220266b6000000000000000000000000000000000000000000000000000000008152600401610639918152604060208201819052601b908201527f4141313320696e6974436f6465206661696c6564206f72204f4f470000000000606082015260800190565b8173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146137df57856040517f220266b600000000000000000000000000000000000000000000000000000000815260040161063991815260406020808301829052908201527f4141313420696e6974436f6465206d7573742072657475726e2073656e646572606082015260800190565b8073ffffffffffffffffffffffffffffffffffffffff163b60000361386857856040517f220266b600000000000000000000000000000000000000000000000000000000815260040161063991815260406020808301829052908201527f4141313520696e6974436f6465206d757374206372656174652073656e646572606082015260800190565b60006138776014828688614434565b6138809161445e565b60601c90508273ffffffffffffffffffffffffffffffffffffffff1686602001517fd51a9c61267aa6196961883ecf5ff2da6619c37dac0fa92122513fb32c032d2d83896000015160a001516040516138fc92919073ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b60405180910390a350505050505050565b6040518060a0016040528061398c604051806101000160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081525090565b8152602001600080191681526020016000815260200160008152602001600081525090565b6000602082840312156139c357600080fd5b813563ffffffff8116811461356057600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60a0810181811067ffffffffffffffff82111715613a2657613a266139d7565b60405250565b610100810181811067ffffffffffffffff82111715613a2657613a266139d7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116810181811067ffffffffffffffff82111715613a9157613a916139d7565b6040525050565b600067ffffffffffffffff821115613ab257613ab26139d7565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b73ffffffffffffffffffffffffffffffffffffffff81168114612bd257600080fd5b8035613b0b81613ade565b919050565b6000818303610180811215613b2457600080fd5b604051613b3081613a06565b80925061010080831215613b4357600080fd5b6040519250613b5183613a2c565b613b5a85613b00565b835260208501356020840152604085013560408401526060850135606084015260808501356080840152613b9060a08601613b00565b60a084015260c085013560c084015260e085013560e084015282825280850135602083015250610120840135604082015261014084013560608201526101608401356080820152505092915050565b60008083601f840112613bf157600080fd5b50813567ffffffffffffffff811115613c0957600080fd5b602083019150836020828501011115613c2157600080fd5b9250929050565b6000806000806101c08587031215613c3f57600080fd5b843567ffffffffffffffff80821115613c5757600080fd5b818701915087601f830112613c6b57600080fd5b8135613c7681613a98565b604051613c838282613a4d565b8281528a6020848701011115613c9857600080fd5b82602086016020830137600060208483010152809850505050613cbe8860208901613b10565b94506101a0870135915080821115613cd557600080fd5b50613ce287828801613bdf565b95989497509550505050565b60008083601f840112613d0057600080fd5b50813567ffffffffffffffff811115613d1857600080fd5b6020830191508360208260051b8501011115613c2157600080fd5b600080600060408486031215613d4857600080fd5b833567ffffffffffffffff811115613d5f57600080fd5b613d6b86828701613cee565b9094509250506020840135613d7f81613ade565b809150509250925092565b60008060408385031215613d9d57600080fd5b8235613da881613ade565b946020939093013593505050565b600060208284031215613dc857600080fd5b813561356081613ade565b600080600080600060608688031215613deb57600080fd5b853567ffffffffffffffff80821115613e0357600080fd5b613e0f89838a01613bdf565b909750955060208801359150613e2482613ade565b90935060408701359080821115613e3a57600080fd5b50613e4788828901613bdf565b969995985093965092949392505050565b60008060208385031215613e6b57600080fd5b823567ffffffffffffffff811115613e8257600080fd5b613e8e85828601613bdf565b90969095509350505050565b60006101608284031215613ead57600080fd5b50919050565b600060208284031215613ec557600080fd5b813567ffffffffffffffff811115613edc57600080fd5b612ce484828501613e9a565b60008060008060608587031215613efe57600080fd5b843567ffffffffffffffff80821115613f1657600080fd5b613f2288838901613e9a565b955060208701359150613f3482613ade565b90935060408601359080821115613cd557600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115612cb657612cb6613f4a565b60005b83811015613fa7578181015183820152602001613f8f565b50506000910152565b60008151808452613fc8816020860160208601613f8c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b828152604060208201526000612ce46040830184613fb0565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffea183360301811261407657600080fd5b9190910192915050565b81810381811115612cb657612cb6613f4a565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa183360301811261407657600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126140fc57600080fd5b83018035915067ffffffffffffffff82111561411757600080fd5b6020019150600581901b3603821315613c2157600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261416457600080fd5b83018035915067ffffffffffffffff82111561417f57600080fd5b602001915036819003821315613c2157600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126141c957600080fd5b830160208101925035905067ffffffffffffffff8111156141e957600080fd5b803603821315613c2157600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600061016061426d8461425385613b00565b73ffffffffffffffffffffffffffffffffffffffff169052565b602083013560208501526142846040840184614194565b82604087015261429783870182846141f8565b925050506142a86060840184614194565b85830360608701526142bb8382846141f8565b925050506080830135608085015260a083013560a085015260c083013560c085015260e083013560e085015261010080840135818601525061012061430281850185614194565b868403838801526143148482846141f8565b935050505061014061432881850185614194565b8684038388015261433a8482846141f8565b979650505050505050565b6040808252810184905260006060600586901b830181019083018783805b898110156143e5577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa087860301845282357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffea18c36030181126143c3578283fd5b6143cf868d8301614241565b9550506020938401939290920191600101614363565b50505050828103602084015261433a8185876141f8565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361442d5761442d613f4a565b5060010190565b6000808585111561444457600080fd5b8386111561445157600080fd5b5050820193919092039150565b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000813581811691601485101561449e5780818660140360031b1b83161692505b505092915050565b602081526000612ce46020830184866141f8565b6000602082840312156144cc57600080fd5b815161356081613ade565b65ffffffffffff8181168382160190808211156144f6576144f6613f4a565b5092915050565b8183823760009101908152919050565b868152856020820152600065ffffffffffff8087166040840152808616606084015250831515608083015260c060a083015261454c60c0830184613fb0565b98975050505050505050565b80518252602081015160208301526040810151151560408301526000606082015165ffffffffffff8082166060860152806080850151166080860152505060a082015160c060a0850152612ce460c0850182613fb0565b60006101408083526145c381840189614558565b9150506145dd602083018780518252602090810151910152565b845160608301526020948501516080830152835160a08301529284015160c0820152815173ffffffffffffffffffffffffffffffffffffffff1660e0820152908301518051610100830152909201516101209092019190915292915050565b60e08152600061464f60e0830187614558565b9050614668602083018680518252602090810151910152565b8351606083015260208401516080830152825160a0830152602083015160c083015295945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6000600385106146fb577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b848252606060208301526147126060830185613fb0565b9050826040830152949350505050565b600060033d111561473b5760046000803e5060005160e01c5b90565b600060443d101561474c5790565b6040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc803d016004833e81513d67ffffffffffffffff816024840111818411171561479a57505050505090565b82850191508151818111156147b25750505050505090565b843d87010160208285010111156147cc5750505050505090565b6147db60208286010187613a4d565b509095945050505050565b7f4141353020706f73744f702072657665727465643a200000000000000000000081526000825161481e816016850160208701613f8c565b9190910160160192915050565b60006101c080835261484081840187896141f8565b9050845173ffffffffffffffffffffffffffffffffffffffff808251166020860152602082015160408601526040820151606086015260608201516080860152608082015160a08601528060a08301511660c08601525060c081015160e085015260e08101516101008501525060208501516101208401526040850151610140840152606085015161016084015260808501516101808401528281036101a084015261433a8185613fb0565b6000602082840312156148fe57600080fd5b5051919050565b6060815260006149196060830187896141f8565b73ffffffffffffffffffffffffffffffffffffffff86166020840152828103604084015261454c8185876141f8565b60608152600061495b6060830186614241565b60208301949094525060400152919050565b7f414132332072657665727465643a2000000000000000000000000000000000008152600082516149a581600f850160208701613f8c565b91909101600f0192915050565b600080604083850312156149c557600080fd5b825167ffffffffffffffff8111156149dc57600080fd5b8301601f810185136149ed57600080fd5b80516149f881613a98565b604051614a058282613a4d565b828152876020848601011115614a1a57600080fd5b614a2b836020830160208701613f8c565b6020969096015195979596505050505050565b7f414133332072657665727465643a2000000000000000000000000000000000008152600082516149a581600f850160208701613f8c56fea164736f6c6343000813000a608060405234801561001057600080fd5b506101ea806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063570e1a3614610030575b600080fd5b61004361003e3660046100f9565b61006c565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b60008061007c601482858761016b565b61008591610195565b60601c90506000610099846014818861016b565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525084519495509360209350849250905082850182875af190506000519350806100f057600093505b50505092915050565b6000806020838503121561010c57600080fd5b823567ffffffffffffffff8082111561012457600080fd5b818501915085601f83011261013857600080fd5b81358181111561014757600080fd5b86602082850101111561015957600080fd5b60209290920196919550909350505050565b6000808585111561017b57600080fd5b8386111561018857600080fd5b5050820193919092039150565b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000081358181169160148510156101d55780818660140360031b1b83161692505b50509291505056fea164736f6c6343000813000a", } var EntryPointABI = EntryPointMetaData.ABI diff --git a/core/gethwrappers/transmission/generated/greeter_wrapper/greeter_wrapper.go b/core/gethwrappers/transmission/generated/greeter_wrapper/greeter_wrapper.go index 9814c6a12c0..0f9e4a7719d 100644 --- a/core/gethwrappers/transmission/generated/greeter_wrapper/greeter_wrapper.go +++ b/core/gethwrappers/transmission/generated/greeter_wrapper/greeter_wrapper.go @@ -30,7 +30,7 @@ var ( var GreeterMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[],\"name\":\"getGreeting\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"greeting\",\"type\":\"string\"}],\"name\":\"setGreeting\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b5061044a806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063a41368621461003b578063fe50cc7214610050575b600080fd5b61004e61004936600461013f565b61006e565b005b61005861007e565b604051610065919061020e565b60405180910390f35b600061007a8282610323565b5050565b60606000805461008d90610281565b80601f01602080910402602001604051908101604052809291908181526020018280546100b990610281565b80156101065780601f106100db57610100808354040283529160200191610106565b820191906000526020600020905b8154815290600101906020018083116100e957829003601f168201915b5050505050905090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561015157600080fd5b813567ffffffffffffffff8082111561016957600080fd5b818401915084601f83011261017d57600080fd5b81358181111561018f5761018f610110565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156101d5576101d5610110565b816040528281528760208487010111156101ee57600080fd5b826020860160208301376000928101602001929092525095945050505050565b600060208083528351808285015260005b8181101561023b5785810183015185820160400152820161021f565b8181111561024d576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b600181811c9082168061029557607f821691505b6020821081036102ce577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f82111561031e57600081815260208120601f850160051c810160208610156102fb5750805b601f850160051c820191505b8181101561031a57828155600101610307565b5050505b505050565b815167ffffffffffffffff81111561033d5761033d610110565b6103518161034b8454610281565b846102d4565b602080601f8311600181146103a4576000841561036e5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b17855561031a565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156103f1578886015182559484019460019091019084016103d2565b508582101561042d57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b0190555056fea164736f6c634300080f000a", + Bin: "0x608060405234801561001057600080fd5b50610443806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063a41368621461003b578063fe50cc7214610050575b600080fd5b61004e61004936600461013f565b61006e565b005b61005861007e565b604051610065919061020e565b60405180910390f35b600061007a828261031c565b5050565b60606000805461008d9061027a565b80601f01602080910402602001604051908101604052809291908181526020018280546100b99061027a565b80156101065780601f106100db57610100808354040283529160200191610106565b820191906000526020600020905b8154815290600101906020018083116100e957829003601f168201915b5050505050905090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561015157600080fd5b813567ffffffffffffffff8082111561016957600080fd5b818401915084601f83011261017d57600080fd5b81358181111561018f5761018f610110565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156101d5576101d5610110565b816040528281528760208487010111156101ee57600080fd5b826020860160208301376000928101602001929092525095945050505050565b600060208083528351808285015260005b8181101561023b5785810183015185820160400152820161021f565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b600181811c9082168061028e57607f821691505b6020821081036102c7577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f82111561031757600081815260208120601f850160051c810160208610156102f45750805b601f850160051c820191505b8181101561031357828155600101610300565b5050505b505050565b815167ffffffffffffffff81111561033657610336610110565b61034a81610344845461027a565b846102cd565b602080601f83116001811461039d57600084156103675750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555610313565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156103ea578886015182559484019460019091019084016103cb565b508582101561042657878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b0190555056fea164736f6c6343000813000a", } var GreeterABI = GreeterMetaData.ABI diff --git a/core/gethwrappers/transmission/generated/paymaster_wrapper/paymaster_wrapper.go b/core/gethwrappers/transmission/generated/paymaster_wrapper/paymaster_wrapper.go index 4910d2b4bb9..63a2712ca3f 100644 --- a/core/gethwrappers/transmission/generated/paymaster_wrapper/paymaster_wrapper.go +++ b/core/gethwrappers/transmission/generated/paymaster_wrapper/paymaster_wrapper.go @@ -46,7 +46,7 @@ type UserOperation struct { var PaymasterMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"linkToken\",\"type\":\"address\"},{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"linkEthFeed\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"entryPoint\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"juelsNeeded\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"subscriptionBalance\",\"type\":\"uint256\"}],\"name\":\"InsufficientFunds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"validator\",\"type\":\"address\"}],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"userOpHash\",\"type\":\"bytes32\"}],\"name\":\"UserOperationAlreadyTried\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_entryPoint\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_linkEthFeed\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_linkToken\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"enumIPaymaster.PostOpMode\",\"name\":\"\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"context\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"actualGasCost\",\"type\":\"uint256\"}],\"name\":\"postOp\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_config\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structUserOperation\",\"name\":\"userOp\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"userOpHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"maxCost\",\"type\":\"uint256\"}],\"name\":\"validatePaymasterUserOp\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"context\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"validationData\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60e06040523480156200001157600080fd5b50604051620014fb380380620014fb8339810160408190526200003491620001a3565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000df565b5050506001600160a01b0392831660805290821660a0521660c052620001f7565b336001600160a01b03821603620001395760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b0381168114620001a057600080fd5b50565b600080600060608486031215620001b957600080fd5b8351620001c6816200018a565b6020850151909350620001d9816200018a565b6040850151909250620001ec816200018a565b809150509250925092565b60805160a05160c05161129c6200025f600039600081816101080152818161049f01528181610507015281816105cd015261063501526000818161018f0152610cb60152600081816101dc015281816103a201528181610ac90152610b81015261129c6000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c80639b9bd4de11610081578063db37983b1161005b578063db37983b146101d7578063f2fde38b146101fe578063f465c77e1461021157600080fd5b80639b9bd4de1461018a578063a4c0ed36146101b1578063a9a23409146101c457600080fd5b806379ba5097116100b257806379ba50971461014f5780638a38f365146101595780638da5cb5b1461016c57600080fd5b8063088070f5146100ce578063140fcfb114610103575b600080fd5b6002546003546100e29163ffffffff169082565b6040805163ffffffff90931683526020830191909152015b60405180910390f35b61012a7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100fa565b610157610232565b005b610157610167366004610d5b565b610334565b60005473ffffffffffffffffffffffffffffffffffffffff1661012a565b61012a7f000000000000000000000000000000000000000000000000000000000000000081565b6101576101bf366004610dfb565b61038a565b6101576101d2366004610e57565b610487565b61012a7f000000000000000000000000000000000000000000000000000000000000000081565b61015761020c366004610eb7565b61059d565b61022461021f366004610edb565b6105b1565b6040516100fa929190610f2f565b60015473ffffffffffffffffffffffffffffffffffffffff1633146102b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b61033c610849565b6040805180820190915263ffffffff9092168083526020909201819052600280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000016909217909155600355565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146103f9576040517f44b0e3c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208114610433576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061044182840184610eb7565b73ffffffffffffffffffffffffffffffffffffffff811660009081526005602052604081208054929350869290919061047b908490610fd9565b90915550505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610534576040517f295a81c100000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526044016102af565b60008061054384860186610ff1565b9150915080610551846108cc565b61055b9190610fd9565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600560205260408120805490919061059090849061100f565b9091555050505050505050565b6105a5610849565b6105ae816108f8565b50565b606060003373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610662576040517f295a81c100000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526044016102af565b60008481526004602052604090205460ff16156106ae576040517f7413dcf8000000000000000000000000000000000000000000000000000000008152600481018590526024016102af565b60006106b9866109ed565b90506000816106c7866108cc565b6106d19190610fd9565b905080600560006106e560208b018b610eb7565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156107b057806005600061073860208b018b610eb7565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546040517f03eb8b540000000000000000000000000000000000000000000000000000000081526004016102af929190918252602082015260400190565b600086815260046020908152604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556107f690880188610eb7565b6040805173ffffffffffffffffffffffffffffffffffffffff9092166020830152810183905260600160405160208183030381529060405261083b6000806000610c29565b935093505050935093915050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146108ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016102af565b565b60006108d6610c61565b6108e883670de0b6b3a7640000611026565b6108f29190611063565b92915050565b3373ffffffffffffffffffffffffffffffffffffffff821603610977576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016102af565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60006109fd61012083018361109e565b9050601403610a0e57506000919050565b6000610a1e61012084018461109e565b6014818110610a2f57610a2f611103565b919091013560f81c9150819050610c23576000610a5061012085018561109e565b610a5e916015908290611132565b810190610a6b919061115c565b90508060200151600014158015610b385750602081015181516040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201527f0000000000000000000000000000000000000000000000000000000000000000909116906370a0823190602401602060405180830381865afa158015610b12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b3691906111e5565b105b15610c2157805160408083015190517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169263a9059cbb92610bd59260040173ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b6020604051808303816000875af1158015610bf4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1891906111fe565b50806040015192505b505b50919050565b600060d08265ffffffffffff16901b60a08465ffffffffffff16901b85610c51576000610c54565b60015b60ff161717949350505050565b600254604080517ffeaf968c000000000000000000000000000000000000000000000000000000008152905160009263ffffffff1691821515918491829173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169163feaf968c9160048083019260a09291908290030181865afa158015610d01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d25919061123f565b509450909250849150508015610d495750610d40824261100f565b8463ffffffff16105b15610d5357506003545b949350505050565b60008060408385031215610d6e57600080fd5b823563ffffffff81168114610d8257600080fd5b946020939093013593505050565b73ffffffffffffffffffffffffffffffffffffffff811681146105ae57600080fd5b60008083601f840112610dc457600080fd5b50813567ffffffffffffffff811115610ddc57600080fd5b602083019150836020828501011115610df457600080fd5b9250929050565b60008060008060608587031215610e1157600080fd5b8435610e1c81610d90565b935060208501359250604085013567ffffffffffffffff811115610e3f57600080fd5b610e4b87828801610db2565b95989497509550505050565b60008060008060608587031215610e6d57600080fd5b843560038110610e7c57600080fd5b9350602085013567ffffffffffffffff811115610e9857600080fd5b610ea487828801610db2565b9598909750949560400135949350505050565b600060208284031215610ec957600080fd5b8135610ed481610d90565b9392505050565b600080600060608486031215610ef057600080fd5b833567ffffffffffffffff811115610f0757600080fd5b84016101608187031215610f1a57600080fd5b95602085013595506040909401359392505050565b604081526000835180604084015260005b81811015610f5d5760208187018101516060868401015201610f40565b81811115610f6f576000606083860101525b50602083019390935250601f919091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01601606001919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115610fec57610fec610faa565b500190565b6000806040838503121561100457600080fd5b8235610d8281610d90565b60008282101561102157611021610faa565b500390565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561105e5761105e610faa565b500290565b600082611099577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126110d357600080fd5b83018035915067ffffffffffffffff8211156110ee57600080fd5b602001915036819003821315610df457600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000808585111561114257600080fd5b8386111561114f57600080fd5b5050820193919092039150565b60006060828403121561116e57600080fd5b6040516060810181811067ffffffffffffffff821117156111b8577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405282356111c681610d90565b8152602083810135908201526040928301359281019290925250919050565b6000602082840312156111f757600080fd5b5051919050565b60006020828403121561121057600080fd5b81518015158114610ed457600080fd5b805169ffffffffffffffffffff8116811461123a57600080fd5b919050565b600080600080600060a0868803121561125757600080fd5b61126086611220565b945060208601519350604086015192506060860151915061128360808701611220565b9050929550929590935056fea164736f6c634300080f000a", + Bin: "0x60e06040523480156200001157600080fd5b50604051620014c4380380620014c48339810160408190526200003491620001a3565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000df565b5050506001600160a01b0392831660805290821660a0521660c052620001f7565b336001600160a01b03821603620001395760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b0381168114620001a057600080fd5b50565b600080600060608486031215620001b957600080fd5b8351620001c6816200018a565b6020850151909350620001d9816200018a565b6040850151909250620001ec816200018a565b809150509250925092565b60805160a05160c0516112656200025f600039600081816101080152818161049f01528181610507015281816105cd015261063501526000818161018f0152610cb60152600081816101dc015281816103a201528181610ac90152610b8101526112656000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c80639b9bd4de11610081578063db37983b1161005b578063db37983b146101d7578063f2fde38b146101fe578063f465c77e1461021157600080fd5b80639b9bd4de1461018a578063a4c0ed36146101b1578063a9a23409146101c457600080fd5b806379ba5097116100b257806379ba50971461014f5780638a38f365146101595780638da5cb5b1461016c57600080fd5b8063088070f5146100ce578063140fcfb114610103575b600080fd5b6002546003546100e29163ffffffff169082565b6040805163ffffffff90931683526020830191909152015b60405180910390f35b61012a7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100fa565b610157610232565b005b610157610167366004610d5b565b610334565b60005473ffffffffffffffffffffffffffffffffffffffff1661012a565b61012a7f000000000000000000000000000000000000000000000000000000000000000081565b6101576101bf366004610dfb565b61038a565b6101576101d2366004610e57565b610487565b61012a7f000000000000000000000000000000000000000000000000000000000000000081565b61015761020c366004610eb7565b61059d565b61022461021f366004610edb565b6105b1565b6040516100fa929190610f2f565b60015473ffffffffffffffffffffffffffffffffffffffff1633146102b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b61033c610849565b6040805180820190915263ffffffff9092168083526020909201819052600280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000016909217909155600355565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146103f9576040517f44b0e3c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208114610433576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061044182840184610eb7565b73ffffffffffffffffffffffffffffffffffffffff811660009081526005602052604081208054929350869290919061047b908490610fd1565b90915550505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610534576040517f295a81c100000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526044016102af565b60008061054384860186610fe4565b9150915080610551846108cc565b61055b9190610fd1565b73ffffffffffffffffffffffffffffffffffffffff831660009081526005602052604081208054909190610590908490611002565b9091555050505050505050565b6105a5610849565b6105ae816108f8565b50565b606060003373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610662576040517f295a81c100000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526044016102af565b60008481526004602052604090205460ff16156106ae576040517f7413dcf8000000000000000000000000000000000000000000000000000000008152600481018590526024016102af565b60006106b9866109ed565b90506000816106c7866108cc565b6106d19190610fd1565b905080600560006106e560208b018b610eb7565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156107b057806005600061073860208b018b610eb7565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546040517f03eb8b540000000000000000000000000000000000000000000000000000000081526004016102af929190918252602082015260400190565b600086815260046020908152604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556107f690880188610eb7565b6040805173ffffffffffffffffffffffffffffffffffffffff9092166020830152810183905260600160405160208183030381529060405261083b6000806000610c29565b935093505050935093915050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146108ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016102af565b565b60006108d6610c61565b6108e883670de0b6b3a7640000611015565b6108f2919061102c565b92915050565b3373ffffffffffffffffffffffffffffffffffffffff821603610977576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016102af565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60006109fd610120830183611067565b9050601403610a0e57506000919050565b6000610a1e610120840184611067565b6014818110610a2f57610a2f6110cc565b919091013560f81c9150819050610c23576000610a50610120850185611067565b610a5e9160159082906110fb565b810190610a6b9190611125565b90508060200151600014158015610b385750602081015181516040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201527f0000000000000000000000000000000000000000000000000000000000000000909116906370a0823190602401602060405180830381865afa158015610b12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b3691906111ae565b105b15610c2157805160408083015190517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169263a9059cbb92610bd59260040173ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b6020604051808303816000875af1158015610bf4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1891906111c7565b50806040015192505b505b50919050565b600060d08265ffffffffffff16901b60a08465ffffffffffff16901b85610c51576000610c54565b60015b60ff161717949350505050565b600254604080517ffeaf968c000000000000000000000000000000000000000000000000000000008152905160009263ffffffff1691821515918491829173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169163feaf968c9160048083019260a09291908290030181865afa158015610d01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d259190611208565b509450909250849150508015610d495750610d408242611002565b8463ffffffff16105b15610d5357506003545b949350505050565b60008060408385031215610d6e57600080fd5b823563ffffffff81168114610d8257600080fd5b946020939093013593505050565b73ffffffffffffffffffffffffffffffffffffffff811681146105ae57600080fd5b60008083601f840112610dc457600080fd5b50813567ffffffffffffffff811115610ddc57600080fd5b602083019150836020828501011115610df457600080fd5b9250929050565b60008060008060608587031215610e1157600080fd5b8435610e1c81610d90565b935060208501359250604085013567ffffffffffffffff811115610e3f57600080fd5b610e4b87828801610db2565b95989497509550505050565b60008060008060608587031215610e6d57600080fd5b843560038110610e7c57600080fd5b9350602085013567ffffffffffffffff811115610e9857600080fd5b610ea487828801610db2565b9598909750949560400135949350505050565b600060208284031215610ec957600080fd5b8135610ed481610d90565b9392505050565b600080600060608486031215610ef057600080fd5b833567ffffffffffffffff811115610f0757600080fd5b84016101608187031215610f1a57600080fd5b95602085013595506040909401359392505050565b604081526000835180604084015260005b81811015610f5d5760208187018101516060868401015201610f40565b5060006060828501015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168401019150508260208301529392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156108f2576108f2610fa2565b60008060408385031215610ff757600080fd5b8235610d8281610d90565b818103818111156108f2576108f2610fa2565b80820281158282048414176108f2576108f2610fa2565b600082611062577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261109c57600080fd5b83018035915067ffffffffffffffff8211156110b757600080fd5b602001915036819003821315610df457600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000808585111561110b57600080fd5b8386111561111857600080fd5b5050820193919092039150565b60006060828403121561113757600080fd5b6040516060810181811067ffffffffffffffff82111715611181577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604052823561118f81610d90565b8152602083810135908201526040928301359281019290925250919050565b6000602082840312156111c057600080fd5b5051919050565b6000602082840312156111d957600080fd5b81518015158114610ed457600080fd5b805169ffffffffffffffffffff8116811461120357600080fd5b919050565b600080600080600060a0868803121561122057600080fd5b611229866111e9565b945060208601519350604086015192506060860151915061124c608087016111e9565b9050929550929590935056fea164736f6c6343000813000a", } var PaymasterABI = PaymasterMetaData.ABI diff --git a/core/gethwrappers/transmission/generated/sca_wrapper/sca_wrapper.go b/core/gethwrappers/transmission/generated/sca_wrapper/sca_wrapper.go index 55a3107710a..989e4058685 100644 --- a/core/gethwrappers/transmission/generated/sca_wrapper/sca_wrapper.go +++ b/core/gethwrappers/transmission/generated/sca_wrapper/sca_wrapper.go @@ -44,7 +44,7 @@ type UserOperation struct { var SCAMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"entryPoint\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"BadFormatOrOOG\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"currentNonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonceGiven\",\"type\":\"uint256\"}],\"name\":\"IncorrectNonce\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"operationHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"InvalidSignature\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"NotAuthorized\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currentTimestamp\",\"type\":\"uint256\"}],\"name\":\"TransactionExpired\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint48\",\"name\":\"deadline\",\"type\":\"uint48\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"executeTransactionFromEntryPoint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_entryPoint\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"verificationGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preVerificationGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxPriorityFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"paymasterAndData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"internalType\":\"structUserOperation\",\"name\":\"userOp\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"userOpHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"validateUserOp\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"validationData\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60c060405234801561001057600080fd5b50604051610acb380380610acb83398101604081905261002f91610062565b6001600160a01b039182166080521660a052610095565b80516001600160a01b038116811461005d57600080fd5b919050565b6000806040838503121561007557600080fd5b61007e83610046565b915061008c60208401610046565b90509250929050565b60805160a051610a046100c760003960008181607101526103c301526000818161010101526102ee0152610a046000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c80637eccf63e116100505780637eccf63e146100de57806389553be4146100e7578063dba6335f146100fc57600080fd5b8063140fcfb11461006c5780633a871cdd146100bd575b600080fd5b6100937f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6100d06100cb36600461063a565b610123565b6040519081526020016100b4565b6100d060005481565b6100fa6100f53660046106ce565b6103ab565b005b6100937f000000000000000000000000000000000000000000000000000000000000000081565b60008054846020013514610179576000546040517f7ba633940000000000000000000000000000000000000000000000000000000081526004810191909152602085013560248201526044015b60405180910390fd5b60006102908430604080517f4750045d47fce615521b32cee713ff8db50147e98aec5ca94926b52651ca3fa060208083019190915281830194909452815180820383018152606080830184528151918601919091207f190000000000000000000000000000000000000000000000000000000000000060808401527f010000000000000000000000000000000000000000000000000000000000000060818401527f1c7d3b72b37a35523e273aaadd7b4cd66f618bb81429ab053412d51f50ccea6160828401524660a284015293901b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660c282015260d6808201939093528151808203909301835260f6019052805191012090565b905060006102a261014087018761076b565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293505073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016915061031c90508284610544565b73ffffffffffffffffffffffffffffffffffffffff161461034d576103446001600080610602565b925050506103a4565b60008054908061035c83610806565b9091555060009050610371606088018861076b565b61037f91600490829061083e565b81019061038c9190610897565b509250505061039e6000826000610602565b93505050505b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461041c576040517f4a0bfec1000000000000000000000000000000000000000000000000000000008152336004820152602401610170565b65ffffffffffff83161580159061043a57508265ffffffffffff1642115b15610481576040517f300249d700000000000000000000000000000000000000000000000000000000815265ffffffffffff84166004820152426024820152604401610170565b6000808673ffffffffffffffffffffffffffffffffffffffff168685856040516104ac929190610993565b60006040518083038185875af1925050503d80600081146104e9576040519150601f19603f3d011682016040523d82523d6000602084013e6104ee565b606091505b50915091508161053b578051600003610533576040517f20e9b5d200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805181602001fd5b50505050505050565b602082015160408084015184516000939284918791908110610568576105686109a3565b016020015160f81c905060018561058083601b6109d2565b6040805160008152602081018083529390935260ff90911690820152606081018590526080810184905260a0016020604051602081039080840390855afa1580156105cf573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00151979650505050505050565b600060d08265ffffffffffff16901b60a08465ffffffffffff16901b8561062a57600061062d565b60015b60ff161717949350505050565b60008060006060848603121561064f57600080fd5b833567ffffffffffffffff81111561066657600080fd5b8401610160818703121561067957600080fd5b95602085013595506040909401359392505050565b73ffffffffffffffffffffffffffffffffffffffff811681146106b057600080fd5b50565b803565ffffffffffff811681146106c957600080fd5b919050565b6000806000806000608086880312156106e657600080fd5b85356106f18161068e565b945060208601359350610706604087016106b3565b9250606086013567ffffffffffffffff8082111561072357600080fd5b818801915088601f83011261073757600080fd5b81358181111561074657600080fd5b89602082850101111561075857600080fd5b9699959850939650602001949392505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126107a057600080fd5b83018035915067ffffffffffffffff8211156107bb57600080fd5b6020019150368190038213156107d057600080fd5b9250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610837576108376107d7565b5060010190565b6000808585111561084e57600080fd5b8386111561085b57600080fd5b5050820193919092039150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080600080608085870312156108ad57600080fd5b84356108b88161068e565b9350602085013592506108cd604086016106b3565b9150606085013567ffffffffffffffff808211156108ea57600080fd5b818701915087601f8301126108fe57600080fd5b81358181111561091057610910610868565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561095657610956610868565b816040528281528a602084870101111561096f57600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060ff821660ff84168060ff038211156109ef576109ef6107d7565b01939250505056fea164736f6c634300080f000a", + Bin: "0x60c060405234801561001057600080fd5b50604051610acb380380610acb83398101604081905261002f91610062565b6001600160a01b039182166080521660a052610095565b80516001600160a01b038116811461005d57600080fd5b919050565b6000806040838503121561007557600080fd5b61007e83610046565b915061008c60208401610046565b90509250929050565b60805160a051610a046100c760003960008181607101526102b801526000818161010101526101e30152610a046000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c80637eccf63e116100505780637eccf63e146100de57806389553be4146100e7578063dba6335f146100fc57600080fd5b8063140fcfb11461006c5780633a871cdd146100bd575b600080fd5b6100937f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6100d06100cb366004610646565b610123565b6040519081526020016100b4565b6100d060005481565b6100fa6100f53660046106da565b6102a0565b005b6100937f000000000000000000000000000000000000000000000000000000000000000081565b60008054846020013514610179576000546040517f7ba633940000000000000000000000000000000000000000000000000000000081526004810191909152602085013560248201526044015b60405180910390fd5b60006101858430610439565b90506000610197610140870187610777565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293505073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016915061021190508284610550565b73ffffffffffffffffffffffffffffffffffffffff161461024257610239600160008061060e565b92505050610299565b60008054908061025183610812565b90915550600090506102666060880188610777565b61027491600490829061084a565b81019061028191906108a3565b5092505050610293600082600061060e565b93505050505b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610311576040517f4a0bfec1000000000000000000000000000000000000000000000000000000008152336004820152602401610170565b65ffffffffffff83161580159061032f57508265ffffffffffff1642115b15610376576040517f300249d700000000000000000000000000000000000000000000000000000000815265ffffffffffff84166004820152426024820152604401610170565b6000808673ffffffffffffffffffffffffffffffffffffffff168685856040516103a192919061099f565b60006040518083038185875af1925050503d80600081146103de576040519150601f19603f3d011682016040523d82523d6000602084013e6103e3565b606091505b509150915081610430578051600003610428576040517f20e9b5d200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805181602001fd5b50505050505050565b604080517f4750045d47fce615521b32cee713ff8db50147e98aec5ca94926b52651ca3fa0602080830191909152818301859052825180830384018152606080840185528151918301919091207f190000000000000000000000000000000000000000000000000000000000000060808501527f010000000000000000000000000000000000000000000000000000000000000060818501527f1c7d3b72b37a35523e273aaadd7b4cd66f618bb81429ab053412d51f50ccea6160828501524660a28501529085901b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660c284015260d6808401919091528351808403909101815260f690920190925280519101205b92915050565b602082015160408084015184516000939284918791908110610574576105746109af565b016020015160f81c905060018561058c83601b6109de565b6040805160008152602081018083529390935260ff90911690820152606081018590526080810184905260a0016020604051602081039080840390855afa1580156105db573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00151979650505050505050565b600060d08265ffffffffffff16901b60a08465ffffffffffff16901b85610636576000610639565b60015b60ff161717949350505050565b60008060006060848603121561065b57600080fd5b833567ffffffffffffffff81111561067257600080fd5b8401610160818703121561068557600080fd5b95602085013595506040909401359392505050565b73ffffffffffffffffffffffffffffffffffffffff811681146106bc57600080fd5b50565b803565ffffffffffff811681146106d557600080fd5b919050565b6000806000806000608086880312156106f257600080fd5b85356106fd8161069a565b945060208601359350610712604087016106bf565b9250606086013567ffffffffffffffff8082111561072f57600080fd5b818801915088601f83011261074357600080fd5b81358181111561075257600080fd5b89602082850101111561076457600080fd5b9699959850939650602001949392505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126107ac57600080fd5b83018035915067ffffffffffffffff8211156107c757600080fd5b6020019150368190038213156107dc57600080fd5b9250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610843576108436107e3565b5060010190565b6000808585111561085a57600080fd5b8386111561086757600080fd5b5050820193919092039150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080600080608085870312156108b957600080fd5b84356108c48161069a565b9350602085013592506108d9604086016106bf565b9150606085013567ffffffffffffffff808211156108f657600080fd5b818701915087601f83011261090a57600080fd5b81358181111561091c5761091c610874565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561096257610962610874565b816040528281528a602084870101111561097b57600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60ff818116838216019081111561054a5761054a6107e356fea164736f6c6343000813000a", } var SCAABI = SCAMetaData.ABI diff --git a/core/gethwrappers/transmission/generated/smart_contract_account_factory/smart_contract_account_factory.go b/core/gethwrappers/transmission/generated/smart_contract_account_factory/smart_contract_account_factory.go index 0b4daf3fa89..aa9205641c5 100644 --- a/core/gethwrappers/transmission/generated/smart_contract_account_factory/smart_contract_account_factory.go +++ b/core/gethwrappers/transmission/generated/smart_contract_account_factory/smart_contract_account_factory.go @@ -32,7 +32,7 @@ var ( var SmartContractAccountFactoryMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[],\"name\":\"DeploymentFailed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"scaAddress\",\"type\":\"address\"}],\"name\":\"ContractCreated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"abiEncodedOwnerAddress\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"}],\"name\":\"deploySmartContractAccount\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"scaAddress\",\"type\":\"address\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b5061021e806100206000396000f3fe60806040526004361061001e5760003560e01c80630af4926f14610023575b600080fd5b610036610031366004610138565b61005f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6000828251836020016000f5905073ffffffffffffffffffffffffffffffffffffffff81166100ba576040517f3011642500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405173ffffffffffffffffffffffffffffffffffffffff821681527fcf78cf0d6f3d8371e1075c69c492ab4ec5d8cf23a1a239b6a51a1d00be7ca3129060200160405180910390a192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806040838503121561014b57600080fd5b82359150602083013567ffffffffffffffff8082111561016a57600080fd5b818501915085601f83011261017e57600080fd5b81358181111561019057610190610109565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156101d6576101d6610109565b816040528281528860208487010111156101ef57600080fd5b826020860160208301376000602084830101528095505050505050925092905056fea164736f6c634300080f000a", + Bin: "0x608060405234801561001057600080fd5b5061021e806100206000396000f3fe60806040526004361061001e5760003560e01c80630af4926f14610023575b600080fd5b610036610031366004610138565b61005f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6000828251836020016000f5905073ffffffffffffffffffffffffffffffffffffffff81166100ba576040517f3011642500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405173ffffffffffffffffffffffffffffffffffffffff821681527fcf78cf0d6f3d8371e1075c69c492ab4ec5d8cf23a1a239b6a51a1d00be7ca3129060200160405180910390a192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806040838503121561014b57600080fd5b82359150602083013567ffffffffffffffff8082111561016a57600080fd5b818501915085601f83011261017e57600080fd5b81358181111561019057610190610109565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156101d6576101d6610109565b816040528281528860208487010111156101ef57600080fd5b826020860160208301376000602084830101528095505050505050925092905056fea164736f6c6343000813000a", } var SmartContractAccountFactoryABI = SmartContractAccountFactoryMetaData.ABI diff --git a/core/gethwrappers/transmission/generated/smart_contract_account_helper/smart_contract_account_helper.go b/core/gethwrappers/transmission/generated/smart_contract_account_helper/smart_contract_account_helper.go index d951227c3a5..36e63e3683e 100644 --- a/core/gethwrappers/transmission/generated/smart_contract_account_helper/smart_contract_account_helper.go +++ b/core/gethwrappers/transmission/generated/smart_contract_account_helper/smart_contract_account_helper.go @@ -30,7 +30,7 @@ var ( var SmartContractAccountHelperMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"entryPoint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"factory\",\"type\":\"address\"}],\"name\":\"calculateSmartContractAccountAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"topupThreshold\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"topupAmount\",\"type\":\"uint256\"}],\"name\":\"getAbiEncodedDirectRequestData\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"endContract\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"getFullEndTxEncoding\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"encoding\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"userOpHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"scaAddress\",\"type\":\"address\"}],\"name\":\"getFullHashForSigning\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"factory\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"entryPoint\",\"type\":\"address\"}],\"name\":\"getInitCode\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"entryPoint\",\"type\":\"address\"}],\"name\":\"getSCAInitCodeWithConstructor\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", - Bin: "0x61162261003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe730000000000000000000000000000000000000000301460806040526004361061007c5760003560e01c8063e0237bef1161005a578063e0237bef14610134578063e464b3631461016c578063fc59bac31461017f57600080fd5b80632c86cb35146100815780634b770f561461010057806382311e3314610113575b600080fd5b6100ea61008f36600461076b565b604080516060808201835273ffffffffffffffffffffffffffffffffffffffff959095168082526020808301958652918301938452825191820152925183820152905182840152805180830390930183526080909101905290565b6040516100f79190610818565b60405180910390f35b6100ea61010e36600461082b565b610192565b61012661012136600461086e565b610336565b6040519081526020016100f7565b61014761014236600461082b565b610454565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100f7565b6100ea61017a36600461089a565b6105df565b6100ea61018d3660046108f3565b61069d565b6040516060907fffffffffffffffffffffffffffffffffffffffff00000000000000000000000084831b16906000906101cd60208201610735565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820381018352601f90910116604081815273ffffffffffffffffffffffffffffffffffffffff8881166020840152871690820152606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261026292916020016109e6565b60405160208183030381529060405290508560601b630af4926f60e01b8383604051602401610292929190610a15565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909516949094179093525161031c939201610a36565b604051602081830303815290604052925050509392505050565b600061044d8383604080517f4750045d47fce615521b32cee713ff8db50147e98aec5ca94926b52651ca3fa060208083019190915281830194909452815180820383018152606080830184528151918601919091207f190000000000000000000000000000000000000000000000000000000000000060808401527f010000000000000000000000000000000000000000000000000000000000000060818401527f1c7d3b72b37a35523e273aaadd7b4cd66f618bb81429ab053412d51f50ccea6160828401524660a284015293901b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660c282015260d6808201939093528151808203909301835260f6019052805191012090565b9392505050565b6040516000907fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b1690829061049060208201610735565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820381018352601f90910116604081815273ffffffffffffffffffffffffffffffffffffffff8981166020840152881690820152606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261052592916020016109e6565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815282825280516020918201207fff000000000000000000000000000000000000000000000000000000000000008285015260609790971b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166021840152603583019490945260558083019690965280518083039096018652607590910190525082519201919091209392505050565b6060604051806020016105f190610735565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820381018352601f90910116604081815273ffffffffffffffffffffffffffffffffffffffff8681166020840152851690820152606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261068692916020016109e6565b604051602081830303815290604052905092915050565b60607f89553be40000000000000000000000000000000000000000000000000000000085856106cc8642610a7e565b856040516020016106e09493929190610abd565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261071c9291602001610b02565b6040516020818303038152906040529050949350505050565b610acb80610b4b83390190565b803573ffffffffffffffffffffffffffffffffffffffff8116811461076657600080fd5b919050565b60008060006060848603121561078057600080fd5b61078984610742565b95602085013595506040909401359392505050565b60005b838110156107b95781810151838201526020016107a1565b838111156107c8576000848401525b50505050565b600081518084526107e681602086016020860161079e565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061044d60208301846107ce565b60008060006060848603121561084057600080fd5b61084984610742565b925061085760208501610742565b915061086560408501610742565b90509250925092565b6000806040838503121561088157600080fd5b8235915061089160208401610742565b90509250929050565b600080604083850312156108ad57600080fd5b6108b683610742565b915061089160208401610742565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000806080858703121561090957600080fd5b61091285610742565b93506020850135925060408501359150606085013567ffffffffffffffff8082111561093d57600080fd5b818701915087601f83011261095157600080fd5b813581811115610963576109636108c4565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156109a9576109a96108c4565b816040528281528a60208487010111156109c257600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b600083516109f881846020880161079e565b835190830190610a0c81836020880161079e565b01949350505050565b828152604060208201526000610a2e60408301846107ce565b949350505050565b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008316815260008251610a7081601485016020870161079e565b919091016014019392505050565b60008219821115610ab8577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152826040820152608060608201526000610af860808301846107ce565b9695505050505050565b7fffffffff000000000000000000000000000000000000000000000000000000008316815260008251610b3c81600485016020870161079e565b91909101600401939250505056fe60c060405234801561001057600080fd5b50604051610acb380380610acb83398101604081905261002f91610062565b6001600160a01b039182166080521660a052610095565b80516001600160a01b038116811461005d57600080fd5b919050565b6000806040838503121561007557600080fd5b61007e83610046565b915061008c60208401610046565b90509250929050565b60805160a051610a046100c760003960008181607101526103c301526000818161010101526102ee0152610a046000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c80637eccf63e116100505780637eccf63e146100de57806389553be4146100e7578063dba6335f146100fc57600080fd5b8063140fcfb11461006c5780633a871cdd146100bd575b600080fd5b6100937f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6100d06100cb36600461063a565b610123565b6040519081526020016100b4565b6100d060005481565b6100fa6100f53660046106ce565b6103ab565b005b6100937f000000000000000000000000000000000000000000000000000000000000000081565b60008054846020013514610179576000546040517f7ba633940000000000000000000000000000000000000000000000000000000081526004810191909152602085013560248201526044015b60405180910390fd5b60006102908430604080517f4750045d47fce615521b32cee713ff8db50147e98aec5ca94926b52651ca3fa060208083019190915281830194909452815180820383018152606080830184528151918601919091207f190000000000000000000000000000000000000000000000000000000000000060808401527f010000000000000000000000000000000000000000000000000000000000000060818401527f1c7d3b72b37a35523e273aaadd7b4cd66f618bb81429ab053412d51f50ccea6160828401524660a284015293901b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660c282015260d6808201939093528151808203909301835260f6019052805191012090565b905060006102a261014087018761076b565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293505073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016915061031c90508284610544565b73ffffffffffffffffffffffffffffffffffffffff161461034d576103446001600080610602565b925050506103a4565b60008054908061035c83610806565b9091555060009050610371606088018861076b565b61037f91600490829061083e565b81019061038c9190610897565b509250505061039e6000826000610602565b93505050505b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461041c576040517f4a0bfec1000000000000000000000000000000000000000000000000000000008152336004820152602401610170565b65ffffffffffff83161580159061043a57508265ffffffffffff1642115b15610481576040517f300249d700000000000000000000000000000000000000000000000000000000815265ffffffffffff84166004820152426024820152604401610170565b6000808673ffffffffffffffffffffffffffffffffffffffff168685856040516104ac929190610993565b60006040518083038185875af1925050503d80600081146104e9576040519150601f19603f3d011682016040523d82523d6000602084013e6104ee565b606091505b50915091508161053b578051600003610533576040517f20e9b5d200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805181602001fd5b50505050505050565b602082015160408084015184516000939284918791908110610568576105686109a3565b016020015160f81c905060018561058083601b6109d2565b6040805160008152602081018083529390935260ff90911690820152606081018590526080810184905260a0016020604051602081039080840390855afa1580156105cf573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00151979650505050505050565b600060d08265ffffffffffff16901b60a08465ffffffffffff16901b8561062a57600061062d565b60015b60ff161717949350505050565b60008060006060848603121561064f57600080fd5b833567ffffffffffffffff81111561066657600080fd5b8401610160818703121561067957600080fd5b95602085013595506040909401359392505050565b73ffffffffffffffffffffffffffffffffffffffff811681146106b057600080fd5b50565b803565ffffffffffff811681146106c957600080fd5b919050565b6000806000806000608086880312156106e657600080fd5b85356106f18161068e565b945060208601359350610706604087016106b3565b9250606086013567ffffffffffffffff8082111561072357600080fd5b818801915088601f83011261073757600080fd5b81358181111561074657600080fd5b89602082850101111561075857600080fd5b9699959850939650602001949392505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126107a057600080fd5b83018035915067ffffffffffffffff8211156107bb57600080fd5b6020019150368190038213156107d057600080fd5b9250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610837576108376107d7565b5060010190565b6000808585111561084e57600080fd5b8386111561085b57600080fd5b5050820193919092039150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080600080608085870312156108ad57600080fd5b84356108b88161068e565b9350602085013592506108cd604086016106b3565b9150606085013567ffffffffffffffff808211156108ea57600080fd5b818701915087601f8301126108fe57600080fd5b81358181111561091057610910610868565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561095657610956610868565b816040528281528a602084870101111561096f57600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060ff821660ff84168060ff038211156109ef576109ef6107d7565b01939250505056fea164736f6c634300080f000aa164736f6c634300080f000a", + Bin: "0x61161361003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe730000000000000000000000000000000000000000301460806040526004361061007c5760003560e01c8063e0237bef1161005a578063e0237bef14610134578063e464b3631461016c578063fc59bac31461017f57600080fd5b80632c86cb35146100815780634b770f561461010057806382311e3314610113575b600080fd5b6100ea61008f36600461076d565b604080516060808201835273ffffffffffffffffffffffffffffffffffffffff959095168082526020808301958652918301938452825191820152925183820152905182840152805180830390930183526080909101905290565b6040516100f7919061080e565b60405180910390f35b6100ea61010e366004610821565b610192565b610126610121366004610864565b610336565b6040519081526020016100f7565b610147610142366004610821565b610456565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100f7565b6100ea61017a366004610890565b6105e1565b6100ea61018d3660046108e9565b61069f565b6040516060907fffffffffffffffffffffffffffffffffffffffff00000000000000000000000084831b16906000906101cd60208201610737565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820381018352601f90910116604081815273ffffffffffffffffffffffffffffffffffffffff8881166020840152871690820152606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261026292916020016109dc565b60405160208183030381529060405290508560601b630af4926f60e01b8383604051602401610292929190610a0b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909516949094179093525161031c939201610a2c565b604051602081830303815290604052925050509392505050565b600061044d8383604080517f4750045d47fce615521b32cee713ff8db50147e98aec5ca94926b52651ca3fa060208083019190915281830194909452815180820383018152606080830184528151918601919091207f190000000000000000000000000000000000000000000000000000000000000060808401527f010000000000000000000000000000000000000000000000000000000000000060818401527f1c7d3b72b37a35523e273aaadd7b4cd66f618bb81429ab053412d51f50ccea6160828401524660a284015293901b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660c282015260d6808201939093528151808203909301835260f6019052805191012090565b90505b92915050565b6040516000907fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b1690829061049260208201610737565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820381018352601f90910116604081815273ffffffffffffffffffffffffffffffffffffffff8981166020840152881690820152606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261052792916020016109dc565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815282825280516020918201207fff000000000000000000000000000000000000000000000000000000000000008285015260609790971b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166021840152603583019490945260558083019690965280518083039096018652607590910190525082519201919091209392505050565b6060604051806020016105f390610737565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820381018352601f90910116604081815273ffffffffffffffffffffffffffffffffffffffff8681166020840152851690820152606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261068892916020016109dc565b604051602081830303815290604052905092915050565b60607f89553be40000000000000000000000000000000000000000000000000000000085856106ce8642610a74565b856040516020016106e29493929190610aae565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261071e9291602001610af3565b6040516020818303038152906040529050949350505050565b610acb80610b3c83390190565b803573ffffffffffffffffffffffffffffffffffffffff8116811461076857600080fd5b919050565b60008060006060848603121561078257600080fd5b61078b84610744565b95602085013595506040909401359392505050565b60005b838110156107bb5781810151838201526020016107a3565b50506000910152565b600081518084526107dc8160208601602086016107a0565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061044d60208301846107c4565b60008060006060848603121561083657600080fd5b61083f84610744565b925061084d60208501610744565b915061085b60408501610744565b90509250925092565b6000806040838503121561087757600080fd5b8235915061088760208401610744565b90509250929050565b600080604083850312156108a357600080fd5b6108ac83610744565b915061088760208401610744565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080600080608085870312156108ff57600080fd5b61090885610744565b93506020850135925060408501359150606085013567ffffffffffffffff8082111561093357600080fd5b818701915087601f83011261094757600080fd5b813581811115610959576109596108ba565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561099f5761099f6108ba565b816040528281528a60208487010111156109b857600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b600083516109ee8184602088016107a0565b835190830190610a028183602088016107a0565b01949350505050565b828152604060208201526000610a2460408301846107c4565b949350505050565b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008316815260008251610a668160148501602087016107a0565b919091016014019392505050565b80820180821115610450577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152826040820152608060608201526000610ae960808301846107c4565b9695505050505050565b7fffffffff000000000000000000000000000000000000000000000000000000008316815260008251610b2d8160048501602087016107a0565b91909101600401939250505056fe60c060405234801561001057600080fd5b50604051610acb380380610acb83398101604081905261002f91610062565b6001600160a01b039182166080521660a052610095565b80516001600160a01b038116811461005d57600080fd5b919050565b6000806040838503121561007557600080fd5b61007e83610046565b915061008c60208401610046565b90509250929050565b60805160a051610a046100c760003960008181607101526102b801526000818161010101526101e30152610a046000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c80637eccf63e116100505780637eccf63e146100de57806389553be4146100e7578063dba6335f146100fc57600080fd5b8063140fcfb11461006c5780633a871cdd146100bd575b600080fd5b6100937f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6100d06100cb366004610646565b610123565b6040519081526020016100b4565b6100d060005481565b6100fa6100f53660046106da565b6102a0565b005b6100937f000000000000000000000000000000000000000000000000000000000000000081565b60008054846020013514610179576000546040517f7ba633940000000000000000000000000000000000000000000000000000000081526004810191909152602085013560248201526044015b60405180910390fd5b60006101858430610439565b90506000610197610140870187610777565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293505073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016915061021190508284610550565b73ffffffffffffffffffffffffffffffffffffffff161461024257610239600160008061060e565b92505050610299565b60008054908061025183610812565b90915550600090506102666060880188610777565b61027491600490829061084a565b81019061028191906108a3565b5092505050610293600082600061060e565b93505050505b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610311576040517f4a0bfec1000000000000000000000000000000000000000000000000000000008152336004820152602401610170565b65ffffffffffff83161580159061032f57508265ffffffffffff1642115b15610376576040517f300249d700000000000000000000000000000000000000000000000000000000815265ffffffffffff84166004820152426024820152604401610170565b6000808673ffffffffffffffffffffffffffffffffffffffff168685856040516103a192919061099f565b60006040518083038185875af1925050503d80600081146103de576040519150601f19603f3d011682016040523d82523d6000602084013e6103e3565b606091505b509150915081610430578051600003610428576040517f20e9b5d200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805181602001fd5b50505050505050565b604080517f4750045d47fce615521b32cee713ff8db50147e98aec5ca94926b52651ca3fa0602080830191909152818301859052825180830384018152606080840185528151918301919091207f190000000000000000000000000000000000000000000000000000000000000060808501527f010000000000000000000000000000000000000000000000000000000000000060818501527f1c7d3b72b37a35523e273aaadd7b4cd66f618bb81429ab053412d51f50ccea6160828501524660a28501529085901b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660c284015260d6808401919091528351808403909101815260f690920190925280519101205b92915050565b602082015160408084015184516000939284918791908110610574576105746109af565b016020015160f81c905060018561058c83601b6109de565b6040805160008152602081018083529390935260ff90911690820152606081018590526080810184905260a0016020604051602081039080840390855afa1580156105db573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00151979650505050505050565b600060d08265ffffffffffff16901b60a08465ffffffffffff16901b85610636576000610639565b60015b60ff161717949350505050565b60008060006060848603121561065b57600080fd5b833567ffffffffffffffff81111561067257600080fd5b8401610160818703121561068557600080fd5b95602085013595506040909401359392505050565b73ffffffffffffffffffffffffffffffffffffffff811681146106bc57600080fd5b50565b803565ffffffffffff811681146106d557600080fd5b919050565b6000806000806000608086880312156106f257600080fd5b85356106fd8161069a565b945060208601359350610712604087016106bf565b9250606086013567ffffffffffffffff8082111561072f57600080fd5b818801915088601f83011261074357600080fd5b81358181111561075257600080fd5b89602082850101111561076457600080fd5b9699959850939650602001949392505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126107ac57600080fd5b83018035915067ffffffffffffffff8211156107c757600080fd5b6020019150368190038213156107dc57600080fd5b9250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610843576108436107e3565b5060010190565b6000808585111561085a57600080fd5b8386111561086757600080fd5b5050820193919092039150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080600080608085870312156108b957600080fd5b84356108c48161069a565b9350602085013592506108d9604086016106bf565b9150606085013567ffffffffffffffff808211156108f657600080fd5b818701915087601f83011261090a57600080fd5b81358181111561091c5761091c610874565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561096257610962610874565b816040528281528a602084870101111561097b57600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60ff818116838216019081111561054a5761054a6107e356fea164736f6c6343000813000aa164736f6c6343000813000a", } var SmartContractAccountHelperABI = SmartContractAccountHelperMetaData.ABI diff --git a/core/gethwrappers/transmission/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/transmission/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 6d5b5c22c58..9b64d6eba0f 100644 --- a/core/gethwrappers/transmission/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/transmission/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -1,9 +1,9 @@ GETH_VERSION: 1.13.8 -entry_point: ../../../contracts/solc/v0.8.15/EntryPoint/EntryPoint.abi ../../../contracts/solc/v0.8.15/EntryPoint/EntryPoint.bin 2cb4bb2ba3efa8df3dfb0a57eb3727d17b68fe202682024fa7cfb4faf026833e -greeter: ../../../contracts/solc/v0.8.15/Greeter.abi ../../../contracts/solc/v0.8.15/Greeter.bin 653dcba5c33a46292073939ce1e639372cf521c0ec2814d4c9f20c72f796f18c -greeter_wrapper: ../../../contracts/solc/v0.8.15/Greeter/Greeter.abi ../../../contracts/solc/v0.8.15/Greeter/Greeter.bin 653dcba5c33a46292073939ce1e639372cf521c0ec2814d4c9f20c72f796f18c -paymaster_wrapper: ../../../contracts/solc/v0.8.15/Paymaster/Paymaster.abi ../../../contracts/solc/v0.8.15/Paymaster/Paymaster.bin 189ef817a5b7a6ff53ddf35b1988465b8aec479c47b77236fe20bf7e67d48100 -sca: ../../../contracts/solc/v0.8.15/SCA.abi ../../../contracts/solc/v0.8.15/SCA.bin ae0f860cdac87d4ac505edbd228bd3ea1108550453aba67aebcb61f09cf70d0b -sca_wrapper: ../../../contracts/solc/v0.8.15/SCA/SCA.abi ../../../contracts/solc/v0.8.15/SCA/SCA.bin 2a8100fbdb41e6ce917ed333a624eaa4a8984b07e2d8d8ca6bba9bc9f74b05d7 -smart_contract_account_factory: ../../../contracts/solc/v0.8.15/SmartContractAccountFactory/SmartContractAccountFactory.abi ../../../contracts/solc/v0.8.15/SmartContractAccountFactory/SmartContractAccountFactory.bin a44d6fa2dbf9cb3441d6d637d89e1cd656f28b6bf4146f58d508067474bf845b -smart_contract_account_helper: ../../../contracts/solc/v0.8.15/SmartContractAccountHelper/SmartContractAccountHelper.abi ../../../contracts/solc/v0.8.15/SmartContractAccountHelper/SmartContractAccountHelper.bin 22f960a74bd1581a12aa4f8f438a3f265f32f43682f5c1897ca50707b9982d56 +entry_point: ../../../contracts/solc/v0.8.19/EntryPoint/EntryPoint.abi ../../../contracts/solc/v0.8.19/EntryPoint/EntryPoint.bin e43da0e61256471b317cab1c87f2425cecba9b81ac21633334f889bab2f0777d +greeter: ../../../contracts/solc/v0.8.19/Greeter.abi ../../../contracts/solc/v0.8.19/Greeter.bin 653dcba5c33a46292073939ce1e639372cf521c0ec2814d4c9f20c72f796f18c +greeter_wrapper: ../../../contracts/solc/v0.8.19/Greeter/Greeter.abi ../../../contracts/solc/v0.8.19/Greeter/Greeter.bin 7f6def58e337a53553a46cb7992cf2d75ec951014d79376fcb869a2b16b53f6d +paymaster_wrapper: ../../../contracts/solc/v0.8.19/Paymaster/Paymaster.abi ../../../contracts/solc/v0.8.19/Paymaster/Paymaster.bin dbdd1341cfa2d5c09730e0decc32339f62d1a4ea89835a51ff774226ddfbd04b +sca: ../../../contracts/solc/v0.8.19/SCA.abi ../../../contracts/solc/v0.8.19/SCA.bin ae0f860cdac87d4ac505edbd228bd3ea1108550453aba67aebcb61f09cf70d0b +sca_wrapper: ../../../contracts/solc/v0.8.19/SCA/SCA.abi ../../../contracts/solc/v0.8.19/SCA/SCA.bin 6ef817bdefad1b5e84f06e0bdc40848000ab00e1a38371435b793946f425a8e6 +smart_contract_account_factory: ../../../contracts/solc/v0.8.19/SmartContractAccountFactory/SmartContractAccountFactory.abi ../../../contracts/solc/v0.8.19/SmartContractAccountFactory/SmartContractAccountFactory.bin a357132e2782c462fa31ed80c270fe002e666a48ecfe407b71c278fc3a0d3679 +smart_contract_account_helper: ../../../contracts/solc/v0.8.19/SmartContractAccountHelper/SmartContractAccountHelper.abi ../../../contracts/solc/v0.8.19/SmartContractAccountHelper/SmartContractAccountHelper.bin a06aff23aded74d53bd342fdc32d80c3b474ff38223df27f3395e9fd90abd12a diff --git a/core/gethwrappers/transmission/go_generate.go b/core/gethwrappers/transmission/go_generate.go index 54c6ecf94ed..b3f2b4b0eb9 100644 --- a/core/gethwrappers/transmission/go_generate.go +++ b/core/gethwrappers/transmission/go_generate.go @@ -3,9 +3,9 @@ package gethwrappers // Transmission -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.15/Greeter/Greeter.abi ../../../contracts/solc/v0.8.15/Greeter/Greeter.bin Greeter greeter_wrapper -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.15/SmartContractAccountFactory/SmartContractAccountFactory.abi ../../../contracts/solc/v0.8.15/SmartContractAccountFactory/SmartContractAccountFactory.bin SmartContractAccountFactory smart_contract_account_factory -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.15/EntryPoint/EntryPoint.abi ../../../contracts/solc/v0.8.15/EntryPoint/EntryPoint.bin EntryPoint entry_point -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.15/SmartContractAccountHelper/SmartContractAccountHelper.abi ../../../contracts/solc/v0.8.15/SmartContractAccountHelper/SmartContractAccountHelper.bin SmartContractAccountHelper smart_contract_account_helper -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.15/SCA/SCA.abi ../../../contracts/solc/v0.8.15/SCA/SCA.bin SCA sca_wrapper -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.15/Paymaster/Paymaster.abi ../../../contracts/solc/v0.8.15/Paymaster/Paymaster.bin Paymaster paymaster_wrapper +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/Greeter/Greeter.abi ../../../contracts/solc/v0.8.19/Greeter/Greeter.bin Greeter greeter_wrapper +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/SmartContractAccountFactory/SmartContractAccountFactory.abi ../../../contracts/solc/v0.8.19/SmartContractAccountFactory/SmartContractAccountFactory.bin SmartContractAccountFactory smart_contract_account_factory +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/EntryPoint/EntryPoint.abi ../../../contracts/solc/v0.8.19/EntryPoint/EntryPoint.bin EntryPoint entry_point +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/SmartContractAccountHelper/SmartContractAccountHelper.abi ../../../contracts/solc/v0.8.19/SmartContractAccountHelper/SmartContractAccountHelper.bin SmartContractAccountHelper smart_contract_account_helper +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/SCA/SCA.abi ../../../contracts/solc/v0.8.19/SCA/SCA.bin SCA sca_wrapper +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/Paymaster/Paymaster.abi ../../../contracts/solc/v0.8.19/Paymaster/Paymaster.bin Paymaster paymaster_wrapper diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index b121b0b0494..48acbd69bb3 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -1559,8 +1559,8 @@ func NewTestChainScopedConfig(t testing.TB) evmconfig.ChainScopedConfig { return evmtest.NewChainScopedConfig(t, cfg) } -func NewTestTxStore(t *testing.T, db *sqlx.DB, cfg pg.QConfig) txmgr.TestEvmTxStore { - return txmgr.NewTxStore(db, logger.TestLogger(t), cfg) +func NewTestTxStore(t *testing.T, db *sqlx.DB) txmgr.TestEvmTxStore { + return txmgr.NewTxStore(db, logger.TestLogger(t)) } // ClearDBTables deletes all rows from the given tables diff --git a/core/internal/cltest/factories.go b/core/internal/cltest/factories.go index 02f56e756d9..66c96c231e7 100644 --- a/core/internal/cltest/factories.go +++ b/core/internal/cltest/factories.go @@ -24,6 +24,7 @@ import ( "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" + "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/auth" @@ -49,9 +50,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" ) -func NewEIP55Address() ethkey.EIP55Address { +func NewEIP55Address() evmtypes.EIP55Address { a := testutils.NewAddress() - e, err := ethkey.NewEIP55Address(a.Hex()) + e, err := evmtypes.NewEIP55Address(a.Hex()) if err != nil { panic(err) } @@ -179,13 +180,14 @@ func MustInsertUnconfirmedEthTx(t *testing.T, txStore txmgr.TestEvmTxStore, nonc etx.Sequence = &n etx.State = txmgrcommon.TxUnconfirmed etx.ChainID = chainID - require.NoError(t, txStore.InsertTx(&etx)) + require.NoError(t, txStore.InsertTx(testutils.Context(t), &etx)) return etx } func MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t *testing.T, txStore txmgr.TestEvmTxStore, nonce int64, fromAddress common.Address, opts ...interface{}) txmgr.Tx { etx := MustInsertUnconfirmedEthTx(t, txStore, nonce, fromAddress, opts...) attempt := NewLegacyEthTxAttempt(t, etx.ID) + ctx := testutils.Context(t) tx := NewLegacyTransaction(uint64(nonce), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) rlp := new(bytes.Buffer) @@ -193,8 +195,8 @@ func MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t *testing.T, txStore attempt.SignedRawTx = rlp.Bytes() attempt.State = txmgrtypes.TxAttemptBroadcast - require.NoError(t, txStore.InsertTxAttempt(&attempt)) - etx, err := txStore.FindTxWithAttempts(etx.ID) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt)) + etx, err := txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) return etx } @@ -202,6 +204,7 @@ func MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t *testing.T, txStore func MustInsertConfirmedEthTxWithLegacyAttempt(t *testing.T, txStore txmgr.TestEvmTxStore, nonce int64, broadcastBeforeBlockNum int64, fromAddress common.Address) txmgr.Tx { timeNow := time.Now() etx := NewEthTx(fromAddress) + ctx := testutils.Context(t) etx.BroadcastAt = &timeNow etx.InitialBroadcastAt = &timeNow @@ -209,11 +212,11 @@ func MustInsertConfirmedEthTxWithLegacyAttempt(t *testing.T, txStore txmgr.TestE etx.Sequence = &n etx.State = txmgrcommon.TxConfirmed etx.MinConfirmations.SetValid(6) - require.NoError(t, txStore.InsertTx(&etx)) + require.NoError(t, txStore.InsertTx(ctx, &etx)) attempt := NewLegacyEthTxAttempt(t, etx.ID) attempt.BroadcastBeforeBlockNum = &broadcastBeforeBlockNum attempt.State = txmgrtypes.TxAttemptBroadcast - require.NoError(t, txStore.InsertTxAttempt(&attempt)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt)) etx.TxAttempts = append(etx.TxAttempts, attempt) return etx } @@ -327,7 +330,7 @@ func MustInsertHead(t *testing.T, db sqlutil.DataSource, number int64) evmtypes. func MustInsertV2JobSpec(t *testing.T, db *sqlx.DB, transmitterAddress common.Address) job.Job { t.Helper() - addr, err := ethkey.NewEIP55Address(transmitterAddress.Hex()) + addr, err := evmtypes.NewEIP55Address(transmitterAddress.Hex()) require.NoError(t, err) pipelineSpec := pipeline.Spec{} @@ -351,7 +354,7 @@ func MustInsertV2JobSpec(t *testing.T, db *sqlx.DB, transmitterAddress common.Ad return jb } -func MustInsertOffchainreportingOracleSpec(t *testing.T, db *sqlx.DB, transmitterAddress ethkey.EIP55Address) job.OCROracleSpec { +func MustInsertOffchainreportingOracleSpec(t *testing.T, db *sqlx.DB, transmitterAddress evmtypes.EIP55Address) job.OCROracleSpec { t.Helper() ocrKeyID := models.MustSha256HashFromHex(DefaultOCRKeyBundleID) @@ -376,7 +379,7 @@ func MakeDirectRequestJobSpec(t *testing.T) *job.Job { return spec } -func MustInsertKeeperJob(t *testing.T, db *sqlx.DB, korm keeper.ORM, from ethkey.EIP55Address, contract ethkey.EIP55Address) job.Job { +func MustInsertKeeperJob(t *testing.T, db *sqlx.DB, korm keeper.ORM, from evmtypes.EIP55Address, contract evmtypes.EIP55Address) job.Job { t.Helper() var keeperSpec job.KeeperSpec @@ -421,7 +424,7 @@ func MustInsertKeeperRegistry(t *testing.T, db *sqlx.DB, korm keeper.ORM, ethKey JobID: job.ID, KeeperIndex: keeperIndex, NumKeepers: numKeepers, - KeeperIndexMap: map[ethkey.EIP55Address]int32{ + KeeperIndexMap: map[evmtypes.EIP55Address]int32{ from: keeperIndex, }, } @@ -455,14 +458,14 @@ func MustInsertPipelineRun(t *testing.T, db *sqlx.DB) (run pipeline.Run) { func MustInsertPipelineRunWithStatus(t *testing.T, db *sqlx.DB, pipelineSpecID int32, status pipeline.RunStatus) (run pipeline.Run) { var finishedAt *time.Time - var outputs pipeline.JSONSerializable + var outputs jsonserializable.JSONSerializable var allErrors pipeline.RunErrors var fatalErrors pipeline.RunErrors now := time.Now() switch status { case pipeline.RunStatusCompleted: finishedAt = &now - outputs = pipeline.JSONSerializable{ + outputs = jsonserializable.JSONSerializable{ Val: "foo", Valid: true, } diff --git a/core/internal/cltest/job_factories.go b/core/internal/cltest/job_factories.go index 399e71ff216..4b2ea66f22d 100644 --- a/core/internal/cltest/job_factories.go +++ b/core/internal/cltest/job_factories.go @@ -10,10 +10,10 @@ import ( "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/bridges" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" ) @@ -38,7 +38,7 @@ const ( ` ) -func MinimalOCRNonBootstrapSpec(contractAddress, transmitterAddress ethkey.EIP55Address, peerID p2pkey.PeerID, keyBundleID string) string { +func MinimalOCRNonBootstrapSpec(contractAddress, transmitterAddress types.EIP55Address, peerID p2pkey.PeerID, keyBundleID string) string { return fmt.Sprintf(minimalOCRNonBootstrapTemplate, contractAddress, peerID, transmitterAddress.Hex(), keyBundleID) } diff --git a/core/internal/features/features_test.go b/core/internal/features/features_test.go index 9c6d9cb8b62..cd231450650 100644 --- a/core/internal/features/features_test.go +++ b/core/internal/features/features_test.go @@ -64,7 +64,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/keystest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr" @@ -815,7 +814,7 @@ func TestIntegration_OCR(t *testing.T) { ports := freeport.GetN(t, numOracles) for i := 0; i < numOracles; i++ { app, peerID, transmitter, key := setupNode(t, owner, ports[i], b, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].FlagsContractAddress = ptr(ethkey.EIP55AddressFromAddress(flagsContractAddress)) + c.EVM[0].FlagsContractAddress = ptr(evmtypes.EIP55AddressFromAddress(flagsContractAddress)) c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(test.eip1559) c.P2P.V2.DefaultBootstrappers = &[]ocrcommontypes.BootstrapperLocator{ @@ -1036,7 +1035,7 @@ func TestIntegration_OCR_ForwarderFlow(t *testing.T) { for i := 0; i < numOracles; i++ { app, peerID, transmitter, forwarder, key := setupForwarderEnabledNode(t, owner, ports[i], b, func(c *chainlink.Config, s *chainlink.Secrets) { c.Feature.LogPoller = ptr(true) - c.EVM[0].FlagsContractAddress = ptr(ethkey.EIP55AddressFromAddress(flagsContractAddress)) + c.EVM[0].FlagsContractAddress = ptr(evmtypes.EIP55AddressFromAddress(flagsContractAddress)) c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) c.P2P.V2.DefaultBootstrappers = &[]ocrcommontypes.BootstrapperLocator{ {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePortV2)}}, diff --git a/core/internal/features/ocr2/features_ocr2_test.go b/core/internal/features/ocr2/features_ocr2_test.go index ce0f3087187..216ca272b1b 100644 --- a/core/internal/features/ocr2/features_ocr2_test.go +++ b/core/internal/features/ocr2/features_ocr2_test.go @@ -437,7 +437,7 @@ typeABI = ''' ''' ` } - ocrJob, err := validate.ValidatedOracleSpecToml(apps[i].Config.OCR2(), apps[i].Config.Insecure(), fmt.Sprintf(` + ocrJob, err := validate.ValidatedOracleSpecToml(testutils.Context(t), apps[i].Config.OCR2(), apps[i].Config.Insecure(), fmt.Sprintf(` type = "offchainreporting2" relay = "evm" schemaVersion = 1 @@ -488,7 +488,7 @@ juelsPerFeeCoinSource = """ answer1 [type=median index=0]; """ juelsPerFeeCoinCacheDuration = "1m" -`, ocrContractAddress, kbs[i].ID(), transmitters[i], fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i, blockBeforeConfig.Number().Int64(), chainReaderSpec, fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i)) +`, ocrContractAddress, kbs[i].ID(), transmitters[i], fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i, blockBeforeConfig.Number().Int64(), chainReaderSpec, fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i), nil) require.NoError(t, err) err = apps[i].AddJobV2(testutils.Context(t), &ocrJob) require.NoError(t, err) @@ -793,7 +793,7 @@ chainID = 1337 URL: models.WebURL(*u), })) - ocrJob, err := validate.ValidatedOracleSpecToml(apps[i].Config.OCR2(), apps[i].Config.Insecure(), fmt.Sprintf(` + ocrJob, err := validate.ValidatedOracleSpecToml(testutils.Context(t), apps[i].Config.OCR2(), apps[i].Config.Insecure(), fmt.Sprintf(` type = "offchainreporting2" relay = "evm" schemaVersion = 1 @@ -841,7 +841,7 @@ juelsPerFeeCoinSource = """ answer1 [type=median index=0]; """ juelsPerFeeCoinCacheDuration = "1m" -`, ocrContractAddress, kbs[i].ID(), transmitters[i], fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i, fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i)) +`, ocrContractAddress, kbs[i].ID(), transmitters[i], fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i, fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i), nil) require.NoError(t, err) err = apps[i].AddJobV2(testutils.Context(t), &ocrJob) require.NoError(t, err) diff --git a/core/internal/gethwrappers2/compile.sh b/core/internal/gethwrappers2/compile.sh deleted file mode 100755 index 03619da3a3e..00000000000 --- a/core/internal/gethwrappers2/compile.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - -set -ex - -optimize_runs="$1" -solpath="$2" -solcoptions=("--optimize" "--optimize-runs" "$optimize_runs" "--metadata-hash" "none") - -basefilename="$(basename "$solpath" .sol)" -pkgname="$(echo $basefilename | tr '[:upper:]' '[:lower:]')" - -here="$(dirname $0)" -pkgdir="${here}/${pkgname}" -mkdir -p "$pkgdir" -outpath="${pkgdir}/${pkgname}.go" -abi="${pkgdir}/${basefilename}.abi" -bin="${pkgdir}/${basefilename}.bin" - -solc-select use 0.7.6 -solc --version | grep 0.7.6 || ( echo "You need solc version 0.7.6" && exit 1 ) - -# FIXME: solc seems to find and compile every .sol file in this path, so invoking this once for every file produces n*3 artifacts -solc "$solpath" ${solcoptions[@]} --abi --bin --combined-json bin,bin-runtime,srcmap-runtime --overwrite -o "$(dirname $outpath)" - -go run wrap.go "$abi" "$bin" "$basefilename" "$pkgname" diff --git a/core/internal/gethwrappers2/go_generate.go b/core/internal/gethwrappers2/go_generate.go deleted file mode 100644 index 80c3a82963a..00000000000 --- a/core/internal/gethwrappers2/go_generate.go +++ /dev/null @@ -1,4 +0,0 @@ -// Package gethwrappers keeps track of the golang wrappers of the solidity contracts -package main - -//TODO how is OffchainAggregator generated?! https://smartcontract-it.atlassian.net/browse/BCF-1930 diff --git a/core/internal/gethwrappers2/wrap.go b/core/internal/gethwrappers2/wrap.go deleted file mode 100644 index 967e703d393..00000000000 --- a/core/internal/gethwrappers2/wrap.go +++ /dev/null @@ -1,48 +0,0 @@ -package main - -import ( - "fmt" - "os" - "path/filepath" - - gethParams "github.com/ethereum/go-ethereum/params" - - gethwrappers2 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers" -) - -func main() { - abiPath := os.Args[1] - binPath := os.Args[2] - className := os.Args[3] - pkgName := os.Args[4] - fmt.Println("Generating", pkgName, "contract wrapper") - - cwd, err := os.Getwd() // gethwrappers directory - if err != nil { - gethwrappers2.Exit("could not get working directory", err) - } - outDir := filepath.Join(cwd, "generated", pkgName) - if mkdErr := os.MkdirAll(outDir, 0700); err != nil { - gethwrappers2.Exit("failed to create wrapper dir", mkdErr) - } - outPath := filepath.Join(outDir, pkgName+".go") - - gethwrappers2.Abigen(gethwrappers2.AbigenArgs{ - Bin: binPath, ABI: abiPath, Out: outPath, Type: className, Pkg: pkgName, - }) - - // Build succeeded, so update the versions db with the new contract data - versions, err := gethwrappers2.ReadVersionsDB() - if err != nil { - gethwrappers2.Exit("could not read current versions database", err) - } - versions.GethVersion = gethParams.Version - versions.ContractVersions[pkgName] = gethwrappers2.ContractVersion{ - Hash: gethwrappers2.VersionHash(abiPath, binPath), - AbiPath: abiPath, - BinaryPath: binPath, - } - if err := gethwrappers2.WriteVersionsDB(versions); err != nil { - gethwrappers2.Exit("could not save versions db", err) - } -} diff --git a/core/internal/mocks/application.go b/core/internal/mocks/application.go index 98d4e8809e0..c18cb7f8426 100644 --- a/core/internal/mocks/application.go +++ b/core/internal/mocks/application.go @@ -17,6 +17,8 @@ import ( job "github.com/smartcontractkit/chainlink/v2/core/services/job" + jsonserializable "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" + keystore "github.com/smartcontractkit/chainlink/v2/core/services/keystore" logger "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -327,6 +329,26 @@ func (_m *Application) GetLogger() logger.SugaredLogger { return r0 } +// GetLoopRegistrarConfig provides a mock function with given fields: +func (_m *Application) GetLoopRegistrarConfig() plugins.RegistrarConfig { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetLoopRegistrarConfig") + } + + var r0 plugins.RegistrarConfig + if rf, ok := ret.Get(0).(func() plugins.RegistrarConfig); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(plugins.RegistrarConfig) + } + } + + return r0 +} + // GetLoopRegistry provides a mock function with given fields: func (_m *Application) GetLoopRegistry() *plugins.LoopRegistry { ret := _m.Called() @@ -550,7 +572,7 @@ func (_m *Application) RunJobV2(ctx context.Context, jobID int32, meta map[strin } // RunWebhookJobV2 provides a mock function with given fields: ctx, jobUUID, requestBody, meta -func (_m *Application) RunWebhookJobV2(ctx context.Context, jobUUID uuid.UUID, requestBody string, meta pipeline.JSONSerializable) (int64, error) { +func (_m *Application) RunWebhookJobV2(ctx context.Context, jobUUID uuid.UUID, requestBody string, meta jsonserializable.JSONSerializable) (int64, error) { ret := _m.Called(ctx, jobUUID, requestBody, meta) if len(ret) == 0 { @@ -559,16 +581,16 @@ func (_m *Application) RunWebhookJobV2(ctx context.Context, jobUUID uuid.UUID, r var r0 int64 var r1 error - if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID, string, pipeline.JSONSerializable) (int64, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID, string, jsonserializable.JSONSerializable) (int64, error)); ok { return rf(ctx, jobUUID, requestBody, meta) } - if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID, string, pipeline.JSONSerializable) int64); ok { + if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID, string, jsonserializable.JSONSerializable) int64); ok { r0 = rf(ctx, jobUUID, requestBody, meta) } else { r0 = ret.Get(0).(int64) } - if rf, ok := ret.Get(1).(func(context.Context, uuid.UUID, string, pipeline.JSONSerializable) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, uuid.UUID, string, jsonserializable.JSONSerializable) error); ok { r1 = rf(ctx, jobUUID, requestBody, meta) } else { r1 = ret.Error(1) diff --git a/core/internal/testutils/configtest/general_config.go b/core/internal/testutils/configtest/general_config.go index c79b1c7c3cb..5ba3bf1724f 100644 --- a/core/internal/testutils/configtest/general_config.go +++ b/core/internal/testutils/configtest/general_config.go @@ -56,6 +56,7 @@ func overrides(c *chainlink.Config, s *chainlink.Secrets) { c.Database.DefaultLockTimeout = commonconfig.MustNewDuration(1 * time.Minute) c.JobPipeline.ReaperInterval = commonconfig.MustNewDuration(0) + c.JobPipeline.VerboseLogging = ptr(true) c.P2P.V2.Enabled = ptr(false) diff --git a/core/scripts/common/vrf/setup-envs/README.md b/core/scripts/common/vrf/setup-envs/README.md index d7790a14ada..924b878eb18 100644 --- a/core/scripts/common/vrf/setup-envs/README.md +++ b/core/scripts/common/vrf/setup-envs/README.md @@ -33,6 +33,8 @@ go run . \ --bhf-creds-file \ --num-eth-keys=1 \ --num-vrf-keys=1 \ +--num-bhs-sending-keys= 1 \ +--num-bhf-sending-keys=1 \ --sending-key-funding-amount="1e17" \ --deploy-contracts-and-create-jobs="true" \ --subscription-balance="1e19" \ @@ -75,6 +77,8 @@ go run . \ --bhf-creds-file \ --num-eth-keys=1 \ --num-vrf-keys=1 \ +--num-bhs-sending-keys= 1 \ +--num-bhf-sending-keys=1 \ --sending-key-funding-amount="1e17" \ --deploy-contracts-and-create-jobs="true" \ --subscription-balance="1e19" \ diff --git a/core/scripts/common/vrf/setup-envs/main.go b/core/scripts/common/vrf/setup-envs/main.go index efd9c2bab3e..55a2cb5c3c2 100644 --- a/core/scripts/common/vrf/setup-envs/main.go +++ b/core/scripts/common/vrf/setup-envs/main.go @@ -69,6 +69,8 @@ func main() { numEthKeys := flag.Int("num-eth-keys", 5, "Number of eth keys to create") provingKeyMaxGasPriceString := flag.String("proving-key-max-gas-price", "1e12", "Max Gas Price for proving key set in Coordinator config") numVRFKeys := flag.Int("num-vrf-keys", 1, "Number of vrf keys to create") + numBHSSendingKeys := flag.Int("num-bhs-sending-keys", 1, "Number of sending keys for BHS to create") + numBHFSendingKeys := flag.Int("num-bhf-sending-keys", 1, "Number of sending keys for BHF to create") batchFulfillmentEnabled := flag.Bool("batch-fulfillment-enabled", constants.BatchFulfillmentEnabled, "whether send randomness fulfillments in batches inside one tx from CL node") batchFulfillmentGasMultiplier := flag.Float64("batch-fulfillment-gas-multiplier", 1.1, "") estimateGasMultiplier := flag.Float64("estimate-gas-multiplier", 1.1, "") @@ -166,7 +168,16 @@ func main() { for key, node := range nodesMap { node := node client, app := connectToNode(&node.URL, output, node.CredsFile) - ethKeys := createETHKeysIfNeeded(client, app, output, numEthKeys, &node.URL) + + // assumption that we are dealing with VRF nodes + numKeysToCreate := numEthKeys + if key == model.BHSNodeName || key == model.BHSBackupNodeName { + numKeysToCreate = numBHSSendingKeys + } else if key == model.BHFNodeName { + numKeysToCreate = numBHFSendingKeys + } + ethKeys := createETHKeysIfNeeded(client, app, output, numKeysToCreate, &node.URL) + if key == model.VRFPrimaryNodeName { vrfKeys := createVRFKeyIfNeeded(client, app, output, numVRFKeys, &node.URL) node.VrfKeys = mapVrfKeysToStringArr(vrfKeys) diff --git a/core/scripts/functions/main.go b/core/scripts/functions/main.go index 2bf35828c91..cf496542b05 100644 --- a/core/scripts/functions/main.go +++ b/core/scripts/functions/main.go @@ -19,6 +19,7 @@ func main() { src.NewGenerateJobSpecsCommand(), src.NewDeployJobSpecsCommand(), src.NewDeleteJobsCommand(), + src.NewFetchKeysCommand(), } commandsList := func(commands []command) string { diff --git a/core/scripts/functions/src/fetch_keys.go b/core/scripts/functions/src/fetch_keys.go new file mode 100644 index 00000000000..4c3b11a7e28 --- /dev/null +++ b/core/scripts/functions/src/fetch_keys.go @@ -0,0 +1,44 @@ +package src + +import ( + "encoding/json" + "flag" + "fmt" + "os" +) + +type fetchKeys struct { +} + +func NewFetchKeysCommand() *fetchKeys { + return &fetchKeys{} +} + +func (g *fetchKeys) Name() string { + return "fetch-keys" +} + +func (g *fetchKeys) Run(args []string) { + fs := flag.NewFlagSet(g.Name(), flag.ContinueOnError) + nodesFile := fs.String("nodes", "", "a file containing nodes urls, logins and passwords") + chainID := fs.Int64("chainid", 80001, "chain id") + if err := fs.Parse(args); err != nil || *nodesFile == "" || *chainID == 0 { + fs.Usage() + os.Exit(1) + } + + nodes := mustReadNodesList(*nodesFile) + nca := mustFetchNodesKeys(*chainID, nodes) + + nodePublicKeys, err := json.MarshalIndent(nca, "", " ") + if err != nil { + panic(err) + } + filepath := "PublicKeys.json" + err = os.WriteFile(filepath, nodePublicKeys, 0600) + if err != nil { + panic(err) + } + fmt.Println("Functions OCR2 public keys have been saved to:", filepath) + +} diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 8b8a757a76c..c4e32d4f276 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -20,11 +20,11 @@ require ( github.com/pelletier/go-toml/v2 v2.1.1 github.com/prometheus/client_golang v1.17.0 github.com/shopspring/decimal v1.3.1 - github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240311111125-22812a072c35 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240314172156-049609b8e1f9 + github.com/smartcontractkit/chainlink-automation v1.0.2 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240404141006-77085a02ce25 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 - github.com/smartcontractkit/libocr v0.0.0-20240229181116-bfb2432a7a66 + github.com/smartcontractkit/libocr v0.0.0-20240326191951-2bbe9382d052 github.com/spf13/cobra v1.6.1 github.com/spf13/viper v1.15.0 github.com/stretchr/testify v1.9.0 @@ -52,11 +52,14 @@ require ( github.com/Depado/ginprom v1.8.0 // indirect github.com/Masterminds/semver/v3 v3.2.1 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/NethermindEth/juno v0.3.1 // indirect + github.com/NethermindEth/starknet.go v0.6.1-0.20231218140327-915109ab5bc1 // indirect github.com/VictoriaMetrics/fastcache v1.12.1 // indirect github.com/XSAM/otelsql v0.27.0 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/avast/retry-go/v4 v4.5.1 // indirect github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect + github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/benbjohnson/clock v1.3.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect @@ -64,6 +67,7 @@ require ( github.com/blendle/zapdriver v1.3.1 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/btcsuite/btcd/btcutil v1.1.3 // indirect + github.com/buger/jsonparser v1.1.1 // indirect github.com/bytedance/sonic v1.10.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect @@ -104,6 +108,7 @@ require ( github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/docker/distribution v2.8.2+incompatible // indirect github.com/docker/go-units v0.5.0 // indirect + github.com/dominikbraun/graph v0.23.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.5.0 // indirect github.com/esote/minmaxheap v1.0.0 // indirect @@ -131,7 +136,7 @@ require ( github.com/go-kit/log v0.2.1 // indirect github.com/go-ldap/ldap/v3 v3.4.6 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-playground/locales v0.14.1 // indirect @@ -146,10 +151,9 @@ require ( github.com/golang-jwt/jwt/v5 v5.2.0 // indirect github.com/golang/glog v1.1.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/btree v1.1.2 // indirect - github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-tpm v0.9.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b // indirect @@ -169,7 +173,7 @@ require ( github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/gtank/merlin v0.1.1 // indirect github.com/gtank/ristretto255 v0.1.2 // indirect - github.com/hashicorp/consul/sdk v0.14.1 // indirect + github.com/hashicorp/consul/sdk v0.16.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-envparse v0.1.0 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect @@ -185,14 +189,15 @@ require ( github.com/huandu/skiplist v1.2.0 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/invopop/jsonschema v0.12.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.14.1 // indirect + github.com/jackc/pgconn v1.14.3 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.2 // indirect + github.com/jackc/pgproto3/v2 v2.3.3 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgtype v1.14.0 // indirect - github.com/jackc/pgx/v4 v4.18.1 // indirect + github.com/jackc/pgx/v4 v4.18.2 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect @@ -208,6 +213,7 @@ require ( github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect @@ -249,13 +255,12 @@ require ( github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shirou/gopsutil/v3 v3.23.11 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect github.com/smartcontractkit/chain-selectors v1.0.10 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 // indirect github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e // indirect - github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240213121419-1272736c2ac0 // indirect + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/wsrpc v0.7.2 // indirect @@ -270,6 +275,7 @@ require ( github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect github.com/tendermint/go-amino v0.16.0 // indirect github.com/teris-io/shortid v0.0.0-20201117134242-e59966efd125 // indirect + github.com/test-go/testify v1.1.4 // indirect github.com/theodesp/go-heaps v0.0.0-20190520121037-88e35354fe0a // indirect github.com/tidwall/btree v1.6.0 // indirect github.com/tidwall/gjson v1.17.0 // indirect @@ -283,6 +289,7 @@ require ( github.com/ulule/limiter/v3 v3.11.2 // indirect github.com/unrolled/secure v1.13.0 // indirect github.com/valyala/fastjson v1.4.1 // indirect + github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/zondax/hid v0.9.1 // indirect @@ -290,26 +297,26 @@ require ( go.dedis.ch/fixbuf v1.0.3 // indirect go.etcd.io/bbolt v1.3.7 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1 // indirect + go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.49.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect - go.opentelemetry.io/otel v1.21.0 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 // indirect - go.opentelemetry.io/otel/metric v1.21.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/otel/sdk v1.21.0 // indirect - go.opentelemetry.io/otel/trace v1.21.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/ratelimit v0.3.0 // indirect go.uber.org/zap v1.26.0 // indirect golang.org/x/arch v0.7.0 // indirect - golang.org/x/crypto v0.19.0 // indirect + golang.org/x/crypto v0.21.0 // indirect golang.org/x/exp v0.0.0-20240213143201-ec583247a57a // indirect golang.org/x/mod v0.15.0 // indirect golang.org/x/net v0.21.0 // indirect golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.17.0 // indirect - golang.org/x/term v0.17.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/term v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.18.0 // indirect @@ -318,7 +325,7 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect google.golang.org/grpc v1.59.0 // indirect - google.golang.org/protobuf v1.32.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/guregu/null.v4 v4.0.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect @@ -326,7 +333,7 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect pgregory.net/rapid v0.5.5 // indirect rsc.io/tmplfunc v0.0.3 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) replace ( diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 38d053c98fc..98b5142ba0a 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -108,6 +108,10 @@ github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0 github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/NethermindEth/juno v0.3.1 h1:AW72LiAm9gqUeCVJWvepnZcTnpU4Vkl0KzPMxS+42FA= +github.com/NethermindEth/juno v0.3.1/go.mod h1:SGbTpgGaCsxhFsKOid7Ylnz//WZ8swtILk+NbHGsk/Q= +github.com/NethermindEth/starknet.go v0.6.1-0.20231218140327-915109ab5bc1 h1:9SBvy3eZut1X+wEyAFqfb7ADGj8IQw7ZnlkMwz0YOTY= +github.com/NethermindEth/starknet.go v0.6.1-0.20231218140327-915109ab5bc1/go.mod h1:V6qrbi1+fTDCftETIT1grBXIf+TvWP/4Aois1a9EF1E= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -155,6 +159,8 @@ github.com/aws/aws-sdk-go v1.45.25/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8P github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -199,6 +205,7 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= @@ -363,6 +370,8 @@ github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKoh github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucVPgCo= +github.com/dominikbraun/graph v0.23.0/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= @@ -484,8 +493,8 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= @@ -571,8 +580,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= @@ -598,8 +607,6 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= -github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= @@ -688,8 +695,8 @@ github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uM github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.14.1 h1:ZiwE2bKb+zro68sWzZ1SgHF3kRMBZ94TwOCFRF4ylPs= -github.com/hashicorp/consul/sdk v0.14.1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg= +github.com/hashicorp/consul/sdk v0.16.0 h1:SE9m0W6DEfgIVCJX7xU+iv/hUl4m/nxqMTnCdMxDpJ8= +github.com/hashicorp/consul/sdk v0.16.0/go.mod h1:7pxqqhqoaPqnBnzXD1StKed62LqJeClzVsUEy85Zr0A= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= @@ -765,6 +772,8 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI= +github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= @@ -780,9 +789,8 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= -github.com/jackc/pgconn v1.14.1 h1:smbxIaZA08n6YuxEX1sDyjV/qkbtUtkH20qLkR9MUR4= -github.com/jackc/pgconn v1.14.1/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= +github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w= +github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= @@ -798,8 +806,8 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.2 h1:7eY55bdBeCz1F2fTzSz69QC+pG46jYq9/jtSPiJ5nn0= -github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= +github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= @@ -813,15 +821,14 @@ github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08 github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0= -github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE= +github.com/jackc/pgx/v4 v4.18.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU= +github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= github.com/jackc/pgx/v5 v5.5.0 h1:NxstgwndsTRy7eq9/kqYc/BZh5w2hHJV86wjvO+1xPw= github.com/jackc/pgx/v5 v5.5.0/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= -github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= @@ -844,6 +851,7 @@ github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwA github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= @@ -916,6 +924,8 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= github.com/manyminds/api2go v0.0.0-20171030193247-e7b693844a6f h1:tVvGiZQFjOXP+9YyGqSA6jE55x1XVxmoPYudncxrZ8U= @@ -1143,6 +1153,8 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= @@ -1171,14 +1183,12 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= -github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCqR1LNS7aI3jT0V+xGrg= github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= -github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240311111125-22812a072c35 h1:GNhRKD3izyzAoGMXDvVUAwEuzz4Atdj3U3RH7eak5Is= -github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240311111125-22812a072c35/go.mod h1:2I0dWdYdK6jHPnSYYy7Y7Xp7L0YTnJ3KZtkhLQflsTU= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240314172156-049609b8e1f9 h1:rlvE17wHiSnrl2d42TWQ2VVx8ho8c9vgznysXj68sRU= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240314172156-049609b8e1f9/go.mod h1:/bJGelrpXvCcDCuaIgt91UN4B9YxZdK1O7VX5lzbysI= +github.com/smartcontractkit/chainlink-automation v1.0.2 h1:xsfyuswL15q2YBGQT3qn2SBz6fnSKiSW7XZ8IZQLpnI= +github.com/smartcontractkit/chainlink-automation v1.0.2/go.mod h1:RjboV0Qd7YP+To+OrzHGXaxUxoSONveCoAK2TQ1INLU= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240404141006-77085a02ce25 h1:fY2wMtlr/VQxPyVVQdi1jFvQHi0VbDnGGVXzLKOZTOY= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240404141006-77085a02ce25/go.mod h1:kstYjAGqBswdZpl7YkSPeXBDVwaY1VaR6tUMPWl8ykA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 h1:I326nw5GwHQHsLKHwtu5Sb9EBLylC8CfUd7BFAS0jtg= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8/go.mod h1:a65NtrK4xZb01mf0dDNghPkN2wXgcqFQ55ADthVBgMc= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= @@ -1187,16 +1197,16 @@ github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 h github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8/go.mod h1:vy1L7NybTy2F/Yv7BOh+oZBa1MACD6gzd1+DkcSkfp8= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e h1:k8HS3GsAFZnxXIW3141VsQP2+EL1XrTtOi/HDt7sdBE= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e/go.mod h1:JiykN+8W5TA4UD2ClrzQCVvcH3NcyLEVv7RwY0busrw= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240213121419-1272736c2ac0 h1:7m9PVtccb8/pvKTXMaGuyceFno1icRyC2SFH7KG7+70= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240213121419-1272736c2ac0/go.mod h1:SZ899lZYQ0maUulWbZg+SWqabHQ1wTbyk3jT8wJfyo8= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595 h1:y6ks0HsSOhPUueOmTcoxDQ50RCS1XINlRDTemZyHjFw= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595/go.mod h1:vV6WfnVIbK5Q1JsIru4YcTG0T1uRpLJm6t2BgCnCSsg= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= github.com/smartcontractkit/go-plugin v0.0.0-20240208201424-b3b91517de16 h1:TFe+FvzxClblt6qRfqEhUfa4kFQx5UobuoFGO2W4mMo= github.com/smartcontractkit/go-plugin v0.0.0-20240208201424-b3b91517de16/go.mod h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -github.com/smartcontractkit/libocr v0.0.0-20240229181116-bfb2432a7a66 h1:xsU00JB9GJxEiN6tDbqgN+fT98ySdxkUwTw6CfBXscw= -github.com/smartcontractkit/libocr v0.0.0-20240229181116-bfb2432a7a66/go.mod h1:SJEZCHgMCAzzBvo9vMV2DQ9onfEcIJCYSViyP4JI6c4= +github.com/smartcontractkit/libocr v0.0.0-20240326191951-2bbe9382d052 h1:1WFjrrVrWoQ9UpVMh7Mx4jDpzhmo1h8hFUKd9awIhIU= +github.com/smartcontractkit/libocr v0.0.0-20240326191951-2bbe9382d052/go.mod h1:SJEZCHgMCAzzBvo9vMV2DQ9onfEcIJCYSViyP4JI6c4= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= @@ -1323,6 +1333,8 @@ github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+ github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vertica/vertica-sql-go v1.3.3 h1:fL+FKEAEy5ONmsvya2WH5T8bhkvY27y/Ik3ReR2T+Qw= github.com/vertica/vertica-sql-go v1.3.3/go.mod h1:jnn2GFuv+O2Jcjktb7zyc4Utlbu9YVqpHH/lx63+1M4= +github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= +github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -1379,26 +1391,26 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1 h1:mMv2jG58h6ZI5t5S9QCVGdzCmAsTakMa3oxVgpSD44g= -go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1/go.mod h1:oqRuNKG0upTaDPbLVCG8AD0G2ETrfDtmh7jViy7ox6M= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.49.0 h1:1f31+6grJmV3X4lxcEvUy13i5/kfDw1nJZwhd8mA4tg= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.49.0/go.mod h1:1P/02zM3OwkX9uki+Wmxw3a5GVb6KUXRsa7m7bOC9Fg= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= -go.opentelemetry.io/contrib/propagators/b3 v1.21.1 h1:WPYiUgmw3+b7b3sQ1bFBFAf0q+Di9dvNc3AtYfnT4RQ= -go.opentelemetry.io/contrib/propagators/b3 v1.21.1/go.mod h1:EmzokPoSqsYMBVK4nRnhsfm5mbn8J1eDuz/U1UaQaWg= -go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= -go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/contrib/propagators/b3 v1.24.0 h1:n4xwCdTx3pZqZs2CjS/CUZAs03y3dZcGhC/FepKtEUY= +go.opentelemetry.io/contrib/propagators/b3 v1.24.0/go.mod h1:k5wRxKRU2uXx2F8uNJ4TaonuEO/V7/5xoz7kdsDACT8= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0= -go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= -go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= go.opentelemetry.io/otel/sdk/metric v1.21.0 h1:smhI5oD714d6jHE6Tie36fPx4WDFIg+Y6RfAY4ICcR0= go.opentelemetry.io/otel/sdk/metric v1.21.0/go.mod h1:FJ8RAsoPGv/wYMgBdUJXOm+6pzFY3YdljnXtv1SBE8Q= -go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= -go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -1457,10 +1469,9 @@ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1675,8 +1686,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1684,8 +1695,8 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= -golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1907,8 +1918,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1994,5 +2005,5 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/core/scripts/vrfv1/README.md b/core/scripts/vrfv1/README.md index 36ce6edb5fd..7b8056b4b5f 100644 --- a/core/scripts/vrfv1/README.md +++ b/core/scripts/vrfv1/README.md @@ -87,13 +87,13 @@ Ownerless Consumer: TX Hash: Since the ownerless consumer does not hold LINK funds, it can only request randomness through a transferAndCall from the -[LINK contract](../../../contracts/src/v0.4/LinkToken.sol). The transaction has +[LINK contract](../../../contracts/src/v0.8/shared/token/ERC677/LinkToken.sol). The transaction has the following steps: 1. An externally owned account (controlled by your private key) initiates a transferAndCall on the LinkToken contract. 2. The LinkToken contract transfers funds to the ownerless consumer. 3. The ownerless consumer requests randomness from the - [VRF Coordinator](../../../contracts/src/v0.6/VRFCoordinator.sol), using the + [VRF Coordinator](https://github.com/smartcontractkit/chainlink-contracts-deprecated/blob/main/contracts/src/v0.6/VRFCoordinator.sol), using the LINK from step 2 to pay for it. To request randomness for your chosen consumer, run: diff --git a/core/scripts/vrfv2plus/testnet/main.go b/core/scripts/vrfv2plus/testnet/main.go index 4f4a47d3563..49be23f1e34 100644 --- a/core/scripts/vrfv2plus/testnet/main.go +++ b/core/scripts/vrfv2plus/testnet/main.go @@ -304,7 +304,7 @@ func main() { ps, err := proof.BigToSeed(decimal.RequireFromString(*preSeed).BigInt()) helpers.PanicErr(err) - parsedSubID := parseSubID(*subID) + parsedSubID := parseUInt256String(*subID) extraArgs, err := extraargs.ExtraArgsV1(*nativePayment) helpers.PanicErr(err) preSeedData := proof.PreSeedDataV2Plus{ @@ -567,7 +567,7 @@ func main() { registerKeyAddress := coordinatorRegisterKey.String("address", "", "coordinator address") registerKeyUncompressedPubKey := coordinatorRegisterKey.String("pubkey", "", "uncompressed pubkey") gasLaneMaxGas := coordinatorRegisterKey.Uint64("gas-lane-max-gas", 1e12, "gas lane max gas price") - helpers.ParseArgs(coordinatorRegisterKey, os.Args[2:], "address", "pubkey", "oracle-address") + helpers.ParseArgs(coordinatorRegisterKey, os.Args[2:], "address", "pubkey") coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*registerKeyAddress), e.Ec) helpers.PanicErr(err) @@ -605,10 +605,20 @@ func main() { coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*address), e.Ec) helpers.PanicErr(err) fmt.Println("sub-id", *subID, "address", *address, coordinator.Address()) - parsedSubID := parseSubID(*subID) + parsedSubID := parseUInt256String(*subID) s, err := coordinator.GetSubscription(nil, parsedSubID) helpers.PanicErr(err) fmt.Printf("Subscription %+v\n", s) + case "coordinator-get-commitment": + coordinatorCommitment := flag.NewFlagSet("coordinator-get-commitment", flag.ExitOnError) + coordinatorAddress := coordinatorCommitment.String("coordinator-address", "", "coordinator address") + requestId := coordinatorCommitment.String("request-id", "", "consumer's request ID") + helpers.ParseArgs(coordinatorCommitment, os.Args[2:], "coordinator-address", "request-id") + coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*coordinatorAddress), e.Ec) + helpers.PanicErr(err) + res, err := coordinator.SRequestCommitments(nil, parseUInt256String(*requestId)) + helpers.PanicErr(err) + fmt.Printf("Request ID: %+v - commitment: %v\n", *requestId, hexutil.Encode(res[:])) case "consumer-deploy": consumerDeployCmd := flag.NewFlagSet("consumer-deploy", flag.ExitOnError) consumerCoordinator := consumerDeployCmd.String("coordinator-address", "", "coordinator address") @@ -757,7 +767,7 @@ func main() { helpers.ParseArgs(addSubConsCmd, os.Args[2:], "coordinator-address", "sub-id", "consumer-address") coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - parsedSubID := parseSubID(*subID) + parsedSubID := parseUInt256String(*subID) v2plusscripts.EoaAddConsumerToSub(e, *coordinator, parsedSubID, *consumerAddress) case "eoa-create-fund-authorize-sub": // Lets just treat the owner key as the EOA controlling the sub @@ -817,7 +827,7 @@ func main() { common.HexToAddress(*consumerAddress), e.Ec) helpers.PanicErr(err) - tx, err := consumer.RequestRandomWords(e.Owner, parseSubID(*subID), uint32(*cbGasLimit), uint16(*requestConfirmations), uint32(*numWords), keyHashBytes, *nativePayment) + tx, err := consumer.RequestRandomWords(e.Owner, parseUInt256String(*subID), uint32(*cbGasLimit), uint16(*requestConfirmations), uint32(*numWords), keyHashBytes, *nativePayment) helpers.PanicErr(err) fmt.Println("TX", helpers.ExplorerLink(e.ChainID, tx.Hash())) r, err := bind.WaitMined(context.Background(), e.Ec, tx) @@ -950,7 +960,7 @@ func main() { helpers.ParseArgs(trans, os.Args[2:], "coordinator-address", "sub-id", "to") coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - tx, err := coordinator.RequestSubscriptionOwnerTransfer(e.Owner, parseSubID(*subID), common.HexToAddress(*to)) + tx, err := coordinator.RequestSubscriptionOwnerTransfer(e.Owner, parseUInt256String(*subID), common.HexToAddress(*to)) helpers.PanicErr(err) helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) case "eoa-accept-sub": @@ -960,7 +970,7 @@ func main() { helpers.ParseArgs(accept, os.Args[2:], "coordinator-address", "sub-id") coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - tx, err := coordinator.AcceptSubscriptionOwnerTransfer(e.Owner, parseSubID(*subID)) + tx, err := coordinator.AcceptSubscriptionOwnerTransfer(e.Owner, parseUInt256String(*subID)) helpers.PanicErr(err) helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) case "eoa-cancel-sub": @@ -970,7 +980,7 @@ func main() { helpers.ParseArgs(cancel, os.Args[2:], "coordinator-address", "sub-id") coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - tx, err := coordinator.CancelSubscription(e.Owner, parseSubID(*subID), e.Owner.From) + tx, err := coordinator.CancelSubscription(e.Owner, parseUInt256String(*subID), e.Owner.From) helpers.PanicErr(err) helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) case "eoa-fund-sub-with-native-token": @@ -983,7 +993,7 @@ func main() { if !s { panic(fmt.Sprintf("failed to parse top up amount '%s'", *amountStr)) } - parsedSubID := parseSubID(*subID) + parsedSubID := parseUInt256String(*subID) v2plusscripts.EoaFundSubWithNative(e, common.HexToAddress(*coordinatorAddress), parsedSubID, amount) case "eoa-fund-sub": @@ -1000,7 +1010,7 @@ func main() { coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - v2plusscripts.EoaFundSubWithLink(e, *coordinator, *consumerLinkAddress, amount, parseSubID(*subID)) + v2plusscripts.EoaFundSubWithLink(e, *coordinator, *consumerLinkAddress, amount, parseUInt256String(*subID)) case "eoa-read": cmd := flag.NewFlagSet("eoa-read", flag.ExitOnError) consumerAddress := cmd.String("consumer", "", "consumer address") @@ -1021,7 +1031,7 @@ func main() { helpers.ParseArgs(cancel, os.Args[2:], "coordinator-address", "sub-id") coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - tx, err := coordinator.OwnerCancelSubscription(e.Owner, parseSubID(*subID)) + tx, err := coordinator.OwnerCancelSubscription(e.Owner, parseUInt256String(*subID)) helpers.PanicErr(err) helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) case "sub-balance": @@ -1031,7 +1041,7 @@ func main() { helpers.ParseArgs(consumerBalanceCmd, os.Args[2:], "coordinator-address", "sub-id") coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - resp, err := coordinator.GetSubscription(nil, parseSubID(*subID)) + resp, err := coordinator.GetSubscription(nil, parseUInt256String(*subID)) helpers.PanicErr(err) fmt.Println("sub id", *subID, "balance:", resp.Balance) case "coordinator-withdrawable-tokens": @@ -1079,6 +1089,20 @@ func main() { helpers.PanicErr(err) helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID, "transfer ownership to", *newOwner) + case "public-key-x-y": + publicKeyXY := flag.NewFlagSet("public-key-x-y", flag.ExitOnError) + uncompressedPubKeyCLI := publicKeyXY.String("pubkey", "", "uncompressed pubkey") + helpers.ParseArgs(publicKeyXY, os.Args[2:], "pubkey") + uncompressedPubKey := *uncompressedPubKeyCLI + // Put key in ECDSA format + if strings.HasPrefix(uncompressedPubKey, "0x") { + uncompressedPubKey = strings.Replace(uncompressedPubKey, "0x", "04", 1) + } + pubBytes, err := hex.DecodeString(uncompressedPubKey) + helpers.PanicErr(err) + pk, err := crypto.UnmarshalPubkey(pubBytes) + helpers.PanicErr(err) + fmt.Printf("PublicKey: %s, X: %s, Y: %s\n", *uncompressedPubKeyCLI, pk.X, pk.Y) case "coordinator-reregister-proving-key": coordinatorReregisterKey := flag.NewFlagSet("coordinator-register-key", flag.ExitOnError) coordinatorAddress := coordinatorReregisterKey.String("coordinator-address", "", "coordinator address") @@ -1130,11 +1154,13 @@ func main() { linkAddress := cmd.String("link-address", "", "address of link token") linkETHFeedAddress := cmd.String("link-eth-feed", "", "address of link-eth-feed") coordinatorAddress := cmd.String("coordinator-address", "", "address of the vrf coordinator v2 contract") - helpers.ParseArgs(cmd, os.Args[2:], "link-address", "link-eth-feed", "coordinator-address") + subID := cmd.String("subscription-id", "", "subscription ID for the wrapper") + helpers.ParseArgs(cmd, os.Args[2:], "link-address", "link-eth-feed", "coordinator-address", "subscription-id") v2plusscripts.WrapperDeploy(e, common.HexToAddress(*linkAddress), common.HexToAddress(*linkETHFeedAddress), - common.HexToAddress(*coordinatorAddress)) + common.HexToAddress(*coordinatorAddress), + parseUInt256String(*subID)) case "wrapper-withdraw": cmd := flag.NewFlagSet("wrapper-withdraw", flag.ExitOnError) wrapperAddress := cmd.String("wrapper-address", "", "address of the VRFV2Wrapper contract") @@ -1164,26 +1190,29 @@ func main() { wrapperAddress := cmd.String("wrapper-address", "", "address of the VRFV2Wrapper contract") wrapperGasOverhead := cmd.Uint("wrapper-gas-overhead", 50_000, "amount of gas overhead in wrapper fulfillment") coordinatorGasOverhead := cmd.Uint("coordinator-gas-overhead", 52_000, "amount of gas overhead in coordinator fulfillment") - wrapperPremiumPercentage := cmd.Uint("wrapper-premium-percentage", 25, "gas premium charged by wrapper") + wrapperNativePremiumPercentage := cmd.Uint("wrapper-native-premium-percentage", 25, "gas premium charged by wrapper for native payment") + wrapperLinkPremiumPercentage := cmd.Uint("wrapper-link-premium-percentage", 25, "gas premium charged by wrapper for link payment") keyHash := cmd.String("key-hash", "", "the keyhash that wrapper requests should use") maxNumWords := cmd.Uint("max-num-words", 10, "the keyhash that wrapper requests should use") fallbackWeiPerUnitLink := cmd.String("fallback-wei-per-unit-link", "", "the fallback wei per unit link") stalenessSeconds := cmd.Uint("staleness-seconds", 86400, "the number of seconds of staleness to allow") - fulfillmentFlatFeeLinkPPM := cmd.Uint("fulfillment-flat-fee-link-ppm", 500, "the link flat fee in ppm to charge for fulfillment") - fulfillmentFlatFeeNativePPM := cmd.Uint("fulfillment-flat-fee-native-ppm", 500, "the native flat fee in ppm to charge for fulfillment") + fulfillmentFlatFeeNativePPM := cmd.Uint("fulfillment-flat-fee-native-ppm", 500, "the native flat fee in ppm to charge for fulfillment denominated in native") + fulfillmentFlatFeeLinkDiscountPPM := cmd.Uint("fulfillment-flat-fee-link-discount-ppm", 500, "the link flat fee discount in ppm to charge for fulfillment denominated in native") helpers.ParseArgs(cmd, os.Args[2:], "wrapper-address", "key-hash", "fallback-wei-per-unit-link") v2plusscripts.WrapperConfigure(e, common.HexToAddress(*wrapperAddress), *wrapperGasOverhead, *coordinatorGasOverhead, - *wrapperPremiumPercentage, + *wrapperNativePremiumPercentage, + *wrapperLinkPremiumPercentage, *keyHash, *maxNumWords, decimal.RequireFromString(*fallbackWeiPerUnitLink).BigInt(), uint32(*stalenessSeconds), - uint32(*fulfillmentFlatFeeLinkPPM), - uint32(*fulfillmentFlatFeeNativePPM)) + uint32(*fulfillmentFlatFeeNativePPM), + uint32(*fulfillmentFlatFeeLinkDiscountPPM)) + case "wrapper-get-fulfillment-tx-size": cmd := flag.NewFlagSet("wrapper-get-fulfillment-tx-size", flag.ExitOnError) wrapperAddress := cmd.String("wrapper-address", "", "address of the VRFV2Wrapper contract") @@ -1287,7 +1316,7 @@ func main() { } } -func parseSubID(subID string) *big.Int { +func parseUInt256String(subID string) *big.Int { parsedSubID, ok := new(big.Int).SetString(subID, 10) if !ok { helpers.PanicErr(fmt.Errorf("sub ID %s cannot be parsed", subID)) diff --git a/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go b/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go index 12c08dd80a3..b792bca10d9 100644 --- a/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go +++ b/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go @@ -55,7 +55,7 @@ func SmokeTestVRF(e helpers.Environment) { // required flags linkAddress := smokeCmd.String("link-address", "", "address of link token") - linkEthAddress := smokeCmd.String("link-eth-feed", "", "address of link eth feed") + linkNativeAddress := smokeCmd.String("link-native-feed", "", "address of link native feed") bhsAddressStr := smokeCmd.String("bhs-address", "", "address of blockhash store") batchBHSAddressStr := smokeCmd.String("batch-bhs-address", "", "address of batch blockhash store") coordinatorAddressStr := smokeCmd.String("coordinator-address", "", "address of the vrf coordinator v2 contract") @@ -69,7 +69,7 @@ func SmokeTestVRF(e helpers.Environment) { maxGasLimit := smokeCmd.Int64("max-gas-limit", 2.5e6, "max gas limit") stalenessSeconds := smokeCmd.Int64("staleness-seconds", 86400, "staleness in seconds") gasAfterPayment := smokeCmd.Int64("gas-after-payment", 33285, "gas after payment calculation") - flatFeeEthPPM := smokeCmd.Int64("flat-fee-eth-ppm", 500, "fulfillment flat fee ETH ppm") + flatFeeNativePPM := smokeCmd.Int64("flat-fee-native-ppm", 500, "fulfillment flat fee Native ppm") flatFeeLinkDiscountPPM := smokeCmd.Int64("flat-fee-link-discount-ppm", 100, "fulfillment flat fee discount for LINK payment denominated in native ppm") nativePremiumPercentage := smokeCmd.Int64("native-premium-percentage", 1, "premium percentage for native payment") linkPremiumPercentage := smokeCmd.Int64("link-premium-percentage", 1, "premium percentage for LINK payment") @@ -95,10 +95,10 @@ func SmokeTestVRF(e helpers.Environment) { linkAddress = &address } - if len(*linkEthAddress) == 0 { - fmt.Println("\nDeploying LINK/ETH Feed...") + if len(*linkNativeAddress) == 0 { + fmt.Println("\nDeploying LINK/Native Feed...") address := helpers.DeployLinkEthFeed(e, *linkAddress, fallbackWeiPerUnitLink).String() - linkEthAddress = &address + linkNativeAddress = &address } var bhsContractAddress common.Address @@ -120,7 +120,7 @@ func SmokeTestVRF(e helpers.Environment) { var coordinatorAddress common.Address if len(*coordinatorAddressStr) == 0 { fmt.Println("\nDeploying Coordinator...") - coordinatorAddress = DeployCoordinator(e, *linkAddress, bhsContractAddress.String(), *linkEthAddress) + coordinatorAddress = DeployCoordinator(e, *linkAddress, bhsContractAddress.String(), *linkNativeAddress) } else { coordinatorAddress = common.HexToAddress(*coordinatorAddressStr) } @@ -146,7 +146,7 @@ func SmokeTestVRF(e helpers.Environment) { uint32(*stalenessSeconds), uint32(*gasAfterPayment), fallbackWeiPerUnitLink, - uint32(*flatFeeEthPPM), + uint32(*flatFeeNativePPM), uint32(*flatFeeLinkDiscountPPM), uint8(*nativePremiumPercentage), uint8(*linkPremiumPercentage), @@ -259,7 +259,7 @@ func SmokeTestVRF(e helpers.Environment) { fmt.Println( "\nDeployment complete.", "\nLINK Token contract address:", *linkAddress, - "\nLINK/ETH Feed contract address:", *linkEthAddress, + "\nLINK/Native Feed contract address:", *linkNativeAddress, "\nBlockhash Store contract address:", bhsContractAddress, "\nBatch Blockhash Store contract address:", batchBHSAddress, "\nVRF Coordinator Address:", coordinatorAddress, @@ -474,7 +474,7 @@ func DeployUniverseViaCLI(e helpers.Environment) { // required flags nativeOnly := deployCmd.Bool("native-only", false, "if true, link and link feed are not set up") linkAddress := deployCmd.String("link-address", "", "address of link token") - linkEthAddress := deployCmd.String("link-eth-feed", "", "address of link eth feed") + linkNativeAddress := deployCmd.String("link-native-feed", "", "address of link native feed") bhsContractAddressString := deployCmd.String("bhs-address", "", "address of BHS contract") batchBHSAddressString := deployCmd.String("batch-bhs-address", "", "address of Batch BHS contract") coordinatorAddressString := deployCmd.String("coordinator-address", "", "address of VRF Coordinator contract") @@ -491,7 +491,7 @@ func DeployUniverseViaCLI(e helpers.Environment) { bhsJobLookBackBlocks := flag.Int("bhs-job-look-back-blocks", 200, "") bhsJobPollPeriod := flag.String("bhs-job-poll-period", "3s", "") bhsJobRunTimeout := flag.String("bhs-job-run-timeout", "1m", "") - simulationBlock := deployCmd.String("simulation-block", "pending", "simulation block can be 'pending' or 'latest'") + simulationBlock := deployCmd.String("simulation-block", "latest", "simulation block can be 'pending' or 'latest'") // optional flags fallbackWeiPerUnitLinkString := deployCmd.String("fallback-wei-per-unit-link", "6e16", "fallback wei/link ratio") @@ -503,7 +503,7 @@ func DeployUniverseViaCLI(e helpers.Environment) { maxGasLimit := deployCmd.Int64("max-gas-limit", constants.MaxGasLimit, "max gas limit") stalenessSeconds := deployCmd.Int64("staleness-seconds", constants.StalenessSeconds, "staleness in seconds") gasAfterPayment := deployCmd.Int64("gas-after-payment", constants.GasAfterPayment, "gas after payment calculation") - flatFeeEthPPM := deployCmd.Int64("flat-fee-eth-ppm", 500, "fulfillment flat fee ETH ppm") + flatFeeNativePPM := deployCmd.Int64("flat-fee-native-ppm", 500, "fulfillment flat fee Native ppm") flatFeeLinkDiscountPPM := deployCmd.Int64("flat-fee-link-discount-ppm", 100, "fulfillment flat fee discount for LINK payment denominated in native ppm") nativePremiumPercentage := deployCmd.Int64("native-premium-percentage", 1, "premium percentage for native payment") linkPremiumPercentage := deployCmd.Int64("link-premium-percentage", 1, "premium percentage for LINK payment") @@ -514,8 +514,8 @@ func DeployUniverseViaCLI(e helpers.Environment) { ) if *nativeOnly { - if *linkAddress != "" || *linkEthAddress != "" { - panic("native-only flag is set, but link address or link eth address is provided") + if *linkAddress != "" || *linkNativeAddress != "" { + panic("native-only flag is set, but link address or link native address is provided") } if *subscriptionBalanceJuelsString != "0" { panic("native-only flag is set, but link subscription balance is provided") @@ -551,7 +551,7 @@ func DeployUniverseViaCLI(e helpers.Environment) { contractAddresses := model.ContractAddresses{ LinkAddress: *linkAddress, - LinkEthAddress: *linkEthAddress, + LinkEthAddress: *linkNativeAddress, BhsContractAddress: bhsContractAddress, BatchBHSAddress: batchBHSAddress, CoordinatorAddress: coordinatorAddress, @@ -564,7 +564,7 @@ func DeployUniverseViaCLI(e helpers.Environment) { StalenessSeconds: *stalenessSeconds, GasAfterPayment: *gasAfterPayment, FallbackWeiPerUnitLink: fallbackWeiPerUnitLink, - FulfillmentFlatFeeNativePPM: uint32(*flatFeeEthPPM), + FulfillmentFlatFeeNativePPM: uint32(*flatFeeNativePPM), FulfillmentFlatFeeLinkDiscountPPM: uint32(*flatFeeLinkDiscountPPM), NativePremiumPercentage: uint8(*nativePremiumPercentage), LinkPremiumPercentage: uint8(*linkPremiumPercentage), @@ -657,7 +657,7 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, } if !nativeOnly && len(contractAddresses.LinkEthAddress) == 0 { - fmt.Println("\nDeploying LINK/ETH Feed...") + fmt.Println("\nDeploying LINK/Native Feed...") contractAddresses.LinkEthAddress = helpers.DeployLinkEthFeed(e, contractAddresses.LinkAddress, coordinatorConfig.FallbackWeiPerUnitLink).String() } @@ -836,7 +836,7 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, fmt.Println( "\nDeployment complete.", "\nLINK Token contract address:", contractAddresses.LinkAddress, - "\nLINK/ETH Feed contract address:", contractAddresses.LinkEthAddress, + "\nLINK/Native Feed contract address:", contractAddresses.LinkEthAddress, "\nBlockhash Store contract address:", contractAddresses.BhsContractAddress, "\nBatch Blockhash Store contract address:", contractAddresses.BatchBHSAddress, "\nVRF Coordinator Address:", contractAddresses.CoordinatorAddress, @@ -865,42 +865,48 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, func DeployWrapperUniverse(e helpers.Environment) { cmd := flag.NewFlagSet("wrapper-universe-deploy", flag.ExitOnError) linkAddress := cmd.String("link-address", "", "address of link token") - linkETHFeedAddress := cmd.String("link-eth-feed", "", "address of link-eth-feed") + linkNativeFeedAddress := cmd.String("link-native-feed", "", "address of link-native-feed") coordinatorAddress := cmd.String("coordinator-address", "", "address of the vrf coordinator v2 contract") + subscriptionID := cmd.String("subscription-id", "", "subscription ID for the wrapper") wrapperGasOverhead := cmd.Uint("wrapper-gas-overhead", 50_000, "amount of gas overhead in wrapper fulfillment") coordinatorGasOverhead := cmd.Uint("coordinator-gas-overhead", 52_000, "amount of gas overhead in coordinator fulfillment") - wrapperPremiumPercentage := cmd.Uint("wrapper-premium-percentage", 25, "gas premium charged by wrapper") + wrapperNativePremiumPercentage := cmd.Uint("wrapper-native-premium-percentage", 25, "gas premium charged by wrapper for native payment") + wrapperLinkPremiumPercentage := cmd.Uint("wrapper-link-premium-percentage", 25, "gas premium charged by wrapper for link payment") keyHash := cmd.String("key-hash", "", "the keyhash that wrapper requests should use") maxNumWords := cmd.Uint("max-num-words", 10, "the keyhash that wrapper requests should use") subFunding := cmd.String("sub-funding", "10000000000000000000", "amount to fund the subscription with") consumerFunding := cmd.String("consumer-funding", "10000000000000000000", "amount to fund the consumer with") fallbackWeiPerUnitLink := cmd.String("fallback-wei-per-unit-link", "", "the fallback wei per unit link") stalenessSeconds := cmd.Uint("staleness-seconds", 86400, "the number of seconds of staleness to allow") - fulfillmentFlatFeeLinkPPM := cmd.Uint("fulfillment-flat-fee-link-ppm", 500, "the link flat fee in ppm to charge for fulfillment") - fulfillmentFlatFeeNativePPM := cmd.Uint("fulfillment-flat-fee-native-ppm", 500, "the native flat fee in ppm to charge for fulfillment") - helpers.ParseArgs(cmd, os.Args[2:], "link-address", "link-eth-feed", "coordinator-address", "key-hash", "fallback-wei-per-unit-link") + fulfillmentFlatFeeNativePPM := cmd.Uint("fulfillment-flat-fee-native-ppm", 500, "the native flat fee in ppm to charge for fulfillment denominated in native") + fulfillmentFlatFeeLinkDiscountPPM := cmd.Uint("fulfillment-flat-fee-link-discount-ppm", 500, "the link flat fee discount in ppm to charge for fulfillment denominated in native") + helpers.ParseArgs(cmd, os.Args[2:], "link-address", "link-native-feed", "coordinator-address", "key-hash", "fallback-wei-per-unit-link") amount, s := big.NewInt(0).SetString(*subFunding, 10) if !s { panic(fmt.Sprintf("failed to parse top up amount '%s'", *subFunding)) } - wrapper, subID := WrapperDeploy(e, + subId := parseSubID(*subscriptionID) + wrapper := WrapperDeploy(e, common.HexToAddress(*linkAddress), - common.HexToAddress(*linkETHFeedAddress), - common.HexToAddress(*coordinatorAddress)) + common.HexToAddress(*linkNativeFeedAddress), + common.HexToAddress(*coordinatorAddress), + subId, + ) WrapperConfigure(e, wrapper, *wrapperGasOverhead, *coordinatorGasOverhead, - *wrapperPremiumPercentage, + *wrapperNativePremiumPercentage, + *wrapperLinkPremiumPercentage, *keyHash, *maxNumWords, decimal.RequireFromString(*fallbackWeiPerUnitLink).BigInt(), uint32(*stalenessSeconds), - uint32(*fulfillmentFlatFeeLinkPPM), uint32(*fulfillmentFlatFeeNativePPM), + uint32(*fulfillmentFlatFeeLinkDiscountPPM), ) consumer := WrapperConsumerDeploy(e, @@ -910,7 +916,7 @@ func DeployWrapperUniverse(e helpers.Environment) { coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - EoaFundSubWithLink(e, *coordinator, *linkAddress, amount, subID) + EoaFundSubWithLink(e, *coordinator, *linkAddress, amount, subId) link, err := link_token_interface.NewLinkToken(common.HexToAddress(*linkAddress), e.Ec) helpers.PanicErr(err) @@ -927,3 +933,11 @@ func DeployWrapperUniverse(e helpers.Environment) { fmt.Println("wrapper address:", wrapper.String()) fmt.Println("wrapper consumer address:", consumer.String()) } + +func parseSubID(subID string) *big.Int { + parsedSubID, ok := new(big.Int).SetString(subID, 10) + if !ok { + helpers.PanicErr(fmt.Errorf("sub ID %s cannot be parsed", subID)) + } + return parsedSubID +} diff --git a/core/scripts/vrfv2plus/testnet/v2plusscripts/util.go b/core/scripts/vrfv2plus/testnet/v2plusscripts/util.go index 716e0058ff4..d18a53dd584 100644 --- a/core/scripts/vrfv2plus/testnet/v2plusscripts/util.go +++ b/core/scripts/vrfv2plus/testnet/v2plusscripts/util.go @@ -200,37 +200,32 @@ func RegisterCoordinatorProvingKey(e helpers.Environment, func WrapperDeploy( e helpers.Environment, - link, linkEthFeed, coordinator common.Address, -) (common.Address, *big.Int) { + link, linkEthFeed, coordinator common.Address, subID *big.Int, +) common.Address { address, tx, _, err := vrfv2plus_wrapper.DeployVRFV2PlusWrapper(e.Owner, e.Ec, link, linkEthFeed, - coordinator) + coordinator, + subID) helpers.PanicErr(err) helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) fmt.Println("VRFV2Wrapper address:", address) - wrapper, err := vrfv2plus_wrapper.NewVRFV2PlusWrapper(address, e.Ec) - helpers.PanicErr(err) - - subID, err := wrapper.SUBSCRIPTIONID(nil) - helpers.PanicErr(err) - fmt.Println("VRFV2Wrapper subscription id:", subID) - - return address, subID + return address } func WrapperConfigure( e helpers.Environment, wrapperAddress common.Address, - wrapperGasOverhead, coordinatorGasOverhead, premiumPercentage uint, + wrapperGasOverhead, coordinatorGasOverhead uint, + nativePremiumPercentage, linkPremiumPercentage uint, keyHash string, maxNumWords uint, fallbackWeiPerUnitLink *big.Int, stalenessSeconds uint32, - fulfillmentFlatFeeLinkPPM uint32, fulfillmentFlatFeeNativePPM uint32, + fulfillmentFlatFeeLinkDiscountPPM uint32, ) { wrapper, err := vrfv2plus_wrapper.NewVRFV2PlusWrapper(wrapperAddress, e.Ec) helpers.PanicErr(err) @@ -239,13 +234,14 @@ func WrapperConfigure( e.Owner, uint32(wrapperGasOverhead), uint32(coordinatorGasOverhead), - uint8(premiumPercentage), + uint8(nativePremiumPercentage), + uint8(linkPremiumPercentage), common.HexToHash(keyHash), uint8(maxNumWords), stalenessSeconds, fallbackWeiPerUnitLink, - fulfillmentFlatFeeLinkPPM, fulfillmentFlatFeeNativePPM, + fulfillmentFlatFeeLinkDiscountPPM, ) helpers.PanicErr(err) @@ -257,7 +253,6 @@ func WrapperConsumerDeploy( link, wrapper common.Address, ) common.Address { address, tx, _, err := vrfv2plus_wrapper_consumer_example.DeployVRFV2PlusWrapperConsumerExample(e.Owner, e.Ec, - link, wrapper) helpers.PanicErr(err) diff --git a/core/services/blockhashstore/batch_bhs.go b/core/services/blockhashstore/batch_bhs.go index ffaa22b2463..58b4467f50c 100644 --- a/core/services/blockhashstore/batch_bhs.go +++ b/core/services/blockhashstore/batch_bhs.go @@ -11,10 +11,10 @@ import ( txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" ) type batchBHSConfig interface { @@ -31,7 +31,7 @@ type BatchBlockhashStore struct { func NewBatchBHS( config batchBHSConfig, - fromAddresses []ethkey.EIP55Address, + fromAddresses []types.EIP55Address, txm txmgr.TxManager, batchbhs batch_blockhash_store.BatchBlockhashStoreInterface, chainID *big.Int, diff --git a/core/services/blockhashstore/bhs.go b/core/services/blockhashstore/bhs.go index 877e7b3dc25..d4dd52c5661 100644 --- a/core/services/blockhashstore/bhs.go +++ b/core/services/blockhashstore/bhs.go @@ -16,10 +16,10 @@ import ( txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/trusted_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" ) var _ BHS = &BulletproofBHS{} @@ -38,7 +38,7 @@ type BulletproofBHS struct { config bpBHSConfig dbConfig bpBHSDatabaseConfig jobID uuid.UUID - fromAddresses []ethkey.EIP55Address + fromAddresses []types.EIP55Address txm txmgr.TxManager abi *abi.ABI trustedAbi *abi.ABI @@ -52,7 +52,7 @@ type BulletproofBHS struct { func NewBulletproofBHS( config bpBHSConfig, dbConfig bpBHSDatabaseConfig, - fromAddresses []ethkey.EIP55Address, + fromAddresses []types.EIP55Address, txm txmgr.TxManager, bhs blockhash_store.BlockhashStoreInterface, trustedBHS *trusted_blockhash_store.TrustedBlockhashStore, diff --git a/core/services/blockhashstore/bhs_test.go b/core/services/blockhashstore/bhs_test.go index f8d33b51a34..75424ee8059 100644 --- a/core/services/blockhashstore/bhs_test.go +++ b/core/services/blockhashstore/bhs_test.go @@ -9,6 +9,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -18,7 +19,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/blockhashstore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -41,7 +41,7 @@ func TestStoreRotatesFromAddresses(t *testing.T) { require.NoError(t, err) k2, err := ks.Eth().Create(ctx, &cltest.FixtureChainID) require.NoError(t, err) - fromAddresses := []ethkey.EIP55Address{k1.EIP55Address, k2.EIP55Address} + fromAddresses := []types.EIP55Address{k1.EIP55Address, k2.EIP55Address} txm := new(txmmocks.MockEvmTxManager) bhsAddress := common.HexToAddress("0x31Ca8bf590360B3198749f852D5c516c642846F6") diff --git a/core/services/blockhashstore/common.go b/core/services/blockhashstore/common.go index a19a3b868f7..30208296a4f 100644 --- a/core/services/blockhashstore/common.go +++ b/core/services/blockhashstore/common.go @@ -8,8 +8,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" ) // Coordinator defines an interface for fetching request and fulfillment metadata from a VRF @@ -133,7 +133,7 @@ func GetSearchWindow(latestBlock, waitBlocks, lookbackBlocks int) (uint64, uint6 } // SendingKeys returns a list of sending keys (common.Address) given EIP55 addresses -func SendingKeys(fromAddresses []ethkey.EIP55Address) []common.Address { +func SendingKeys(fromAddresses []types.EIP55Address) []common.Address { var keys []common.Address for _, a := range fromAddresses { keys = append(keys, a.Address()) diff --git a/core/services/blockhashstore/delegate.go b/core/services/blockhashstore/delegate.go index c8954ad1c2b..9a11c057c32 100644 --- a/core/services/blockhashstore/delegate.go +++ b/core/services/blockhashstore/delegate.go @@ -9,6 +9,7 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" v1 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" @@ -18,7 +19,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -74,7 +74,7 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.Servi if len(keys) == 0 { return nil, fmt.Errorf("missing sending keys for chain ID: %v", chain.ID()) } - fromAddresses := []ethkey.EIP55Address{keys[0].EIP55Address} + fromAddresses := []types.EIP55Address{keys[0].EIP55Address} if jb.BlockhashStoreSpec.FromAddresses != nil { fromAddresses = jb.BlockhashStoreSpec.FromAddresses } diff --git a/core/services/blockhashstore/validate_test.go b/core/services/blockhashstore/validate_test.go index 48487bb5489..099e5db02ca 100644 --- a/core/services/blockhashstore/validate_test.go +++ b/core/services/blockhashstore/validate_test.go @@ -6,15 +6,15 @@ import ( "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" ) func TestValidate(t *testing.T) { - v1Coordinator := ethkey.EIP55Address("0x1F72B4A5DCf7CC6d2E38423bF2f4BFA7db97d139") - v2Coordinator := ethkey.EIP55Address("0x2be990eE17832b59E0086534c5ea2459Aa75E38F") - fromAddresses := []ethkey.EIP55Address{("0x469aA2CD13e037DC5236320783dCfd0e641c0559")} + v1Coordinator := types.EIP55Address("0x1F72B4A5DCf7CC6d2E38423bF2f4BFA7db97d139") + v2Coordinator := types.EIP55Address("0x2be990eE17832b59E0086534c5ea2459Aa75E38F") + fromAddresses := []types.EIP55Address{("0x469aA2CD13e037DC5236320783dCfd0e641c0559")} var tests = []struct { name string @@ -45,7 +45,7 @@ fromAddresses = ["0x469aA2CD13e037DC5236320783dCfd0e641c0559"]`, os.BlockhashStoreSpec.CoordinatorV2Address) require.Equal(t, int32(59), os.BlockhashStoreSpec.WaitBlocks) require.Equal(t, int32(159), os.BlockhashStoreSpec.LookbackBlocks) - require.Equal(t, ethkey.EIP55Address("0x3e20Cef636EdA7ba135bCbA4fe6177Bd3cE0aB17"), + require.Equal(t, types.EIP55Address("0x3e20Cef636EdA7ba135bCbA4fe6177Bd3cE0aB17"), os.BlockhashStoreSpec.BlockhashStoreAddress) require.Equal(t, 23*time.Second, os.BlockhashStoreSpec.PollPeriod) require.Equal(t, 7*time.Second, os.BlockhashStoreSpec.RunTimeout) diff --git a/core/services/blockheaderfeeder/block_header_feeder.go b/core/services/blockheaderfeeder/block_header_feeder.go index d1bcab4297a..b1e8ba7f2f3 100644 --- a/core/services/blockheaderfeeder/block_header_feeder.go +++ b/core/services/blockheaderfeeder/block_header_feeder.go @@ -12,10 +12,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/blockhashstore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" ) var ( @@ -48,7 +48,7 @@ func NewBlockHeaderFeeder( gethks keystore.Eth, getBlockhashesBatchSize uint16, storeBlockhashesBatchSize uint16, - fromAddresses []ethkey.EIP55Address, + fromAddresses []types.EIP55Address, chainID *big.Int, ) *BlockHeaderFeeder { return &BlockHeaderFeeder{ @@ -86,7 +86,7 @@ type BlockHeaderFeeder struct { getBlockhashesBatchSize uint16 storeBlockhashesBatchSize uint16 gethks keystore.Eth - fromAddresses []ethkey.EIP55Address + fromAddresses []types.EIP55Address chainID *big.Int } diff --git a/core/services/blockheaderfeeder/block_header_feeder_test.go b/core/services/blockheaderfeeder/block_header_feeder_test.go index 1b855caf9d2..afd7525c9e2 100644 --- a/core/services/blockheaderfeeder/block_header_feeder_test.go +++ b/core/services/blockheaderfeeder/block_header_feeder_test.go @@ -9,10 +9,10 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/blockhashstore" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" keystoremocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" ) @@ -200,7 +200,7 @@ func (test testCase) testFeeder(t *testing.T) { blockHeaderProvider := &blockhashstore.TestBlockHeaderProvider{} fromAddress := "0x469aA2CD13e037DC5236320783dCfd0e641c0559" - fromAddresses := []ethkey.EIP55Address{ethkey.EIP55Address(fromAddress)} + fromAddresses := []types.EIP55Address{types.EIP55Address(fromAddress)} ks := keystoremocks.NewEth(t) ks.On("GetRoundRobinAddress", mock.Anything, testutils.FixtureChainID, mock.Anything).Maybe().Return(common.HexToAddress(fromAddress), nil) @@ -244,7 +244,7 @@ func TestFeeder_CachesStoredBlocks(t *testing.T) { batchBHS := &blockhashstore.TestBatchBHS{Stored: []uint64{75}} blockHeaderProvider := &blockhashstore.TestBlockHeaderProvider{} fromAddress := "0x469aA2CD13e037DC5236320783dCfd0e641c0559" - fromAddresses := []ethkey.EIP55Address{ethkey.EIP55Address(fromAddress)} + fromAddresses := []types.EIP55Address{types.EIP55Address(fromAddress)} ks := keystoremocks.NewEth(t) ks.On("GetRoundRobinAddress", mock.Anything, testutils.FixtureChainID, mock.Anything).Maybe().Return(common.HexToAddress(fromAddress), nil) diff --git a/core/services/blockheaderfeeder/validate_test.go b/core/services/blockheaderfeeder/validate_test.go index cdab0322a40..66413a615bd 100644 --- a/core/services/blockheaderfeeder/validate_test.go +++ b/core/services/blockheaderfeeder/validate_test.go @@ -6,16 +6,16 @@ import ( "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" ) func TestValidate(t *testing.T) { - v1Coordinator := ethkey.EIP55Address("0x1F72B4A5DCf7CC6d2E38423bF2f4BFA7db97d139") - v2Coordinator := ethkey.EIP55Address("0x2be990eE17832b59E0086534c5ea2459Aa75E38F") - v2PlusCoordinator := ethkey.EIP55Address("0x92B5e28Ac583812874e4271380c7d070C5FB6E6b") - fromAddresses := []ethkey.EIP55Address{("0x469aA2CD13e037DC5236320783dCfd0e641c0559")} + v1Coordinator := types.EIP55Address("0x1F72B4A5DCf7CC6d2E38423bF2f4BFA7db97d139") + v2Coordinator := types.EIP55Address("0x2be990eE17832b59E0086534c5ea2459Aa75E38F") + v2PlusCoordinator := types.EIP55Address("0x92B5e28Ac583812874e4271380c7d070C5FB6E6b") + fromAddresses := []types.EIP55Address{("0x469aA2CD13e037DC5236320783dCfd0e641c0559")} var tests = []struct { name string @@ -53,9 +53,9 @@ storeBlockhashesBatchSize = 10 os.BlockHeaderFeederSpec.CoordinatorV2PlusAddress) require.Equal(t, int32(2000), os.BlockHeaderFeederSpec.LookbackBlocks) require.Equal(t, int32(500), os.BlockHeaderFeederSpec.WaitBlocks) - require.Equal(t, ethkey.EIP55Address("0x3e20Cef636EdA7ba135bCbA4fe6177Bd3cE0aB17"), + require.Equal(t, types.EIP55Address("0x3e20Cef636EdA7ba135bCbA4fe6177Bd3cE0aB17"), os.BlockHeaderFeederSpec.BlockhashStoreAddress) - require.Equal(t, ethkey.EIP55Address("0xD04E5b2ea4e55AEbe6f7522bc2A69Ec6639bfc63"), + require.Equal(t, types.EIP55Address("0xD04E5b2ea4e55AEbe6f7522bc2A69Ec6639bfc63"), os.BlockHeaderFeederSpec.BatchBlockhashStoreAddress) require.Equal(t, 23*time.Second, os.BlockHeaderFeederSpec.PollPeriod) require.Equal(t, 7*time.Second, os.BlockHeaderFeederSpec.RunTimeout) diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index ca8f118b149..e71ad3095b2 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -22,12 +22,14 @@ import ( commonservices "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-common/pkg/utils" + "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/core/capabilities" "github.com/smartcontractkit/chainlink/v2/core/static" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/build" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" evmutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" @@ -87,6 +89,7 @@ type Application interface { GetExternalInitiatorManager() webhook.ExternalInitiatorManager GetRelayers() RelayerChainInteroperators GetLoopRegistry() *plugins.LoopRegistry + GetLoopRegistrarConfig() plugins.RegistrarConfig // V2 Jobs (TOML specified) JobSpawner() job.Spawner @@ -99,7 +102,7 @@ type Application interface { TxmStorageService() txmgr.EvmTxStore AddJobV2(ctx context.Context, job *job.Job) error DeleteJob(ctx context.Context, jobID int32) error - RunWebhookJobV2(ctx context.Context, jobUUID uuid.UUID, requestBody string, meta pipeline.JSONSerializable) (int64, error) + RunWebhookJobV2(ctx context.Context, jobUUID uuid.UUID, requestBody string, meta jsonserializable.JSONSerializable) (int64, error) ResumeJobV2(ctx context.Context, taskID uuid.UUID, result pipeline.Result) error // Testing only RunJobV2(ctx context.Context, jobID int32, meta map[string]interface{}) (int64, error) @@ -148,6 +151,7 @@ type ChainlinkApplication struct { secretGenerator SecretGenerator profiler *pyroscope.Profiler loopRegistry *plugins.LoopRegistry + loopRegistrarConfig plugins.RegistrarConfig started bool startStopMu sync.Mutex @@ -194,11 +198,13 @@ func NewApplication(opts ApplicationOpts) (Application, error) { if cfg.Capabilities().Peering().Enabled() { externalPeerWrapper := externalp2p.NewExternalPeerWrapper(keyStore.P2P(), cfg.Capabilities().Peering(), globalLogger) + signer := externalPeerWrapper srvcs = append(srvcs, externalPeerWrapper) // NOTE: RegistrySyncer will depend on a Relayer when fully implemented - registrySyncer := capabilities.NewRegistrySyncer(externalPeerWrapper, registry, globalLogger) - srvcs = append(srvcs, registrySyncer) + dispatcher := remote.NewDispatcher(externalPeerWrapper, signer, registry, globalLogger) + registrySyncer := capabilities.NewRegistrySyncer(externalPeerWrapper, registry, dispatcher, globalLogger) + srvcs = append(srvcs, dispatcher, registrySyncer) } // LOOPs can be created as options, in the case of LOOP relayers, or @@ -307,7 +313,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { mercuryORM = mercury.NewORM(sqlxDB, globalLogger, cfg.Database()) pipelineRunner = pipeline.NewRunner(pipelineORM, bridgeORM, cfg.JobPipeline(), cfg.WebServer(), legacyEVMChains, keyStore.Eth(), keyStore.VRF(), globalLogger, restrictedHTTPClient, unrestrictedHTTPClient) jobORM = job.NewORM(sqlxDB, pipelineORM, bridgeORM, keyStore, globalLogger, cfg.Database()) - txmORM = txmgr.NewTxStore(sqlxDB, globalLogger, cfg.Database()) + txmORM = txmgr.NewTxStore(sqlxDB, globalLogger) streamRegistry = streams.NewRegistry(globalLogger, pipelineRunner) ) @@ -421,10 +427,14 @@ func NewApplication(opts ApplicationOpts) (Application, error) { } else { globalLogger.Debug("Off-chain reporting disabled") } + + loopRegistrarConfig := plugins.NewRegistrarConfig(opts.GRPCOpts, opts.LoopRegistry.Register, opts.LoopRegistry.Unregister) + if cfg.OCR2().Enabled() { globalLogger.Debug("Off-chain reporting v2 enabled") - registrarConfig := plugins.NewRegistrarConfig(opts.GRPCOpts, opts.LoopRegistry.Register) - ocr2DelegateConfig := ocr2.NewDelegateConfig(cfg.OCR2(), cfg.Mercury(), cfg.Threshold(), cfg.Insecure(), cfg.JobPipeline(), cfg.Database(), registrarConfig) + + ocr2DelegateConfig := ocr2.NewDelegateConfig(cfg.OCR2(), cfg.Mercury(), cfg.Threshold(), cfg.Insecure(), cfg.JobPipeline(), cfg.Database(), loopRegistrarConfig) + delegates[job.OffchainReporting2] = ocr2.NewDelegate( sqlxDB, jobORM, @@ -492,6 +502,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { legacyEVMChains, globalLogger, opts.Version, + loopRegistrarConfig, ) } else { feedsService = &feeds.NullService{} @@ -530,6 +541,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { secretGenerator: opts.SecretGenerator, profiler: profiler, loopRegistry: loopRegistry, + loopRegistrarConfig: loopRegistrarConfig, sqlxDB: opts.SqlxDB, db: opts.DB, @@ -600,6 +612,9 @@ func (app *ChainlinkApplication) StopIfStarted() error { func (app *ChainlinkApplication) GetLoopRegistry() *plugins.LoopRegistry { return app.loopRegistry } +func (app *ChainlinkApplication) GetLoopRegistrarConfig() plugins.RegistrarConfig { + return app.loopRegistrarConfig +} // Stop allows the application to exit by halting schedules, closing // logs, and closing the DB connection. @@ -739,7 +754,7 @@ func (app *ChainlinkApplication) DeleteJob(ctx context.Context, jobID int32) err return app.jobSpawner.DeleteJob(jobID, pg.WithParentCtx(ctx)) } -func (app *ChainlinkApplication) RunWebhookJobV2(ctx context.Context, jobUUID uuid.UUID, requestBody string, meta pipeline.JSONSerializable) (int64, error) { +func (app *ChainlinkApplication) RunWebhookJobV2(ctx context.Context, jobUUID uuid.UUID, requestBody string, meta jsonserializable.JSONSerializable) (int64, error) { return app.webhookJobRunner.RunJob(ctx, jobUUID, requestBody, meta) } diff --git a/core/services/chainlink/config_job_pipeline.go b/core/services/chainlink/config_job_pipeline.go index 95106b84199..8d9858d2a44 100644 --- a/core/services/chainlink/config_job_pipeline.go +++ b/core/services/chainlink/config_job_pipeline.go @@ -45,3 +45,7 @@ func (j *jobPipelineConfig) ResultWriteQueueDepth() uint64 { func (j *jobPipelineConfig) ExternalInitiatorsEnabled() bool { return *j.c.ExternalInitiatorsEnabled } + +func (j *jobPipelineConfig) VerboseLogging() bool { + return *j.c.VerboseLogging +} diff --git a/core/services/chainlink/config_ocr.go b/core/services/chainlink/config_ocr.go index 072c724871a..cf6127e713a 100644 --- a/core/services/chainlink/config_ocr.go +++ b/core/services/chainlink/config_ocr.go @@ -5,9 +5,9 @@ import ( "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" ) var _ config.OCR = (*ocrConfig)(nil) @@ -48,7 +48,7 @@ func (o *ocrConfig) SimulateTransactions() bool { return *o.c.SimulateTransactions } -func (o *ocrConfig) TransmitterAddress() (ethkey.EIP55Address, error) { +func (o *ocrConfig) TransmitterAddress() (types.EIP55Address, error) { a := *o.c.TransmitterAddress if a.IsZero() { return a, errors.Wrap(config.ErrEnvUnset, "OCR.TransmitterAddress is not set") diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index 6cf9537f065..27e5c9317fa 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -30,12 +30,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" legacy "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink/cfgtest" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -186,8 +186,9 @@ var ( Chain: stkcfg.Chain{ ConfirmationPoll: commoncfg.MustNewDuration(time.Hour), }, + FeederURL: commoncfg.MustParseURL("http://feeder.url"), Nodes: []*stkcfg.Node{ - {Name: ptr("primary"), URL: commoncfg.MustParseURL("http://stark.node")}, + {Name: ptr("primary"), URL: commoncfg.MustParseURL("http://stark.node"), APIKey: ptr("key")}, }, }, }, @@ -209,8 +210,8 @@ func TestConfig_Marshal(t *testing.T) { require.NoError(t, err) return &d } - mustAddress := func(s string) *ethkey.EIP55Address { - a, err := ethkey.NewEIP55Address(s) + mustAddress := func(s string) *types.EIP55Address { + a, err := types.NewEIP55Address(s) require.NoError(t, err) return &a } @@ -370,6 +371,7 @@ func TestConfig_Marshal(t *testing.T) { ReaperInterval: commoncfg.MustNewDuration(4 * time.Hour), ReaperThreshold: commoncfg.MustNewDuration(7 * 24 * time.Hour), ResultWriteQueueDepth: ptr[uint32](10), + VerboseLogging: ptr(false), HTTPRequest: toml.JobPipelineHTTPRequest{ MaxSize: ptr[utils.FileSize](100 * utils.MB), DefaultTimeout: commoncfg.MustNewDuration(time.Minute), @@ -403,7 +405,7 @@ func TestConfig_Marshal(t *testing.T) { DefaultTransactionQueueDepth: ptr[uint32](12), KeyBundleID: ptr(models.MustSha256HashFromHex("acdd42797a8b921b2910497badc50006")), SimulateTransactions: ptr(true), - TransmitterAddress: ptr(ethkey.MustEIP55Address("0xa0788FC17B1dEe36f057c42B6F373A34B014687e")), + TransmitterAddress: ptr(types.MustEIP55Address("0xa0788FC17B1dEe36f057c42B6F373A34B014687e")), CaptureEATelemetry: ptr(false), TraceLogging: ptr(false), } @@ -509,7 +511,7 @@ func TestConfig_Marshal(t *testing.T) { LimitDefault: ptr[uint64](12), LimitMax: ptr[uint64](17), LimitMultiplier: mustDecimal("1.234"), - LimitTransfer: ptr[uint32](100), + LimitTransfer: ptr[uint64](100), TipCapDefault: assets.NewWeiI(2), TipCapMin: assets.NewWeiI(1), PriceDefault: assets.NewWeiI(math.MaxInt64), @@ -574,12 +576,13 @@ func TestConfig_Marshal(t *testing.T) { }, NodePool: evmcfg.NodePool{ - PollFailureThreshold: ptr[uint32](5), - PollInterval: &minute, - SelectionMode: &selectionMode, - SyncThreshold: ptr[uint32](13), - LeaseDuration: &zeroSeconds, - NodeIsSyncingEnabled: ptr(true), + PollFailureThreshold: ptr[uint32](5), + PollInterval: &minute, + SelectionMode: &selectionMode, + SyncThreshold: ptr[uint32](13), + LeaseDuration: &zeroSeconds, + NodeIsSyncingEnabled: ptr(true), + FinalizedBlockPollInterval: &second, }, OCR: evmcfg.OCR{ ContractConfirmations: ptr[uint16](11), @@ -652,8 +655,9 @@ func TestConfig_Marshal(t *testing.T) { TxTimeout: commoncfg.MustNewDuration(13 * time.Second), ConfirmationPoll: commoncfg.MustNewDuration(42 * time.Second), }, + FeederURL: commoncfg.MustParseURL("http://feeder.url"), Nodes: []*stkcfg.Node{ - {Name: ptr("primary"), URL: commoncfg.MustParseURL("http://stark.node")}, + {Name: ptr("primary"), URL: commoncfg.MustParseURL("http://stark.node"), APIKey: ptr("key")}, }, }, } @@ -845,6 +849,7 @@ MaxSuccessfulRuns = 123456 ReaperInterval = '4h0m0s' ReaperThreshold = '168h0m0s' ResultWriteQueueDepth = 10 +VerboseLogging = false [JobPipeline.HTTPRequest] DefaultTimeout = '1m0s' @@ -1018,6 +1023,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 13 LeaseDuration = '0s' NodeIsSyncingEnabled = true +FinalizedBlockPollInterval = '1s' [EVM.OCR] ContractConfirmations = 11 @@ -1106,6 +1112,7 @@ URL = 'http://solana.bar' `}, {"Starknet", Config{Starknet: full.Starknet}, `[[Starknet]] ChainID = 'foobar' +FeederURL = 'http://feeder.url' Enabled = true OCR2CachePollPeriod = '6h0m0s' OCR2CacheTTL = '3m0s' @@ -1116,6 +1123,7 @@ ConfirmationPoll = '42s' [[Starknet.Nodes]] Name = 'primary' URL = 'http://stark.node' +APIKey = 'key' `}, {"Mercury", Config{Core: toml.Core{Mercury: full.Mercury}}, `[Mercury] [Mercury.Cache] @@ -1138,6 +1146,7 @@ CertFile = '/path/to/cert.pem' require.NoError(t, config.DecodeTOML(strings.NewReader(s), &got)) ts, err := got.TOMLString() + require.NoError(t, err) assert.Equal(t, tt.config, got, diff.Diff(s, ts)) }) @@ -1149,7 +1158,7 @@ func TestConfig_full(t *testing.T) { require.NoError(t, config.DecodeTOML(strings.NewReader(fullTOML), &got)) // Except for some EVM node fields. for c := range got.EVM { - addr, err := ethkey.NewEIP55Address("0x2a3e23c6f242F5345320814aC8a1b4E58707D292") + addr, err := types.NewEIP55Address("0x2a3e23c6f242F5345320814aC8a1b4E58707D292") require.NoError(t, err) if got.EVM[c].ChainWriter.FromAddress == nil { got.EVM[c].ChainWriter.FromAddress = &addr @@ -1543,6 +1552,7 @@ func TestConfig_SetFrom(t *testing.T) { require.NoError(t, c.SetFrom(&f)) } ts, err := c.TOMLString() + require.NoError(t, err) assert.Equal(t, tt.exp, ts) }) diff --git a/core/services/chainlink/relayer_chain_interoperators_test.go b/core/services/chainlink/relayer_chain_interoperators_test.go index 4cb6f57f8ba..c90811de768 100644 --- a/core/services/chainlink/relayer_chain_interoperators_test.go +++ b/core/services/chainlink/relayer_chain_interoperators_test.go @@ -100,32 +100,38 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { c.Starknet = stkcfg.TOMLConfigs{ &stkcfg.TOMLConfig{ - ChainID: &starknetChainID1, - Enabled: ptr(true), - Chain: stkcfg.Chain{}, + ChainID: &starknetChainID1, + Enabled: ptr(true), + Chain: stkcfg.Chain{}, + FeederURL: commonconfig.MustParseURL("http://feeder.url"), Nodes: []*stkcfg.Node{ { - Name: ptr("starknet chain 1 node 1"), - URL: ((*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:8547").URL())), + Name: ptr("starknet chain 1 node 1"), + URL: ((*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:8547").URL())), + APIKey: ptr("key"), }, { - Name: ptr("starknet chain 1 node 2"), - URL: ((*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:8548").URL())), + Name: ptr("starknet chain 1 node 2"), + URL: ((*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:8548").URL())), + APIKey: ptr("key"), }, { - Name: ptr("starknet chain 1 node 3"), - URL: ((*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:8549").URL())), + Name: ptr("starknet chain 1 node 3"), + URL: ((*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:8549").URL())), + APIKey: ptr("key"), }, }, }, &stkcfg.TOMLConfig{ - ChainID: &starknetChainID2, - Enabled: ptr(true), - Chain: stkcfg.Chain{}, + ChainID: &starknetChainID2, + Enabled: ptr(true), + Chain: stkcfg.Chain{}, + FeederURL: commonconfig.MustParseURL("http://feeder.url"), Nodes: []*stkcfg.Node{ { - Name: ptr("starknet chain 2 node 1"), - URL: ((*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:3547").URL())), + Name: ptr("starknet chain 2 node 1"), + URL: ((*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:3547").URL())), + APIKey: ptr("key"), }, }, }, diff --git a/core/services/chainlink/testdata/config-empty-effective.toml b/core/services/chainlink/testdata/config-empty-effective.toml index 8fdb2858cdb..759a380d15c 100644 --- a/core/services/chainlink/testdata/config-empty-effective.toml +++ b/core/services/chainlink/testdata/config-empty-effective.toml @@ -13,7 +13,7 @@ DefaultLockTimeout = '15s' DefaultQueryTimeout = '10s' LogQueries = false MaxIdleConns = 10 -MaxOpenConns = 20 +MaxOpenConns = 100 MigrateOnStartup = true [Database.Backup] @@ -116,6 +116,7 @@ MaxSuccessfulRuns = 10000 ReaperInterval = '1h0m0s' ReaperThreshold = '24h0m0s' ResultWriteQueueDepth = 100 +VerboseLogging = true [JobPipeline.HTTPRequest] DefaultTimeout = '15s' diff --git a/core/services/chainlink/testdata/config-full.toml b/core/services/chainlink/testdata/config-full.toml index cd8a17e538a..76c4aa0cade 100644 --- a/core/services/chainlink/testdata/config-full.toml +++ b/core/services/chainlink/testdata/config-full.toml @@ -122,6 +122,7 @@ MaxSuccessfulRuns = 123456 ReaperInterval = '4h0m0s' ReaperThreshold = '168h0m0s' ResultWriteQueueDepth = 10 +VerboseLogging = false [JobPipeline.HTTPRequest] DefaultTimeout = '1m0s' @@ -341,6 +342,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 13 LeaseDuration = '0s' NodeIsSyncingEnabled = true +FinalizedBlockPollInterval = '1s' [EVM.OCR] ContractConfirmations = 11 @@ -429,6 +431,7 @@ URL = 'http://solana.bar' [[Starknet]] ChainID = 'foobar' +FeederURL = 'http://feeder.url' Enabled = true OCR2CachePollPeriod = '6h0m0s' OCR2CacheTTL = '3m0s' @@ -439,3 +442,4 @@ ConfirmationPoll = '42s' [[Starknet.Nodes]] Name = 'primary' URL = 'http://stark.node' +APIKey = 'key' diff --git a/core/services/chainlink/testdata/config-invalid.toml b/core/services/chainlink/testdata/config-invalid.toml index d11cd48d6ef..7d1ed17c3c2 100644 --- a/core/services/chainlink/testdata/config-invalid.toml +++ b/core/services/chainlink/testdata/config-invalid.toml @@ -132,10 +132,12 @@ Name = 'bar' [[Starknet.Nodes]] Name = 'primary' URL = 'http://stark.node' +APIKey = 'key' [[Starknet.Nodes]] Name = 'primary' URL = 'http://second.stark.node' +APIKey = 'key' [[Starknet]] diff --git a/core/services/chainlink/testdata/config-multi-chain-effective.toml b/core/services/chainlink/testdata/config-multi-chain-effective.toml index 45d52432ee5..a6cba2aaac3 100644 --- a/core/services/chainlink/testdata/config-multi-chain-effective.toml +++ b/core/services/chainlink/testdata/config-multi-chain-effective.toml @@ -13,7 +13,7 @@ DefaultLockTimeout = '15s' DefaultQueryTimeout = '10s' LogQueries = false MaxIdleConns = 10 -MaxOpenConns = 20 +MaxOpenConns = 100 MigrateOnStartup = true [Database.Backup] @@ -116,6 +116,7 @@ MaxSuccessfulRuns = 10000 ReaperInterval = '1h0m0s' ReaperThreshold = '24h0m0s' ResultWriteQueueDepth = 100 +VerboseLogging = true [JobPipeline.HTTPRequest] DefaultTimeout = '30s' @@ -312,6 +313,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [EVM.OCR] ContractConfirmations = 4 @@ -323,7 +325,7 @@ ObservationGracePeriod = '1s' [EVM.OCR2] [EVM.OCR2.Automation] -GasLimit = 5400000 +GasLimit = 10500000 [[EVM.Nodes]] Name = 'primary' @@ -402,6 +404,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [EVM.OCR] ContractConfirmations = 4 @@ -486,6 +489,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [EVM.OCR] ContractConfirmations = 4 @@ -585,6 +589,7 @@ URL = 'http://testnet.solana.com' [[Starknet]] ChainID = 'foobar' +FeederURL = 'http://feeder.url' OCR2CachePollPeriod = '5s' OCR2CacheTTL = '1m0s' RequestTimeout = '10s' @@ -594,3 +599,4 @@ ConfirmationPoll = '1h0m0s' [[Starknet.Nodes]] Name = 'primary' URL = 'http://stark.node' +APIKey = 'key' diff --git a/core/services/chainlink/testdata/config-multi-chain.toml b/core/services/chainlink/testdata/config-multi-chain.toml index 53425dd1afe..e45255a4373 100644 --- a/core/services/chainlink/testdata/config-multi-chain.toml +++ b/core/services/chainlink/testdata/config-multi-chain.toml @@ -103,8 +103,10 @@ URL = 'http://testnet.solana.com' [[Starknet]] ChainID = 'foobar' +FeederURL = 'http://feeder.url' ConfirmationPoll = '1h0m0s' [[Starknet.Nodes]] Name = 'primary' URL = 'http://stark.node' +APIKey = 'key' diff --git a/core/services/directrequest/delegate.go b/core/services/directrequest/delegate.go index aa0f8cd4de0..d6afc215fb9 100644 --- a/core/services/directrequest/delegate.go +++ b/core/services/directrequest/delegate.go @@ -136,7 +136,7 @@ type listener struct { minIncomingConfirmations uint32 requesters models.AddressCollection minContractPayment *assets.Link - chStop chan struct{} + chStop services.StopChan } func (l *listener) HealthReport() map[string]error { @@ -239,6 +239,9 @@ func (l *listener) processCancelOracleRequests() { } func (l *listener) handleReceivedLogs(mailbox *mailbox.Mailbox[log.Broadcast]) { + ctx, cancel := l.chStop.NewCtx() + defer cancel() + for { select { case <-l.chStop: @@ -249,7 +252,7 @@ func (l *listener) handleReceivedLogs(mailbox *mailbox.Mailbox[log.Broadcast]) { if !exists { return } - was, err := l.logBroadcaster.WasAlreadyConsumed(lb) + was, err := l.logBroadcaster.WasAlreadyConsumed(ctx, lb) if err != nil { l.logger.Errorw("Could not determine if log was already consumed", "err", err) continue @@ -260,7 +263,7 @@ func (l *listener) handleReceivedLogs(mailbox *mailbox.Mailbox[log.Broadcast]) { logJobSpecID := lb.RawLog().Topics[1] if logJobSpecID == (common.Hash{}) || (logJobSpecID != l.job.ExternalIDEncodeStringToTopic() && logJobSpecID != l.job.ExternalIDEncodeBytesToTopic()) { l.logger.Debugw("Skipping Run for Log with wrong Job ID", "logJobSpecID", logJobSpecID) - l.markLogConsumed(lb) + l.markLogConsumed(ctx, lb) continue } @@ -272,9 +275,9 @@ func (l *listener) handleReceivedLogs(mailbox *mailbox.Mailbox[log.Broadcast]) { switch log := log.(type) { case *operator_wrapper.OperatorOracleRequest: - l.handleOracleRequest(log, lb) + l.handleOracleRequest(ctx, log, lb) case *operator_wrapper.OperatorCancelOracleRequest: - l.handleCancelOracleRequest(log, lb) + l.handleCancelOracleRequest(ctx, log, lb) default: l.logger.Warnf("Unexpected log type %T", log) } @@ -295,7 +298,7 @@ func oracleRequestToMap(request *operator_wrapper.OperatorOracleRequest) map[str return result } -func (l *listener) handleOracleRequest(request *operator_wrapper.OperatorOracleRequest, lb log.Broadcast) { +func (l *listener) handleOracleRequest(ctx context.Context, request *operator_wrapper.OperatorOracleRequest, lb log.Broadcast) { l.logger.Infow("Oracle request received", "specId", fmt.Sprintf("%0x", request.SpecId), "requester", request.Requester, @@ -313,7 +316,7 @@ func (l *listener) handleOracleRequest(request *operator_wrapper.OperatorOracleR "requester", request.Requester, "allowedRequesters", l.requesters.ToStrings(), ) - l.markLogConsumed(lb) + l.markLogConsumed(ctx, lb) return } @@ -330,7 +333,7 @@ func (l *listener) handleOracleRequest(request *operator_wrapper.OperatorOracleR "minContractPayment", minContractPayment.String(), "requestPayment", requestPayment.String(), ) - l.markLogConsumed(lb) + l.markLogConsumed(ctx, lb) return } } @@ -372,7 +375,7 @@ func (l *listener) handleOracleRequest(request *operator_wrapper.OperatorOracleR }) run := pipeline.NewRun(*l.job.PipelineSpec, vars) _, err := l.pipelineRunner.Run(ctx, run, l.logger, true, func(tx pg.Queryer) error { - l.markLogConsumed(lb, pg.WithQueryer(tx)) + l.markLogConsumed(ctx, lb) return nil }) if ctx.Err() != nil { @@ -395,16 +398,16 @@ func (l *listener) allowRequester(requester common.Address) bool { } // Cancels runs that haven't been started yet, with the given request ID -func (l *listener) handleCancelOracleRequest(request *operator_wrapper.OperatorCancelOracleRequest, lb log.Broadcast) { +func (l *listener) handleCancelOracleRequest(ctx context.Context, request *operator_wrapper.OperatorCancelOracleRequest, lb log.Broadcast) { runCloserChannelIf, loaded := l.runs.LoadAndDelete(formatRequestId(request.RequestId)) if loaded { close(runCloserChannelIf.(services.StopChan)) } - l.markLogConsumed(lb) + l.markLogConsumed(ctx, lb) } -func (l *listener) markLogConsumed(lb log.Broadcast, qopts ...pg.QOpt) { - if err := l.logBroadcaster.MarkConsumed(lb, qopts...); err != nil { +func (l *listener) markLogConsumed(ctx context.Context, lb log.Broadcast) { + if err := l.logBroadcaster.MarkConsumed(ctx, lb); err != nil { l.logger.Errorw("Unable to mark log consumed", "err", err, "log", lb.String()) } } diff --git a/core/services/directrequest/validate.go b/core/services/directrequest/validate.go index 271e720660f..8cb9899d3f9 100644 --- a/core/services/directrequest/validate.go +++ b/core/services/directrequest/validate.go @@ -5,15 +5,15 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) type DirectRequestToml struct { - ContractAddress ethkey.EIP55Address `toml:"contractAddress"` + ContractAddress types.EIP55Address `toml:"contractAddress"` Requesters models.AddressCollection `toml:"requesters"` MinContractPayment *assets.Link `toml:"minContractPaymentLinkJuels"` EVMChainID *big.Big `toml:"evmChainID"` diff --git a/core/services/feeds/service.go b/core/services/feeds/service.go index fa5ad51a65a..2f3b309b45c 100644 --- a/core/services/feeds/service.go +++ b/core/services/feeds/service.go @@ -18,7 +18,9 @@ import ( "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/plugins" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -26,7 +28,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr" @@ -102,22 +103,23 @@ type Service interface { type service struct { services.StateMachine - orm ORM - jobORM job.ORM - q pg.Q - csaKeyStore keystore.CSA - p2pKeyStore keystore.P2P - ocr1KeyStore keystore.OCR - ocr2KeyStore keystore.OCR2 - jobSpawner job.Spawner - insecureCfg InsecureConfig - jobCfg JobConfig - ocrCfg OCRConfig - ocr2cfg OCR2Config - connMgr ConnectionsManager - legacyChains legacyevm.LegacyChainContainer - lggr logger.Logger - version string + orm ORM + jobORM job.ORM + q pg.Q + csaKeyStore keystore.CSA + p2pKeyStore keystore.P2P + ocr1KeyStore keystore.OCR + ocr2KeyStore keystore.OCR2 + jobSpawner job.Spawner + insecureCfg InsecureConfig + jobCfg JobConfig + ocrCfg OCRConfig + ocr2cfg OCR2Config + connMgr ConnectionsManager + legacyChains legacyevm.LegacyChainContainer + lggr logger.Logger + version string + loopRegistrarConfig plugins.RegistrarConfig } // NewService constructs a new feeds service @@ -135,25 +137,27 @@ func NewService( legacyChains legacyevm.LegacyChainContainer, lggr logger.Logger, version string, + rc plugins.RegistrarConfig, ) *service { lggr = lggr.Named("Feeds") svc := &service{ - orm: orm, - jobORM: jobORM, - q: pg.NewQ(db, lggr, dbCfg), - jobSpawner: jobSpawner, - p2pKeyStore: keyStore.P2P(), - csaKeyStore: keyStore.CSA(), - ocr1KeyStore: keyStore.OCR(), - ocr2KeyStore: keyStore.OCR2(), - insecureCfg: insecureCfg, - jobCfg: jobCfg, - ocrCfg: ocrCfg, - ocr2cfg: ocr2Cfg, - connMgr: newConnectionsManager(lggr), - legacyChains: legacyChains, - lggr: lggr, - version: version, + orm: orm, + jobORM: jobORM, + q: pg.NewQ(db, lggr, dbCfg), + jobSpawner: jobSpawner, + p2pKeyStore: keyStore.P2P(), + csaKeyStore: keyStore.CSA(), + ocr1KeyStore: keyStore.OCR(), + ocr2KeyStore: keyStore.OCR2(), + insecureCfg: insecureCfg, + jobCfg: jobCfg, + ocrCfg: ocrCfg, + ocr2cfg: ocr2Cfg, + connMgr: newConnectionsManager(lggr), + legacyChains: legacyChains, + lggr: lggr, + version: version, + loopRegistrarConfig: rc, } return svc @@ -534,7 +538,7 @@ type ProposeJobArgs struct { // belonging to another feeds manager, we do not update it. func (s *service) ProposeJob(ctx context.Context, args *ProposeJobArgs) (int64, error) { // Validate the args - if err := s.validateProposeJobArgs(*args); err != nil { + if err := s.validateProposeJobArgs(ctx, *args); err != nil { return 0, err } @@ -717,7 +721,7 @@ func (s *service) ApproveSpec(ctx context.Context, id int64, force bool) error { return errors.Wrap(err, "fms rpc client") } - j, err := s.generateJob(spec.Definition) + j, err := s.generateJob(ctx, spec.Definition) if err != nil { return errors.Wrap(err, "could not generate job from spec") } @@ -1101,7 +1105,7 @@ func (s *service) findExistingJobForOCR2(j *job.Job, qopts pg.QOpt) (int32, erro // findExistingJobForOCRFlux looks for existing job for OCR or flux func (s *service) findExistingJobForOCRFlux(j *job.Job, qopts pg.QOpt) (int32, error) { - var address ethkey.EIP55Address + var address types.EIP55Address var evmChainID *big.Big switch j.Type { @@ -1121,7 +1125,7 @@ func (s *service) findExistingJobForOCRFlux(j *job.Job, qopts pg.QOpt) (int32, e } // generateJob validates and generates a job from a spec. -func (s *service) generateJob(spec string) (*job.Job, error) { +func (s *service) generateJob(ctx context.Context, spec string) (*job.Job, error) { jobType, err := job.ValidateSpec(spec) if err != nil { return nil, errors.Wrap(err, "failed to parse job spec TOML") @@ -1138,7 +1142,7 @@ func (s *service) generateJob(spec string) (*job.Job, error) { if !s.ocr2cfg.Enabled() { return nil, ErrOCR2Disabled } - js, err = ocr2.ValidatedOracleSpecToml(s.ocr2cfg, s.insecureCfg, spec) + js, err = ocr2.ValidatedOracleSpecToml(ctx, s.ocr2cfg, s.insecureCfg, spec, s.loopRegistrarConfig) case job.Bootstrap: if !s.ocr2cfg.Enabled() { return nil, ErrOCR2Disabled @@ -1297,9 +1301,9 @@ func (s *service) newOCR2ConfigMsg(cfg OCR2ConfigModel) (*pb.OCR2Config, error) return msg, nil } -func (s *service) validateProposeJobArgs(args ProposeJobArgs) error { +func (s *service) validateProposeJobArgs(ctx context.Context, args ProposeJobArgs) error { // Validate the job spec - j, err := s.generateJob(args.Spec) + j, err := s.generateJob(ctx, args.Spec) if err != nil { return errors.Wrap(err, "failed to generate a job based on spec") } diff --git a/core/services/feeds/service_test.go b/core/services/feeds/service_test.go index 0e590fa9038..5283b03affe 100644 --- a/core/services/feeds/service_test.go +++ b/core/services/feeds/service_test.go @@ -20,6 +20,7 @@ import ( commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -35,7 +36,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" jobmocks "github.com/smartcontractkit/chainlink/v2/core/services/job/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/keystest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" @@ -186,7 +186,7 @@ func setupTestServiceCfg(t *testing.T, overrideCfg func(c *chainlink.Config, s * keyStore.On("P2P").Return(p2pKeystore) keyStore.On("OCR").Return(ocr1Keystore) keyStore.On("OCR2").Return(ocr2Keystore) - svc := feeds.NewService(orm, jobORM, db, spawner, keyStore, scopedConfig.Insecure(), scopedConfig.JobPipeline(), scopedConfig.OCR(), scopedConfig.OCR2(), scopedConfig.Database(), legacyChains, lggr, "1.0.0") + svc := feeds.NewService(orm, jobORM, db, spawner, keyStore, scopedConfig.Insecure(), scopedConfig.JobPipeline(), scopedConfig.OCR(), scopedConfig.OCR2(), scopedConfig.Database(), legacyChains, lggr, "1.0.0", nil) svc.SetConnectionsManager(connMgr) return &TestService{ @@ -1547,7 +1547,7 @@ func Test_Service_ListSpecsByJobProposalIDs(t *testing.T) { func Test_Service_ApproveSpec(t *testing.T) { var evmChainID *big.Big - address := ethkey.EIP55AddressFromAddress(common.Address{}) + address := types.EIP55AddressFromAddress(common.Address{}) externalJobID := uuid.New() var ( diff --git a/core/services/fluxmonitorv2/flux_monitor.go b/core/services/fluxmonitorv2/flux_monitor.go index 724c03daa91..73034faa3ce 100644 --- a/core/services/fluxmonitorv2/flux_monitor.go +++ b/core/services/fluxmonitorv2/flux_monitor.go @@ -516,9 +516,11 @@ func (fm *FluxMonitor) processLogs() { } func (fm *FluxMonitor) processBroadcast(broadcast log.Broadcast) { + ctx, cancel := fm.chStop.NewCtx() + defer cancel() // If the log is a duplicate of one we've seen before, ignore it (this // happens because of the LogBroadcaster's backfilling behavior). - consumed, err := fm.logBroadcaster.WasAlreadyConsumed(broadcast) + consumed, err := fm.logBroadcaster.WasAlreadyConsumed(ctx, broadcast) if err != nil { fm.logger.Errorf("Error determining if log was already consumed: %v", err) @@ -535,10 +537,10 @@ func (fm *FluxMonitor) processBroadcast(broadcast log.Broadcast) { fm.respondToNewRoundLog(*log, broadcast) case *flux_aggregator_wrapper.FluxAggregatorAnswerUpdated: fm.respondToAnswerUpdatedLog(*log) - fm.markLogAsConsumed(broadcast, decodedLog, started) + fm.markLogAsConsumed(ctx, broadcast, decodedLog, started) case *flags_wrapper.FlagsFlagRaised: fm.respondToFlagsRaisedLog() - fm.markLogAsConsumed(broadcast, decodedLog, started) + fm.markLogAsConsumed(ctx, broadcast, decodedLog, started) case *flags_wrapper.FlagsFlagLowered: // Only reactivate if it is hibernating if fm.pollManager.isHibernating.Load() { @@ -550,8 +552,8 @@ func (fm *FluxMonitor) processBroadcast(broadcast log.Broadcast) { } } -func (fm *FluxMonitor) markLogAsConsumed(broadcast log.Broadcast, decodedLog interface{}, started time.Time) { - if err := fm.logBroadcaster.MarkConsumed(broadcast); err != nil { +func (fm *FluxMonitor) markLogAsConsumed(ctx context.Context, broadcast log.Broadcast, decodedLog interface{}, started time.Time) { + if err := fm.logBroadcaster.MarkConsumed(ctx, broadcast); err != nil { fm.logger.Errorw("Failed to mark log as consumed", "err", err, "logType", fmt.Sprintf("%T", decodedLog), "log", broadcast.String(), "elapsed", time.Since(started)) } @@ -606,7 +608,7 @@ func (fm *FluxMonitor) respondToNewRoundLog(log flux_aggregator_wrapper.FluxAggr var markConsumed = true defer func() { if markConsumed { - if err := fm.logBroadcaster.MarkConsumed(lb); err != nil { + if err := fm.logBroadcaster.MarkConsumed(ctx, lb); err != nil { fm.logger.Errorw("Failed to mark log consumed", "err", err, "log", lb.String()) } } @@ -784,7 +786,7 @@ func (fm *FluxMonitor) respondToNewRoundLog(log flux_aggregator_wrapper.FluxAggr if err2 := fm.queueTransactionForTxm(ctx, tx, run.ID, answer, roundState.RoundId, &log); err2 != nil { return err2 } - return fm.logBroadcaster.MarkConsumed(lb, pg.WithQueryer(tx)) + return fm.logBroadcaster.MarkConsumed(ctx, lb) }) // Either the tx failed and we want to reprocess the log, or it succeeded and already marked it consumed markConsumed = false @@ -830,7 +832,7 @@ func (fm *FluxMonitor) pollIfEligible(pollReq PollRequestType, deviationChecker var markConsumed = true defer func() { if markConsumed && broadcast != nil { - if err := fm.logBroadcaster.MarkConsumed(broadcast); err != nil { + if err := fm.logBroadcaster.MarkConsumed(ctx, broadcast); err != nil { l.Errorw("Failed to mark log consumed", "err", err, "log", broadcast.String()) } } @@ -1012,7 +1014,7 @@ func (fm *FluxMonitor) pollIfEligible(pollReq PollRequestType, deviationChecker } if broadcast != nil { // In the case of a flag lowered, the pollEligible call is triggered by a log. - return fm.logBroadcaster.MarkConsumed(broadcast, pg.WithQueryer(tx)) + return fm.logBroadcaster.MarkConsumed(ctx, broadcast) } return nil }) diff --git a/core/services/fluxmonitorv2/integrations_test.go b/core/services/fluxmonitorv2/integrations_test.go index 7f45e6eb19c..b2dc9dd423a 100644 --- a/core/services/fluxmonitorv2/integrations_test.go +++ b/core/services/fluxmonitorv2/integrations_test.go @@ -30,6 +30,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" evmutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flags_wrapper" faw "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flux_aggregator_wrapper" @@ -416,8 +417,8 @@ func checkLogWasConsumed(t *testing.T, fa fluxAggregatorUniverse, db *sqlx.DB, p g.Eventually(func() bool { block := fa.backend.Blockchain().GetBlockByNumber(blockNumber) require.NotNil(t, block) - orm := log.NewORM(db, lggr, cfg, fa.evmChainID) - consumed, err := orm.WasBroadcastConsumed(block.Hash(), 0, pipelineSpecID) + orm := log.NewORM(db, fa.evmChainID) + consumed, err := orm.WasBroadcastConsumed(testutils.Context(t), block.Hash(), 0, pipelineSpecID) require.NoError(t, err) fa.backend.Commit() return consumed @@ -623,7 +624,7 @@ func TestFluxMonitor_NewRound(t *testing.T) { app := startApplication(t, fa, func(c *chainlink.Config, s *chainlink.Secrets) { c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(100 * time.Millisecond) c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(1 * time.Second) - flags := ethkey.EIP55AddressFromAddress(fa.flagsContractAddress) + flags := types.EIP55AddressFromAddress(fa.flagsContractAddress) c.EVM[0].FlagsContractAddress = &flags }) @@ -689,7 +690,7 @@ ds1 -> ds1_parse return lb.(log.BroadcasterInTest).TrackedAddressesCount() }, testutils.WaitTimeout(t), 200*time.Millisecond).Should(gomega.BeNumerically(">=", 2)) - // Have the the fake node start a new round + // Have the fake node start a new round submitAnswer(t, answerParams{ fa: &fa, roundId: 1, @@ -734,7 +735,7 @@ func TestFluxMonitor_HibernationMode(t *testing.T) { app := startApplication(t, fa, func(c *chainlink.Config, s *chainlink.Secrets) { c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(100 * time.Millisecond) c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(1 * time.Second) - flags := ethkey.EIP55AddressFromAddress(fa.flagsContractAddress) + flags := types.EIP55AddressFromAddress(fa.flagsContractAddress) c.EVM[0].FlagsContractAddress = &flags }) diff --git a/core/services/fluxmonitorv2/orm_test.go b/core/services/fluxmonitorv2/orm_test.go index 17e03a674f0..21a80735863 100644 --- a/core/services/fluxmonitorv2/orm_test.go +++ b/core/services/fluxmonitorv2/orm_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" commontxmmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" @@ -116,12 +117,12 @@ func TestORM_UpdateFluxMonitorRoundStats(t *testing.T) { FinishedAt: null.TimeFrom(f), AllErrors: pipeline.RunErrors{null.String{}}, FatalErrors: pipeline.RunErrors{null.String{}}, - Outputs: pipeline.JSONSerializable{Val: []interface{}{10}, Valid: true}, + Outputs: jsonserializable.JSONSerializable{Val: []interface{}{10}, Valid: true}, PipelineTaskRuns: []pipeline.TaskRun{ { ID: uuid.New(), Type: pipeline.TaskTypeHTTP, - Output: pipeline.JSONSerializable{Val: 10, Valid: true}, + Output: jsonserializable.JSONSerializable{Val: 10, Valid: true}, CreatedAt: f, FinishedAt: null.TimeFrom(f), }, diff --git a/core/services/gateway/handlers/functions/subscriptions/subscriptions.go b/core/services/gateway/handlers/functions/subscriptions/subscriptions.go index 610aaa1d7f1..e90201a31a9 100644 --- a/core/services/gateway/handlers/functions/subscriptions/subscriptions.go +++ b/core/services/gateway/handlers/functions/subscriptions/subscriptions.go @@ -138,7 +138,7 @@ func (s *onchainSubscriptions) queryLoop() { latestBlockHeight, err := s.client.LatestBlockHeight(ctx) if err != nil || latestBlockHeight == nil { - s.lggr.Errorw("Error calling LatestBlockHeight", "err", err, "latestBlockHeight", latestBlockHeight.Int64()) + s.lggr.Errorw("Error calling LatestBlockHeight", "err", err, "latestBlockHeight", latestBlockHeight) return } diff --git a/core/services/job/job_orm_test.go b/core/services/job/job_orm_test.go index 9716231868c..d763386a00d 100644 --- a/core/services/job/job_orm_test.go +++ b/core/services/job/job_orm_test.go @@ -15,10 +15,12 @@ import ( "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" @@ -483,7 +485,7 @@ func TestORM_CreateJob_VRFV2(t *testing.T) { actual = append(actual, common.BytesToAddress(b).String()) } require.ElementsMatch(t, fromAddresses, actual) - var vrfOwnerAddress ethkey.EIP55Address + var vrfOwnerAddress evmtypes.EIP55Address require.NoError(t, db.Get(&vrfOwnerAddress, `SELECT vrf_owner_address FROM vrf_specs LIMIT 1`)) require.Equal(t, "0x32891BD79647DC9136Fc0a59AAB48c7825eb624c", vrfOwnerAddress.Address().String()) require.NoError(t, jobORM.DeleteJob(jb.ID)) @@ -567,7 +569,7 @@ func TestORM_CreateJob_VRFV2Plus(t *testing.T) { actual = append(actual, common.BytesToAddress(b).String()) } require.ElementsMatch(t, fromAddresses, actual) - var vrfOwnerAddress ethkey.EIP55Address + var vrfOwnerAddress evmtypes.EIP55Address require.Error(t, db.Get(&vrfOwnerAddress, `SELECT vrf_owner_address FROM vrf_specs LIMIT 1`)) require.NoError(t, jobORM.DeleteJob(jb.ID)) cltest.AssertCount(t, db, "vrf_specs", 0) @@ -795,7 +797,7 @@ func TestORM_CreateJob_OCR2_DuplicatedContractAddress(t *testing.T) { _, address := cltest.MustInsertRandomKey(t, keyStore.Eth()) - jb, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal()) + jb, err := ocr2validate.ValidatedOracleSpecToml(testutils.Context(t), config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal(), nil) require.NoError(t, err) const juelsPerFeeCoinSource = ` @@ -811,7 +813,7 @@ func TestORM_CreateJob_OCR2_DuplicatedContractAddress(t *testing.T) { err = jobORM.CreateJob(&jb) require.NoError(t, err) - jb2, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal()) + jb2, err := ocr2validate.ValidatedOracleSpecToml(testutils.Context(t), config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal(), nil) require.NoError(t, err) jb2.Name = null.StringFrom("Job with same chain id & contract address") @@ -821,7 +823,7 @@ func TestORM_CreateJob_OCR2_DuplicatedContractAddress(t *testing.T) { err = jobORM.CreateJob(&jb2) require.Error(t, err) - jb3, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal()) + jb3, err := ocr2validate.ValidatedOracleSpecToml(testutils.Context(t), config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal(), nil) require.NoError(t, err) jb3.Name = null.StringFrom("Job with different chain id & same contract address") jb3.OCR2OracleSpec.TransmitterID = null.StringFrom(address.String()) @@ -854,7 +856,7 @@ func TestORM_CreateJob_OCR2_Sending_Keys_Transmitter_Keys_Validations(t *testing jobORM := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore, config.Database()) - jb, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal()) + jb, err := ocr2validate.ValidatedOracleSpecToml(testutils.Context(t), config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal(), nil) require.NoError(t, err) t.Run("sending keys or transmitterID must be defined", func(t *testing.T) { @@ -895,7 +897,7 @@ func TestORM_ValidateKeyStoreMatch(t *testing.T) { var jb job.Job { var err error - jb, err = ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal()) + jb, err = ocr2validate.ValidatedOracleSpecToml(testutils.Context(t), config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal(), nil) require.NoError(t, err) } @@ -1087,7 +1089,7 @@ func Test_FindJob(t *testing.T) { ) require.NoError(t, err) - jobOCR2, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal()) + jobOCR2, err := ocr2validate.ValidatedOracleSpecToml(testutils.Context(t), config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal(), nil) require.NoError(t, err) jobOCR2.OCR2OracleSpec.TransmitterID = null.StringFrom(address.String()) @@ -1102,16 +1104,20 @@ func Test_FindJob(t *testing.T) { ocr2WithFeedID1 := "0x0001000000000000000000000000000000000000000000000000000000000001" ocr2WithFeedID2 := "0x0001000000000000000000000000000000000000000000000000000000000002" jobOCR2WithFeedID1, err := ocr2validate.ValidatedOracleSpecToml( + testutils.Context(t), config.OCR2(), config.Insecure(), fmt.Sprintf(mercuryOracleTOML, cltest.DefaultCSAKey.PublicKeyString(), ocr2WithFeedID1), + nil, ) require.NoError(t, err) jobOCR2WithFeedID2, err := ocr2validate.ValidatedOracleSpecToml( + testutils.Context(t), config.OCR2(), config.Insecure(), fmt.Sprintf(mercuryOracleTOML, cltest.DefaultCSAKey.PublicKeyString(), ocr2WithFeedID2), + nil, ) jobOCR2WithFeedID2.ExternalJobID = uuid.New() jobOCR2WithFeedID2.Name = null.StringFrom("new name") @@ -1724,7 +1730,7 @@ func mustInsertPipelineRun(t *testing.T, orm pipeline.ORM, j job.Job) pipeline.R run := pipeline.Run{ PipelineSpecID: j.PipelineSpecID, State: pipeline.RunStatusRunning, - Outputs: pipeline.JSONSerializable{Valid: false}, + Outputs: jsonserializable.JSONSerializable{Valid: false}, AllErrors: pipeline.RunErrors{}, CreatedAt: time.Now(), FinishedAt: null.Time{}, diff --git a/core/services/job/kv_orm.go b/core/services/job/kv_orm.go index 890336b4ec7..6108c123a62 100644 --- a/core/services/job/kv_orm.go +++ b/core/services/job/kv_orm.go @@ -1,12 +1,11 @@ package job import ( - "encoding/json" + "context" "fmt" "time" "github.com/jmoiron/sqlx" - "github.com/jmoiron/sqlx/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -16,8 +15,8 @@ import ( // //go:generate mockery --quiet --name KVStore --output ./mocks/ --case=underscore type KVStore interface { - Store(key string, val interface{}) error - Get(key string, dest interface{}) error + Store(ctx context.Context, key string, val []byte) error + Get(ctx context.Context, key string) ([]byte, error) } type kVStore struct { @@ -37,32 +36,28 @@ func NewKVStore(jobID int32, db *sqlx.DB, cfg pg.QConfig, lggr logger.Logger) kV } } -// Store saves serializable value by key. -func (kv kVStore) Store(key string, val interface{}) error { - jsonVal, err := json.Marshal(val) - if err != nil { - return err - } +// Store saves []byte value by key. +func (kv kVStore) Store(ctx context.Context, key string, val []byte) error { - sql := `INSERT INTO job_kv_store (job_id, key, val) + sql := `INSERT INTO job_kv_store (job_id, key, val_bytea) VALUES ($1, $2, $3) ON CONFLICT (job_id, key) DO UPDATE SET - val = EXCLUDED.val, + val_bytea = EXCLUDED.val_bytea, updated_at = $4;` - if err = kv.q.ExecQ(sql, kv.jobID, key, types.JSONText(jsonVal), time.Now()); err != nil { - return fmt.Errorf("failed to store value: %s for key: %s for jobID: %d : %w", string(jsonVal), key, kv.jobID, err) + if _, err := kv.q.ExecContext(ctx, sql, kv.jobID, key, val, time.Now()); err != nil { + return fmt.Errorf("failed to store value: %s for key: %s for jobID: %d : %w", string(val), key, kv.jobID, err) } return nil } -// Get retrieves serializable value by key. -func (kv kVStore) Get(key string, dest interface{}) error { - var ret json.RawMessage - sql := "SELECT val FROM job_kv_store WHERE job_id = $1 AND key = $2" - if err := kv.q.Get(&ret, sql, kv.jobID, key); err != nil { - return fmt.Errorf("failed to get value by key: %s for jobID: %d : %w", key, kv.jobID, err) +// Get retrieves []byte value by key. +func (kv kVStore) Get(ctx context.Context, key string) ([]byte, error) { + var val []byte + sql := "SELECT val_bytea FROM job_kv_store WHERE job_id = $1 AND key = $2" + if err := kv.q.GetContext(ctx, &val, sql, kv.jobID, key); err != nil { + return nil, fmt.Errorf("failed to get value by key: %s for jobID: %d : %w", key, kv.jobID, err) } - return json.Unmarshal(ret, dest) + return val, nil } diff --git a/core/services/job/kv_orm_test.go b/core/services/job/kv_orm_test.go index 794e27b3c9f..94a6ec15f1f 100644 --- a/core/services/job/kv_orm_test.go +++ b/core/services/job/kv_orm_test.go @@ -1,10 +1,12 @@ package job_test import ( + "context" "fmt" - "reflect" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/bridges" @@ -19,6 +21,9 @@ import ( ) func TestJobKVStore(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + config := configtest.NewTestGeneralConfig(t) db := pgtest.NewSqlxDB(t) @@ -36,50 +41,36 @@ func TestJobKVStore(t *testing.T) { jb.ID = jobID require.NoError(t, jobORM.CreateJob(&jb)) - type testData struct { - Test string - } - - type nested struct { - Contact testData // Nested struct - } - - values := []interface{}{ - 42, // int - "hello", // string - 3.14, // float64 - true, // bool - []int{1, 2, 3}, // slice of ints - map[string]int{"a": 1, "b": 2}, // map of string to int - testData{Test: "value1"}, // regular struct - nested{testData{"value2"}}, // nested struct + var values = [][]byte{ + []byte("Hello"), + []byte("World"), + []byte("Go"), } - for i, value := range values { + for i, insertBytes := range values { testKey := "test_key_" + fmt.Sprint(i) - require.NoError(t, kvStore.Store(testKey, value)) - - // Get the type of the current value - valueType := reflect.TypeOf(value) - // Create a new instance of the value's type - temp := reflect.New(valueType).Interface() + require.NoError(t, kvStore.Store(ctx, testKey, insertBytes)) - require.NoError(t, kvStore.Get(testKey, &temp)) + var readBytes []byte + readBytes, err = kvStore.Get(ctx, testKey) + assert.NoError(t, err) - tempValue := reflect.ValueOf(temp).Elem().Interface() - require.Equal(t, value, tempValue) + require.Equal(t, insertBytes, readBytes) } key := "test_key_updating" - td1 := testData{Test: "value1"} - td2 := testData{Test: "value2"} + td1 := []byte("value1") + td2 := []byte("value2") - var retData testData - require.NoError(t, kvStore.Store(key, td1)) - require.NoError(t, kvStore.Get(key, &retData)) - require.Equal(t, td1, retData) + require.NoError(t, kvStore.Store(ctx, key, td1)) + fetchedBytes, err := kvStore.Get(ctx, key) + require.NoError(t, err) + require.Equal(t, td1, fetchedBytes) + + require.NoError(t, kvStore.Store(ctx, key, td2)) + fetchedBytes, err = kvStore.Get(ctx, key) + require.NoError(t, err) + require.Equal(t, td2, fetchedBytes) - require.NoError(t, kvStore.Store(key, td2)) - require.NoError(t, kvStore.Get(key, &retData)) - require.Equal(t, td2, retData) + require.NoError(t, jobORM.DeleteJob(jobID)) } diff --git a/core/services/job/mocks/kv_store.go b/core/services/job/mocks/kv_store.go index 48e4538f606..139978f3579 100644 --- a/core/services/job/mocks/kv_store.go +++ b/core/services/job/mocks/kv_store.go @@ -2,42 +2,58 @@ package mocks -import mock "github.com/stretchr/testify/mock" +import ( + context "context" + + mock "github.com/stretchr/testify/mock" +) // KVStore is an autogenerated mock type for the KVStore type type KVStore struct { mock.Mock } -// Get provides a mock function with given fields: key, dest -func (_m *KVStore) Get(key string, dest interface{}) error { - ret := _m.Called(key, dest) +// Get provides a mock function with given fields: ctx, key +func (_m *KVStore) Get(ctx context.Context, key string) ([]byte, error) { + ret := _m.Called(ctx, key) if len(ret) == 0 { panic("no return value specified for Get") } - var r0 error - if rf, ok := ret.Get(0).(func(string, interface{}) error); ok { - r0 = rf(key, dest) + var r0 []byte + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) ([]byte, error)); ok { + return rf(ctx, key) + } + if rf, ok := ret.Get(0).(func(context.Context, string) []byte); ok { + r0 = rf(ctx, key) } else { - r0 = ret.Error(0) + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } } - return r0 + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, key) + } else { + r1 = ret.Error(1) + } + + return r0, r1 } -// Store provides a mock function with given fields: key, val -func (_m *KVStore) Store(key string, val interface{}) error { - ret := _m.Called(key, val) +// Store provides a mock function with given fields: ctx, key, val +func (_m *KVStore) Store(ctx context.Context, key string, val []byte) error { + ret := _m.Called(ctx, key, val) if len(ret) == 0 { panic("no return value specified for Store") } var r0 error - if rf, ok := ret.Get(0).(func(string, interface{}) error); ok { - r0 = rf(key, val) + if rf, ok := ret.Get(0).(func(context.Context, string, []byte) error); ok { + r0 = rf(ctx, key, val) } else { r0 = ret.Error(0) } diff --git a/core/services/job/mocks/orm.go b/core/services/job/mocks/orm.go index 062c6e936bc..1068f511cdc 100644 --- a/core/services/job/mocks/orm.go +++ b/core/services/job/mocks/orm.go @@ -8,8 +8,6 @@ import ( context "context" - ethkey "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - job "github.com/smartcontractkit/chainlink/v2/core/services/job" mock "github.com/stretchr/testify/mock" @@ -18,6 +16,8 @@ import ( pipeline "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + types "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + uuid "github.com/google/uuid" ) @@ -222,7 +222,7 @@ func (_m *ORM) FindJobByExternalJobID(_a0 uuid.UUID, qopts ...pg.QOpt) (job.Job, } // FindJobIDByAddress provides a mock function with given fields: address, evmChainID, qopts -func (_m *ORM) FindJobIDByAddress(address ethkey.EIP55Address, evmChainID *big.Big, qopts ...pg.QOpt) (int32, error) { +func (_m *ORM) FindJobIDByAddress(address types.EIP55Address, evmChainID *big.Big, qopts ...pg.QOpt) (int32, error) { _va := make([]interface{}, len(qopts)) for _i := range qopts { _va[_i] = qopts[_i] @@ -238,16 +238,16 @@ func (_m *ORM) FindJobIDByAddress(address ethkey.EIP55Address, evmChainID *big.B var r0 int32 var r1 error - if rf, ok := ret.Get(0).(func(ethkey.EIP55Address, *big.Big, ...pg.QOpt) (int32, error)); ok { + if rf, ok := ret.Get(0).(func(types.EIP55Address, *big.Big, ...pg.QOpt) (int32, error)); ok { return rf(address, evmChainID, qopts...) } - if rf, ok := ret.Get(0).(func(ethkey.EIP55Address, *big.Big, ...pg.QOpt) int32); ok { + if rf, ok := ret.Get(0).(func(types.EIP55Address, *big.Big, ...pg.QOpt) int32); ok { r0 = rf(address, evmChainID, qopts...) } else { r0 = ret.Get(0).(int32) } - if rf, ok := ret.Get(1).(func(ethkey.EIP55Address, *big.Big, ...pg.QOpt) error); ok { + if rf, ok := ret.Get(1).(func(types.EIP55Address, *big.Big, ...pg.QOpt) error); ok { r1 = rf(address, evmChainID, qopts...) } else { r1 = ret.Error(1) diff --git a/core/services/job/models.go b/core/services/job/models.go index 233912d09c2..218be21bc54 100644 --- a/core/services/job/models.go +++ b/core/services/job/models.go @@ -20,10 +20,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" clnull "github.com/smartcontractkit/chainlink/v2/core/null" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" @@ -247,24 +247,24 @@ func (pr *PipelineRun) SetID(value string) error { // OCROracleSpec defines the job spec for OCR jobs. type OCROracleSpec struct { - ID int32 `toml:"-"` - ContractAddress ethkey.EIP55Address `toml:"contractAddress"` - P2PV2Bootstrappers pq.StringArray `toml:"p2pv2Bootstrappers" db:"p2pv2_bootstrappers"` - IsBootstrapPeer bool `toml:"isBootstrapPeer"` - EncryptedOCRKeyBundleID *models.Sha256Hash `toml:"keyBundleID"` - TransmitterAddress *ethkey.EIP55Address `toml:"transmitterAddress"` - ObservationTimeout models.Interval `toml:"observationTimeout"` - BlockchainTimeout models.Interval `toml:"blockchainTimeout"` - ContractConfigTrackerSubscribeInterval models.Interval `toml:"contractConfigTrackerSubscribeInterval"` - ContractConfigTrackerPollInterval models.Interval `toml:"contractConfigTrackerPollInterval"` - ContractConfigConfirmations uint16 `toml:"contractConfigConfirmations"` - EVMChainID *big.Big `toml:"evmChainID" db:"evm_chain_id"` - DatabaseTimeout *models.Interval `toml:"databaseTimeout"` - ObservationGracePeriod *models.Interval `toml:"observationGracePeriod"` - ContractTransmitterTransmitTimeout *models.Interval `toml:"contractTransmitterTransmitTimeout"` - CaptureEATelemetry bool `toml:"captureEATelemetry"` - CreatedAt time.Time `toml:"-"` - UpdatedAt time.Time `toml:"-"` + ID int32 `toml:"-"` + ContractAddress evmtypes.EIP55Address `toml:"contractAddress"` + P2PV2Bootstrappers pq.StringArray `toml:"p2pv2Bootstrappers" db:"p2pv2_bootstrappers"` + IsBootstrapPeer bool `toml:"isBootstrapPeer"` + EncryptedOCRKeyBundleID *models.Sha256Hash `toml:"keyBundleID"` + TransmitterAddress *evmtypes.EIP55Address `toml:"transmitterAddress"` + ObservationTimeout models.Interval `toml:"observationTimeout"` + BlockchainTimeout models.Interval `toml:"blockchainTimeout"` + ContractConfigTrackerSubscribeInterval models.Interval `toml:"contractConfigTrackerSubscribeInterval"` + ContractConfigTrackerPollInterval models.Interval `toml:"contractConfigTrackerPollInterval"` + ContractConfigConfirmations uint16 `toml:"contractConfigConfirmations"` + EVMChainID *big.Big `toml:"evmChainID" db:"evm_chain_id"` + DatabaseTimeout *models.Interval `toml:"databaseTimeout"` + ObservationGracePeriod *models.Interval `toml:"observationGracePeriod"` + ContractTransmitterTransmitTimeout *models.Interval `toml:"contractTransmitterTransmitTimeout"` + CaptureEATelemetry bool `toml:"captureEATelemetry"` + CreatedAt time.Time `toml:"-"` + UpdatedAt time.Time `toml:"-"` } // GetID is a getter function that returns the ID of the spec. @@ -443,7 +443,7 @@ func (w *WebhookSpec) SetID(value string) error { type DirectRequestSpec struct { ID int32 `toml:"-"` - ContractAddress ethkey.EIP55Address `toml:"contractAddress"` + ContractAddress evmtypes.EIP55Address `toml:"contractAddress"` MinIncomingConfirmations clnull.Uint32 `toml:"minIncomingConfirmations"` Requesters models.AddressCollection `toml:"requesters"` MinContractPayment *commonassets.Link `toml:"minContractPaymentLinkJuels"` @@ -473,9 +473,9 @@ func (s *CronSpec) SetID(value string) error { } type FluxMonitorSpec struct { - ID int32 `toml:"-"` - ContractAddress ethkey.EIP55Address `toml:"contractAddress"` - Threshold tomlutils.Float32 `toml:"threshold,float"` + ID int32 `toml:"-"` + ContractAddress evmtypes.EIP55Address `toml:"contractAddress"` + Threshold tomlutils.Float32 `toml:"threshold,float"` // AbsoluteThreshold is the maximum absolute change allowed in a fluxmonitored // value before a new round should be kicked off, so that the current value // can be reported on-chain. @@ -494,13 +494,13 @@ type FluxMonitorSpec struct { } type KeeperSpec struct { - ID int32 `toml:"-"` - ContractAddress ethkey.EIP55Address `toml:"contractAddress"` - MinIncomingConfirmations *uint32 `toml:"minIncomingConfirmations"` - FromAddress ethkey.EIP55Address `toml:"fromAddress"` - EVMChainID *big.Big `toml:"evmChainID"` - CreatedAt time.Time `toml:"-"` - UpdatedAt time.Time `toml:"-"` + ID int32 `toml:"-"` + ContractAddress evmtypes.EIP55Address `toml:"contractAddress"` + MinIncomingConfirmations *uint32 `toml:"minIncomingConfirmations"` + FromAddress evmtypes.EIP55Address `toml:"fromAddress"` + EVMChainID *big.Big `toml:"evmChainID"` + CreatedAt time.Time `toml:"-"` + UpdatedAt time.Time `toml:"-"` } type VRFSpec struct { @@ -508,7 +508,7 @@ type VRFSpec struct { // BatchCoordinatorAddress is the address of the batch vrf coordinator to use. // This is required if batchFulfillmentEnabled is set to true in the job spec. - BatchCoordinatorAddress *ethkey.EIP55Address `toml:"batchCoordinatorAddress"` + BatchCoordinatorAddress *evmtypes.EIP55Address `toml:"batchCoordinatorAddress"` // BatchFulfillmentEnabled indicates to the vrf job to use the batch vrf coordinator // for fulfilling requests. If set to true, batchCoordinatorAddress must be set in // the job spec. @@ -523,16 +523,16 @@ type VRFSpec struct { // VRFOwnerAddress is the address of the VRFOwner address to use. // // V2 only. - VRFOwnerAddress *ethkey.EIP55Address `toml:"vrfOwnerAddress"` + VRFOwnerAddress *evmtypes.EIP55Address `toml:"vrfOwnerAddress"` - CoordinatorAddress ethkey.EIP55Address `toml:"coordinatorAddress"` - PublicKey secp256k1.PublicKey `toml:"publicKey"` - MinIncomingConfirmations uint32 `toml:"minIncomingConfirmations"` - EVMChainID *big.Big `toml:"evmChainID"` - FromAddresses []ethkey.EIP55Address `toml:"fromAddresses"` - PollPeriod time.Duration `toml:"pollPeriod"` // For v2 jobs - RequestedConfsDelay int64 `toml:"requestedConfsDelay"` // For v2 jobs. Optional, defaults to 0 if not provided. - RequestTimeout time.Duration `toml:"requestTimeout"` // Optional, defaults to 24hr if not provided. + CoordinatorAddress evmtypes.EIP55Address `toml:"coordinatorAddress"` + PublicKey secp256k1.PublicKey `toml:"publicKey"` + MinIncomingConfirmations uint32 `toml:"minIncomingConfirmations"` + EVMChainID *big.Big `toml:"evmChainID"` + FromAddresses []evmtypes.EIP55Address `toml:"fromAddresses"` + PollPeriod time.Duration `toml:"pollPeriod"` // For v2 jobs + RequestedConfsDelay int64 `toml:"requestedConfsDelay"` // For v2 jobs. Optional, defaults to 0 if not provided. + RequestTimeout time.Duration `toml:"requestTimeout"` // Optional, defaults to 24hr if not provided. // GasLanePrice specifies the gas lane price for this VRF job. // If the specified keys in FromAddresses do not have the provided gas price the job @@ -563,15 +563,15 @@ type BlockhashStoreSpec struct { // CoordinatorV1Address is the VRF V1 coordinator to watch for unfulfilled requests. If empty, // no V1 coordinator will be watched. - CoordinatorV1Address *ethkey.EIP55Address `toml:"coordinatorV1Address"` + CoordinatorV1Address *evmtypes.EIP55Address `toml:"coordinatorV1Address"` // CoordinatorV2Address is the VRF V2 coordinator to watch for unfulfilled requests. If empty, // no V2 coordinator will be watched. - CoordinatorV2Address *ethkey.EIP55Address `toml:"coordinatorV2Address"` + CoordinatorV2Address *evmtypes.EIP55Address `toml:"coordinatorV2Address"` // CoordinatorV2PlusAddress is the VRF V2Plus coordinator to watch for unfulfilled requests. If empty, // no V2Plus coordinator will be watched. - CoordinatorV2PlusAddress *ethkey.EIP55Address `toml:"coordinatorV2PlusAddress"` + CoordinatorV2PlusAddress *evmtypes.EIP55Address `toml:"coordinatorV2PlusAddress"` // LookbackBlocks defines the maximum age of blocks whose hashes should be stored. LookbackBlocks int32 `toml:"lookbackBlocks"` @@ -587,10 +587,10 @@ type BlockhashStoreSpec struct { // BlockhashStoreAddress is the address of the BlockhashStore contract to store blockhashes // into. - BlockhashStoreAddress ethkey.EIP55Address `toml:"blockhashStoreAddress"` + BlockhashStoreAddress evmtypes.EIP55Address `toml:"blockhashStoreAddress"` // BatchBlockhashStoreAddress is the address of the trusted BlockhashStore contract to store blockhashes - TrustedBlockhashStoreAddress *ethkey.EIP55Address `toml:"trustedBlockhashStoreAddress"` + TrustedBlockhashStoreAddress *evmtypes.EIP55Address `toml:"trustedBlockhashStoreAddress"` // BatchBlockhashStoreBatchSize is the number of blockhashes to store in a single batch TrustedBlockhashStoreBatchSize int32 `toml:"trustedBlockhashStoreBatchSize"` @@ -605,7 +605,7 @@ type BlockhashStoreSpec struct { EVMChainID *big.Big `toml:"evmChainID"` // FromAddress is the sender address that should be used to store blockhashes. - FromAddresses []ethkey.EIP55Address `toml:"fromAddresses"` + FromAddresses []evmtypes.EIP55Address `toml:"fromAddresses"` // CreatedAt is the time this job was created. CreatedAt time.Time `toml:"-"` @@ -620,15 +620,15 @@ type BlockHeaderFeederSpec struct { // CoordinatorV1Address is the VRF V1 coordinator to watch for unfulfilled requests. If empty, // no V1 coordinator will be watched. - CoordinatorV1Address *ethkey.EIP55Address `toml:"coordinatorV1Address"` + CoordinatorV1Address *evmtypes.EIP55Address `toml:"coordinatorV1Address"` // CoordinatorV2Address is the VRF V2 coordinator to watch for unfulfilled requests. If empty, // no V2 coordinator will be watched. - CoordinatorV2Address *ethkey.EIP55Address `toml:"coordinatorV2Address"` + CoordinatorV2Address *evmtypes.EIP55Address `toml:"coordinatorV2Address"` // CoordinatorV2PlusAddress is the VRF V2Plus coordinator to watch for unfulfilled requests. If empty, // no V2Plus coordinator will be watched. - CoordinatorV2PlusAddress *ethkey.EIP55Address `toml:"coordinatorV2PlusAddress"` + CoordinatorV2PlusAddress *evmtypes.EIP55Address `toml:"coordinatorV2PlusAddress"` // LookbackBlocks defines the maximum age of blocks whose hashes should be stored. LookbackBlocks int32 `toml:"lookbackBlocks"` @@ -638,11 +638,11 @@ type BlockHeaderFeederSpec struct { // BlockhashStoreAddress is the address of the BlockhashStore contract to store blockhashes // into. - BlockhashStoreAddress ethkey.EIP55Address `toml:"blockhashStoreAddress"` + BlockhashStoreAddress evmtypes.EIP55Address `toml:"blockhashStoreAddress"` // BatchBlockhashStoreAddress is the address of the BatchBlockhashStore contract to store blockhashes // into. - BatchBlockhashStoreAddress ethkey.EIP55Address `toml:"batchBlockhashStoreAddress"` + BatchBlockhashStoreAddress evmtypes.EIP55Address `toml:"batchBlockhashStoreAddress"` // PollPeriod defines how often recent blocks should be scanned for blockhash storage. PollPeriod time.Duration `toml:"pollPeriod"` @@ -654,7 +654,7 @@ type BlockHeaderFeederSpec struct { EVMChainID *big.Big `toml:"evmChainID"` // FromAddress is the sender address that should be used to store blockhashes. - FromAddresses []ethkey.EIP55Address `toml:"fromAddresses"` + FromAddresses []evmtypes.EIP55Address `toml:"fromAddresses"` // GetBlockHashesBatchSize is the RPC call batch size for retrieving blockhashes GetBlockhashesBatchSize uint16 `toml:"getBlockhashesBatchSize"` @@ -675,7 +675,7 @@ type LegacyGasStationServerSpec struct { // ForwarderAddress is the address of EIP2771 forwarder that verifies signature // and forwards requests to target contracts - ForwarderAddress ethkey.EIP55Address `toml:"forwarderAddress"` + ForwarderAddress evmtypes.EIP55Address `toml:"forwarderAddress"` // EVMChainID defines the chain ID from which the meta-transaction request originates. EVMChainID *big.Big `toml:"evmChainID"` @@ -685,7 +685,7 @@ type LegacyGasStationServerSpec struct { CCIPChainSelector *big.Big `toml:"ccipChainSelector"` // FromAddress is the sender address that should be used to send meta-transactions - FromAddresses []ethkey.EIP55Address `toml:"fromAddresses"` + FromAddresses []evmtypes.EIP55Address `toml:"fromAddresses"` // CreatedAt is the time this job was created. CreatedAt time.Time `toml:"-"` @@ -700,10 +700,10 @@ type LegacyGasStationSidecarSpec struct { // ForwarderAddress is the address of EIP2771 forwarder that verifies signature // and forwards requests to target contracts - ForwarderAddress ethkey.EIP55Address `toml:"forwarderAddress"` + ForwarderAddress evmtypes.EIP55Address `toml:"forwarderAddress"` // OffRampAddress is the address of CCIP OffRamp for the given chainID - OffRampAddress ethkey.EIP55Address `toml:"offRampAddress"` + OffRampAddress evmtypes.EIP55Address `toml:"offRampAddress"` // LookbackBlocks defines the maximum number of blocks to search for on-chain events. LookbackBlocks int32 `toml:"lookbackBlocks"` @@ -785,13 +785,13 @@ type EALSpec struct { // ForwarderAddress is the address of EIP2771 forwarder that verifies signature // and forwards requests to target contracts - ForwarderAddress ethkey.EIP55Address `toml:"forwarderAddress"` + ForwarderAddress evmtypes.EIP55Address `toml:"forwarderAddress"` // EVMChainID defines the chain ID from which the meta-transaction request originates. EVMChainID *big.Big `toml:"evmChainID"` // FromAddress is the sender address that should be used to send meta-transactions - FromAddresses []ethkey.EIP55Address `toml:"fromAddresses"` + FromAddresses []evmtypes.EIP55Address `toml:"fromAddresses"` // LookbackBlocks defines the maximum age of blocks to lookback in status tracker LookbackBlocks int32 `toml:"lookbackBlocks"` diff --git a/core/services/job/orm.go b/core/services/job/orm.go index c608e2cc544..6c8533d1dee 100644 --- a/core/services/job/orm.go +++ b/core/services/job/orm.go @@ -22,12 +22,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/bridges" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" medianconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/median/config" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" @@ -52,7 +52,7 @@ type ORM interface { FindJobTx(ctx context.Context, id int32) (Job, error) FindJob(ctx context.Context, id int32) (Job, error) FindJobByExternalJobID(uuid uuid.UUID, qopts ...pg.QOpt) (Job, error) - FindJobIDByAddress(address ethkey.EIP55Address, evmChainID *big.Big, qopts ...pg.QOpt) (int32, error) + FindJobIDByAddress(address evmtypes.EIP55Address, evmChainID *big.Big, qopts ...pg.QOpt) (int32, error) FindOCR2JobIDByAddress(contractID string, feedID *common.Hash, qopts ...pg.QOpt) (int32, error) FindJobIDsWithBridge(name string) ([]int32, error) DeleteJob(id int32, qopts ...pg.QOpt) error @@ -731,7 +731,7 @@ type OCRConfig interface { ContractSubscribeInterval() time.Duration KeyBundleID() (string, error) ObservationTimeout() time.Duration - TransmitterAddress() (ethkey.EIP55Address, error) + TransmitterAddress() (evmtypes.EIP55Address, error) } // LoadConfigVarsLocalOCR loads local OCR vars into the OCROracleSpec. @@ -842,7 +842,7 @@ func (o *orm) FindJobByExternalJobID(externalJobID uuid.UUID, qopts ...pg.QOpt) } // FindJobIDByAddress - finds a job id by contract address. Currently only OCR and FM jobs are supported -func (o *orm) FindJobIDByAddress(address ethkey.EIP55Address, evmChainID *big.Big, qopts ...pg.QOpt) (jobID int32, err error) { +func (o *orm) FindJobIDByAddress(address evmtypes.EIP55Address, evmChainID *big.Big, qopts ...pg.QOpt) (jobID int32, err error) { q := o.q.WithOpts(qopts...) err = q.Transaction(func(tx pg.Queryer) error { stmt := ` @@ -1321,7 +1321,7 @@ func toVRFSpecRow(spec *VRFSpec) vrfSpecRow { func (r vrfSpecRow) toVRFSpec() *VRFSpec { for _, a := range r.FromAddresses { r.VRFSpec.FromAddresses = append(r.VRFSpec.FromAddresses, - ethkey.EIP55AddressFromAddress(common.BytesToAddress(a))) + evmtypes.EIP55AddressFromAddress(common.BytesToAddress(a))) } return r.VRFSpec } @@ -1360,7 +1360,7 @@ func toBlockhashStoreSpecRow(spec *BlockhashStoreSpec) blockhashStoreSpecRow { func (r blockhashStoreSpecRow) toBlockhashStoreSpec() *BlockhashStoreSpec { for _, a := range r.FromAddresses { r.BlockhashStoreSpec.FromAddresses = append(r.BlockhashStoreSpec.FromAddresses, - ethkey.EIP55AddressFromAddress(common.BytesToAddress(a))) + evmtypes.EIP55AddressFromAddress(common.BytesToAddress(a))) } return r.BlockhashStoreSpec } @@ -1399,7 +1399,7 @@ func toBlockHeaderFeederSpecRow(spec *BlockHeaderFeederSpec) blockHeaderFeederSp func (r blockHeaderFeederSpecRow) toBlockHeaderFeederSpec() *BlockHeaderFeederSpec { for _, a := range r.FromAddresses { r.BlockHeaderFeederSpec.FromAddresses = append(r.BlockHeaderFeederSpec.FromAddresses, - ethkey.EIP55AddressFromAddress(common.BytesToAddress(a))) + evmtypes.EIP55AddressFromAddress(common.BytesToAddress(a))) } return r.BlockHeaderFeederSpec } @@ -1438,7 +1438,7 @@ func toLegacyGasStationServerSpecRow(spec *LegacyGasStationServerSpec) legacyGas func (r legacyGasStationServerSpecRow) toLegacyGasStationServerSpec() *LegacyGasStationServerSpec { for _, a := range r.FromAddresses { r.LegacyGasStationServerSpec.FromAddresses = append(r.LegacyGasStationServerSpec.FromAddresses, - ethkey.EIP55AddressFromAddress(common.BytesToAddress(a))) + evmtypes.EIP55AddressFromAddress(common.BytesToAddress(a))) } return r.LegacyGasStationServerSpec } diff --git a/core/services/job/runner_integration_test.go b/core/services/job/runner_integration_test.go index 2722e190e24..3a1f69afa1b 100644 --- a/core/services/job/runner_integration_test.go +++ b/core/services/job/runner_integration_test.go @@ -25,10 +25,12 @@ import ( commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -38,7 +40,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" @@ -67,7 +68,7 @@ func TestRunner(t *testing.T) { require.NoError(t, err) kbid := models.MustSha256HashFromHex(kb.ID()) c.OCR.KeyBundleID = &kbid - taddress := ethkey.EIP55AddressFromAddress(transmitterAddress) + taddress := types.EIP55AddressFromAddress(transmitterAddress) c.OCR.TransmitterAddress = &taddress c.OCR2.DatabaseTimeout = commonconfig.MustNewDuration(time.Second) c.OCR2.ContractTransmitterTransmitTimeout = commonconfig.MustNewDuration(time.Second) @@ -226,7 +227,7 @@ func TestRunner(t *testing.T) { assert.Contains(t, err.Error(), "not all bridges exist") // Same for ocr2 - jb2, err := validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), fmt.Sprintf(` + jb2, err := validate.ValidatedOracleSpecToml(testutils.Context(t), config.OCR2(), config.Insecure(), fmt.Sprintf(` type = "offchainreporting2" pluginType = "median" schemaVersion = 1 @@ -253,7 +254,7 @@ ds1_multiply [type=multiply times=1.23]; ds1 -> ds1_parse -> ds1_multiply -> answer1; answer1 [type=median index=0]; """ -`, placeHolderAddress.String(), b.Name.String())) +`, placeHolderAddress.String(), b.Name.String()), nil) require.NoError(t, err) // Should error creating it because of the juels per fee coin non-existent bridge err = jobORM.CreateJob(&jb2) @@ -261,7 +262,7 @@ answer1 [type=median index=0]; assert.Contains(t, err.Error(), "not all bridges exist") // Duplicate bridge names that exist is ok - jb3, err := validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), fmt.Sprintf(` + jb3, err := validate.ValidatedOracleSpecToml(testutils.Context(t), config.OCR2(), config.Insecure(), fmt.Sprintf(` type = "offchainreporting2" pluginType = "median" schemaVersion = 1 @@ -292,7 +293,7 @@ ds2_multiply [type=multiply times=1.23]; ds2 -> ds2_parse -> ds2_multiply -> answer1; answer1 [type=median index=0]; """ -`, placeHolderAddress, b.Name.String(), b.Name.String(), b.Name.String())) +`, placeHolderAddress, b.Name.String(), b.Name.String(), b.Name.String()), nil) require.NoError(t, err) // Should not error with duplicate bridges err = jobORM.CreateJob(&jb3) @@ -908,7 +909,7 @@ func TestRunner_Success_Callback_AsyncJob(t *testing.T) { require.Empty(t, run.PipelineTaskRuns[1].Error) require.Empty(t, run.PipelineTaskRuns[2].Error) require.Empty(t, run.PipelineTaskRuns[3].Error) - require.Equal(t, pipeline.JSONSerializable{Val: []interface{}{"123450000000000000000"}, Valid: true}, run.Outputs) + require.Equal(t, jsonserializable.JSONSerializable{Val: []interface{}{"123450000000000000000"}, Valid: true}, run.Outputs) require.Equal(t, pipeline.RunErrors{null.String{NullString: sql.NullString{String: "", Valid: false}}}, run.FatalErrors) }) // Delete the job @@ -1086,7 +1087,7 @@ func TestRunner_Error_Callback_AsyncJob(t *testing.T) { assert.Equal(t, "something exploded in EA", run.PipelineTaskRuns[1].Error.String) assert.True(t, run.PipelineTaskRuns[2].Error.Valid) assert.True(t, run.PipelineTaskRuns[3].Error.Valid) - require.Equal(t, pipeline.JSONSerializable{Val: []interface{}{interface{}(nil)}, Valid: true}, run.Outputs) + require.Equal(t, jsonserializable.JSONSerializable{Val: []interface{}{interface{}(nil)}, Valid: true}, run.Outputs) require.Equal(t, pipeline.RunErrors{null.String{NullString: sql.NullString{String: "task inputs: too many errors", Valid: true}}}, run.FatalErrors) }) // Delete the job diff --git a/core/services/job/spawner_test.go b/core/services/job/spawner_test.go index 71357a675c3..b6de9d790fa 100644 --- a/core/services/job/spawner_test.go +++ b/core/services/job/spawner_test.go @@ -302,7 +302,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db, lggr, config.Database()), keyStore, config.Database()) mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) - processConfig := plugins.NewRegistrarConfig(loop.GRPCOpts{}, func(name string) (*plugins.RegisteredLoop, error) { return nil, nil }) + processConfig := plugins.NewRegistrarConfig(loop.GRPCOpts{}, func(name string) (*plugins.RegisteredLoop, error) { return nil, nil }, func(loopId string) {}) ocr2DelegateConfig := ocr2.NewDelegateConfig(config.OCR2(), config.Mercury(), config.Threshold(), config.Insecure(), config.JobPipeline(), config.Database(), processConfig) d := ocr2.NewDelegate(nil, orm, nil, nil, nil, nil, nil, monitoringEndpoint, legacyChains, lggr, ocr2DelegateConfig, diff --git a/core/services/keeper/helpers_test.go b/core/services/keeper/helpers_test.go index fcdc009f5c1..fdcb12b01b1 100644 --- a/core/services/keeper/helpers_test.go +++ b/core/services/keeper/helpers_test.go @@ -11,10 +11,6 @@ func (rs *RegistrySynchronizer) ExportedFullSync() { rs.fullSync() } -func (rs *RegistrySynchronizer) ExportedProcessLogs() { - rs.processLogs() -} - func (rw *RegistryWrapper) GetUpkeepIdFromRawRegistrationLog(rawLog types.Log) (*big.Int, error) { switch rw.Version { case RegistryVersion_1_0, RegistryVersion_1_1: diff --git a/core/services/keeper/integration_test.go b/core/services/keeper/integration_test.go index e92d2c2a58f..d78b1fb2ca5 100644 --- a/core/services/keeper/integration_test.go +++ b/core/services/keeper/integration_test.go @@ -20,6 +20,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/basic_upkeep_contract" @@ -36,7 +37,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keeper" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" webpresenters "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -77,7 +77,7 @@ func deployKeeperRegistry( require.NoError(t, err) backend.Commit() - wrapper, err := keeper.NewRegistryWrapper(ethkey.EIP55AddressFromAddress(regAddr), backend) + wrapper, err := keeper.NewRegistryWrapper(evmtypes.EIP55AddressFromAddress(regAddr), backend) require.NoError(t, err) return regAddr, wrapper case keeper.RegistryVersion_1_2: @@ -104,7 +104,7 @@ func deployKeeperRegistry( ) require.NoError(t, err) backend.Commit() - wrapper, err := keeper.NewRegistryWrapper(ethkey.EIP55AddressFromAddress(regAddr), backend) + wrapper, err := keeper.NewRegistryWrapper(evmtypes.EIP55AddressFromAddress(regAddr), backend) require.NoError(t, err) return regAddr, wrapper case keeper.RegistryVersion_1_3: @@ -140,7 +140,7 @@ func deployKeeperRegistry( ) require.NoError(t, err) backend.Commit() - wrapper, err := keeper.NewRegistryWrapper(ethkey.EIP55AddressFromAddress(regAddr), backend) + wrapper, err := keeper.NewRegistryWrapper(evmtypes.EIP55AddressFromAddress(regAddr), backend) require.NoError(t, err) return regAddr, wrapper default: @@ -181,7 +181,7 @@ func TestKeeperEthIntegration(t *testing.T) { // setup node key nodeKey := cltest.MustGenerateRandomKey(t) nodeAddress := nodeKey.Address - nodeAddressEIP55 := ethkey.EIP55AddressFromAddress(nodeAddress) + nodeAddressEIP55 := evmtypes.EIP55AddressFromAddress(nodeAddress) // setup blockchain sergey := testutils.MustNewSimTransactor(t) // owns all the link @@ -254,7 +254,7 @@ func TestKeeperEthIntegration(t *testing.T) { require.NoError(t, app.Start(testutils.Context(t))) // create job - regAddrEIP55 := ethkey.EIP55AddressFromAddress(regAddr) + regAddrEIP55 := evmtypes.EIP55AddressFromAddress(regAddr) job := cltest.MustInsertKeeperJob(t, db, korm, nodeAddressEIP55, regAddrEIP55) err = app.JobSpawner().StartService(testutils.Context(t), job) require.NoError(t, err) @@ -333,7 +333,7 @@ func TestKeeperForwarderEthIntegration(t *testing.T) { // setup node key nodeKey := cltest.MustGenerateRandomKey(t) nodeAddress := nodeKey.Address - nodeAddressEIP55 := ethkey.EIP55AddressFromAddress(nodeAddress) + nodeAddressEIP55 := evmtypes.EIP55AddressFromAddress(nodeAddress) // setup blockchain sergey := testutils.MustNewSimTransactor(t) // owns all the link @@ -423,7 +423,7 @@ func TestKeeperForwarderEthIntegration(t *testing.T) { require.Equal(t, addr, fwdrAddress) // create job - regAddrEIP55 := ethkey.EIP55AddressFromAddress(regAddr) + regAddrEIP55 := evmtypes.EIP55AddressFromAddress(regAddr) jb := job.Job{ ID: 1, @@ -447,9 +447,9 @@ func TestKeeperForwarderEthIntegration(t *testing.T) { JobID: jb.ID, KeeperIndex: 0, NumKeepers: 2, - KeeperIndexMap: map[ethkey.EIP55Address]int32{ + KeeperIndexMap: map[evmtypes.EIP55Address]int32{ nodeAddressEIP55: 0, - ethkey.EIP55AddressFromAddress(nelly.From): 1, + evmtypes.EIP55AddressFromAddress(nelly.From): 1, }, } err = korm.UpsertRegistry(®istry) @@ -489,7 +489,7 @@ func TestMaxPerformDataSize(t *testing.T) { // setup node key nodeKey := cltest.MustGenerateRandomKey(t) nodeAddress := nodeKey.Address - nodeAddressEIP55 := ethkey.EIP55AddressFromAddress(nodeAddress) + nodeAddressEIP55 := evmtypes.EIP55AddressFromAddress(nodeAddress) // setup blockchain sergey := testutils.MustNewSimTransactor(t) // owns all the link @@ -558,7 +558,7 @@ func TestMaxPerformDataSize(t *testing.T) { require.NoError(t, app.Start(testutils.Context(t))) // create job - regAddrEIP55 := ethkey.EIP55AddressFromAddress(regAddr) + regAddrEIP55 := evmtypes.EIP55AddressFromAddress(regAddr) job := cltest.MustInsertKeeperJob(t, db, korm, nodeAddressEIP55, regAddrEIP55) err = app.JobSpawner().StartService(testutils.Context(t), job) require.NoError(t, err) diff --git a/core/services/keeper/models.go b/core/services/keeper/models.go index fe034bcc505..69bd0e6a577 100644 --- a/core/services/keeper/models.go +++ b/core/services/keeper/models.go @@ -8,20 +8,20 @@ import ( "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/null" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" ) -type KeeperIndexMap map[ethkey.EIP55Address]int32 +type KeeperIndexMap map[types.EIP55Address]int32 type Registry struct { ID int64 BlockCountPerTurn int32 CheckGas uint32 - ContractAddress ethkey.EIP55Address - FromAddress ethkey.EIP55Address + ContractAddress types.EIP55Address + FromAddress types.EIP55Address JobID int32 KeeperIndex int32 NumKeepers int32 diff --git a/core/services/keeper/orm.go b/core/services/keeper/orm.go index fc8770cd864..55dd6c52e68 100644 --- a/core/services/keeper/orm.go +++ b/core/services/keeper/orm.go @@ -7,9 +7,9 @@ import ( "github.com/lib/pq" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) @@ -40,7 +40,7 @@ func (korm ORM) Registries() ([]Registry, error) { } // RegistryByContractAddress returns a single registry based on provided address -func (korm ORM) RegistryByContractAddress(registryAddress ethkey.EIP55Address) (Registry, error) { +func (korm ORM) RegistryByContractAddress(registryAddress types.EIP55Address) (Registry, error) { var registry Registry err := korm.q.Get(®istry, `SELECT * FROM keeper_registries WHERE keeper_registries.contract_address = $1`, registryAddress) return registry, errors.Wrap(err, "failed to get registry") @@ -86,7 +86,7 @@ RETURNING * } // UpdateUpkeepLastKeeperIndex updates the last keeper index for an upkeep -func (korm ORM) UpdateUpkeepLastKeeperIndex(jobID int32, upkeepID *big.Big, fromAddress ethkey.EIP55Address) error { +func (korm ORM) UpdateUpkeepLastKeeperIndex(jobID int32, upkeepID *big.Big, fromAddress types.EIP55Address) error { _, err := korm.q.Exec(` UPDATE upkeep_registrations SET @@ -125,7 +125,7 @@ DELETE FROM upkeep_registrations WHERE registry_id IN ( // -- OR is it my buddy's turn AND they were the last keeper to do the perform for this upkeep // DEV: note we cast upkeep_id and binaryHash as 32 bits, even though both are 256 bit numbers when performing XOR. This is enough information // to distribute the upkeeps over the keepers so long as num keepers < 4294967296 -func (korm ORM) EligibleUpkeepsForRegistry(registryAddress ethkey.EIP55Address, blockNumber int64, gracePeriod int64, binaryHash string) (upkeeps []UpkeepRegistration, err error) { +func (korm ORM) EligibleUpkeepsForRegistry(registryAddress types.EIP55Address, blockNumber int64, gracePeriod int64, binaryHash string) (upkeeps []UpkeepRegistration, err error) { stmt := ` SELECT upkeep_registrations.* FROM upkeep_registrations @@ -212,7 +212,7 @@ WHERE registry_id = $1 } // SetLastRunInfoForUpkeepOnJob sets the last run block height and the associated keeper index only if the new block height is greater than the previous. -func (korm ORM) SetLastRunInfoForUpkeepOnJob(jobID int32, upkeepID *big.Big, height int64, fromAddress ethkey.EIP55Address, qopts ...pg.QOpt) (int64, error) { +func (korm ORM) SetLastRunInfoForUpkeepOnJob(jobID int32, upkeepID *big.Big, height int64, fromAddress types.EIP55Address, qopts ...pg.QOpt) (int64, error) { res, err := korm.q.WithOpts(qopts...).Exec(` UPDATE upkeep_registrations SET last_run_block_height = $1, diff --git a/core/services/keeper/orm_test.go b/core/services/keeper/orm_test.go index 2ce459886ae..ed58554ef0d 100644 --- a/core/services/keeper/orm_test.go +++ b/core/services/keeper/orm_test.go @@ -15,6 +15,7 @@ import ( "github.com/jmoiron/sqlx" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" evmutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -23,7 +24,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keeper" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/utils" bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" ) @@ -400,9 +400,9 @@ func TestKeeperDB_NewSetLastRunInfoForUpkeepOnJob(t *testing.T) { registry, j := cltest.MustInsertKeeperRegistry(t, db, orm, ethKeyStore, 0, 1, 20) upkeep := cltest.MustInsertUpkeepForRegistry(t, db, config.Database(), registry) registry.NumKeepers = 2 - registry.KeeperIndexMap = map[ethkey.EIP55Address]int32{ + registry.KeeperIndexMap = map[types.EIP55Address]int32{ registry.FromAddress: 0, - ethkey.EIP55AddressFromAddress(evmutils.ZeroAddress): 1, + types.EIP55AddressFromAddress(evmutils.ZeroAddress): 1, } err := orm.UpsertRegistry(®istry) require.NoError(t, err, "UPDATE keeper_registries") @@ -418,7 +418,7 @@ func TestKeeperDB_NewSetLastRunInfoForUpkeepOnJob(t *testing.T) { require.Equal(t, rowsAffected, int64(0)) assertLastRunHeight(t, db, upkeep, 100, 0) // update to same block height allowed - rowsAffected, err = orm.SetLastRunInfoForUpkeepOnJob(j.ID, upkeep.UpkeepID, 100, ethkey.EIP55AddressFromAddress(evmutils.ZeroAddress)) + rowsAffected, err = orm.SetLastRunInfoForUpkeepOnJob(j.ID, upkeep.UpkeepID, 100, types.EIP55AddressFromAddress(evmutils.ZeroAddress)) require.NoError(t, err) require.Equal(t, rowsAffected, int64(1)) assertLastRunHeight(t, db, upkeep, 100, 1) diff --git a/core/services/keeper/registry_interface.go b/core/services/keeper/registry_interface.go index fd1c2314a41..c80be29154a 100644 --- a/core/services/keeper/registry_interface.go +++ b/core/services/keeper/registry_interface.go @@ -17,7 +17,6 @@ import ( registry1_2 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_2" registry1_3 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_3" type_and_version "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/type_and_version_interface_wrapper" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" ) type RegistryVersion int32 @@ -53,7 +52,7 @@ type upkeepGetter interface { // RegistryWrapper implements a layer on top of different versions of registry wrappers // to provide a unified layer to rest of the codebase type RegistryWrapper struct { - Address ethkey.EIP55Address + Address evmtypes.EIP55Address Version RegistryVersion contract1_1 *registry1_1.KeeperRegistry contract1_2 *registry1_2.KeeperRegistry @@ -61,7 +60,7 @@ type RegistryWrapper struct { evmClient evmclient.Client } -func NewRegistryWrapper(address ethkey.EIP55Address, evmClient evmclient.Client) (*RegistryWrapper, error) { +func NewRegistryWrapper(address evmtypes.EIP55Address, evmClient evmclient.Client) (*RegistryWrapper, error) { interface_wrapper, err := type_and_version.NewTypeAndVersionInterface( address.Address(), evmClient, diff --git a/core/services/keeper/registry_synchronizer_core.go b/core/services/keeper/registry_synchronizer_core.go index f26c38fc2e1..86c79ac0007 100644 --- a/core/services/keeper/registry_synchronizer_core.go +++ b/core/services/keeper/registry_synchronizer_core.go @@ -40,7 +40,7 @@ type RegistrySynchronizerOptions struct { type RegistrySynchronizer struct { services.StateMachine - chStop chan struct{} + chStop services.StopChan registryWrapper RegistryWrapper interval time.Duration job job.Job @@ -114,6 +114,9 @@ func (rs *RegistrySynchronizer) run() { defer rs.wgDone.Done() defer syncTicker.Stop() + ctx, cancel := rs.chStop.NewCtx() + defer cancel() + rs.fullSync() for { @@ -124,7 +127,7 @@ func (rs *RegistrySynchronizer) run() { rs.fullSync() syncTicker.Reset(rs.interval) case <-rs.mbLogs.Notify(): - rs.processLogs() + rs.processLogs(ctx) } } } diff --git a/core/services/keeper/registry_synchronizer_process_logs.go b/core/services/keeper/registry_synchronizer_process_logs.go index 7b82f49ae4c..5dfdc7b6950 100644 --- a/core/services/keeper/registry_synchronizer_process_logs.go +++ b/core/services/keeper/registry_synchronizer_process_logs.go @@ -1,20 +1,21 @@ package keeper import ( + "context" "fmt" "reflect" "github.com/pkg/errors" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" registry1_1 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_1" registry1_2 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_2" registry1_3 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_3" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" ) -func (rs *RegistrySynchronizer) processLogs() { +func (rs *RegistrySynchronizer) processLogs(ctx context.Context) { for _, broadcast := range rs.mbLogs.RetrieveAll() { eventLog := broadcast.DecodedLog() if eventLog == nil || reflect.ValueOf(eventLog).IsNil() { @@ -22,7 +23,7 @@ func (rs *RegistrySynchronizer) processLogs() { continue } - was, err := rs.logBroadcaster.WasAlreadyConsumed(broadcast) + was, err := rs.logBroadcaster.WasAlreadyConsumed(ctx, broadcast) if err != nil { rs.logger.Warn(errors.Wrap(err, "unable to check if log was consumed")) continue @@ -84,7 +85,7 @@ func (rs *RegistrySynchronizer) processLogs() { rs.logger.Error(err) } - err = rs.logBroadcaster.MarkConsumed(broadcast) + err = rs.logBroadcaster.MarkConsumed(ctx, broadcast) if err != nil { rs.logger.Error(errors.Wrapf(err, "unable to mark %T log as consumed, log: %v", broadcast.RawLog(), broadcast.String())) } @@ -144,7 +145,7 @@ func (rs *RegistrySynchronizer) handleUpkeepPerformed(broadcast log.Broadcast) e if err != nil { return errors.Wrap(err, "Unable to fetch upkeep ID from performed log") } - rowsAffected, err := rs.orm.SetLastRunInfoForUpkeepOnJob(rs.job.ID, big.New(log.UpkeepID), int64(broadcast.RawLog().BlockNumber), ethkey.EIP55AddressFromAddress(log.FromKeeper)) + rowsAffected, err := rs.orm.SetLastRunInfoForUpkeepOnJob(rs.job.ID, big.New(log.UpkeepID), int64(broadcast.RawLog().BlockNumber), types.EIP55AddressFromAddress(log.FromKeeper)) if err != nil { return errors.Wrap(err, "failed to set last run to 0") } @@ -152,7 +153,7 @@ func (rs *RegistrySynchronizer) handleUpkeepPerformed(broadcast log.Broadcast) e "jobID", rs.job.ID, "upkeepID", log.UpkeepID.String(), "blockNumber", int64(broadcast.RawLog().BlockNumber), - "fromAddr", ethkey.EIP55AddressFromAddress(log.FromKeeper), + "fromAddr", types.EIP55AddressFromAddress(log.FromKeeper), "rowsAffected", rowsAffected, ) return nil diff --git a/core/services/keeper/registry_synchronizer_sync.go b/core/services/keeper/registry_synchronizer_sync.go index 7614ed15edb..cdca9512976 100644 --- a/core/services/keeper/registry_synchronizer_sync.go +++ b/core/services/keeper/registry_synchronizer_sync.go @@ -7,9 +7,9 @@ import ( "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" ) func (rs *RegistrySynchronizer) fullSync() { @@ -130,7 +130,7 @@ func (rs *RegistrySynchronizer) syncUpkeep(getter upkeepGetter, registry Registr return errors.Wrap(err, "failed to upsert upkeep") } - if err := rs.orm.UpdateUpkeepLastKeeperIndex(rs.job.ID, upkeepID, ethkey.EIP55AddressFromAddress(upkeep.LastKeeper)); err != nil { + if err := rs.orm.UpdateUpkeepLastKeeperIndex(rs.job.ID, upkeepID, types.EIP55AddressFromAddress(upkeep.LastKeeper)); err != nil { return errors.Wrap(err, "failed to update upkeep last keeper index") } @@ -149,9 +149,9 @@ func (rs *RegistrySynchronizer) newRegistryFromChain() (Registry, error) { } keeperIndex := int32(-1) - keeperMap := map[ethkey.EIP55Address]int32{} + keeperMap := map[types.EIP55Address]int32{} for idx, address := range registryConfig.KeeperAddresses { - keeperMap[ethkey.EIP55AddressFromAddress(address)] = int32(idx) + keeperMap[types.EIP55AddressFromAddress(address)] = int32(idx) if address == fromAddress { keeperIndex = int32(idx) } @@ -174,7 +174,7 @@ func (rs *RegistrySynchronizer) newRegistryFromChain() (Registry, error) { // CalcPositioningConstant calculates a positioning constant. // The positioning constant is fixed because upkeepID and registryAddress are immutable -func CalcPositioningConstant(upkeepID *big.Big, registryAddress ethkey.EIP55Address) (int32, error) { +func CalcPositioningConstant(upkeepID *big.Big, registryAddress types.EIP55Address) (int32, error) { upkeepBytes := make([]byte, binary.MaxVarintLen64) binary.PutVarint(upkeepBytes, upkeepID.Mod(big.NewI(math.MaxInt64)).Int64()) bytesToHash := utils.ConcatBytes(upkeepBytes, registryAddress.Bytes()) diff --git a/core/services/keeper/registry_synchronizer_sync_test.go b/core/services/keeper/registry_synchronizer_sync_test.go index e6f42a83201..e4d8e44e20a 100644 --- a/core/services/keeper/registry_synchronizer_sync_test.go +++ b/core/services/keeper/registry_synchronizer_sync_test.go @@ -10,10 +10,10 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" ) // GetUpkeepFailure implements the upkeepGetter interface with an induced error and nil @@ -32,7 +32,7 @@ func TestSyncUpkeepWithCallback_UpkeepNotFound(t *testing.T) { logger: log.(logger.SugaredLogger), } - addr := ethkey.EIP55Address(testutils.NewAddress().Hex()) + addr := types.EIP55Address(testutils.NewAddress().Hex()) registry := Registry{ ContractAddress: addr, } diff --git a/core/services/keeper/upkeep_executer_test.go b/core/services/keeper/upkeep_executer_test.go index 9b6d64c2e20..8299f47c853 100644 --- a/core/services/keeper/upkeep_executer_test.go +++ b/core/services/keeper/upkeep_executer_test.go @@ -337,8 +337,7 @@ func Test_UpkeepExecuter_PerformsUpkeep_Error(t *testing.T) { g.Eventually(wasCalled.Load).Should(gomega.Equal(true)) - cfg := pgtest.NewQConfig(false) - txStore := txmgr.NewTxStore(db, logger.TestLogger(t), cfg) + txStore := txmgr.NewTxStore(db, logger.TestLogger(t)) txes, err := txStore.GetAllTxes(testutils.Context(t)) require.NoError(t, err) require.Len(t, txes, 0) diff --git a/core/services/keeper/upkeep_executer_unit_test.go b/core/services/keeper/upkeep_executer_unit_test.go index 8589720ca5f..9b7a5609e94 100644 --- a/core/services/keeper/upkeep_executer_unit_test.go +++ b/core/services/keeper/upkeep_executer_unit_test.go @@ -7,10 +7,10 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" ) @@ -24,8 +24,8 @@ func (r *registry) PerformGasOverhead() uint32 { return r.pgo } func (r *registry) MaxPerformDataSize() uint32 { return r.mpds } func TestBuildJobSpec(t *testing.T) { - from := ethkey.EIP55Address(testutils.NewAddress().Hex()) - contract := ethkey.EIP55Address(testutils.NewAddress().Hex()) + from := types.EIP55Address(testutils.NewAddress().Hex()) + contract := types.EIP55Address(testutils.NewAddress().Hex()) chainID := "250" jb := job.Job{ ID: 10, diff --git a/core/services/keystore/eth_test.go b/core/services/keystore/eth_test.go index 573830638ab..6bc346bf4f8 100644 --- a/core/services/keystore/eth_test.go +++ b/core/services/keystore/eth_test.go @@ -115,7 +115,7 @@ func Test_EthKeyStore(t *testing.T) { cltest.AssertCount(t, db, statesTableName, 1) // add one eth_tx - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 0, 42, key.Address) _, err = ethKeyStore.Delete(ctx, key.ID()) diff --git a/core/services/keystore/keys/ethkey/export.go b/core/services/keystore/keys/ethkey/export.go index 451a7453433..dfa85dedc98 100644 --- a/core/services/keystore/keys/ethkey/export.go +++ b/core/services/keystore/keys/ethkey/export.go @@ -5,12 +5,13 @@ import ( "github.com/google/uuid" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/utils" ) type EncryptedEthKeyExport struct { KeyType string `json:"keyType"` - Address EIP55Address `json:"address"` + Address types.EIP55Address `json:"address"` Crypto keystore.CryptoJSON `json:"crypto"` } diff --git a/core/services/keystore/keys/ethkey/key.go b/core/services/keystore/keys/ethkey/key.go index 6335ed55adc..02f256b320d 100644 --- a/core/services/keystore/keys/ethkey/key.go +++ b/core/services/keystore/keys/ethkey/key.go @@ -4,6 +4,7 @@ import ( "time" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ) // NOTE: This model refers to the OLD key and is only used for migrations @@ -14,7 +15,7 @@ import ( // By default, a key is assumed to represent an ethereum account. type Key struct { ID int32 - Address EIP55Address + Address types.EIP55Address JSON sqlutil.JSON `json:"-"` CreatedAt time.Time `json:"-"` UpdatedAt time.Time `json:"-"` diff --git a/core/services/keystore/keys/ethkey/key_v2.go b/core/services/keystore/keys/ethkey/key_v2.go index 15dc15d3f02..88cc9185787 100644 --- a/core/services/keystore/keys/ethkey/key_v2.go +++ b/core/services/keystore/keys/ethkey/key_v2.go @@ -9,6 +9,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ) var curve = crypto.S256() @@ -22,7 +24,7 @@ func (raw Raw) Key() KeyV2 { privateKey.D = d privateKey.PublicKey.X, privateKey.PublicKey.Y = curve.ScalarBaseMult(d.Bytes()) address := crypto.PubkeyToAddress(privateKey.PublicKey) - eip55 := EIP55AddressFromAddress(address) + eip55 := types.EIP55AddressFromAddress(address) return KeyV2{ Address: address, EIP55Address: eip55, @@ -42,7 +44,7 @@ var _ fmt.GoStringer = &KeyV2{} type KeyV2 struct { Address common.Address - EIP55Address EIP55Address + EIP55Address types.EIP55Address privateKey *ecdsa.PrivateKey } @@ -56,7 +58,7 @@ func NewV2() (KeyV2, error) { func FromPrivateKey(privKey *ecdsa.PrivateKey) (key KeyV2) { address := crypto.PubkeyToAddress(privKey.PublicKey) - eip55 := EIP55AddressFromAddress(address) + eip55 := types.EIP55AddressFromAddress(address) return KeyV2{ Address: address, EIP55Address: eip55, diff --git a/core/services/keystore/keys/ethkey/key_v2_test.go b/core/services/keystore/keys/ethkey/key_v2_test.go index 82b1084eb97..79a470103ed 100644 --- a/core/services/keystore/keys/ethkey/key_v2_test.go +++ b/core/services/keystore/keys/ethkey/key_v2_test.go @@ -8,6 +8,8 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ) func TestEthKeyV2_ToKey(t *testing.T) { @@ -20,7 +22,7 @@ func TestEthKeyV2_ToKey(t *testing.T) { assert.Equal(t, k.privateKey, privateKeyECDSA) assert.Equal(t, k.privateKey.PublicKey.X, privateKeyECDSA.PublicKey.X) assert.Equal(t, k.privateKey.PublicKey.Y, privateKeyECDSA.PublicKey.Y) - assert.Equal(t, EIP55AddressFromAddress(crypto.PubkeyToAddress(privateKeyECDSA.PublicKey)).Hex(), k.ID()) + assert.Equal(t, types.EIP55AddressFromAddress(crypto.PubkeyToAddress(privateKeyECDSA.PublicKey)).Hex(), k.ID()) } func TestEthKeyV2_RawPrivateKey(t *testing.T) { diff --git a/core/services/keystore/keys/ethkey/models.go b/core/services/keystore/keys/ethkey/models.go index df4c474b7b9..43af2caffc5 100644 --- a/core/services/keystore/keys/ethkey/models.go +++ b/core/services/keystore/keys/ethkey/models.go @@ -3,12 +3,13 @@ package ethkey import ( "time" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) type State struct { ID int32 - Address EIP55Address + Address types.EIP55Address EVMChainID big.Big Disabled bool CreatedAt time.Time diff --git a/core/services/keystore/keys/starkkey/key.go b/core/services/keystore/keys/starkkey/key.go index 62d9e077073..7723d4ce4fb 100644 --- a/core/services/keystore/keys/starkkey/key.go +++ b/core/services/keystore/keys/starkkey/key.go @@ -6,8 +6,8 @@ import ( "io" "math/big" - "github.com/smartcontractkit/caigo" - caigotypes "github.com/smartcontractkit/caigo/types" + "github.com/NethermindEth/juno/core/felt" + "github.com/NethermindEth/starknet.go/curve" ) // Raw represents the Stark private key @@ -19,7 +19,7 @@ func (raw Raw) Key() Key { var err error k.priv = new(big.Int).SetBytes(raw) - k.pub.X, k.pub.Y, err = caigo.Curve.PrivateToPoint(k.priv) + k.pub.X, k.pub.Y, err = curve.Curve.PrivateToPoint(k.priv) if err != nil { panic(err) // key not generated } @@ -75,7 +75,7 @@ func (key Key) ID() string { // it is the X component of the ECDSA pubkey and used in the deployment of the account contract // this func is used in exporting it via CLI and API func (key Key) StarkKeyStr() string { - return caigotypes.BigToFelt(key.pub.X).String() + return new(felt.Felt).SetBytes(key.pub.X.Bytes()).String() } // Raw from private key diff --git a/core/services/keystore/keys/starkkey/ocr2key.go b/core/services/keystore/keys/starkkey/ocr2key.go index 417687b62a6..41e0db7de8e 100644 --- a/core/services/keystore/keys/starkkey/ocr2key.go +++ b/core/services/keystore/keys/starkkey/ocr2key.go @@ -7,8 +7,8 @@ import ( "github.com/pkg/errors" - "github.com/smartcontractkit/caigo" - caigotypes "github.com/smartcontractkit/caigo/types" + "github.com/NethermindEth/juno/core/felt" + "github.com/NethermindEth/starknet.go/curve" "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ) @@ -26,7 +26,8 @@ func NewOCR2Key(material io.Reader) (*OCR2Key, error) { } func (sk *OCR2Key) PublicKey() types.OnchainPublicKey { - return caigotypes.BigToFelt(sk.pub.X).Bytes() + ans := new(felt.Felt).SetBytes(sk.pub.X.Bytes()).Bytes() + return ans[:] } func ReportToSigData(reportCtx types.ReportContext, report types.Report) (*big.Int, error) { @@ -46,7 +47,7 @@ func ReportToSigData(reportCtx types.ReportContext, report types.Report) (*big.I dataArray = append(dataArray, new(big.Int).SetBytes(splitReport[i])) } - hash, err := caigo.Curve.ComputeHashOnElements(dataArray) + hash, err := curve.Curve.ComputeHashOnElements(dataArray) if err != nil { return &big.Int{}, err } @@ -58,14 +59,14 @@ func (sk *OCR2Key) Sign(reportCtx types.ReportContext, report types.Report) ([]b if err != nil { return []byte{}, err } - r, s, err := caigo.Curve.Sign(hash, sk.priv) + r, s, err := curve.Curve.Sign(hash, sk.priv) if err != nil { return []byte{}, err } // enforce s <= N/2 to prevent signature malleability - if s.Cmp(new(big.Int).Rsh(caigo.Curve.N, 1)) > 0 { - s.Sub(caigo.Curve.N, s) + if s.Cmp(new(big.Int).Rsh(curve.Curve.N, 1)) > 0 { + s.Sub(curve.Curve.N, s) } // encoding: public key (32 bytes) + r (32 bytes) + s (32 bytes) @@ -97,7 +98,7 @@ func (sk *OCR2Key) Verify(publicKey types.OnchainPublicKey, reportCtx types.Repo // convert OnchainPublicKey (starkkey) into ecdsa public keys (prepend 2 or 3 to indicate +/- Y coord) var keys [2]PublicKey keys[0].X = new(big.Int).SetBytes(publicKey) - keys[0].Y = caigo.Curve.GetYCoordinate(keys[0].X) + keys[0].Y = curve.Curve.GetYCoordinate(keys[0].X) // When there is no point with the provided x-coordinate, the GetYCoordinate function returns the nil value. if keys[0].Y == nil { @@ -116,11 +117,11 @@ func (sk *OCR2Key) Verify(publicKey types.OnchainPublicKey, reportCtx types.Repo s := new(big.Int).SetBytes(signature[64:]) // Only allow canonical signatures to avoid signature malleability. Verify s <= N/2 - if s.Cmp(new(big.Int).Rsh(caigo.Curve.N, 1)) == 1 { + if s.Cmp(new(big.Int).Rsh(curve.Curve.N, 1)) == 1 { return false } - return caigo.Curve.Verify(hash, r, s, keys[0].X, keys[0].Y) || caigo.Curve.Verify(hash, r, s, keys[1].X, keys[1].Y) + return curve.Curve.Verify(hash, r, s, keys[0].X, keys[0].Y) || curve.Curve.Verify(hash, r, s, keys[1].X, keys[1].Y) } func (sk *OCR2Key) Verify3(publicKey types.OnchainPublicKey, cd types.ConfigDigest, seqNr uint64, r types.Report, signature []byte) bool { diff --git a/core/services/keystore/keys/starkkey/ocr2key_test.go b/core/services/keystore/keys/starkkey/ocr2key_test.go index e2d20258463..69436e5ce7f 100644 --- a/core/services/keystore/keys/starkkey/ocr2key_test.go +++ b/core/services/keystore/keys/starkkey/ocr2key_test.go @@ -6,7 +6,7 @@ import ( "math/big" "testing" - caigotypes "github.com/smartcontractkit/caigo/types" + "github.com/NethermindEth/juno/core/felt" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/stretchr/testify/assert" @@ -34,13 +34,15 @@ import ( func TestStarknetKeyring_TestVector(t *testing.T) { var kr1 OCR2Key bigKey, _ := new(big.Int).SetString("2137244795266879235401249500471353867704187908407744160927664772020405449078", 10) - feltKey := caigotypes.BigToFelt(bigKey) - err := kr1.Unmarshal(feltKey.Bytes()) + feltKey, err := new(felt.Felt).SetString(bigKey.String()) + require.NoError(t, err) + bytesKey := feltKey.Bytes() + err = kr1.Unmarshal(bytesKey[:]) require.NoError(t, err) // kr2, err := NewOCR2Key(cryptorand.Reader) // require.NoError(t, err) - bytes, err := caigotypes.HexToBytes("0x004acf99cb25a4803916f086440c661295b105a485efdc649ac4de9536da25b") + bytes, err := hex.DecodeString("0004acf99cb25a4803916f086440c661295b105a485efdc649ac4de9536da25b") require.NoError(t, err) configDigest, err := ocrtypes.BytesToConfigDigest(bytes) require.NoError(t, err) @@ -58,44 +60,51 @@ func TestStarknetKeyring_TestVector(t *testing.T) { } var report []byte - report = append(report, caigotypes.BigToFelt(big.NewInt(1)).Bytes()...) - report = append(report, caigotypes.StrToFelt("0x00010203000000000000000000000000000000000000000000000000000000").Bytes()...) - report = append(report, caigotypes.BigToFelt(big.NewInt(4)).Bytes()...) - report = append(report, caigotypes.BigToFelt(big.NewInt(99)).Bytes()...) - report = append(report, caigotypes.BigToFelt(big.NewInt(99)).Bytes()...) - report = append(report, caigotypes.BigToFelt(big.NewInt(99)).Bytes()...) - report = append(report, caigotypes.BigToFelt(big.NewInt(99)).Bytes()...) - report = append(report, caigotypes.BigToFelt(big.NewInt(1)).Bytes()...) + b1 := new(felt.Felt).SetUint64(1).Bytes() + report = append(report, b1[:]...) + b2Bytes, err := hex.DecodeString("00010203000000000000000000000000000000000000000000000000000000") + require.NoError(t, err) + b2 := new(felt.Felt).SetBytes(b2Bytes).Bytes() + report = append(report, b2[:]...) + b3 := new(felt.Felt).SetUint64(4).Bytes() + report = append(report, b3[:]...) + b4 := new(felt.Felt).SetUint64(99).Bytes() + report = append(report, b4[:]...) + report = append(report, b4[:]...) + report = append(report, b4[:]...) + report = append(report, b4[:]...) + report = append(report, b1[:]...) // check that report hash matches expected msg, err := ReportToSigData(ctx, report) require.NoError(t, err) - expected, err := caigotypes.HexToBytes("0x1332a8dabaabef63b03438ca50760cb9f5c0292cbf015b2395e50e6157df4e3") + expected, err := new(felt.Felt).SetString("0x1332a8dabaabef63b03438ca50760cb9f5c0292cbf015b2395e50e6157df4e3") + expectedBytes := expected.Bytes() require.NoError(t, err) - assert.Equal(t, expected, msg.Bytes()) + assert.Equal(t, expectedBytes[:], msg.Bytes()) // check that signature matches expected sig, err := kr1.Sign(ctx, report) require.NoError(t, err) - pub := caigotypes.BytesToFelt(sig[0:32]) - r := caigotypes.BytesToFelt(sig[32:64]) - s := caigotypes.BytesToFelt(sig[64:]) + pub := new(felt.Felt).SetBytes(sig[0:32]) + r := new(felt.Felt).SetBytes(sig[32:64]) + s := new(felt.Felt).SetBytes(sig[64:]) bigPubExpected, _ := new(big.Int).SetString("1118148281956858477519852250235501663092798578871088714409528077622994994907", 10) - feltPubExpected := caigotypes.BigToFelt(bigPubExpected) + feltPubExpected := new(felt.Felt).SetBytes(bigPubExpected.Bytes()) assert.Equal(t, feltPubExpected, pub) bigRExpected, _ := new(big.Int).SetString("2898571078985034687500959842265381508927681132188252715370774777831313601543", 10) - feltRExpected := caigotypes.BigToFelt(bigRExpected) + feltRExpected := new(felt.Felt).SetBytes(bigRExpected.Bytes()) assert.Equal(t, feltRExpected, r) // test for malleability otherS, _ := new(big.Int).SetString("1930849708769648077928186998643944706551011476358007177069185543644456022504", 10) bigSExpected, _ := new(big.Int).SetString("1687653079896483135769135784451125398975732275358080312084893914240056843079", 10) - feltSExpected := caigotypes.BigToFelt(bigSExpected) + feltSExpected := new(felt.Felt).SetBytes(bigSExpected.Bytes()) assert.NotEqual(t, otherS, s, "signature not in canonical form") assert.Equal(t, feltSExpected, s) } diff --git a/core/services/keystore/keys/starkkey/utils.go b/core/services/keystore/keys/starkkey/utils.go index 19ba54799d3..d8706ba9dbc 100644 --- a/core/services/keystore/keys/starkkey/utils.go +++ b/core/services/keystore/keys/starkkey/utils.go @@ -6,7 +6,7 @@ import ( "io" "math/big" - "github.com/smartcontractkit/caigo" + "github.com/NethermindEth/starknet.go/curve" ) // constants @@ -14,23 +14,24 @@ var ( byteLen = 32 ) -// reimplements parts of https://github.com/smartcontractkit/caigo/blob/main/utils.go#L85 +// reimplements parts of +// https://github.com/NethermindEth/starknet.go/blob/0bdaab716ce24a521304744a8fbd8e01800c241d/curve/curve.go#L702 // generate the PK as a pseudo-random number in the interval [1, CurveOrder - 1] // using io.Reader, and Key struct func GenerateKey(material io.Reader) (k Key, err error) { - max := new(big.Int).Sub(caigo.Curve.N, big.NewInt(1)) + max := new(big.Int).Sub(curve.Curve.N, big.NewInt(1)) k.priv, err = rand.Int(material, max) if err != nil { return k, err } - k.pub.X, k.pub.Y, err = caigo.Curve.PrivateToPoint(k.priv) + k.pub.X, k.pub.Y, err = curve.Curve.PrivateToPoint(k.priv) if err != nil { return k, err } - if !caigo.Curve.IsOnCurve(k.pub.X, k.pub.Y) { + if !curve.Curve.IsOnCurve(k.pub.X, k.pub.Y) { return k, fmt.Errorf("key gen is not on stark curve") } diff --git a/core/services/keystore/keys/vrfkey/private_key.go b/core/services/keystore/keys/vrfkey/private_key.go index 667ddadab47..dd2545fdd28 100644 --- a/core/services/keystore/keys/vrfkey/private_key.go +++ b/core/services/keystore/keys/vrfkey/private_key.go @@ -57,7 +57,7 @@ func (k *PrivateKey) GoString() string { // Decrypt returns the PrivateKey in e, decrypted via auth, or an error func Decrypt(e EncryptedVRFKey, auth string) (*PrivateKey, error) { // NOTE: We do this shuffle to an anonymous struct - // solely to add a a throwaway UUID, so we can leverage + // solely to add a throwaway UUID, so we can leverage // the keystore.DecryptKey from the geth which requires it // as of 1.10.0. keyJSON, err := json.Marshal(struct { diff --git a/core/services/keystore/starknet.go b/core/services/keystore/starknet.go index 251c74d0e00..6b6afa987c6 100644 --- a/core/services/keystore/starknet.go +++ b/core/services/keystore/starknet.go @@ -7,7 +7,7 @@ import ( "github.com/pkg/errors" - "github.com/smartcontractkit/caigo" + "github.com/NethermindEth/starknet.go/curve" "github.com/smartcontractkit/chainlink-common/pkg/loop" adapters "github.com/smartcontractkit/chainlink-common/pkg/loop/adapters/starknet" @@ -179,7 +179,7 @@ func (lk *StarknetLooppSigner) Sign(ctx context.Context, id string, hash []byte) } starkHash := new(big.Int).SetBytes(hash) - x, y, err := caigo.Curve.Sign(starkHash, k.ToPrivKey()) + x, y, err := curve.Curve.Sign(starkHash, k.ToPrivKey()) if err != nil { return nil, fmt.Errorf("error signing data with curve: %w", err) } diff --git a/core/services/keystore/starknet_test.go b/core/services/keystore/starknet_test.go index a007b01f120..43624a4159e 100644 --- a/core/services/keystore/starknet_test.go +++ b/core/services/keystore/starknet_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/caigo" + "github.com/NethermindEth/starknet.go/curve" "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -138,15 +138,15 @@ func TestStarknetSigner(t *testing.T) { adapter := starktxm.NewKeystoreAdapter(lk) baseKs.On("Get", starknetSenderAddr).Return(starkKey, nil) - hash, err := caigo.Curve.PedersenHash([]*big.Int{big.NewInt(42)}) + hash, err := curve.Curve.PedersenHash([]*big.Int{big.NewInt(42)}) require.NoError(t, err) r, s, err := adapter.Sign(testutils.Context(t), starknetSenderAddr, hash) require.NoError(t, err) require.NotNil(t, r) require.NotNil(t, s) - pubx, puby, err := caigo.Curve.PrivateToPoint(starkKey.ToPrivKey()) + pubx, puby, err := curve.Curve.PrivateToPoint(starkKey.ToPrivKey()) require.NoError(t, err) - require.True(t, caigo.Curve.Verify(hash, r, s, pubx, puby)) + require.True(t, curve.Curve.Verify(hash, r, s, pubx, puby)) }) } diff --git a/core/services/ocr/config_overrider.go b/core/services/ocr/config_overrider.go index ac87d0e3924..a58cb402695 100644 --- a/core/services/ocr/config_overrider.go +++ b/core/services/ocr/config_overrider.go @@ -14,8 +14,8 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -23,7 +23,7 @@ type ConfigOverriderImpl struct { services.StateMachine logger logger.Logger flags *ContractFlags - contractAddress ethkey.EIP55Address + contractAddress types.EIP55Address pollTicker utils.TickerBase lastStateChangeTimestamp time.Time @@ -49,7 +49,7 @@ type DeltaCConfig interface { func NewConfigOverriderImpl( logger logger.Logger, cfg DeltaCConfig, - contractAddress ethkey.EIP55Address, + contractAddress types.EIP55Address, flags *ContractFlags, pollTicker utils.TickerBase, ) (*ConfigOverriderImpl, error) { diff --git a/core/services/ocr/config_overrider_test.go b/core/services/ocr/config_overrider_test.go index e01102a62f8..1f782989e66 100644 --- a/core/services/ocr/config_overrider_test.go +++ b/core/services/ocr/config_overrider_test.go @@ -15,18 +15,18 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" evmutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/mocks" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr" "github.com/smartcontractkit/chainlink/v2/core/utils" ) type configOverriderUni struct { overrider *ocr.ConfigOverriderImpl - contractAddress ethkey.EIP55Address + contractAddress types.EIP55Address } type deltaCConfig struct{} @@ -164,10 +164,10 @@ func Test_OCRConfigOverrider(t *testing.T) { flagsContract := mocks.NewFlags(t) flags := &ocr.ContractFlags{FlagsInterface: flagsContract} - address1, err := ethkey.NewEIP55Address(common.BigToAddress(big.NewInt(10000)).Hex()) + address1, err := types.NewEIP55Address(common.BigToAddress(big.NewInt(10000)).Hex()) require.NoError(t, err) - address2, err := ethkey.NewEIP55Address(common.BigToAddress(big.NewInt(1234567890)).Hex()) + address2, err := types.NewEIP55Address(common.BigToAddress(big.NewInt(1234567890)).Hex()) require.NoError(t, err) overrider1a, err := ocr.NewConfigOverriderImpl(testLogger, deltaCConfig{}, address1, flags, nil) @@ -185,7 +185,7 @@ func Test_OCRConfigOverrider(t *testing.T) { }) } -func checkFlagsAddress(t *testing.T, contractAddress ethkey.EIP55Address) func(args mock.Arguments) { +func checkFlagsAddress(t *testing.T, contractAddress types.EIP55Address) func(args mock.Arguments) { return func(args mock.Arguments) { require.Equal(t, []common.Address{ evmutils.ZeroAddress, diff --git a/core/services/ocr/contract_tracker.go b/core/services/ocr/contract_tracker.go index 4c3260511d5..e4845ee3bc2 100644 --- a/core/services/ocr/contract_tracker.go +++ b/core/services/ocr/contract_tracker.go @@ -241,7 +241,10 @@ func (t *OCRContractTracker) processLogs() { // HandleLog complies with LogListener interface // It is not thread safe func (t *OCRContractTracker) HandleLog(lb log.Broadcast) { - was, err := t.logBroadcaster.WasAlreadyConsumed(lb) + ctx, cancel := t.chStop.NewCtx() + defer cancel() + + was, err := t.logBroadcaster.WasAlreadyConsumed(ctx, lb) if err != nil { t.logger.Errorw("could not determine if log was already consumed", "err", err) return @@ -252,14 +255,14 @@ func (t *OCRContractTracker) HandleLog(lb log.Broadcast) { raw := lb.RawLog() if raw.Address != t.contract.Address() { t.logger.Errorf("log address of 0x%x does not match configured contract address of 0x%x", raw.Address, t.contract.Address()) - if err2 := t.logBroadcaster.MarkConsumed(lb); err2 != nil { + if err2 := t.logBroadcaster.MarkConsumed(ctx, lb); err2 != nil { t.logger.Errorw("failed to mark log consumed", "err", err2) } return } topics := raw.Topics if len(topics) == 0 { - if err2 := t.logBroadcaster.MarkConsumed(lb); err2 != nil { + if err2 := t.logBroadcaster.MarkConsumed(ctx, lb); err2 != nil { t.logger.Errorw("failed to mark log consumed", "err", err2) } return @@ -272,7 +275,7 @@ func (t *OCRContractTracker) HandleLog(lb log.Broadcast) { configSet, err = t.contractFilterer.ParseConfigSet(raw) if err != nil { t.logger.Errorw("could not parse config set", "err", err) - if err2 := t.logBroadcaster.MarkConsumed(lb); err2 != nil { + if err2 := t.logBroadcaster.MarkConsumed(ctx, lb); err2 != nil { t.logger.Errorw("failed to mark log consumed", "err", err2) } return @@ -289,7 +292,7 @@ func (t *OCRContractTracker) HandleLog(lb log.Broadcast) { rr, err = t.contractFilterer.ParseRoundRequested(raw) if err != nil { t.logger.Errorw("could not parse round requested", "err", err) - if err2 := t.logBroadcaster.MarkConsumed(lb); err2 != nil { + if err2 := t.logBroadcaster.MarkConsumed(ctx, lb); err2 != nil { t.logger.Errorw("failed to mark log consumed", "err", err2) } return @@ -299,7 +302,7 @@ func (t *OCRContractTracker) HandleLog(lb log.Broadcast) { if err = t.ocrDB.SaveLatestRoundRequested(tx, *rr); err != nil { return err } - return t.logBroadcaster.MarkConsumed(lb, pg.WithQueryer(tx)) + return t.logBroadcaster.MarkConsumed(ctx, lb) }) if err != nil { t.logger.Error(err) @@ -317,7 +320,7 @@ func (t *OCRContractTracker) HandleLog(lb log.Broadcast) { t.logger.Debugw("got unrecognised log topic", "topic", topics[0]) } if !consumed { - if err := t.logBroadcaster.MarkConsumed(lb); err != nil { + if err := t.logBroadcaster.MarkConsumed(ctx, lb); err != nil { t.logger.Errorw("failed to mark log consumed", "err", err) } } diff --git a/core/services/ocr/delegate.go b/core/services/ocr/delegate.go index 0411aea6923..bcdda397e20 100644 --- a/core/services/ocr/delegate.go +++ b/core/services/ocr/delegate.go @@ -21,12 +21,12 @@ import ( txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/offchain_aggregator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" @@ -323,7 +323,7 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) (services [] return services, nil } -func (d *Delegate) maybeCreateConfigOverrider(logger logger.Logger, chain legacyevm.Chain, contractAddress ethkey.EIP55Address) (*ConfigOverriderImpl, error) { +func (d *Delegate) maybeCreateConfigOverrider(logger logger.Logger, chain legacyevm.Chain, contractAddress types.EIP55Address) (*ConfigOverriderImpl, error) { flagsContractAddress := chain.Config().EVM().FlagsContractAddress() if flagsContractAddress != "" { flags, err := NewFlags(flagsContractAddress, chain.Client()) diff --git a/core/services/ocr/validate.go b/core/services/ocr/validate.go index 0524ed24d0b..a0f2353eac1 100644 --- a/core/services/ocr/validate.go +++ b/core/services/ocr/validate.go @@ -12,9 +12,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/common/config" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" ) @@ -29,7 +29,7 @@ type OCRValidationConfig interface { ContractSubscribeInterval() time.Duration KeyBundleID() (string, error) ObservationTimeout() time.Duration - TransmitterAddress() (ethkey.EIP55Address, error) + TransmitterAddress() (types.EIP55Address, error) } type insecureConfig interface { diff --git a/core/services/ocr2/database_test.go b/core/services/ocr2/database_test.go index b70ac629da1..486bf1fd708 100644 --- a/core/services/ocr2/database_test.go +++ b/core/services/ocr2/database_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" medianconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/median/config" "github.com/stretchr/testify/assert" @@ -19,14 +20,13 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/testhelpers" ) const defaultPluginID = 0 -func MustInsertOCROracleSpec(t *testing.T, db *sqlx.DB, transmitterAddress ethkey.EIP55Address) job.OCR2OracleSpec { +func MustInsertOCROracleSpec(t *testing.T, db *sqlx.DB, transmitterAddress types.EIP55Address) job.OCR2OracleSpec { t.Helper() spec := job.OCR2OracleSpec{} diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 38297d96bc7..a053b53992d 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -471,7 +471,8 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.Servi return d.newServicesOCR2Functions(ctx, lggr, jb, bootstrapPeers, kb, ocrDB, thresholdPluginDB, s4PluginDB, lc, ocrLogger) case types.GenericPlugin: - return d.newServicesGenericPlugin(ctx, lggr, jb, bootstrapPeers, kb, ocrDB, lc, ocrLogger, d.capabilitiesRegistry) + return d.newServicesGenericPlugin(ctx, lggr, jb, bootstrapPeers, kb, ocrDB, lc, ocrLogger, d.capabilitiesRegistry, + kvStore) default: return nil, errors.Errorf("plugin type %s not supported", spec.PluginType) @@ -531,9 +532,9 @@ func (d *Delegate) newServicesGenericPlugin( lc ocrtypes.LocalConfig, ocrLogger commontypes.Logger, capabilitiesRegistry types.CapabilitiesRegistry, + keyValueStore types.KeyValueStore, ) (srvs []job.ServiceCtx, err error) { spec := jb.OCR2OracleSpec - // NOTE: we don't need to validate this config, since that happens as part of creating the job. // See: validate/validate.go's `validateSpec`. pCfg := validate.OCR2GenericPluginConfig{} @@ -649,7 +650,8 @@ func (d *Delegate) newServicesGenericPlugin( switch pCfg.OCRVersion { case 2: - plugin := reportingplugins.NewLOOPPService(pluginLggr, grpcOpts, cmdFn, pluginConfig, providerClientConn, pr, ta, errorLog) + plugin := reportingplugins.NewLOOPPService(pluginLggr, grpcOpts, cmdFn, pluginConfig, providerClientConn, pr, ta, + errorLog, keyValueStore) oracleArgs := libocr2.OCR2OracleArgs{ BinaryNetworkEndpointFactory: d.peerWrapper.Peer2, V2Bootstrappers: bootstrapPeers, @@ -674,7 +676,8 @@ func (d *Delegate) newServicesGenericPlugin( case 3: //OCR3 with OCR2 OnchainKeyring and ContractTransmitter - plugin := ocr3.NewLOOPPService(pluginLggr, grpcOpts, cmdFn, pluginConfig, providerClientConn, pr, ta, errorLog, capabilitiesRegistry) + plugin := ocr3.NewLOOPPService(pluginLggr, grpcOpts, cmdFn, pluginConfig, providerClientConn, pr, ta, errorLog, + capabilitiesRegistry, keyValueStore) contractTransmitter := ocrcommon.NewOCR3ContractTransmitterAdapter(provider.ContractTransmitter()) oracleArgs := libocr2.OCR3OracleArgs[[]byte]{ BinaryNetworkEndpointFactory: d.peerWrapper.Peer2, diff --git a/core/services/ocr2/delegate_test.go b/core/services/ocr2/delegate_test.go index 3da0c9cbfd6..ea8693d48ce 100644 --- a/core/services/ocr2/delegate_test.go +++ b/core/services/ocr2/delegate_test.go @@ -136,7 +136,7 @@ func TestGetEVMEffectiveTransmitterID(t *testing.T) { } t.Run("when sending keys are not defined, the first one should be set to transmitterID", func(t *testing.T) { - jb, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal()) + jb, err := ocr2validate.ValidatedOracleSpecToml(testutils.Context(t), config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal(), nil) require.NoError(t, err) jb.OCR2OracleSpec.TransmitterID = null.StringFrom("some transmitterID string") jb.OCR2OracleSpec.RelayConfig["sendingKeys"] = nil @@ -150,7 +150,7 @@ func TestGetEVMEffectiveTransmitterID(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - jb, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal()) + jb, err := ocr2validate.ValidatedOracleSpecToml(testutils.Context(t), config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal(), nil) require.NoError(t, err) setTestCase(&jb, tc, txManager) chain, err := legacyChains.Get(customChainID.String()) @@ -173,7 +173,7 @@ func TestGetEVMEffectiveTransmitterID(t *testing.T) { } t.Run("when forwarders are enabled and chain retrieval fails, error should be handled", func(t *testing.T) { - jb, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal()) + jb, err := ocr2validate.ValidatedOracleSpecToml(testutils.Context(t), config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal(), nil) require.NoError(t, err) jb.ForwardingAllowed = true jb.OCR2OracleSpec.TransmitterID = null.StringFrom("0x7e57000000000000000000000000000000000001") diff --git a/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go b/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go index 1216eec0a63..ab4b114906e 100644 --- a/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go +++ b/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go @@ -428,7 +428,7 @@ func AddOCR2Job(t *testing.T, app *cltest.TestApplication, contractAddress commo Name: "ea_bridge", URL: models.WebURL(*u), })) - job, err := validate.ValidatedOracleSpecToml(app.Config.OCR2(), app.Config.Insecure(), fmt.Sprintf(` + job, err := validate.ValidatedOracleSpecToml(testutils.Context(t), app.Config.OCR2(), app.Config.Insecure(), fmt.Sprintf(` type = "offchainreporting2" name = "functions-node" schemaVersion = 1 @@ -470,7 +470,7 @@ func AddOCR2Job(t *testing.T, app *cltest.TestApplication, contractAddress commo [pluginConfig.s4Constraints] maxPayloadSizeBytes = 10_1000 maxSlotsPerUser = 10 - `, contractAddress, keyBundleID, transmitter, DefaultDONId)) + `, contractAddress, keyBundleID, transmitter, DefaultDONId), nil) require.NoError(t, err) err = app.AddJobV2(testutils.Context(t), &job) require.NoError(t, err) diff --git a/core/services/ocr2/plugins/generic/pipeline_runner_adapter.go b/core/services/ocr2/plugins/generic/pipeline_runner_adapter.go index 872f83d3c35..b13d7b35e0b 100644 --- a/core/services/ocr2/plugins/generic/pipeline_runner_adapter.go +++ b/core/services/ocr2/plugins/generic/pipeline_runner_adapter.go @@ -55,9 +55,8 @@ func (p *PipelineRunnerAdapter) ExecuteRun(ctx context.Context, spec string, var ID: trr.ID.String(), Type: string(trr.Task.Type()), Index: int(trr.Task.OutputIndex()), - TaskValue: types.TaskValue{ - Value: trr.Result.Value, + Value: trr.Result.OutputDB(), Error: trr.Result.Error, IsTerminal: len(trr.Task.Outputs()) == 0, }, diff --git a/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go b/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go index c2060a92905..a4bc8eb0b16 100644 --- a/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go +++ b/core/services/ocr2/plugins/generic/pipeline_runner_adapter_test.go @@ -57,7 +57,7 @@ func TestAdapter_Integration(t *testing.T) { results, err := pra.ExecuteRun(testutils.Context(t), spec, types.Vars{Vars: map[string]interface{}{"val": 1}}, types.Options{}) require.NoError(t, err) - finalResult := results[0].Value.(decimal.Decimal) + finalResult := results[0].Value.Val.(decimal.Decimal) assert.True(t, decimal.NewFromInt(3).Equal(finalResult)) } diff --git a/core/services/ocr2/plugins/llo/helpers_test.go b/core/services/ocr2/plugins/llo/helpers_test.go index ae9850134b9..8112cf1b0ba 100644 --- a/core/services/ocr2/plugins/llo/helpers_test.go +++ b/core/services/ocr2/plugins/llo/helpers_test.go @@ -141,7 +141,7 @@ func (node *Node) AddStreamJob(t *testing.T, spec string) { func (node *Node) AddLLOJob(t *testing.T, spec string) { c := node.App.GetConfig() - job, err := validate.ValidatedOracleSpecToml(c.OCR2(), c.Insecure(), spec) + job, err := validate.ValidatedOracleSpecToml(testutils.Context(t), c.OCR2(), c.Insecure(), spec, nil) require.NoError(t, err) err = node.App.AddJobV2(testutils.Context(t), &job) require.NoError(t, err) diff --git a/core/services/ocr2/plugins/median/services.go b/core/services/ocr2/plugins/median/services.go index a432045c867..4615f934511 100644 --- a/core/services/ocr2/plugins/median/services.go +++ b/core/services/ocr2/plugins/median/services.go @@ -129,9 +129,12 @@ func NewMedianServices(ctx context.Context, if !pluginConfig.JuelsPerFeeCoinCacheDisabled { lggr.Infof("juelsPerFeeCoin data source caching is enabled") - if juelsPerFeeCoinSource, err = ocrcommon.NewInMemoryDataSourceCache(juelsPerFeeCoinSource, kvStore, pluginConfig.JuelsPerFeeCoinCacheDuration.Duration()); err != nil { - return nil, err + juelsPerFeeCoinSourceCache, err2 := ocrcommon.NewInMemoryDataSourceCache(juelsPerFeeCoinSource, kvStore, pluginConfig.JuelsPerFeeCoinCacheDuration.Duration()) + if err2 != nil { + return nil, err2 } + juelsPerFeeCoinSource = juelsPerFeeCoinSourceCache + srvs = append(srvs, juelsPerFeeCoinSourceCache) } if cmdName := env.MedianPlugin.Cmd.Get(); cmdName != "" { diff --git a/core/services/ocr2/plugins/mercury/helpers_test.go b/core/services/ocr2/plugins/mercury/helpers_test.go index c7273cd374e..43d709453b7 100644 --- a/core/services/ocr2/plugins/mercury/helpers_test.go +++ b/core/services/ocr2/plugins/mercury/helpers_test.go @@ -137,7 +137,7 @@ type Node struct { func (node *Node) AddJob(t *testing.T, spec string) { c := node.App.GetConfig() - job, err := validate.ValidatedOracleSpecToml(c.OCR2(), c.Insecure(), spec) + job, err := validate.ValidatedOracleSpecToml(testutils.Context(t), c.OCR2(), c.Insecure(), spec, nil) require.NoError(t, err) err = node.App.AddJobV2(testutils.Context(t), &job) require.NoError(t, err) @@ -168,6 +168,7 @@ func setupNode( // [JobPipeline] // MaxSuccessfulRuns = 0 c.JobPipeline.MaxSuccessfulRuns = ptr(uint64(0)) + c.JobPipeline.VerboseLogging = ptr(true) // [Feature] // UICSAKeys=true diff --git a/core/services/ocr2/plugins/mercury/plugin_test.go b/core/services/ocr2/plugins/mercury/plugin_test.go index 4e6d4d82a7e..3934105a390 100644 --- a/core/services/ocr2/plugins/mercury/plugin_test.go +++ b/core/services/ocr2/plugins/mercury/plugin_test.go @@ -267,6 +267,8 @@ var _ commontypes.MercuryProvider = (*testProvider)(nil) type testRegistrarConfig struct{} +func (c *testRegistrarConfig) UnregisterLOOP(ID string) {} + // RegisterLOOP implements plugins.RegistrarConfig. func (*testRegistrarConfig) RegisterLOOP(config plugins.CmdConfig) (func() *exec.Cmd, loop.GRPCOpts, error) { return nil, loop.GRPCOpts{}, nil diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer.go index 6418d683869..af934a08013 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer.go @@ -231,7 +231,8 @@ func (b *logEventBuffer) enqueue(id *big.Int, logs ...logpoller.Log) int { } if added > 0 { lggr.Debugw("Added logs to buffer", "addedLogs", added, "dropped", dropped, "latestBlock", latestBlock) - prommetrics.AutomationLogsInLogBuffer.Add(float64(added - dropped)) + prommetrics.AutomationLogBufferFlow.WithLabelValues(prommetrics.LogBufferFlowDirectionIngress).Add(float64(added)) + prommetrics.AutomationLogBufferFlow.WithLabelValues(prommetrics.LogBufferFlowDirectionDropped).Add(float64(dropped)) } return added - dropped @@ -333,7 +334,7 @@ func (b *logEventBuffer) dequeueRange(start, end int64, upkeepLimit, totalLimit if len(results) > 0 { b.lggr.Debugw("Dequeued logs", "results", len(results), "start", start, "end", end) - prommetrics.AutomationLogsInLogBuffer.Sub(float64(len(results))) + prommetrics.AutomationLogBufferFlow.WithLabelValues(prommetrics.LogBufferFlowDirectionEgress).Add(float64(len(results))) } return results diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/factory.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/factory.go index 2b48fec2b37..263fa69223f 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/factory.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/factory.go @@ -1,6 +1,7 @@ package logprovider import ( + "math/big" "time" "golang.org/x/time/rate" @@ -13,11 +14,12 @@ import ( // New creates a new log event provider and recoverer. // using default values for the options. -func New(lggr logger.Logger, poller logpoller.LogPoller, c client.Client, stateStore core.UpkeepStateReader, finalityDepth uint32) (LogEventProvider, LogRecoverer) { +func New(lggr logger.Logger, poller logpoller.LogPoller, c client.Client, stateStore core.UpkeepStateReader, finalityDepth uint32, chainID *big.Int) (LogEventProvider, LogRecoverer) { filterStore := NewUpkeepFilterStore() packer := NewLogEventsPacker() opts := NewOptions(int64(finalityDepth)) - provider := NewLogProvider(lggr, poller, packer, filterStore, opts) + + provider := NewLogProvider(lggr, poller, chainID, packer, filterStore, opts) recoverer := NewLogRecoverer(lggr, poller, c, stateStore, packer, filterStore, opts) return provider, recoverer diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/integration_test.go index 1fc642a946f..51cdeccafdf 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/integration_test.go @@ -91,7 +91,7 @@ func TestIntegration_LogEventProvider(t *testing.T) { // assuming that our service was closed and restarted, // we should be able to backfill old logs and fetch new ones filterStore := logprovider.NewUpkeepFilterStore() - logProvider2 := logprovider.NewLogProvider(logger.TestLogger(t), lp, logprovider.NewLogEventsPacker(), filterStore, opts) + logProvider2 := logprovider.NewLogProvider(logger.TestLogger(t), lp, big.NewInt(1), logprovider.NewLogEventsPacker(), filterStore, opts) poll(backend.Commit()) go func() { @@ -676,7 +676,7 @@ func setup(lggr logger.Logger, poller logpoller.LogPoller, c client.Client, stat o := logprovider.NewOptions(200) opts = &o } - provider := logprovider.NewLogProvider(lggr, poller, packer, filterStore, *opts) + provider := logprovider.NewLogProvider(lggr, poller, big.NewInt(1), packer, filterStore, *opts) recoverer := logprovider.NewLogRecoverer(lggr, poller, c, stateStore, packer, filterStore, *opts) return provider, recoverer diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider.go index ed84410548d..60505a2989e 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider.go @@ -102,9 +102,18 @@ type logEventProvider struct { opts LogTriggersOptions currentPartitionIdx uint64 + + chainID *big.Int } -func NewLogProvider(lggr logger.Logger, poller logpoller.LogPoller, packer LogDataPacker, filterStore UpkeepFilterStore, opts LogTriggersOptions) *logEventProvider { +func NewLogProvider(lggr logger.Logger, poller logpoller.LogPoller, chainID *big.Int, packer LogDataPacker, filterStore UpkeepFilterStore, opts LogTriggersOptions) *logEventProvider { + defaultBlockRate := defaultBlockRateForChain(chainID) + defaultLogLimit := defaultLogLimitForChain(chainID) + + // TODO apply these to the log buffer later + _ = defaultBlockRate + _ = defaultLogLimit + return &logEventProvider{ threadCtrl: utils.NewThreadControl(), lggr: lggr.Named("KeepersRegistry.LogEventProvider"), @@ -113,7 +122,25 @@ func NewLogProvider(lggr logger.Logger, poller logpoller.LogPoller, packer LogDa poller: poller, opts: opts, filterStore: filterStore, + chainID: chainID, + } +} + +func (p *logEventProvider) SetConfig(cfg ocr2keepers.LogEventProviderConfig) { + blockRate := cfg.BlockRate + logLimit := cfg.LogLimit + + if blockRate == 0 { + blockRate = defaultBlockRateForChain(p.chainID) + } + if logLimit == 0 { + logLimit = defaultLogLimitForChain(p.chainID) } + + p.lggr.With("where", "setConfig").Infow("setting config ", "bockRate", blockRate, "logLimit", logLimit) + + // TODO set block rate and log limit on the buffer + //p.buffer.SetConfig(blockRate, logLimit) } func (p *logEventProvider) Start(context.Context) error { @@ -408,3 +435,25 @@ func (p *logEventProvider) readLogs(ctx context.Context, latest int64, filters [ return merr } + +func defaultBlockRateForChain(chainID *big.Int) uint32 { + switch chainID.Int64() { + case 42161, 421613, 421614: // Arbitrum + return 4 + default: + return 1 + } +} + +func defaultLogLimitForChain(chainID *big.Int) uint32 { + switch chainID.Int64() { + case 42161, 421613, 421614: // Arbitrum + return 1 + case 1, 4, 5, 42, 11155111: // Eth + return 20 + case 10, 420, 56, 97, 137, 80001, 43113, 43114, 8453, 84531: // Optimism, BSC, Polygon, Avax, Base + return 5 + default: + return 1 + } +} diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle_test.go index 5d87a986a56..96a397827be 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle_test.go @@ -100,7 +100,7 @@ func TestLogEventProvider_LifeCycle(t *testing.T) { }, } - p := NewLogProvider(logger.TestLogger(t), nil, &mockedPacker{}, NewUpkeepFilterStore(), NewOptions(200)) + p := NewLogProvider(logger.TestLogger(t), nil, big.NewInt(1), &mockedPacker{}, NewUpkeepFilterStore(), NewOptions(200)) for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { @@ -152,7 +152,7 @@ func TestEventLogProvider_RefreshActiveUpkeeps(t *testing.T) { mp.On("LatestBlock", mock.Anything).Return(logpoller.LogPollerBlock{}, nil) mp.On("ReplayAsync", mock.Anything).Return(nil) - p := NewLogProvider(logger.TestLogger(t), mp, &mockedPacker{}, NewUpkeepFilterStore(), NewOptions(200)) + p := NewLogProvider(logger.TestLogger(t), mp, big.NewInt(1), &mockedPacker{}, NewUpkeepFilterStore(), NewOptions(200)) require.NoError(t, p.RegisterFilter(ctx, FilterOptions{ UpkeepID: core.GenUpkeepID(types.LogTrigger, "1111").BigInt(), @@ -231,7 +231,7 @@ func TestLogEventProvider_ValidateLogTriggerConfig(t *testing.T) { }, } - p := NewLogProvider(logger.TestLogger(t), nil, &mockedPacker{}, NewUpkeepFilterStore(), NewOptions(200)) + p := NewLogProvider(logger.TestLogger(t), nil, big.NewInt(1), &mockedPacker{}, NewUpkeepFilterStore(), NewOptions(200)) for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { err := p.validateLogTriggerConfig(tc.cfg) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_test.go index 6ed68d4028a..ade2c630ebd 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_test.go @@ -22,7 +22,7 @@ import ( ) func TestLogEventProvider_GetFilters(t *testing.T) { - p := NewLogProvider(logger.TestLogger(t), nil, &mockedPacker{}, NewUpkeepFilterStore(), NewOptions(200)) + p := NewLogProvider(logger.TestLogger(t), nil, big.NewInt(1), &mockedPacker{}, NewUpkeepFilterStore(), NewOptions(200)) _, f := newEntry(p, 1) p.filterStore.AddActiveUpkeeps(f) @@ -64,7 +64,7 @@ func TestLogEventProvider_GetFilters(t *testing.T) { } func TestLogEventProvider_UpdateEntriesLastPoll(t *testing.T) { - p := NewLogProvider(logger.TestLogger(t), nil, &mockedPacker{}, NewUpkeepFilterStore(), NewOptions(200)) + p := NewLogProvider(logger.TestLogger(t), nil, big.NewInt(1), &mockedPacker{}, NewUpkeepFilterStore(), NewOptions(200)) n := 10 @@ -180,7 +180,7 @@ func TestLogEventProvider_ScheduleReadJobs(t *testing.T) { opts := NewOptions(200) opts.ReadInterval = readInterval - p := NewLogProvider(logger.TestLogger(t), mp, &mockedPacker{}, NewUpkeepFilterStore(), opts) + p := NewLogProvider(logger.TestLogger(t), mp, big.NewInt(1), &mockedPacker{}, NewUpkeepFilterStore(), opts) var ids []*big.Int for i, id := range tc.ids { @@ -255,7 +255,7 @@ func TestLogEventProvider_ReadLogs(t *testing.T) { }, nil) filterStore := NewUpkeepFilterStore() - p := NewLogProvider(logger.TestLogger(t), mp, &mockedPacker{}, filterStore, NewOptions(200)) + p := NewLogProvider(logger.TestLogger(t), mp, big.NewInt(1), &mockedPacker{}, filterStore, NewOptions(200)) var ids []*big.Int for i := 0; i < 10; i++ { diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go index b9847dd3e0d..5a4b701f61a 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go @@ -25,6 +25,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" v02 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02" v03 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/prommetrics" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -121,6 +122,7 @@ func (s *streams) buildResult(ctx context.Context, i int, checkResult ocr2keeper lookupLggr := s.lggr.With("where", "StreamsLookup") if checkResult.IneligibilityReason != uint8(encoding.UpkeepFailureReasonTargetCheckReverted) { // Streams Lookup only works when upkeep target check reverts + prommetrics.AutomationStreamsLookupError.WithLabelValues(prommetrics.StreamsLookupErrorReasonNotReverted).Inc() return } @@ -134,11 +136,13 @@ func (s *streams) buildResult(ctx context.Context, i int, checkResult ocr2keeper if err != nil { lookupLggr.Debugf("at block %d upkeep %s DecodeStreamsLookupRequest failed: %v", block, upkeepId, err) // user contract did not revert with StreamsLookup error + prommetrics.AutomationStreamsLookupError.WithLabelValues(prommetrics.StreamsLookupErrorDecodeRequestFailed).Inc() return } streamsLookupResponse := &mercury.StreamsLookup{StreamsLookupError: streamsLookupErr} if s.mercuryConfig.Credentials() == nil { lookupLggr.Errorf("at block %d upkeep %s tries to access mercury server but mercury credential is not configured", block, upkeepId) + prommetrics.AutomationStreamsLookupError.WithLabelValues(prommetrics.StreamsLookupErrorCredentialsNotConfigured).Inc() return } @@ -179,6 +183,7 @@ func (s *streams) doLookup(ctx context.Context, wg *sync.WaitGroup, lookup *merc values, errCode, err := s.DoMercuryRequest(ctx, lookup, checkResults, i) if err != nil { s.lggr.Errorf("at block %d upkeep %s requested time %s DoMercuryRequest err: %s", lookup.Block, lookup.UpkeepId, lookup.Time, err.Error()) + prommetrics.AutomationStreamsLookupError.WithLabelValues(prommetrics.StreamsLookupErrorDoMercuryRequest).Inc() return } @@ -187,6 +192,7 @@ func (s *streams) doLookup(ctx context.Context, wg *sync.WaitGroup, lookup *merc if err != nil { s.lggr.Errorf("at block %d upkeep %s requested time %s CheckErrorHandler err: %s", lookup.Block, lookup.UpkeepId, lookup.Time, err.Error()) } + prommetrics.AutomationStreamsLookupError.WithLabelValues(prommetrics.StreamsLookupErrorCodeNotNil).Inc() return } @@ -194,10 +200,12 @@ func (s *streams) doLookup(ctx context.Context, wg *sync.WaitGroup, lookup *merc err = s.CheckCallback(ctx, values, lookup, checkResults, i) if err != nil { s.lggr.Errorf("at block %d upkeep %s requested time %s CheckCallback err: %s", lookup.Block, lookup.UpkeepId, lookup.Time, err.Error()) + prommetrics.AutomationStreamsLookupError.WithLabelValues(prommetrics.StreamsLookupErrorCheckCallback).Inc() } } func (s *streams) CheckCallback(ctx context.Context, values [][]byte, lookup *mercury.StreamsLookup, checkResults []ocr2keepers.CheckResult, i int) error { + prommetrics.AutomationStreamsLookupStep.WithLabelValues(prommetrics.StreamsLookupStepCheckCallback).Inc() payload, err := s.abi.Pack("checkCallback", lookup.UpkeepId, values, lookup.ExtraData) if err != nil { checkResults[i].Retryable = false @@ -243,6 +251,7 @@ func (s *streams) makeCallbackEthCall(ctx context.Context, payload []byte, looku // Does the mercury request for the checkResult. Returns either the looked up values or an error code if something is wrong with mercury // In case of any pipeline processing issues, returns an error and also sets approriate state on the checkResult itself func (s *streams) DoMercuryRequest(ctx context.Context, lookup *mercury.StreamsLookup, checkResults []ocr2keepers.CheckResult, i int) ([][]byte, encoding.ErrCode, error) { + prommetrics.AutomationStreamsLookupStep.WithLabelValues(prommetrics.StreamsLookupStepDoMercuryRequest).Inc() var state, values, errCode, retryable, retryInterval = encoding.NoPipelineError, [][]byte{}, encoding.ErrCodeNil, false, 0 * time.Second var err error pluginRetryKey := generatePluginRetryKey(checkResults[i].WorkID, lookup.Block) @@ -276,11 +285,13 @@ func (s *streams) DoMercuryRequest(ctx context.Context, lookup *mercury.StreamsL func (s *streams) CheckErrorHandler(ctx context.Context, errCode encoding.ErrCode, lookup *mercury.StreamsLookup, checkResults []ocr2keepers.CheckResult, i int) error { s.lggr.Debugf("at block %d upkeep %s requested time %s CheckErrorHandler error code: %d", lookup.Block, lookup.UpkeepId, lookup.Time, errCode) + prommetrics.AutomationStreamsLookupStep.WithLabelValues(prommetrics.StreamsLookupStepCheckErrorHandler).Inc() userPayload, err := s.packer.PackUserCheckErrorHandler(errCode, lookup.ExtraData) if err != nil { checkResults[i].Retryable = false checkResults[i].PipelineExecutionState = uint8(encoding.PackUnpackDecodeFailed) + prommetrics.AutomationStreamsLookupError.WithLabelValues(prommetrics.StreamsLookupErrorPackUserCheckErrorHandler).Inc() return err } @@ -288,6 +299,7 @@ func (s *streams) CheckErrorHandler(ctx context.Context, errCode encoding.ErrCod if err != nil { checkResults[i].Retryable = false checkResults[i].PipelineExecutionState = uint8(encoding.PackUnpackDecodeFailed) + prommetrics.AutomationStreamsLookupError.WithLabelValues(prommetrics.StreamsLookupErrorPackExecuteCallback).Inc() return err } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/request.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/request.go index 6b612a3f350..5e954475a8d 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/request.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/request.go @@ -21,6 +21,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/prommetrics" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -172,6 +173,7 @@ func (c *client) singleFeedRequest(ctx context.Context, ch chan<- mercury.Mercur sent := false retryErr := retry.Do( func() error { + prommetrics.AutomationStreamsRetries.WithLabelValues(prommetrics.StreamsVersion02).Inc() var httpResponse *http.Response var responseBody []byte var blobBytes []byte @@ -206,6 +208,7 @@ func (c *client) singleFeedRequest(ctx context.Context, ch chan<- mercury.Mercur return nil } + prommetrics.AutomationStreamsResponses.WithLabelValues(prommetrics.StreamsVersion02, fmt.Sprintf("%d", httpResponse.StatusCode)).Inc() switch httpResponse.StatusCode { case http.StatusNotFound, http.StatusInternalServerError, http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout: // Considered as pipeline error, but if retry attempts go over threshold, is changed upstream to ErrCode diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/request.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/request.go index 8ac8696ddbb..39a26b6b5d9 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/request.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/request.go @@ -20,6 +20,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/prommetrics" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -149,6 +150,7 @@ func (c *client) multiFeedsRequest(ctx context.Context, ch chan<- mercury.Mercur defer cancel() retryErr := retry.Do( func() error { + prommetrics.AutomationStreamsRetries.WithLabelValues(prommetrics.StreamsVersion03).Inc() retryable = false resp, err := c.httpClient.Do(req) if err != nil { @@ -180,6 +182,7 @@ func (c *client) multiFeedsRequest(ctx context.Context, ch chan<- mercury.Mercur } c.lggr.Infof("at timestamp %s upkeep %s received status code %d from mercury v0.3", sl.Time.String(), sl.UpkeepId.String(), resp.StatusCode) + prommetrics.AutomationStreamsResponses.WithLabelValues(prommetrics.StreamsVersion03, fmt.Sprintf("%d", resp.StatusCode)).Inc() switch resp.StatusCode { case http.StatusUnauthorized: c.lggr.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by unauthorized upkeep", sl.Time.String(), sl.UpkeepId.String(), resp.StatusCode) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/prommetrics/metrics.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/prommetrics/metrics.go index cebbac59884..6b68f5c6afd 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/prommetrics/metrics.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/prommetrics/metrics.go @@ -5,34 +5,103 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" ) -// AutomationNamespace is the namespace for all Automation related metrics -const AutomationLogTriggerNamespace = "automation_log_trigger" +// Namespaces +const ( + NamespaceAutomationLogTrigger = "automation_log_trigger" + NamespaceAutomationStreams = "automation_streams" +) + +// Streams steps +const ( + StreamsLookupStepDoMercuryRequest = "do_mercury_request" + StreamsLookupStepCheckErrorHandler = "check_error_handler" + StreamsLookupStepCheckCallback = "check_callback" +) + +// Streams error labels +const ( + StreamsLookupErrorReasonNotReverted = "reason_not_target_check_reverted" + StreamsLookupErrorDecodeRequestFailed = "decode_request_failed" + StreamsLookupErrorCredentialsNotConfigured = "credentials_not_configured" + StreamsLookupErrorDoMercuryRequest = "do_mercury_request" + StreamsLookupErrorCodeNotNil = "err_code_not_nil" + StreamsLookupErrorCheckCallback = "check_callback" + StreamsLookupErrorPackUserCheckErrorHandler = "pack_user_check_error_handler" + StreamsLookupErrorPackExecuteCallback = "pack_execute_callback" +) + +// Streams versions +const ( + StreamsVersion02 = "v02" + StreamsVersion03 = "v03" +) + +// Metric labels +const ( + LogBufferFlowDirectionIngress = "ingress" + LogBufferFlowDirectionEgress = "egress" + LogBufferFlowDirectionDropped = "dropped" +) // Automation metrics var ( - AutomationLogsInLogBuffer = promauto.NewGauge(prometheus.GaugeOpts{ - Namespace: AutomationLogTriggerNamespace, + // Log Trigger metrics + AutomationLogBufferFlow = promauto.NewCounterVec(prometheus.CounterOpts{ + Namespace: NamespaceAutomationLogTrigger, Name: "num_logs_in_log_buffer", Help: "The total number of logs currently being stored in the log buffer", + }, []string{ + "direction", }) AutomationRecovererMissedLogs = promauto.NewCounter(prometheus.CounterOpts{ - Namespace: AutomationLogTriggerNamespace, + Namespace: NamespaceAutomationLogTrigger, Name: "num_recoverer_missed_logs", Help: "How many valid log triggers were identified as being missed by the recoverer", }) AutomationRecovererPendingPayloads = promauto.NewGauge(prometheus.GaugeOpts{ - Namespace: AutomationLogTriggerNamespace, + Namespace: NamespaceAutomationLogTrigger, Name: "num_recoverer_pending_payloads", Help: "How many log trigger payloads are currently pending in the recoverer", }) AutomationActiveUpkeeps = promauto.NewGauge(prometheus.GaugeOpts{ - Namespace: AutomationLogTriggerNamespace, + Namespace: NamespaceAutomationLogTrigger, Name: "num_active_upkeeps", Help: "How many log trigger upkeeps are currently active", }) AutomationLogProviderLatestBlock = promauto.NewGauge(prometheus.GaugeOpts{ - Namespace: AutomationLogTriggerNamespace, + Namespace: NamespaceAutomationLogTrigger, Name: "log_provider_latest_block", Help: "The latest block number the log provider has seen", }) + + // Streams metrics + AutomationStreamsLookupStep = promauto.NewCounterVec(prometheus.CounterOpts{ + Namespace: NamespaceAutomationStreams, + Name: "streams_lookup_step_count", + Help: "How many times individual steps of the streams lookup process run", + }, []string{ + "step", + }) + AutomationStreamsLookupError = promauto.NewCounterVec(prometheus.CounterOpts{ + Namespace: NamespaceAutomationStreams, + Name: "streams_lookup_error_count", + Help: "Errors occurred during a streams lookup attempt", + }, []string{ + "error", + }) + AutomationStreamsRetries = promauto.NewCounterVec(prometheus.CounterOpts{ + Namespace: NamespaceAutomationStreams, + Name: "streams_retries", + Help: "Count of the times a streams lookup was retried", + }, []string{ + "version", + }) + AutomationStreamsResponses = promauto.NewCounterVec(prometheus.CounterOpts{ + Namespace: NamespaceAutomationStreams, + Name: "streams_responses", + Help: "Count of individual response codes from streams lookup", + }, []string{ + "version", + "status", + }) ) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry.go index bb6bd3c0aff..206932cf543 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry.go @@ -6,6 +6,7 @@ import ( "fmt" "math/big" "net/http" + "strings" "sync" "time" @@ -90,12 +91,7 @@ func NewEvmRegistry( blockSub *BlockSubscriber, finalityDepth uint32, ) *EvmRegistry { - mercuryConfig := &MercuryConfig{ - cred: mc, - Abi: core.StreamsCompatibleABI, - AllowListCache: cache.New(defaultAllowListExpiration, cleanupInterval), - pluginRetryCache: cache.New(defaultPluginRetryExpiration, cleanupInterval), - } + mercuryConfig := NewMercuryConfig(mc, core.StreamsCompatibleABI) hc := http.DefaultClient return &EvmRegistry{ @@ -138,9 +134,16 @@ type MercuryConfig struct { pluginRetryCache *cache.Cache } -func NewMercuryConfig(credentials *types.MercuryCredentials, abi abi.ABI) *MercuryConfig { +func NewMercuryConfig(cred *types.MercuryCredentials, abi abi.ABI) *MercuryConfig { + c := &types.MercuryCredentials{} + if cred != nil { + c.Password = cred.Password + c.Username = cred.Username + c.URL = strings.TrimRight(cred.URL, "/") + c.LegacyURL = strings.TrimRight(cred.LegacyURL, "/") + } return &MercuryConfig{ - cred: credentials, + cred: c, Abi: abi, AllowListCache: cache.New(defaultPluginRetryExpiration, cleanupInterval), pluginRetryCache: cache.New(defaultPluginRetryExpiration, cleanupInterval), diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_test.go index 024c5e79925..4dcb72fde86 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_test.go @@ -8,14 +8,15 @@ import ( "testing" "time" - types2 "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" coreTypes "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + types2 "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/smartcontractkit/chainlink-common/pkg/types" + types3 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" @@ -29,6 +30,49 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider" ) +func TestMercuryConfig_RemoveTrailingSlash(t *testing.T) { + tests := []struct { + Name string + URL string + LegacyURL string + }{ + { + Name: "Both have trailing slashes", + URL: "http://example.com/", + LegacyURL: "http://legacy.example.com/", + }, + { + Name: "One has trailing slashes", + URL: "http://example.com", + LegacyURL: "http://legacy.example.com/", + }, + { + Name: "Neither has trailing slashes", + URL: "http://example.com", + LegacyURL: "http://legacy.example.com", + }, + } + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + mockConfig := NewMercuryConfig(&types.MercuryCredentials{ + URL: test.URL, + LegacyURL: test.LegacyURL, + Username: "user", + Password: "pass", + }, core.StreamsCompatibleABI) + + result := mockConfig.Credentials() + + // Assert that trailing slashes are removed + assert.Equal(t, "http://example.com", result.URL) + assert.Equal(t, "http://legacy.example.com", result.LegacyURL) + assert.Equal(t, "user", result.Username) + assert.Equal(t, "pass", result.Password) + }) + } +} + func TestPollLogs(t *testing.T) { tests := []struct { Name string diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_test.go index 236e89ae671..ea752256232 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_test.go @@ -164,7 +164,7 @@ type Node struct { func (node *Node) AddJob(t *testing.T, spec string) { c := node.App.GetConfig() - jb, err := validate.ValidatedOracleSpecToml(c.OCR2(), c.Insecure(), spec) + jb, err := validate.ValidatedOracleSpecToml(testutils.Context(t), c.OCR2(), c.Insecure(), spec, nil) require.NoError(t, err) err = node.App.AddJobV2(testutils.Context(t), &jb) require.NoError(t, err) diff --git a/core/services/ocr2/plugins/ocr2keeper/util.go b/core/services/ocr2/plugins/ocr2keeper/util.go index 4fdddfe7f02..35bd62eeed8 100644 --- a/core/services/ocr2/plugins/ocr2keeper/util.go +++ b/core/services/ocr2/plugins/ocr2keeper/util.go @@ -18,10 +18,10 @@ import ( ocr2keepers20runner "github.com/smartcontractkit/chainlink-automation/pkg/v2/runner" ocr2keepers21 "github.com/smartcontractkit/chainlink-common/pkg/types/automation" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" evmregistry20 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20" evmregistry21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21" evmregistry21transmit "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit" @@ -86,7 +86,7 @@ func EVMDependencies20( return nil, nil, nil, nil, err } - rAddr := ethkey.MustEIP55Address(spec.OCR2OracleSpec.ContractID).Address() + rAddr := evmtypes.MustEIP55Address(spec.OCR2OracleSpec.ContractID).Address() if registry, err = evmregistry20.NewEVMRegistryService(rAddr, chain, lggr); err != nil { return nil, nil, nil, nil, err } @@ -103,7 +103,7 @@ func EVMDependencies20( } func FilterNamesFromSpec20(spec *job.OCR2OracleSpec) (names []string, err error) { - addr, err := ethkey.NewEIP55Address(spec.ContractID) + addr, err := evmtypes.NewEIP55Address(spec.ContractID) if err != nil { return nil, err } @@ -117,7 +117,7 @@ func EVMDependencies21( } func FilterNamesFromSpec21(spec *job.OCR2OracleSpec) (names []string, err error) { - addr, err := ethkey.NewEIP55Address(spec.ContractID) + addr, err := evmtypes.NewEIP55Address(spec.ContractID) if err != nil { return nil, err } diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go index e7dd3174413..e7688556124 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go @@ -37,7 +37,6 @@ import ( vrf_wrapper "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_coordinator" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" ocr2vrfconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2vrf/config" ) @@ -82,7 +81,7 @@ var ( }, promLabels) promCallbacksToReport = promauto.NewHistogramVec(prometheus.HistogramOpts{ Name: "ocr2vrf_coordinator_callbacks_to_report", - Help: "Number of unfulfilled and and in-flight callbacks fit in current report in reportBlocks", + Help: "Number of unfulfilled and in-flight callbacks fit in current report in reportBlocks", Buckets: counterBuckets, }, promLabels) promBlocksInReport = promauto.NewHistogramVec(prometheus.HistogramOpts{ @@ -1142,16 +1141,16 @@ func filterName(beaconAddress, coordinatorAddress, dkgAddress common.Address) st func FilterNamesFromSpec(spec *job.OCR2OracleSpec) (names []string, err error) { var cfg ocr2vrfconfig.PluginConfig - var beaconAddress, coordinatorAddress, dkgAddress ethkey.EIP55Address + var beaconAddress, coordinatorAddress, dkgAddress evmtypes.EIP55Address if err = json.Unmarshal(spec.PluginConfig.Bytes(), &cfg); err != nil { err = errors.Wrap(err, "failed to unmarshal ocr2vrf plugin config") return nil, err } - if beaconAddress, err = ethkey.NewEIP55Address(spec.ContractID); err == nil { - if coordinatorAddress, err = ethkey.NewEIP55Address(cfg.VRFCoordinatorAddress); err == nil { - if dkgAddress, err = ethkey.NewEIP55Address(cfg.DKGContractAddress); err == nil { + if beaconAddress, err = evmtypes.NewEIP55Address(spec.ContractID); err == nil { + if coordinatorAddress, err = evmtypes.NewEIP55Address(cfg.VRFCoordinatorAddress); err == nil { + if dkgAddress, err = evmtypes.NewEIP55Address(cfg.DKGContractAddress); err == nil { return []string{filterName(beaconAddress.Address(), coordinatorAddress.Address(), dkgAddress.Address())}, nil } } diff --git a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go index 8f743a370c2..769bffd584f 100644 --- a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go @@ -498,7 +498,7 @@ linkEthFeedAddress = "%s" uni.feedAddress.String(), ) t.Log("Creating OCR2VRF job with spec:", jobSpec) - ocrJob2, err2 := validate.ValidatedOracleSpecToml(apps[i].Config.OCR2(), apps[i].Config.Insecure(), jobSpec) + ocrJob2, err2 := validate.ValidatedOracleSpecToml(testutils.Context(t), apps[i].Config.OCR2(), apps[i].Config.Insecure(), jobSpec, nil) require.NoError(t, err2) err2 = apps[i].AddJobV2(ctx, &ocrJob2) require.NoError(t, err2) diff --git a/core/services/ocr2/validate/validate.go b/core/services/ocr2/validate/validate.go index 5846eaa032f..19c8043f25b 100644 --- a/core/services/ocr2/validate/validate.go +++ b/core/services/ocr2/validate/validate.go @@ -1,17 +1,22 @@ package validate import ( + "context" "encoding/hex" "encoding/json" "errors" "fmt" + "os/exec" "github.com/lib/pq" "github.com/pelletier/go-toml" pkgerrors "github.com/pkg/errors" libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/loop/reportingplugins" "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink/v2/core/services/job" dkgconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/dkg/config" lloconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/llo/config" @@ -19,10 +24,11 @@ import ( ocr2vrfconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2vrf/config" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" "github.com/smartcontractkit/chainlink/v2/core/services/relay" + "github.com/smartcontractkit/chainlink/v2/plugins" ) // ValidatedOracleSpecToml validates an oracle spec that came from TOML -func ValidatedOracleSpecToml(config OCR2Config, insConf InsecureConfig, tomlString string) (job.Job, error) { +func ValidatedOracleSpecToml(ctx context.Context, config OCR2Config, insConf InsecureConfig, tomlString string, rc plugins.RegistrarConfig) (job.Job, error) { var jb = job.Job{} var spec job.OCR2OracleSpec tree, err := toml.Load(tomlString) @@ -58,7 +64,7 @@ func ValidatedOracleSpecToml(config OCR2Config, insConf InsecureConfig, tomlStri } } - if err = validateSpec(tree, jb); err != nil { + if err = validateSpec(ctx, tree, jb, rc); err != nil { return jb, err } if err = validateTimingParameters(config, insConf, spec); err != nil { @@ -92,7 +98,7 @@ func validateTimingParameters(ocr2Conf OCR2Config, insConf InsecureConfig, spec return libocr2.SanityCheckLocalConfig(lc) } -func validateSpec(tree *toml.Tree, spec job.Job) error { +func validateSpec(ctx context.Context, tree *toml.Tree, spec job.Job, rc plugins.RegistrarConfig) error { expected, notExpected := ocrcommon.CloneSet(params), ocrcommon.CloneSet(notExpectedParams) if err := ocrcommon.ValidateExplicitlySetKeys(tree, expected, notExpected, "ocr2"); err != nil { return err @@ -117,7 +123,7 @@ func validateSpec(tree *toml.Tree, spec job.Job) error { case types.LLO: return validateOCR2LLOSpec(spec.OCR2OracleSpec.PluginConfig) case types.GenericPlugin: - return validateOCR2GenericPluginSpec(spec.OCR2OracleSpec.PluginConfig) + return validateGenericPluginSpec(ctx, spec.OCR2OracleSpec, rc) case "": return errors.New("no plugin specified") default: @@ -167,9 +173,9 @@ func (o *OCR2GenericPluginConfig) UnmarshalJSON(data []byte) error { return nil } -func validateOCR2GenericPluginSpec(jsonConfig job.JSONConfig) error { +func validateGenericPluginSpec(ctx context.Context, spec *job.OCR2OracleSpec, rc plugins.RegistrarConfig) error { p := OCR2GenericPluginConfig{} - err := json.Unmarshal(jsonConfig.Bytes(), &p) + err := json.Unmarshal(spec.PluginConfig.Bytes(), &p) if err != nil { return err } @@ -178,11 +184,60 @@ func validateOCR2GenericPluginSpec(jsonConfig job.JSONConfig) error { return errors.New("generic config invalid: must provide plugin name") } - if p.TelemetryType == "" { - return errors.New("generic config invalid: must provide telemetry type") + if p.OCRVersion != 2 && p.OCRVersion != 3 { + return errors.New("generic config invalid: only OCR version 2 and 3 are supported") } - return nil + plugEnv := env.NewPlugin(p.PluginName) + + command := p.Command + if command == "" { + command = plugEnv.Cmd.Get() + } + + if command == "" { + return errors.New("generic config invalid: no command found") + } + + _, err = exec.LookPath(command) + if err != nil { + return fmt.Errorf("failed to find binary %q", command) + } + + envVars, err := plugins.ParseEnvFile(plugEnv.Env.Get()) + if err != nil { + return fmt.Errorf("failed to parse env file: %w", err) + } + if len(p.EnvVars) > 0 { + for k, v := range p.EnvVars { + envVars = append(envVars, k+"="+v) + } + } + + loopID := fmt.Sprintf("%s-%s-%s", p.PluginName, spec.ContractID, spec.GetID()) + //Starting and stopping a LOOPP isn't efficient; ideally, we'd initiate the LOOPP once and then reference + //it later to conserve resources. This code will be revisited once BCF-3126 is implemented, and we have + //the ability to reference the LOOPP for future use. + cmdFn, grpcOpts, err := rc.RegisterLOOP(plugins.CmdConfig{ + ID: loopID, + Cmd: command, + Env: envVars, + }) + if err != nil { + return fmt.Errorf("failed to register loop: %w", err) + } + defer rc.UnregisterLOOP(loopID) + + pluginLggr, _ := logger.New() + plugin := reportingplugins.NewLOOPPServiceValidation(pluginLggr, grpcOpts, cmdFn) + + err = plugin.Start(ctx) + if err != nil { + return err + } + defer plugin.Close() + + return plugin.ValidateConfig(ctx, spec.PluginConfig) } func validateDKGSpec(jsonConfig job.JSONConfig) error { diff --git a/core/services/ocr2/validate/validate_test.go b/core/services/ocr2/validate/validate_test.go index 52dbe5f0042..305a727d030 100644 --- a/core/services/ocr2/validate/validate_test.go +++ b/core/services/ocr2/validate/validate_test.go @@ -601,15 +601,42 @@ transmitterID = "0x74103Cf8b436465870b26aa9Fa2F62AD62b22E35" [relayConfig] chainID = 4 -[pluginConfig.coreConfig] +[pluginConfig] `, assertion: func(t *testing.T, os job.Job, err error) { require.Error(t, err) require.ErrorContains(t, err, "must provide plugin name") }, + }, { + name: "Generic plugin config validation - ocr version", + toml: ` +type = "offchainreporting2" +schemaVersion = 1 +name = "dkg" +externalJobID = "6d46d85f-d38c-4f4a-9f00-ac29a25b6330" +maxTaskDuration = "1s" +contractID = "0x3e54dCc49F16411A3aaa4cDbC41A25bCa9763Cee" +ocrKeyBundleID = "08d14c6eed757414d72055d28de6caf06535806c6a14e450f3a2f1c854420e17" +p2pv2Bootstrappers = [ + "12D3KooWSbPRwXY4gxFRJT7LWCnjgGbR4S839nfCRCDgQUiNenxa@127.0.0.1:8000" +] +relay = "evm" +pluginType = "plugin" +transmitterID = "0x74103Cf8b436465870b26aa9Fa2F62AD62b22E35" + +[relayConfig] +chainID = 4 + +[pluginConfig] +PluginName="some random name" +`, + assertion: func(t *testing.T, os job.Job, err error) { + require.Error(t, err) + require.ErrorContains(t, err, "only OCR version 2 and 3 are supported") + }, }, { - name: "Generic plugin config validation - plugin name provided", + name: "Generic plugin config validation - no command", toml: ` type = "offchainreporting2" schemaVersion = 1 @@ -629,15 +656,16 @@ transmitterID = "0x74103Cf8b436465870b26aa9Fa2F62AD62b22E35" chainID = 4 [pluginConfig] -pluginName = "median" +PluginName="some random name" +OCRVersion=2 `, assertion: func(t *testing.T, os job.Job, err error) { require.Error(t, err) - require.ErrorContains(t, err, "must provide telemetry type") + require.ErrorContains(t, err, "no command found") }, }, { - name: "Generic plugin config validation - all provided", + name: "Generic plugin config validation - no binary", toml: ` type = "offchainreporting2" schemaVersion = 1 @@ -657,11 +685,13 @@ transmitterID = "0x74103Cf8b436465870b26aa9Fa2F62AD62b22E35" chainID = 4 [pluginConfig] -pluginName = "median" -telemetryType = "median" +PluginName="some random name" +OCRVersion=2 +Command="some random command" `, assertion: func(t *testing.T, os job.Job, err error) { - require.NoError(t, err) + require.Error(t, err) + require.ErrorContains(t, err, "failed to find binary") }, }, } @@ -674,7 +704,7 @@ telemetryType = "median" tc.overrides(c, s) } }) - s, err := validate.ValidatedOracleSpecToml(c.OCR2(), c.Insecure(), tc.toml) + s, err := validate.ValidatedOracleSpecToml(testutils.Context(t), c.OCR2(), c.Insecure(), tc.toml, nil) tc.assertion(t, s, err) }) } diff --git a/core/services/ocrcommon/arbitrum_block_translator_test.go b/core/services/ocrcommon/arbitrum_block_translator_test.go index 1ad3a6c5950..fa6875fb798 100644 --- a/core/services/ocrcommon/arbitrum_block_translator_test.go +++ b/core/services/ocrcommon/arbitrum_block_translator_test.go @@ -1,6 +1,7 @@ package ocrcommon_test import ( + "database/sql" "math/big" mrand "math/rand" "testing" @@ -10,7 +11,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" "github.com/ethereum/go-ethereum/common" @@ -239,7 +239,7 @@ func generateDeterministicL2Blocks() (heads []evmtypes.Head) { for i := 0; i <= l2max; i++ { head := evmtypes.Head{ Number: int64(i), - L1BlockNumber: null.Int64From(l1BlockNumber), + L1BlockNumber: sql.NullInt64{Int64: l1BlockNumber, Valid: true}, Hash: utils.NewHash(), ParentHash: parentHash, } diff --git a/core/services/ocrcommon/data_source.go b/core/services/ocrcommon/data_source.go index 011b8d0644d..e90382a06af 100644 --- a/core/services/ocrcommon/data_source.go +++ b/core/services/ocrcommon/data_source.go @@ -2,7 +2,9 @@ package ocrcommon import ( "context" + "encoding/json" errjoin "errors" + "fmt" "math/big" "sync" "time" @@ -12,6 +14,7 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/bridges" serializablebig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -101,9 +104,16 @@ func NewInMemoryDataSource(pr pipeline.Runner, jb job.Job, spec pipeline.Spec, l } const defaultCacheFreshness = time.Minute * 5 +const defaultCacheFreshnessAlert = time.Hour * 24 const dataSourceCacheKey = "dscache" -func NewInMemoryDataSourceCache(ds median.DataSource, kvStore job.KVStore, cacheFreshness time.Duration) (median.DataSource, error) { +type DataSourceCacheService interface { + Start(context.Context) error + Close() error + median.DataSource +} + +func NewInMemoryDataSourceCache(ds median.DataSource, kvStore job.KVStore, cacheFreshness time.Duration) (DataSourceCacheService, error) { inMemoryDS, ok := ds.(*inMemoryDataSource) if !ok { return nil, errors.Errorf("unsupported data source type: %T, only inMemoryDataSource supported", ds) @@ -117,8 +127,9 @@ func NewInMemoryDataSourceCache(ds median.DataSource, kvStore job.KVStore, cache kvStore: kvStore, cacheFreshness: cacheFreshness, inMemoryDataSource: inMemoryDS, + chStop: make(chan struct{}), + chDone: make(chan struct{}), } - go func() { dsCache.updater() }() return dsCache, nil } @@ -158,7 +169,7 @@ func (ds *inMemoryDataSource) currentAnswer() (*big.Int, *big.Int) { func (ds *inMemoryDataSource) executeRun(ctx context.Context) (*pipeline.Run, pipeline.TaskRunResults, error) { md, err := bridges.MarshalBridgeMetaData(ds.currentAnswer()) if err != nil { - ds.lggr.Warnw("unable to attach metadata for run", "err", err) + ds.lggr.Warnf("unable to attach metadata for run, err: %v", err) } vars := pipeline.NewVarsFrom(map[string]interface{}{ @@ -224,24 +235,53 @@ type inMemoryDataSourceCache struct { // Even if updates fail, previous values are returned. cacheFreshness time.Duration mu sync.RWMutex + chStop services.StopChan + chDone chan struct{} latestUpdateErr error latestTrrs pipeline.TaskRunResults latestResult pipeline.FinalResult kvStore job.KVStore } +func (ds *inMemoryDataSourceCache) Start(context.Context) error { + go func() { ds.updater() }() + return nil +} + +func (ds *inMemoryDataSourceCache) Close() error { + close(ds.chStop) + <-ds.chDone + return nil +} + // updater periodically updates data source cache. func (ds *inMemoryDataSourceCache) updater() { ticker := time.NewTicker(ds.cacheFreshness) - for ; true; <-ticker.C { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) + updateCache := func() { + ctx, cancel := ds.chStop.CtxCancel(context.WithTimeout(context.Background(), time.Second*10)) + defer cancel() if err := ds.updateCache(ctx); err != nil { - ds.lggr.Warnf("failed to update cache", "err", err) + ds.lggr.Warnf("failed to update cache, err: %v", err) + } + } + + updateCache() + for { + select { + case <-ticker.C: + updateCache() + case <-ds.chStop: + close(ds.chDone) + return } - cancel() } } +type ResultTimePair struct { + Result serializablebig.Big `json:"result"` + Time time.Time `json:"time"` +} + func (ds *inMemoryDataSourceCache) updateCache(ctx context.Context) error { ds.mu.Lock() defer ds.mu.Unlock() @@ -257,7 +297,7 @@ func (ds *inMemoryDataSourceCache) updateCache(ctx context.Context) error { ds.latestUpdateErr = latestUpdateErr // raise log severity if previousUpdateErr != nil { - ds.lggr.Errorf("consecutive cache updates errored: previous err: %w new err: %w", previousUpdateErr, ds.latestUpdateErr) + ds.lggr.Warnf("consecutive cache updates errored: previous err: %v new err: %v", previousUpdateErr, ds.latestUpdateErr) } return errors.Wrapf(ds.latestUpdateErr, "error executing run for spec ID %v", ds.spec.ID) } @@ -270,8 +310,14 @@ func (ds *inMemoryDataSourceCache) updateCache(ctx context.Context) error { } // backup in case data source fails continuously and node gets rebooted - if err = ds.kvStore.Store(dataSourceCacheKey, serializablebig.New(value)); err != nil { - ds.lggr.Errorf("failed to persist latest task run value", err) + + timePairBytes, err := json.Marshal(&ResultTimePair{Result: *serializablebig.New(value), Time: time.Now()}) + if err != nil { + return fmt.Errorf("failed to marshal result time pair, err: %w", err) + } + + if err = ds.kvStore.Store(ctx, dataSourceCacheKey, timePairBytes); err != nil { + ds.lggr.Errorf("failed to persist latest task run value, err: %v", err) } return nil @@ -287,7 +333,7 @@ func (ds *inMemoryDataSourceCache) get(ctx context.Context) (pipeline.FinalResul ds.mu.RUnlock() if err := ds.updateCache(ctx); err != nil { - ds.lggr.Warnf("failed to update cache, returning stale result now", "err", err) + ds.lggr.Warnf("failed to update cache err: %v, returning stale result now, err: %v", err) } ds.mu.RLock() @@ -296,11 +342,24 @@ func (ds *inMemoryDataSourceCache) get(ctx context.Context) (pipeline.FinalResul } func (ds *inMemoryDataSourceCache) Observe(ctx context.Context, timestamp ocr2types.ReportTimestamp) (*big.Int, error) { - var val serializablebig.Big + var resTime ResultTimePair latestResult, latestTrrs := ds.get(ctx) if latestTrrs == nil { - ds.lggr.Errorf("cache is empty, returning persisted value now") - return val.ToInt(), ds.kvStore.Get(dataSourceCacheKey, &val) + ds.lggr.Warnf("cache is empty, returning persisted value now") + + timePairBytes, err := ds.kvStore.Get(ctx, dataSourceCacheKey) + if err != nil { + return nil, fmt.Errorf("failed to get result time pair bytes, err: %w", err) + } + + if err := json.Unmarshal(timePairBytes, &resTime); err != nil { + return nil, fmt.Errorf("failed to unmarshal result time pair bytes, err: %w", err) + } + + if time.Since(resTime.Time) >= defaultCacheFreshnessAlert { + ds.lggr.Errorf("cache hasn't been updated for over %v, latestUpdateErr is: %v", defaultCacheFreshnessAlert, ds.latestUpdateErr) + } + return resTime.Result.ToInt(), nil } setEATelemetry(ds.inMemoryDataSource, latestResult, latestTrrs, ObservationTimestamp{ diff --git a/core/services/ocrcommon/data_source_test.go b/core/services/ocrcommon/data_source_test.go index a921bc060ff..b9b19d30bf2 100644 --- a/core/services/ocrcommon/data_source_test.go +++ b/core/services/ocrcommon/data_source_test.go @@ -1,6 +1,7 @@ package ocrcommon_test import ( + "encoding/json" "fmt" "math/big" "testing" @@ -14,6 +15,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" serializablebig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -74,10 +76,11 @@ func Test_CachedInMemoryDataSourceErrHandling(t *testing.T) { runner := pipelinemocks.NewRunner(t) ds := ocrcommon.NewInMemoryDataSource(runner, job.Job{}, pipeline.Spec{}, logger.TestLogger(t)) mockKVStore := mocks.KVStore{} - mockKVStore.On("Store", mock.Anything, mock.Anything).Return(nil) - mockKVStore.On("Get", mock.Anything, mock.AnythingOfType("*big.Big")).Return(nil) + mockKVStore.On("Store", mock.Anything, mock.Anything, mock.Anything).Return(nil) + mockKVStore.On("Get", mock.Anything, mock.Anything).Return(nil, nil) dsCache, err := ocrcommon.NewInMemoryDataSourceCache(ds, &mockKVStore, time.Second*2) require.NoError(t, err) + servicetest.Run(t, dsCache) mockVal := int64(1) // Test if Observe notices that cache updater failed and can refresh the cache on its own @@ -98,26 +101,26 @@ func Test_CachedInMemoryDataSourceErrHandling(t *testing.T) { }) t.Run("test total updater fail with persisted value recovery", func(t *testing.T) { - persistedVal := big.NewInt(1337) runner := pipelinemocks.NewRunner(t) ds := ocrcommon.NewInMemoryDataSource(runner, job.Job{}, pipeline.Spec{}, logger.TestLogger(t)) mockKVStore := mocks.KVStore{} - mockKVStore.On("Get", mock.Anything, mock.AnythingOfType("*big.Big")).Return(nil).Run(func(args mock.Arguments) { - arg := args.Get(1).(*serializablebig.Big) - arg.ToInt().Set(persistedVal) - }) + persistedVal := serializablebig.NewI(1337) + + result, err := json.Marshal(&ocrcommon.ResultTimePair{Result: *persistedVal, Time: time.Now()}) + assert.NoError(t, err) + mockKVStore.On("Get", mock.Anything, mock.Anything).Return(result, nil) // set updater to a long time so that it doesn't log errors after the test is done dsCache, err := ocrcommon.NewInMemoryDataSourceCache(ds, &mockKVStore, time.Hour*100) require.NoError(t, err) changeResultValue(runner, "-1", true, false) + servicetest.Run(t, dsCache) time.Sleep(time.Millisecond * 100) val, err := dsCache.Observe(testutils.Context(t), types.ReportTimestamp{}) require.NoError(t, err) assert.Equal(t, persistedVal.String(), val.String()) - }) t.Run("test total updater fail with no persisted value ", func(t *testing.T) { @@ -125,12 +128,13 @@ func Test_CachedInMemoryDataSourceErrHandling(t *testing.T) { ds := ocrcommon.NewInMemoryDataSource(runner, job.Job{}, pipeline.Spec{}, logger.TestLogger(t)) mockKVStore := mocks.KVStore{} - mockKVStore.On("Get", mock.Anything, mock.AnythingOfType("*big.Big")).Return(nil).Return(assert.AnError) + mockKVStore.On("Get", mock.Anything, mock.Anything).Return(nil, assert.AnError) // set updater to a long time so that it doesn't log errors after the test is done dsCache, err := ocrcommon.NewInMemoryDataSourceCache(ds, &mockKVStore, time.Hour*100) require.NoError(t, err) changeResultValue(runner, "-1", true, false) + servicetest.Run(t, dsCache) time.Sleep(time.Millisecond * 100) _, err = dsCache.Observe(testutils.Context(t), types.ReportTimestamp{}) diff --git a/core/services/ocrcommon/telemetry_test.go b/core/services/ocrcommon/telemetry_test.go index caa8ccfcc01..e7a59622d97 100644 --- a/core/services/ocrcommon/telemetry_test.go +++ b/core/services/ocrcommon/telemetry_test.go @@ -19,11 +19,11 @@ import ( mercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" mercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/mocks" @@ -126,7 +126,7 @@ func TestGetContract(t *testing.T) { job: &j, lggr: nil, } - contractAddress := ethkey.EIP55Address(utils.RandomAddress().String()) + contractAddress := evmtypes.EIP55Address(utils.RandomAddress().String()) j.Type = job.Type(pipeline.OffchainReportingJobType) j.OCROracleSpec.ContractAddress = contractAddress @@ -208,7 +208,7 @@ func TestSendEATelemetry(t *testing.T) { jb := job.Job{ Type: job.Type(pipeline.OffchainReportingJobType), OCROracleSpec: &job.OCROracleSpec{ - ContractAddress: ethkey.EIP55AddressFromAddress(feedAddress), + ContractAddress: evmtypes.EIP55AddressFromAddress(feedAddress), CaptureEATelemetry: true, EVMChainID: (*ubig.Big)(big.NewInt(9)), }, diff --git a/core/services/p2p/peer.go b/core/services/p2p/peer.go index 2ed84f6a3f1..e4a6e52f930 100644 --- a/core/services/p2p/peer.go +++ b/core/services/p2p/peer.go @@ -102,6 +102,10 @@ func NewPeer(cfg PeerConfig, lggr logger.Logger) (*peer, error) { }, nil } +func (p *peer) ID() ragetypes.PeerID { + return p.myID +} + func (p *peer) UpdateConnections(peers map[ragetypes.PeerID]p2ptypes.StreamConfig) error { p.lggr.Infow("updating peer addresses", "peers", peers) if !p.isBootstrap { diff --git a/core/services/p2p/types/mocks/peer.go b/core/services/p2p/types/mocks/peer.go index ac4e4eee73d..23824b99a44 100644 --- a/core/services/p2p/types/mocks/peer.go +++ b/core/services/p2p/types/mocks/peer.go @@ -54,6 +54,26 @@ func (_m *Peer) HealthReport() map[string]error { return r0 } +// ID provides a mock function with given fields: +func (_m *Peer) ID() ragep2ptypes.PeerID { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for ID") + } + + var r0 ragep2ptypes.PeerID + if rf, ok := ret.Get(0).(func() ragep2ptypes.PeerID); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(ragep2ptypes.PeerID) + } + } + + return r0 +} + // Name provides a mock function with given fields: func (_m *Peer) Name() string { ret := _m.Called() diff --git a/core/services/p2p/types/mocks/signer.go b/core/services/p2p/types/mocks/signer.go new file mode 100644 index 00000000000..274116be57c --- /dev/null +++ b/core/services/p2p/types/mocks/signer.go @@ -0,0 +1,54 @@ +// Code generated by mockery v2.38.0. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// Signer is an autogenerated mock type for the Signer type +type Signer struct { + mock.Mock +} + +// Sign provides a mock function with given fields: data +func (_m *Signer) Sign(data []byte) ([]byte, error) { + ret := _m.Called(data) + + if len(ret) == 0 { + panic("no return value specified for Sign") + } + + var r0 []byte + var r1 error + if rf, ok := ret.Get(0).(func([]byte) ([]byte, error)); ok { + return rf(data) + } + if rf, ok := ret.Get(0).(func([]byte) []byte); ok { + r0 = rf(data) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + if rf, ok := ret.Get(1).(func([]byte) error); ok { + r1 = rf(data) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewSigner creates a new instance of Signer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewSigner(t interface { + mock.TestingT + Cleanup(func()) +}) *Signer { + mock := &Signer{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/services/p2p/types/types.go b/core/services/p2p/types/types.go index 0f395d75409..837e075860a 100644 --- a/core/services/p2p/types/types.go +++ b/core/services/p2p/types/types.go @@ -7,11 +7,16 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" ) +const PeerIDLength = 32 + +type PeerID = ragetypes.PeerID + //go:generate mockery --quiet --name Peer --output ./mocks/ --case=underscore type Peer interface { services.Service - UpdateConnections(peers map[ragetypes.PeerID]StreamConfig) error - Send(peerID ragetypes.PeerID, msg []byte) error + ID() PeerID + UpdateConnections(peers map[PeerID]StreamConfig) error + Send(peerID PeerID, msg []byte) error Receive() <-chan Message } @@ -21,8 +26,13 @@ type PeerWrapper interface { GetPeer() Peer } +//go:generate mockery --quiet --name Signer --output ./mocks/ --case=underscore +type Signer interface { + Sign(data []byte) ([]byte, error) +} + type Message struct { - Sender ragetypes.PeerID + Sender PeerID Payload []byte } diff --git a/core/services/p2p/wrapper/wrapper.go b/core/services/p2p/wrapper/wrapper.go index 138d1ef21fc..fd47c6c2dd2 100644 --- a/core/services/p2p/wrapper/wrapper.go +++ b/core/services/p2p/wrapper/wrapper.go @@ -2,6 +2,7 @@ package wrapper import ( "context" + "crypto/ed25519" "fmt" "github.com/prometheus/client_golang/prometheus" @@ -20,10 +21,12 @@ type peerWrapper struct { peer types.Peer keystoreP2P keystore.P2P p2pConfig config.P2P + privateKey ed25519.PrivateKey lggr logger.Logger } var _ types.PeerWrapper = &peerWrapper{} +var _ types.Signer = &peerWrapper{} func NewExternalPeerWrapper(keystoreP2P keystore.P2P, p2pConfig config.P2P, lggr logger.Logger) *peerWrapper { return &peerWrapper{ @@ -76,7 +79,7 @@ func convertBootstrapperLocators(bootstrappers []commontypes.BootstrapperLocator for i, a := range b.Addrs { addrs[i] = ragetypes.Address(a) } - var rageID ragetypes.PeerID + var rageID types.PeerID err := rageID.UnmarshalText([]byte(b.PeerID)) if err != nil { return nil, fmt.Errorf("failed to unmarshal v2 peer ID (%q) from BootstrapperLocator: %w", b.PeerID, err) @@ -94,6 +97,7 @@ func (e *peerWrapper) Start(ctx context.Context) error { if err != nil { return err } + e.privateKey = cfg.PrivateKey e.lggr.Info("Starting external P2P peer") peer, err := p2p.NewPeer(cfg, e.lggr) if err != nil { @@ -118,3 +122,10 @@ func (e *peerWrapper) HealthReport() map[string]error { func (e *peerWrapper) Name() string { return "PeerWrapper" } + +func (e *peerWrapper) Sign(msg []byte) ([]byte, error) { + if e.privateKey == nil { + return nil, fmt.Errorf("private key not set") + } + return ed25519.Sign(e.privateKey, msg), nil +} diff --git a/core/services/pg/connection.go b/core/services/pg/connection.go index 3fcfd3f4ad4..79d74c6e610 100644 --- a/core/services/pg/connection.go +++ b/core/services/pg/connection.go @@ -82,8 +82,7 @@ func NewConnection(uri string, dialect dialects.DialectName, config ConnectionCo if _, err = db.Exec(stmt); err != nil { return nil, err } - db.SetMaxOpenConns(config.MaxOpenConns()) - db.SetMaxIdleConns(config.MaxIdleConns()) + setMaxConns(db, config) if os.Getenv("SKIP_PG_VERSION_CHECK") != "true" { if err := checkVersion(db, MinRequiredPGVersion); err != nil { @@ -94,6 +93,33 @@ func NewConnection(uri string, dialect dialects.DialectName, config ConnectionCo return db, disallowReplica(db) } +func setMaxConns(db *sqlx.DB, config ConnectionConfig) { + db.SetMaxOpenConns(config.MaxOpenConns()) + db.SetMaxIdleConns(config.MaxIdleConns()) + + // HACK: In the case of mercury jobs, one conn is needed per job for good + // performance. Most nops will forget to increase the defaults to account + // for this so we detect it here instead. + // + // This problem will be solved by replacing mercury with parallel + // compositions (llo plugin). + // + // See: https://smartcontract-it.atlassian.net/browse/MERC-3654 + var cnt int + if err := db.Get(&cnt, `SELECT COUNT(*) FROM ocr2_oracle_specs WHERE plugin_type = 'mercury'`); err != nil { + log.Printf("Error checking mercury jobs: %s", err.Error()) + return + } + if cnt > config.MaxOpenConns() { + log.Printf("Detected %d mercury jobs, increasing max open connections from %d to %d", cnt, config.MaxOpenConns(), cnt) + db.SetMaxOpenConns(cnt) + } + if cnt > config.MaxIdleConns() { + log.Printf("Detected %d mercury jobs, increasing max idle connections from %d to %d", cnt, config.MaxIdleConns(), cnt) + db.SetMaxIdleConns(cnt) + } +} + type Getter interface { Get(dest interface{}, query string, args ...interface{}) error } diff --git a/core/services/pipeline/common.go b/core/services/pipeline/common.go index a07319643c3..a88b2165a2e 100644 --- a/core/services/pipeline/common.go +++ b/core/services/pipeline/common.go @@ -1,12 +1,8 @@ package pipeline import ( - "bytes" "context" - "database/sql/driver" - "encoding/json" "errors" - "math/big" "net/url" "reflect" "sort" @@ -14,7 +10,6 @@ import ( "strings" "time" - "github.com/ethereum/go-ethereum/common" "github.com/google/uuid" "github.com/mitchellh/mapstructure" pkgerrors "github.com/pkg/errors" @@ -22,10 +17,10 @@ import ( commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" cutils "github.com/smartcontractkit/chainlink-common/pkg/utils" + "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/logger" cnull "github.com/smartcontractkit/chainlink/v2/core/null" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) const ( @@ -71,6 +66,7 @@ type ( MaxRunDuration() time.Duration ReaperInterval() time.Duration ReaperThreshold() time.Duration + VerboseLogging() bool } BridgeConfig interface { @@ -139,8 +135,8 @@ type Result struct { } // OutputDB dumps a single result output for a pipeline_run or pipeline_task_run -func (result Result) OutputDB() JSONSerializable { - return JSONSerializable{Val: result.Value, Valid: !(result.Value == nil || (reflect.ValueOf(result.Value).Kind() == reflect.Ptr && reflect.ValueOf(result.Value).IsNil()))} +func (result Result) OutputDB() jsonserializable.JSONSerializable { + return jsonserializable.JSONSerializable{Val: result.Value, Valid: !(result.Value == nil || (reflect.ValueOf(result.Value).Kind() == reflect.Ptr && reflect.ValueOf(result.Value).IsNil()))} } // ErrorDB dumps a single result error for a pipeline_task_run @@ -200,8 +196,8 @@ func (result FinalResult) SingularResult() (Result, error) { // TaskSpecID will always be non-zero type TaskRunResult struct { ID uuid.UUID - Task Task - TaskRun TaskRun + Task Task `json:"-"` + TaskRun TaskRun `json:"-"` Result Result Attempts uint CreatedAt time.Time @@ -267,106 +263,6 @@ func (trrs *TaskRunResults) GetNextTaskOf(task TaskRunResult) *TaskRunResult { return nil } -type JSONSerializable struct { - Val interface{} - Valid bool -} - -func reinterpetJsonNumbers(val interface{}) (interface{}, error) { - switch v := val.(type) { - case json.Number: - return getJsonNumberValue(v) - case []interface{}: - s := make([]interface{}, len(v)) - for i, vv := range v { - ival, ierr := reinterpetJsonNumbers(vv) - if ierr != nil { - return nil, ierr - } - s[i] = ival - } - return s, nil - case map[string]interface{}: - m := make(map[string]interface{}, len(v)) - for k, vv := range v { - ival, ierr := reinterpetJsonNumbers(vv) - if ierr != nil { - return nil, ierr - } - m[k] = ival - } - return m, nil - } - return val, nil -} - -// UnmarshalJSON implements custom unmarshaling logic -func (js *JSONSerializable) UnmarshalJSON(bs []byte) error { - if js == nil { - *js = JSONSerializable{} - } - if len(bs) == 0 { - js.Valid = false - return nil - } - - var decoded interface{} - d := json.NewDecoder(bytes.NewReader(bs)) - d.UseNumber() - if err := d.Decode(&decoded); err != nil { - return err - } - - if decoded != nil { - reinterpreted, err := reinterpetJsonNumbers(decoded) - if err != nil { - return err - } - - *js = JSONSerializable{ - Valid: true, - Val: reinterpreted, - } - } - - return nil -} - -// MarshalJSON implements custom marshaling logic -func (js JSONSerializable) MarshalJSON() ([]byte, error) { - if !js.Valid { - return json.Marshal(nil) - } - jsWithHex := replaceBytesWithHex(js.Val) - return json.Marshal(jsWithHex) -} - -func (js *JSONSerializable) Scan(value interface{}) error { - if value == nil { - *js = JSONSerializable{} - return nil - } - bytes, ok := value.([]byte) - if !ok { - return pkgerrors.Errorf("JSONSerializable#Scan received a value of type %T", value) - } - if js == nil { - *js = JSONSerializable{} - } - return js.UnmarshalJSON(bytes) -} - -func (js JSONSerializable) Value() (driver.Value, error) { - if !js.Valid { - return nil, nil - } - return js.MarshalJSON() -} - -func (js *JSONSerializable) Empty() bool { - return js == nil || !js.Valid -} - type TaskType string func (t TaskType) String() string { @@ -588,100 +484,6 @@ func SelectGasLimit(ge config.GasEstimator, jobType string, specGasLimit *uint32 return ge.LimitDefault() } -// replaceBytesWithHex replaces all []byte with hex-encoded strings -func replaceBytesWithHex(val interface{}) interface{} { - switch value := val.(type) { - case nil: - return value - case []byte: - return utils.StringToHex(string(value)) - case common.Address: - return value.Hex() - case common.Hash: - return value.Hex() - case [][]byte: - var list []string - for _, bytes := range value { - list = append(list, utils.StringToHex(string(bytes))) - } - return list - case []common.Address: - var list []string - for _, addr := range value { - list = append(list, addr.Hex()) - } - return list - case []common.Hash: - var list []string - for _, hash := range value { - list = append(list, hash.Hex()) - } - return list - case []interface{}: - if value == nil { - return value - } - var list []interface{} - for _, item := range value { - list = append(list, replaceBytesWithHex(item)) - } - return list - case map[string]interface{}: - if value == nil { - return value - } - m := make(map[string]interface{}) - for k, v := range value { - m[k] = replaceBytesWithHex(v) - } - return m - default: - // This handles solidity types: bytes1..bytes32, - // which map to [1]uint8..[32]uint8 when decoded. - // We persist them as hex strings, and we know ETH ABI encoders - // can parse hex strings, same as BytesParam does. - if s := uint8ArrayToSlice(value); s != nil { - return replaceBytesWithHex(s) - } - return value - } -} - -// uint8ArrayToSlice converts [N]uint8 array to slice. -func uint8ArrayToSlice(arr interface{}) interface{} { - t := reflect.TypeOf(arr) - if t.Kind() != reflect.Array || t.Elem().Kind() != reflect.Uint8 { - return nil - } - v := reflect.ValueOf(arr) - s := reflect.MakeSlice(reflect.SliceOf(t.Elem()), v.Len(), v.Len()) - reflect.Copy(s, v) - return s.Interface() -} - -func getJsonNumberValue(value json.Number) (interface{}, error) { - var result interface{} - - bn, ok := new(big.Int).SetString(value.String(), 10) - if ok { - if bn.IsInt64() { - result = bn.Int64() - } else if bn.IsUint64() { - result = bn.Uint64() - } else { - result = bn - } - } else { - f, err := value.Float64() - if err != nil { - return nil, pkgerrors.Errorf("failed to parse json.Value: %v", err) - } - result = f - } - - return result, nil -} - func selectBlock(block string) (string, error) { if block == "" { return "latest", nil diff --git a/core/services/pipeline/common_test.go b/core/services/pipeline/common_test.go index ea3f4d90c3b..f94167d723c 100644 --- a/core/services/pipeline/common_test.go +++ b/core/services/pipeline/common_test.go @@ -1,12 +1,9 @@ package pipeline_test import ( - "encoding/json" - "math/big" "testing" "time" - "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -175,97 +172,6 @@ func TestUnmarshalTaskFromMap(t *testing.T) { } } -func TestMarshalJSONSerializable_replaceBytesWithHex(t *testing.T) { - t.Parallel() - - type jsm = map[string]interface{} - - toJSONSerializable := func(val jsm) *pipeline.JSONSerializable { - return &pipeline.JSONSerializable{ - Valid: true, - Val: val, - } - } - - var ( - testAddr1 = common.HexToAddress("0x2ab9a2Dc53736b361b72d900CdF9F78F9406f111") - testAddr2 = common.HexToAddress("0x2ab9a2Dc53736b361b72d900CdF9F78F9406f222") - testHash1 = common.HexToHash("0x317cfd032b5d6657995f17fe768f7cc4ea0ada27ad421c4caa685a9071eaf111") - testHash2 = common.HexToHash("0x317cfd032b5d6657995f17fe768f7cc4ea0ada27ad421c4caa685a9071eaf222") - ) - - tests := []struct { - name string - input *pipeline.JSONSerializable - expected string - err error - }{ - {"invalid input", &pipeline.JSONSerializable{Valid: false}, "null", nil}, - {"empty object", toJSONSerializable(jsm{}), "{}", nil}, - {"byte slice", toJSONSerializable(jsm{"slice": []byte{0x10, 0x20, 0x30}}), - `{"slice":"0x102030"}`, nil}, - {"address", toJSONSerializable(jsm{"addr": testAddr1}), - `{"addr":"0x2aB9a2dc53736B361B72d900cDF9f78f9406f111"}`, nil}, - {"hash", toJSONSerializable(jsm{"hash": testHash1}), - `{"hash":"0x317cfd032b5d6657995f17fe768f7cc4ea0ada27ad421c4caa685a9071eaf111"}`, nil}, - {"slice of byte slice", toJSONSerializable(jsm{"slices": [][]byte{{0x10, 0x11, 0x12}, {0x20, 0x21, 0x22}}}), - `{"slices":["0x101112","0x202122"]}`, nil}, - {"slice of addresses", toJSONSerializable(jsm{"addresses": []common.Address{testAddr1, testAddr2}}), - `{"addresses":["0x2aB9a2dc53736B361B72d900cDF9f78f9406f111","0x2aB9A2Dc53736b361b72D900CDf9f78f9406F222"]}`, nil}, - {"slice of hashes", toJSONSerializable(jsm{"hashes": []common.Hash{testHash1, testHash2}}), - `{"hashes":["0x317cfd032b5d6657995f17fe768f7cc4ea0ada27ad421c4caa685a9071eaf111","0x317cfd032b5d6657995f17fe768f7cc4ea0ada27ad421c4caa685a9071eaf222"]}`, nil}, - {"slice of interfaces", toJSONSerializable(jsm{"ifaces": []interface{}{[]byte{0x10, 0x11, 0x12}, []byte{0x20, 0x21, 0x22}}}), - `{"ifaces":["0x101112","0x202122"]}`, nil}, - {"map", toJSONSerializable(jsm{"map": jsm{"slice": []byte{0x10, 0x11, 0x12}, "addr": testAddr1}}), - `{"map":{"addr":"0x2aB9a2dc53736B361B72d900cDF9f78f9406f111","slice":"0x101112"}}`, nil}, - {"byte array 4", toJSONSerializable(jsm{"ba4": [4]byte{1, 2, 3, 4}}), - `{"ba4":"0x01020304"}`, nil}, - {"byte array 8", toJSONSerializable(jsm{"ba8": [8]uint8{1, 2, 3, 4, 5, 6, 7, 8}}), - `{"ba8":"0x0102030405060708"}`, nil}, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - bytes, err := test.input.MarshalJSON() - assert.Equal(t, test.expected, string(bytes)) - assert.Equal(t, test.err, errors.Cause(err)) - }) - } -} - -func TestUnmarshalJSONSerializable(t *testing.T) { - t.Parallel() - - big, ok := new(big.Int).SetString("18446744073709551616", 10) - assert.True(t, ok) - - tests := []struct { - name, input string - expected interface{} - }{ - {"null json", `null`, nil}, - {"bool", `true`, true}, - {"string", `"foo"`, "foo"}, - {"object with int", `{"foo": 42}`, map[string]interface{}{"foo": int64(42)}}, - {"object with float", `{"foo": 3.14}`, map[string]interface{}{"foo": float64(3.14)}}, - {"object with big int", `{"foo": 18446744073709551616}`, map[string]interface{}{"foo": big}}, - {"slice", `[42, 3.14]`, []interface{}{int64(42), float64(3.14)}}, - {"nested map", `{"m": {"foo": 42}}`, map[string]interface{}{"m": map[string]interface{}{"foo": int64(42)}}}, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - var i pipeline.JSONSerializable - err := json.Unmarshal([]byte(test.input), &i) - require.NoError(t, err) - if test.expected != nil { - assert.True(t, i.Valid) - assert.Equal(t, test.expected, i.Val) - } - }) - } -} - func TestCheckInputs(t *testing.T) { t.Parallel() diff --git a/core/services/pipeline/getters.go b/core/services/pipeline/getters.go index 64e2c057306..bbeb0050d68 100644 --- a/core/services/pipeline/getters.go +++ b/core/services/pipeline/getters.go @@ -8,6 +8,8 @@ import ( "time" "github.com/pkg/errors" + + "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" ) // GetterFunc is a function that either returns a value or an error. @@ -131,7 +133,7 @@ func JSONWithVarExprs(jsExpr string, vars Vars, allowErrors bool) GetterFunc { if err := jd.Decode(&val); err != nil { return nil, errors.Wrapf(ErrBadInput, "while unmarshalling JSON: %v; js: %s", err, string(replaced)) } - reinterpreted, err := reinterpetJsonNumbers(val) + reinterpreted, err := jsonserializable.ReinterpretJSONNumbers(val) if err != nil { return nil, errors.Wrapf(ErrBadInput, "while processing json.Number: %v; js: %s", err, string(replaced)) } diff --git a/core/services/pipeline/mocks/config.go b/core/services/pipeline/mocks/config.go index 581a84dc049..b29a3cc9e11 100644 --- a/core/services/pipeline/mocks/config.go +++ b/core/services/pipeline/mocks/config.go @@ -104,6 +104,24 @@ func (_m *Config) ReaperThreshold() time.Duration { return r0 } +// VerboseLogging provides a mock function with given fields: +func (_m *Config) VerboseLogging() bool { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for VerboseLogging") + } + + var r0 bool + if rf, ok := ret.Get(0).(func() bool); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + // NewConfig creates a new instance of Config. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewConfig(t interface { diff --git a/core/services/pipeline/models.go b/core/services/pipeline/models.go index d2c722f98b8..e0596700e08 100644 --- a/core/services/pipeline/models.go +++ b/core/services/pipeline/models.go @@ -14,6 +14,7 @@ import ( "go.uber.org/multierr" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) @@ -44,22 +45,22 @@ func (s *Spec) ParsePipeline() (*Pipeline, error) { } type Run struct { - ID int64 `json:"-"` - PipelineSpecID int32 `json:"-"` - PipelineSpec Spec `json:"pipelineSpec"` - Meta JSONSerializable `json:"meta"` + ID int64 `json:"-"` + PipelineSpecID int32 `json:"-"` + PipelineSpec Spec `json:"pipelineSpec"` + Meta jsonserializable.JSONSerializable `json:"meta"` // The errors are only ever strings // DB example: [null, null, "my error"] - AllErrors RunErrors `json:"all_errors"` - FatalErrors RunErrors `json:"fatal_errors"` - Inputs JSONSerializable `json:"inputs"` + AllErrors RunErrors `json:"all_errors"` + FatalErrors RunErrors `json:"fatal_errors"` + Inputs jsonserializable.JSONSerializable `json:"inputs"` // Its expected that Output.Val is of type []interface{}. // DB example: [1234, {"a": 10}, null] - Outputs JSONSerializable `json:"outputs"` - CreatedAt time.Time `json:"createdAt"` - FinishedAt null.Time `json:"finishedAt"` - PipelineTaskRuns []TaskRun `json:"taskRuns"` - State RunStatus `json:"state"` + Outputs jsonserializable.JSONSerializable `json:"outputs"` + CreatedAt time.Time `json:"createdAt"` + FinishedAt null.Time `json:"finishedAt"` + PipelineTaskRuns []TaskRun `json:"taskRuns"` + State RunStatus `json:"state"` Pending bool // FailSilently is used to signal that a task with the failEarly flag has failed, and we want to not put this in the db @@ -261,16 +262,16 @@ func (rr ResumeRequest) ToResult() (Result, error) { } type TaskRun struct { - ID uuid.UUID `json:"id"` - Type TaskType `json:"type"` - PipelineRun Run `json:"-"` - PipelineRunID int64 `json:"-"` - Output JSONSerializable `json:"output"` - Error null.String `json:"error"` - CreatedAt time.Time `json:"createdAt"` - FinishedAt null.Time `json:"finishedAt"` - Index int32 `json:"index"` - DotID string `json:"dotId"` + ID uuid.UUID `json:"id"` + Type TaskType `json:"type"` + PipelineRun Run `json:"-"` + PipelineRunID int64 `json:"-"` + Output jsonserializable.JSONSerializable `json:"output"` + Error null.String `json:"error"` + CreatedAt time.Time `json:"createdAt"` + FinishedAt null.Time `json:"finishedAt"` + Index int32 `json:"index"` + DotID string `json:"dotId"` // Used internally for sorting completed results task Task diff --git a/core/services/pipeline/models_test.go b/core/services/pipeline/models_test.go index 1356f5e1f14..e32dea26275 100644 --- a/core/services/pipeline/models_test.go +++ b/core/services/pipeline/models_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" ) @@ -38,7 +39,7 @@ func TestRun_Status(t *testing.T) { run: &pipeline.Run{ AllErrors: pipeline.RunErrors{}, FatalErrors: pipeline.RunErrors{}, - Outputs: pipeline.JSONSerializable{}, + Outputs: jsonserializable.JSONSerializable{}, FinishedAt: null.Time{}, }, want: pipeline.RunStatusRunning, @@ -48,7 +49,7 @@ func TestRun_Status(t *testing.T) { run: &pipeline.Run{ AllErrors: pipeline.RunErrors{}, FatalErrors: pipeline.RunErrors{}, - Outputs: pipeline.JSONSerializable{Val: []interface{}{10, 10}, Valid: true}, + Outputs: jsonserializable.JSONSerializable{Val: []interface{}{10, 10}, Valid: true}, FinishedAt: now, }, want: pipeline.RunStatusCompleted, @@ -58,7 +59,7 @@ func TestRun_Status(t *testing.T) { run: &pipeline.Run{ AllErrors: pipeline.RunErrors{null.StringFrom(errors.New("fail").Error())}, FatalErrors: pipeline.RunErrors{null.StringFrom(errors.New("fail").Error())}, - Outputs: pipeline.JSONSerializable{}, + Outputs: jsonserializable.JSONSerializable{}, FinishedAt: null.Time{}, }, want: pipeline.RunStatusErrored, @@ -86,7 +87,7 @@ func TestRun_StringOutputs(t *testing.T) { t.Run("invalid outputs", func(t *testing.T) { run := &pipeline.Run{ - Outputs: pipeline.JSONSerializable{ + Outputs: jsonserializable.JSONSerializable{ Valid: false, }, } @@ -116,7 +117,7 @@ func TestRun_StringOutputs(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { run := &pipeline.Run{ - Outputs: pipeline.JSONSerializable{ + Outputs: jsonserializable.JSONSerializable{ Valid: true, Val: []interface{}{tc.val}, }, diff --git a/core/services/pipeline/orm.go b/core/services/pipeline/orm.go index 70ff244ab3c..602746ffffb 100644 --- a/core/services/pipeline/orm.go +++ b/core/services/pipeline/orm.go @@ -123,7 +123,7 @@ func NewORM(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig, jobPipelineMaxSucce } func (o *orm) Start(_ context.Context) error { - return o.StartOnce("pipeline.ORM", func() error { + return o.StartOnce("PipelineORM", func() error { var msg string if o.maxSuccessfulRuns == 0 { msg = "Pipeline runs saving is disabled for all jobs: MaxSuccessfulRuns=0" @@ -136,7 +136,7 @@ func (o *orm) Start(_ context.Context) error { } func (o *orm) Close() error { - return o.StopOnce("pipeline.ORM", func() error { + return o.StopOnce("PipelineORM", func() error { o.cncl() o.wg.Wait() return nil diff --git a/core/services/pipeline/orm_test.go b/core/services/pipeline/orm_test.go index 5578bdcd4ca..6a6efa0dc3a 100644 --- a/core/services/pipeline/orm_test.go +++ b/core/services/pipeline/orm_test.go @@ -13,6 +13,7 @@ import ( "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" + "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -96,7 +97,7 @@ func mustInsertPipelineRun(t *testing.T, orm pipeline.ORM) pipeline.Run { run := pipeline.Run{ State: pipeline.RunStatusRunning, - Outputs: pipeline.JSONSerializable{}, + Outputs: jsonserializable.JSONSerializable{}, AllErrors: pipeline.RunErrors{}, FatalErrors: pipeline.RunErrors{}, FinishedAt: null.Time{}, @@ -131,7 +132,7 @@ answer2 [type=bridge name=election_winner index=1]; run := &pipeline.Run{ PipelineSpecID: specID, State: pipeline.RunStatusRunning, - Outputs: pipeline.JSONSerializable{}, + Outputs: jsonserializable.JSONSerializable{}, CreatedAt: time.Now(), } @@ -158,7 +159,7 @@ func TestInsertFinishedRuns(t *testing.T) { FatalErrors: pipeline.RunErrors{}, CreatedAt: now, FinishedAt: null.Time{}, - Outputs: pipeline.JSONSerializable{}, + Outputs: jsonserializable.JSONSerializable{}, } require.NoError(t, orm.InsertRun(&r)) @@ -177,13 +178,13 @@ func TestInsertFinishedRuns(t *testing.T) { PipelineRunID: r.ID, Type: "median", DotID: "answer2", - Output: pipeline.JSONSerializable{Val: 1, Valid: true}, + Output: jsonserializable.JSONSerializable{Val: 1, Valid: true}, CreatedAt: now, FinishedAt: null.TimeFrom(now.Add(200 * time.Millisecond)), }, } r.FinishedAt = null.TimeFrom(now.Add(300 * time.Millisecond)) - r.Outputs = pipeline.JSONSerializable{ + r.Outputs = jsonserializable.JSONSerializable{ Val: "stuff", Valid: true, } @@ -221,7 +222,7 @@ func Test_PipelineORM_StoreRun_ShouldUpsert(t *testing.T) { PipelineRunID: run.ID, Type: "median", DotID: "answer2", - Output: pipeline.JSONSerializable{Val: 1, Valid: true}, + Output: jsonserializable.JSONSerializable{Val: 1, Valid: true}, CreatedAt: now, FinishedAt: null.TimeFrom(now), }, @@ -252,7 +253,7 @@ func Test_PipelineORM_StoreRun_ShouldUpsert(t *testing.T) { PipelineRunID: run.ID, Type: "bridge", DotID: "ds1", - Output: pipeline.JSONSerializable{Val: 2, Valid: true}, + Output: jsonserializable.JSONSerializable{Val: 2, Valid: true}, CreatedAt: now, FinishedAt: null.TimeFrom(now), }, @@ -299,7 +300,7 @@ func Test_PipelineORM_StoreRun_DetectsRestarts(t *testing.T) { PipelineRunID: run.ID, Type: "bridge", DotID: "ds1", - Output: pipeline.JSONSerializable{Val: 2, Valid: true}, + Output: jsonserializable.JSONSerializable{Val: 2, Valid: true}, CreatedAt: now, FinishedAt: null.TimeFrom(now), }) @@ -322,7 +323,7 @@ func Test_PipelineORM_StoreRun_DetectsRestarts(t *testing.T) { PipelineRunID: run.ID, Type: "median", DotID: "answer2", - Output: pipeline.JSONSerializable{Val: 1, Valid: true}, + Output: jsonserializable.JSONSerializable{Val: 1, Valid: true}, CreatedAt: now, FinishedAt: null.TimeFrom(now), }, @@ -375,7 +376,7 @@ func Test_PipelineORM_StoreRun_UpdateTaskRunResult(t *testing.T) { PipelineRunID: run.ID, Type: "cbor_parse", DotID: "ds2", - Output: pipeline.JSONSerializable{Val: cborOutput, Valid: true}, + Output: jsonserializable.JSONSerializable{Val: cborOutput, Valid: true}, CreatedAt: now, FinishedAt: null.TimeFrom(now), }, @@ -385,7 +386,7 @@ func Test_PipelineORM_StoreRun_UpdateTaskRunResult(t *testing.T) { PipelineRunID: run.ID, Type: "median", DotID: "answer2", - Output: pipeline.JSONSerializable{Val: 1, Valid: true}, + Output: jsonserializable.JSONSerializable{Val: 1, Valid: true}, CreatedAt: now, FinishedAt: null.TimeFrom(now), }, @@ -415,12 +416,12 @@ func Test_PipelineORM_StoreRun_UpdateTaskRunResult(t *testing.T) { // assert that the task is now updated task := run.ByDotID("ds1") require.True(t, task.FinishedAt.Valid) - require.Equal(t, pipeline.JSONSerializable{Val: "foo", Valid: true}, task.Output) + require.Equal(t, jsonserializable.JSONSerializable{Val: "foo", Valid: true}, task.Output) // assert correct task run serialization task2 := run.ByDotID("ds2") cborOutput["contractAddress"] = "0x8bd112d3f8f92e41c861939545ad387307af9703" - require.Equal(t, pipeline.JSONSerializable{Val: cborOutput, Valid: true}, task2.Output) + require.Equal(t, jsonserializable.JSONSerializable{Val: cborOutput, Valid: true}, task2.Output) } func Test_PipelineORM_DeleteRun(t *testing.T) { @@ -446,7 +447,7 @@ func Test_PipelineORM_DeleteRun(t *testing.T) { PipelineRunID: run.ID, Type: "median", DotID: "answer2", - Output: pipeline.JSONSerializable{Val: 1, Valid: true}, + Output: jsonserializable.JSONSerializable{Val: 1, Valid: true}, CreatedAt: now, FinishedAt: null.TimeFrom(now), }, @@ -482,14 +483,14 @@ func Test_PipelineORM_DeleteRunsOlderThan(t *testing.T) { PipelineRunID: run.ID, Type: "median", DotID: "answer2", - Output: pipeline.JSONSerializable{Val: 1, Valid: true}, + Output: jsonserializable.JSONSerializable{Val: 1, Valid: true}, CreatedAt: now, FinishedAt: null.TimeFrom(now.Add(-1 * time.Second)), }, } run.State = pipeline.RunStatusCompleted run.FinishedAt = null.TimeFrom(now.Add(-1 * time.Second)) - run.Outputs = pipeline.JSONSerializable{Val: 1, Valid: true} + run.Outputs = jsonserializable.JSONSerializable{Val: 1, Valid: true} run.AllErrors = pipeline.RunErrors{null.StringFrom("SOMETHING")} restart, err := orm.StoreRun(run) @@ -556,13 +557,13 @@ func Test_GetUnfinishedRuns_Keepers(t *testing.T) { err = porm.CreateRun(&pipeline.Run{ PipelineSpecID: keeperJob.PipelineSpecID, State: pipeline.RunStatusRunning, - Outputs: pipeline.JSONSerializable{}, + Outputs: jsonserializable.JSONSerializable{}, CreatedAt: time.Now(), PipelineTaskRuns: []pipeline.TaskRun{{ ID: runID1, Type: pipeline.TaskTypeETHTx, Index: 0, - Output: pipeline.JSONSerializable{}, + Output: jsonserializable.JSONSerializable{}, CreatedAt: time.Now(), DotID: "perform_upkeep_tx", }}, @@ -572,13 +573,13 @@ func Test_GetUnfinishedRuns_Keepers(t *testing.T) { err = porm.CreateRun(&pipeline.Run{ PipelineSpecID: keeperJob.PipelineSpecID, State: pipeline.RunStatusRunning, - Outputs: pipeline.JSONSerializable{}, + Outputs: jsonserializable.JSONSerializable{}, CreatedAt: time.Now(), PipelineTaskRuns: []pipeline.TaskRun{{ ID: runID2, Type: pipeline.TaskTypeETHCall, Index: 1, - Output: pipeline.JSONSerializable{}, + Output: jsonserializable.JSONSerializable{}, CreatedAt: time.Now(), DotID: "check_upkeep_tx", }}, @@ -654,13 +655,13 @@ func Test_GetUnfinishedRuns_DirectRequest(t *testing.T) { err = porm.CreateRun(&pipeline.Run{ PipelineSpecID: drJob.PipelineSpecID, State: pipeline.RunStatusRunning, - Outputs: pipeline.JSONSerializable{}, + Outputs: jsonserializable.JSONSerializable{}, CreatedAt: time.Now(), PipelineTaskRuns: []pipeline.TaskRun{{ ID: runningID, Type: pipeline.TaskTypeHTTP, Index: 0, - Output: pipeline.JSONSerializable{}, + Output: jsonserializable.JSONSerializable{}, CreatedAt: time.Now(), DotID: "ds1", }}, @@ -670,13 +671,13 @@ func Test_GetUnfinishedRuns_DirectRequest(t *testing.T) { err = porm.CreateRun(&pipeline.Run{ PipelineSpecID: drJob.PipelineSpecID, State: pipeline.RunStatusSuspended, - Outputs: pipeline.JSONSerializable{}, + Outputs: jsonserializable.JSONSerializable{}, CreatedAt: time.Now(), PipelineTaskRuns: []pipeline.TaskRun{{ ID: uuid.New(), Type: pipeline.TaskTypeHTTP, Index: 1, - Output: pipeline.JSONSerializable{}, + Output: jsonserializable.JSONSerializable{}, CreatedAt: time.Now(), DotID: "ds1", }}, diff --git a/core/services/pipeline/runner.go b/core/services/pipeline/runner.go index cc6214abf5a..3b89a1d4945 100644 --- a/core/services/pipeline/runner.go +++ b/core/services/pipeline/runner.go @@ -16,6 +16,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" commonutils "github.com/smartcontractkit/chainlink-common/pkg/utils" + "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink/v2/core/bridges" @@ -204,8 +205,8 @@ func NewRun(spec Spec, vars Vars) *Run { State: RunStatusRunning, PipelineSpec: spec, PipelineSpecID: spec.ID, - Inputs: JSONSerializable{Val: vars.vars, Valid: true}, - Outputs: JSONSerializable{Val: nil, Valid: false}, + Inputs: jsonserializable.JSONSerializable{Val: vars.vars, Valid: true}, + Outputs: jsonserializable.JSONSerializable{Val: nil, Valid: false}, CreatedAt: time.Now(), } } @@ -319,7 +320,7 @@ func (r *runner) InitializePipeline(spec Spec) (pipeline *Pipeline, err error) { } func (r *runner) run(ctx context.Context, pipeline *Pipeline, run *Run, vars Vars, l logger.Logger) TaskRunResults { - l = l.With("jobID", run.PipelineSpec.JobID, "jobName", run.PipelineSpec.JobName) + l = l.With("run.ID", run.ID, "executionID", uuid.New(), "specID", run.PipelineSpecID, "jobID", run.PipelineSpec.JobID, "jobName", run.PipelineSpec.JobName) l.Debug("Initiating tasks for pipeline run of spec") scheduler := newScheduler(pipeline, run, vars, l) @@ -362,12 +363,12 @@ func (r *runner) run(ctx context.Context, pipeline *Pipeline, run *Run, vars Var run.FailSilently = scheduler.exiting run.State = RunStatusSuspended + var runTime time.Duration if !scheduler.pending { run.FinishedAt = null.TimeFrom(time.Now()) // NOTE: runTime can be very long now because it'll include suspend - runTime := run.FinishedAt.Time.Sub(run.CreatedAt) - l.Debugw("Finished all tasks for pipeline run", "specID", run.PipelineSpecID, "runTime", runTime) + runTime = run.FinishedAt.Time.Sub(run.CreatedAt) PromPipelineRunTotalTimeToCompletion.WithLabelValues(fmt.Sprintf("%d", run.PipelineSpec.JobID), run.PipelineSpec.JobName).Set(float64(runTime)) } @@ -389,6 +390,9 @@ func (r *runner) run(ctx context.Context, pipeline *Pipeline, run *Run, vars Var }) sort.Slice(run.PipelineTaskRuns, func(i, j int) bool { + if run.PipelineTaskRuns[i].task.OutputIndex() == run.PipelineTaskRuns[j].task.OutputIndex() { + return run.PipelineTaskRuns[i].FinishedAt.ValueOrZero().Before(run.PipelineTaskRuns[j].FinishedAt.ValueOrZero()) + } return run.PipelineTaskRuns[i].task.OutputIndex() < run.PipelineTaskRuns[j].task.OutputIndex() }) } @@ -411,7 +415,7 @@ func (r *runner) run(ctx context.Context, pipeline *Pipeline, run *Run, vars Var } run.AllErrors = errors run.FatalErrors = fatalErrors - run.Outputs = JSONSerializable{Val: outputs, Valid: true} + run.Outputs = jsonserializable.JSONSerializable{Val: outputs, Valid: true} if run.HasFatalErrors() { run.State = RunStatusErrored @@ -439,6 +443,33 @@ func (r *runner) run(ctx context.Context, pipeline *Pipeline, run *Run, vars Var idxs[i] = taskRunResults[i].Task.OutputIndex() } + if r.config.VerboseLogging() { + l = l.With( + "run.PipelineTaskRuns", run.PipelineTaskRuns, + "run.Outputs", run.Outputs, + "run.CreatedAt", run.CreatedAt, + "run.FinishedAt", run.FinishedAt, + "run.Meta", run.Meta, + "run.Inputs", run.Inputs, + ) + } + if run.HasFatalErrors() { + l = l.With("run.FatalErrors", run.FatalErrors) + } + if run.HasErrors() { + l = l.With("run.AllErrors", run.AllErrors) + } + l = l.With("run.State", run.State, "fatal", run.HasFatalErrors(), "runTime", runTime) + if run.HasFatalErrors() { + // This will also log at error level in OCR if it fails Observe so the + // level is appropriate + l.Errorw("Completed pipeline run with fatal errors") + } else if run.HasErrors() { + l.Debugw("Completed pipeline run with errors") + } else { + l.Debugw("Completed pipeline run successfully") + } + return taskRunResults } @@ -480,7 +511,9 @@ func (r *runner) executeTaskRun(ctx context.Context, spec Spec, taskRun *memoryT loggerFields = append(loggerFields, "resultString", fmt.Sprintf("%q", v)) loggerFields = append(loggerFields, "resultHex", fmt.Sprintf("%x", v)) } - l.Tracew("Pipeline task completed", loggerFields...) + if r.config.VerboseLogging() { + l.Tracew("Pipeline task completed", loggerFields...) + } now := time.Now() diff --git a/core/services/pipeline/runner_test.go b/core/services/pipeline/runner_test.go index 5b4aaef7e88..7a417ef9d94 100644 --- a/core/services/pipeline/runner_test.go +++ b/core/services/pipeline/runner_test.go @@ -20,6 +20,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/bridges" @@ -651,7 +652,7 @@ ds5 [type=http method="GET" url="%s" index=2] // Now simulate a new result coming in task := run.ByDotID("ds1") task.Error = null.NewString("", false) - task.Output = pipeline.JSONSerializable{ + task.Output = jsonserializable.JSONSerializable{ Val: `{"data":{"result":"9700"}}` + "\n", Valid: true, } @@ -766,7 +767,7 @@ ds5 [type=http method="GET" url="%s" index=2] // Now simulate a new result coming in while we were running task := run.ByDotID("ds1") task.Error = null.NewString("", false) - task.Output = pipeline.JSONSerializable{ + task.Output = jsonserializable.JSONSerializable{ Val: `{"data":{"result":"9700"}}` + "\n", Valid: true, } diff --git a/core/services/pipeline/task.http_test.go b/core/services/pipeline/task.http_test.go index 36ccc147a78..d53e2247c68 100644 --- a/core/services/pipeline/task.http_test.go +++ b/core/services/pipeline/task.http_test.go @@ -15,6 +15,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -73,7 +74,7 @@ func TestHTTPTask_Variables(t *testing.T) { tests := []struct { name string requestData string - meta pipeline.JSONSerializable + meta jsonserializable.JSONSerializable inputs []pipeline.Result vars pipeline.Vars expectedRequestData map[string]interface{} @@ -83,7 +84,7 @@ func TestHTTPTask_Variables(t *testing.T) { { "requestData (empty) + meta", ``, - pipeline.JSONSerializable{validMeta, true}, + jsonserializable.JSONSerializable{Val: validMeta, Valid: true}, []pipeline.Result{{Value: 123.45}}, pipeline.NewVarsFrom(map[string]interface{}{"some_data": map[string]interface{}{"foo": 543.21}}), map[string]interface{}{}, @@ -93,7 +94,7 @@ func TestHTTPTask_Variables(t *testing.T) { { "requestData (pure variable) + meta", `$(some_data)`, - pipeline.JSONSerializable{validMeta, true}, + jsonserializable.JSONSerializable{Val: validMeta, Valid: true}, []pipeline.Result{{Value: 123.45}}, pipeline.NewVarsFrom(map[string]interface{}{"some_data": map[string]interface{}{"foo": 543.21}}), map[string]interface{}{"foo": 543.21}, @@ -103,7 +104,7 @@ func TestHTTPTask_Variables(t *testing.T) { { "requestData (pure variable)", `$(some_data)`, - pipeline.JSONSerializable{nil, false}, + jsonserializable.JSONSerializable{Val: nil, Valid: false}, []pipeline.Result{{Value: 123.45}}, pipeline.NewVarsFrom(map[string]interface{}{"some_data": map[string]interface{}{"foo": 543.21}}), map[string]interface{}{"foo": 543.21}, @@ -113,7 +114,7 @@ func TestHTTPTask_Variables(t *testing.T) { { "requestData (pure variable, missing)", `$(some_data)`, - pipeline.JSONSerializable{validMeta, true}, + jsonserializable.JSONSerializable{Val: validMeta, Valid: true}, []pipeline.Result{{Value: 123.45}}, pipeline.NewVarsFrom(map[string]interface{}{"not_some_data": map[string]interface{}{"foo": 543.21}}), nil, @@ -123,7 +124,7 @@ func TestHTTPTask_Variables(t *testing.T) { { "requestData (pure variable, not a map)", `$(some_data)`, - pipeline.JSONSerializable{validMeta, true}, + jsonserializable.JSONSerializable{Val: validMeta, Valid: true}, []pipeline.Result{{Value: 123.45}}, pipeline.NewVarsFrom(map[string]interface{}{"some_data": 543.21}), nil, @@ -133,7 +134,7 @@ func TestHTTPTask_Variables(t *testing.T) { { "requestData (interpolation) + meta", `{"data":{"result":$(medianize)}}`, - pipeline.JSONSerializable{validMeta, true}, + jsonserializable.JSONSerializable{Val: validMeta, Valid: true}, []pipeline.Result{{Value: 123.45}}, pipeline.NewVarsFrom(map[string]interface{}{"medianize": 543.21}), map[string]interface{}{"data": map[string]interface{}{"result": 543.21}}, @@ -143,7 +144,7 @@ func TestHTTPTask_Variables(t *testing.T) { { "requestData (interpolation, missing)", `{"data":{"result":$(medianize)}}`, - pipeline.JSONSerializable{validMeta, true}, + jsonserializable.JSONSerializable{Val: validMeta, Valid: true}, []pipeline.Result{{Value: 123.45}}, pipeline.NewVarsFrom(map[string]interface{}{"nope": "foo bar"}), nil, diff --git a/core/services/pipeline/task.jsonparse.go b/core/services/pipeline/task.jsonparse.go index 8eef106c3a9..cd8f713e7ed 100644 --- a/core/services/pipeline/task.jsonparse.go +++ b/core/services/pipeline/task.jsonparse.go @@ -10,6 +10,7 @@ import ( "github.com/pkg/errors" "go.uber.org/multierr" + "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" "github.com/smartcontractkit/chainlink/v2/core/logger" ) @@ -109,7 +110,7 @@ func (t *JSONParseTask) Run(_ context.Context, l logger.Logger, vars Vars, input } } - decoded, err = reinterpetJsonNumbers(decoded) + decoded, err = jsonserializable.ReinterpretJSONNumbers(decoded) if err != nil { return Result{Error: multierr.Combine(ErrBadInput, err)}, runInfo } diff --git a/core/services/promreporter/prom_reporter_test.go b/core/services/promreporter/prom_reporter_test.go index a2a744ae924..9627b52f871 100644 --- a/core/services/promreporter/prom_reporter_test.go +++ b/core/services/promreporter/prom_reporter_test.go @@ -96,7 +96,7 @@ func Test_PromReporter_OnNewLongestChain(t *testing.T) { t.Run("with unconfirmed evm.txes", func(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index 2819ae3f9e8..ddddb82aaed 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -25,10 +25,10 @@ import ( txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txm "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/llo" "github.com/smartcontractkit/chainlink/v2/core/services/llo/bm" lloconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/llo/config" @@ -374,8 +374,8 @@ func (r *Relayer) NewConfigProvider(args commontypes.RelayArgs) (configProvider } func FilterNamesFromRelayArgs(args commontypes.RelayArgs) (filterNames []string, err error) { - var addr ethkey.EIP55Address - if addr, err = ethkey.NewEIP55Address(args.ContractID); err != nil { + var addr evmtypes.EIP55Address + if addr, err = evmtypes.NewEIP55Address(args.ContractID); err != nil { return nil, err } var relayConfig types.RelayConfig diff --git a/core/services/relay/evm/functions.go b/core/services/relay/evm/functions.go index da423c6d5fc..ed7b247f46b 100644 --- a/core/services/relay/evm/functions.go +++ b/core/services/relay/evm/functions.go @@ -21,7 +21,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/config" - "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" functionsRelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/functions" evmRelayTypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" ) @@ -197,7 +196,12 @@ func newFunctionsContractTransmitter(ctx context.Context, contractVersion uint32 gasLimit = uint64(*ocr2Limit) } - transmitter, err := ocrcommon.NewTransmitter( + functionsTransmitter, err := functionsRelay.NewFunctionsContractTransmitter( + configWatcher.chain.Client(), + OCR2AggregatorTransmissionContractABI, + configWatcher.chain.LogPoller(), + lggr, + contractVersion, configWatcher.chain.TxManager(), fromAddresses, gasLimit, @@ -207,20 +211,6 @@ func newFunctionsContractTransmitter(ctx context.Context, contractVersion uint32 configWatcher.chain.ID(), ethKeystore, ) - - if err != nil { - return nil, errors.Wrap(err, "failed to create transmitter") - } - - functionsTransmitter, err := functionsRelay.NewFunctionsContractTransmitter( - configWatcher.chain.Client(), - OCR2AggregatorTransmissionContractABI, - transmitter, - configWatcher.chain.LogPoller(), - lggr, - nil, - contractVersion, - ) if err != nil { return nil, err } diff --git a/core/services/relay/evm/functions/contract_transmitter.go b/core/services/relay/evm/functions/contract_transmitter.go index 051b1f0bef9..4a8ba25fd9d 100644 --- a/core/services/relay/evm/functions/contract_transmitter.go +++ b/core/services/relay/evm/functions/contract_transmitter.go @@ -16,6 +16,7 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" @@ -25,33 +26,38 @@ import ( evmRelayTypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" ) +type roundRobinKeystore interface { + GetRoundRobinAddress(ctx context.Context, chainID *big.Int, addresses ...common.Address) (address common.Address, err error) +} + +type txManager interface { + CreateTransaction(ctx context.Context, txRequest txmgr.TxRequest) (tx txmgr.Tx, err error) +} + type FunctionsContractTransmitter interface { services.ServiceCtx ocrtypes.ContractTransmitter } -type Transmitter interface { - CreateEthTransaction(ctx context.Context, toAddress common.Address, payload []byte, txMeta *txmgr.TxMeta) error - FromAddress() common.Address -} - type ReportToEthMetadata func([]byte) (*txmgr.TxMeta, error) -func reportToEvmTxMetaNoop([]byte) (*txmgr.TxMeta, error) { - return nil, nil -} - type contractTransmitter struct { - contractAddress atomic.Pointer[common.Address] - contractABI abi.ABI - transmitter Transmitter - transmittedEventSig common.Hash - contractReader contractReader - lp logpoller.LogPoller - lggr logger.Logger - reportToEvmTxMeta ReportToEthMetadata - contractVersion uint32 - reportCodec encoding.ReportCodec + contractAddress atomic.Pointer[common.Address] + contractABI abi.ABI + transmittedEventSig common.Hash + contractReader contractReader + lp logpoller.LogPoller + lggr logger.Logger + contractVersion uint32 + reportCodec encoding.ReportCodec + txm txManager + fromAddresses []common.Address + gasLimit uint64 + effectiveTransmitterAddress common.Address + strategy types.TxStrategy + checker txmgr.TransmitCheckerSpec + chainID *big.Int + keystore roundRobinKeystore } var _ FunctionsContractTransmitter = &contractTransmitter{} @@ -64,12 +70,23 @@ func transmitterFilterName(addr common.Address) string { func NewFunctionsContractTransmitter( caller contractReader, contractABI abi.ABI, - transmitter Transmitter, lp logpoller.LogPoller, lggr logger.Logger, - reportToEvmTxMeta ReportToEthMetadata, contractVersion uint32, + txm txManager, + fromAddresses []common.Address, + gasLimit uint64, + effectiveTransmitterAddress common.Address, + strategy types.TxStrategy, + checker txmgr.TransmitCheckerSpec, + chainID *big.Int, + keystore roundRobinKeystore, ) (*contractTransmitter, error) { + // Ensure that a keystore is provided. + if keystore == nil { + return nil, errors.New("nil keystore provided to transmitter") + } + transmitted, ok := contractABI.Events["Transmitted"] if !ok { return nil, errors.New("invalid ABI, missing transmitted") @@ -79,26 +96,58 @@ func NewFunctionsContractTransmitter( return nil, fmt.Errorf("unsupported contract version: %d", contractVersion) } - if reportToEvmTxMeta == nil { - reportToEvmTxMeta = reportToEvmTxMetaNoop - } codec, err := encoding.NewReportCodec(contractVersion) if err != nil { return nil, err } return &contractTransmitter{ - contractABI: contractABI, - transmitter: transmitter, - transmittedEventSig: transmitted.ID, - lp: lp, - contractReader: caller, - lggr: lggr.Named("OCRContractTransmitter"), - reportToEvmTxMeta: reportToEvmTxMeta, - contractVersion: contractVersion, - reportCodec: codec, + contractABI: contractABI, + transmittedEventSig: transmitted.ID, + lp: lp, + contractReader: caller, + lggr: lggr.Named("OCRFunctionsContractTransmitter"), + contractVersion: contractVersion, + reportCodec: codec, + txm: txm, + fromAddresses: fromAddresses, + gasLimit: gasLimit, + effectiveTransmitterAddress: effectiveTransmitterAddress, + strategy: strategy, + checker: checker, + chainID: chainID, + keystore: keystore, }, nil } +func (oc *contractTransmitter) createEthTransaction(ctx context.Context, toAddress common.Address, payload []byte) error { + + roundRobinFromAddress, err := oc.keystore.GetRoundRobinAddress(ctx, oc.chainID, oc.fromAddresses...) + if err != nil { + return errors.Wrap(err, "skipped OCR transmission, error getting round-robin address") + } + + _, err = oc.txm.CreateTransaction(ctx, txmgr.TxRequest{ + FromAddress: roundRobinFromAddress, + ToAddress: toAddress, + EncodedPayload: payload, + FeeLimit: oc.gasLimit, + ForwarderAddress: oc.forwarderAddress(), + Strategy: oc.strategy, + Checker: oc.checker, + Meta: nil, + }) + return errors.Wrap(err, "skipped OCR transmission") +} + +func (oc *contractTransmitter) forwarderAddress() common.Address { + for _, a := range oc.fromAddresses { + if a == oc.effectiveTransmitterAddress { + return common.Address{} + } + } + return oc.effectiveTransmitterAddress +} + // Transmit sends the report to the on-chain smart contract's Transmit method. func (oc *contractTransmitter) Transmit(ctx context.Context, reportCtx ocrtypes.ReportContext, report ocrtypes.Report, signatures []ocrtypes.AttributedOnchainSignature) error { var rs [][32]byte @@ -118,11 +167,6 @@ func (oc *contractTransmitter) Transmit(ctx context.Context, reportCtx ocrtypes. } rawReportCtx := evmutil.RawReportContext(reportCtx) - txMeta, err := oc.reportToEvmTxMeta(report) - if err != nil { - oc.lggr.Warnw("failed to generate tx metadata for report", "err", err) - } - var destinationContract common.Address switch oc.contractVersion { case 1: @@ -160,8 +204,8 @@ func (oc *contractTransmitter) Transmit(ctx context.Context, reportCtx ocrtypes. return errors.Wrap(err, "abi.Pack failed") } - oc.lggr.Debugw("FunctionsContractTransmitter: transmitting report", "contractAddress", destinationContract, "txMeta", txMeta, "payloadSize", len(payload)) - return errors.Wrap(oc.transmitter.CreateEthTransaction(ctx, destinationContract, payload, txMeta), "failed to send Eth transaction") + oc.lggr.Debugw("FunctionsContractTransmitter: transmitting report", "contractAddress", destinationContract, "txMeta", nil, "payloadSize", len(payload)) + return errors.Wrap(oc.createEthTransaction(ctx, destinationContract, payload), "failed to send Eth transaction") } type contractReader interface { @@ -240,7 +284,7 @@ func (oc *contractTransmitter) LatestConfigDigestAndEpoch(ctx context.Context) ( // FromAccount returns the account from which the transmitter invokes the contract func (oc *contractTransmitter) FromAccount() (ocrtypes.Account, error) { - return ocrtypes.Account(oc.transmitter.FromAddress().String()), nil + return ocrtypes.Account(oc.effectiveTransmitterAddress.String()), nil } func (oc *contractTransmitter) Start(ctx context.Context) error { return nil } diff --git a/core/services/relay/evm/functions/contract_transmitter_test.go b/core/services/relay/evm/functions/contract_transmitter_test.go index e9712a3687c..fb50f6941b2 100644 --- a/core/services/relay/evm/functions/contract_transmitter_test.go +++ b/core/services/relay/evm/functions/contract_transmitter_test.go @@ -1,42 +1,46 @@ package functions_test import ( - "context" "encoding/hex" + "math/big" "strings" "testing" "github.com/ethereum/go-ethereum/accounts/abi" gethcommon "github.com/ethereum/go-ethereum/common" "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" + "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + commontxmmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/types/mocks" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" lpmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/functions" ) -type mockTransmitter struct { - toAddress gethcommon.Address +func newMockTxStrategy(t *testing.T) *commontxmmocks.TxStrategy { + return commontxmmocks.NewTxStrategy(t) } -func (m *mockTransmitter) CreateEthTransaction(ctx context.Context, toAddress gethcommon.Address, payload []byte, _ *txmgr.TxMeta) error { - m.toAddress = toAddress - return nil -} -func (mockTransmitter) FromAddress() gethcommon.Address { return testutils.NewAddress() } - func TestContractTransmitter_LatestConfigDigestAndEpoch(t *testing.T) { t.Parallel() ctx := testutils.Context(t) + db := pgtest.NewSqlxDB(t) + cfg := configtest.NewTestGeneralConfig(t) + ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + digestStr := "000130da6b9315bd59af6b0a3f5463c0d0a39e92eaa34cbcbdbace7b3bfcc776" lggr := logger.TestLogger(t) c := evmclimocks.NewClient(t) @@ -49,11 +53,29 @@ func TestContractTransmitter_LatestConfigDigestAndEpoch(t *testing.T) { c.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(digestAndEpochDontScanLogs, nil).Once() contractABI, err := abi.JSON(strings.NewReader(ocr2aggregator.OCR2AggregatorABI)) require.NoError(t, err) + txm := txmmocks.NewMockEvmTxManager(t) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + gasLimit := uint64(1000) + chainID := big.NewInt(0) + effectiveTransmitterAddress := fromAddress + strategy := newMockTxStrategy(t) lp.On("RegisterFilter", mock.Anything, mock.Anything).Return(nil) - functionsTransmitter, err := functions.NewFunctionsContractTransmitter(c, contractABI, &mockTransmitter{}, lp, lggr, func(b []byte) (*txmgr.TxMeta, error) { - return &txmgr.TxMeta{}, nil - }, 1) + functionsTransmitter, err := functions.NewFunctionsContractTransmitter( + c, + contractABI, + lp, + lggr, + 1, + txm, + []gethcommon.Address{fromAddress}, + gasLimit, + effectiveTransmitterAddress, + strategy, + txmgr.TransmitCheckerSpec{}, + chainID, + ethKeyStore, + ) require.NoError(t, err) require.NoError(t, functionsTransmitter.UpdateRoutes(ctx, gethcommon.Address{}, gethcommon.Address{})) @@ -67,18 +89,39 @@ func TestContractTransmitter_Transmit_V1(t *testing.T) { t.Parallel() ctx := testutils.Context(t) + db := pgtest.NewSqlxDB(t) + cfg := configtest.NewTestGeneralConfig(t) + ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + contractVersion := uint32(1) configuredDestAddress, coordinatorAddress := testutils.NewAddress(), testutils.NewAddress() lggr := logger.TestLogger(t) c := evmclimocks.NewClient(t) lp := lpmocks.NewLogPoller(t) contractABI, _ := abi.JSON(strings.NewReader(ocr2aggregator.OCR2AggregatorABI)) + txm := txmmocks.NewMockEvmTxManager(t) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + gasLimit := uint64(1000) + chainID := big.NewInt(0) + effectiveTransmitterAddress := fromAddress + strategy := newMockTxStrategy(t) lp.On("RegisterFilter", mock.Anything, mock.Anything).Return(nil) - ocrTransmitter := mockTransmitter{} - ot, err := functions.NewFunctionsContractTransmitter(c, contractABI, &ocrTransmitter, lp, lggr, func(b []byte) (*txmgr.TxMeta, error) { - return &txmgr.TxMeta{}, nil - }, contractVersion) + ot, err := functions.NewFunctionsContractTransmitter( + c, + contractABI, + lp, + lggr, + contractVersion, + txm, + []gethcommon.Address{fromAddress}, + gasLimit, + effectiveTransmitterAddress, + strategy, + txmgr.TransmitCheckerSpec{}, + chainID, + ethKeyStore, + ) require.NoError(t, err) require.NoError(t, ot.UpdateRoutes(ctx, configuredDestAddress, configuredDestAddress)) @@ -94,10 +137,24 @@ func TestContractTransmitter_Transmit_V1(t *testing.T) { require.NoError(t, err) reportBytes, err := codec.EncodeReport(processedRequests) require.NoError(t, err) + rawReportCtx := evmutil.RawReportContext(ocrtypes.ReportContext{}) + var rs [][32]byte + var ss [][32]byte + var vs [32]byte + payload, err := contractABI.Pack("transmit", rawReportCtx, reportBytes, rs, ss, vs) + require.NoError(t, err) // success + txm.On("CreateTransaction", mock.Anything, txmgr.TxRequest{ + FromAddress: fromAddress, + ToAddress: coordinatorAddress, + EncodedPayload: payload, + FeeLimit: gasLimit, + ForwarderAddress: gethcommon.Address{}, + Meta: nil, + Strategy: strategy, + }).Return(txmgr.Tx{}, nil).Once() require.NoError(t, ot.Transmit(testutils.Context(t), ocrtypes.ReportContext{}, reportBytes, []ocrtypes.AttributedOnchainSignature{})) - require.Equal(t, coordinatorAddress, ocrTransmitter.toAddress) // failure on too many signatures signatures := []ocrtypes.AttributedOnchainSignature{} @@ -111,18 +168,39 @@ func TestContractTransmitter_Transmit_V1_CoordinatorMismatch(t *testing.T) { t.Parallel() ctx := testutils.Context(t) + db := pgtest.NewSqlxDB(t) + cfg := configtest.NewTestGeneralConfig(t) + ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + contractVersion := uint32(1) configuredDestAddress, coordinatorAddress1, coordinatorAddress2 := testutils.NewAddress(), testutils.NewAddress(), testutils.NewAddress() lggr := logger.TestLogger(t) c := evmclimocks.NewClient(t) lp := lpmocks.NewLogPoller(t) contractABI, _ := abi.JSON(strings.NewReader(ocr2aggregator.OCR2AggregatorABI)) + txm := txmmocks.NewMockEvmTxManager(t) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + gasLimit := uint64(1000) + chainID := big.NewInt(0) + effectiveTransmitterAddress := fromAddress + strategy := newMockTxStrategy(t) lp.On("RegisterFilter", mock.Anything, mock.Anything).Return(nil) - ocrTransmitter := mockTransmitter{} - ot, err := functions.NewFunctionsContractTransmitter(c, contractABI, &ocrTransmitter, lp, lggr, func(b []byte) (*txmgr.TxMeta, error) { - return &txmgr.TxMeta{}, nil - }, contractVersion) + ot, err := functions.NewFunctionsContractTransmitter( + c, + contractABI, + lp, + lggr, + contractVersion, + txm, + []gethcommon.Address{fromAddress}, + gasLimit, + effectiveTransmitterAddress, + strategy, + txmgr.TransmitCheckerSpec{}, + chainID, + ethKeyStore, + ) require.NoError(t, err) require.NoError(t, ot.UpdateRoutes(ctx, configuredDestAddress, configuredDestAddress)) @@ -144,7 +222,21 @@ func TestContractTransmitter_Transmit_V1_CoordinatorMismatch(t *testing.T) { require.NoError(t, err) reportBytes, err := codec.EncodeReport(processedRequests) require.NoError(t, err) + rawReportCtx := evmutil.RawReportContext(ocrtypes.ReportContext{}) + var rs [][32]byte + var ss [][32]byte + var vs [32]byte + payload, err := contractABI.Pack("transmit", rawReportCtx, reportBytes, rs, ss, vs) + require.NoError(t, err) + txm.On("CreateTransaction", mock.Anything, txmgr.TxRequest{ + FromAddress: fromAddress, + ToAddress: coordinatorAddress1, + EncodedPayload: payload, + FeeLimit: gasLimit, + ForwarderAddress: gethcommon.Address{}, + Meta: nil, + Strategy: strategy, + }).Return(txmgr.Tx{}, nil).Once() require.NoError(t, ot.Transmit(testutils.Context(t), ocrtypes.ReportContext{}, reportBytes, []ocrtypes.AttributedOnchainSignature{})) - require.Equal(t, coordinatorAddress1, ocrTransmitter.toAddress) } diff --git a/core/services/relay/evm/mercury/wsrpc/pb/mercury.pb.go b/core/services/relay/evm/mercury/wsrpc/pb/mercury.pb.go index ab4d2f68dad..0f4045bdf14 100644 --- a/core/services/relay/evm/mercury/wsrpc/pb/mercury.pb.go +++ b/core/services/relay/evm/mercury/wsrpc/pb/mercury.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 +// protoc-gen-go v1.33.0 // protoc v4.25.1 // source: mercury.proto diff --git a/core/services/relay/evm/ocr2keeper.go b/core/services/relay/evm/ocr2keeper.go index f6342df5280..742bab3a696 100644 --- a/core/services/relay/evm/ocr2keeper.go +++ b/core/services/relay/evm/ocr2keeper.go @@ -17,11 +17,11 @@ import ( commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/types/automation" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" ac "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_automation_v21_plus_common" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" evm "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider" @@ -105,7 +105,7 @@ func (r *ocr2keeperRelayer) NewOCR2KeeperProvider(rargs commontypes.RelayArgs, p services.configWatcher = cfgWatcher services.contractTransmitter = contractTransmitter - addr := ethkey.MustEIP55Address(rargs.ContractID).Address() + addr := evmtypes.MustEIP55Address(rargs.ContractID).Address() registryContract, err := ac.NewIAutomationV21PlusCommon(addr, client.Client()) if err != nil { @@ -130,7 +130,7 @@ func (r *ocr2keeperRelayer) NewOCR2KeeperProvider(rargs commontypes.RelayArgs, p scanner := upkeepstate.NewPerformedEventsScanner(r.lggr, client.LogPoller(), addr, finalityDepth) services.upkeepStateStore = upkeepstate.NewUpkeepStateStore(orm, r.lggr, scanner) - logProvider, logRecoverer := logprovider.New(r.lggr, client.LogPoller(), client.Client(), services.upkeepStateStore, finalityDepth) + logProvider, logRecoverer := logprovider.New(r.lggr, client.LogPoller(), client.Client(), services.upkeepStateStore, finalityDepth, client.ID()) services.logEventProvider = logProvider services.logRecoverer = logRecoverer blockSubscriber := evm.NewBlockSubscriber(client.HeadBroadcaster(), client.LogPoller(), finalityDepth, r.lggr) diff --git a/core/services/relay/evm/request_round_tracker.go b/core/services/relay/evm/request_round_tracker.go index 1f1ed71fc31..1e77ce28089 100644 --- a/core/services/relay/evm/request_round_tracker.go +++ b/core/services/relay/evm/request_round_tracker.go @@ -110,7 +110,7 @@ func (t *RequestRoundTracker) Close() error { // HandleLog complies with LogListener interface // It is not thread safe func (t *RequestRoundTracker) HandleLog(lb log.Broadcast) { - was, err := t.logBroadcaster.WasAlreadyConsumed(lb) + was, err := t.logBroadcaster.WasAlreadyConsumed(t.ctx, lb) if err != nil { t.lggr.Errorw("OCRContract: could not determine if log was already consumed", "err", err) return @@ -121,12 +121,12 @@ func (t *RequestRoundTracker) HandleLog(lb log.Broadcast) { raw := lb.RawLog() if raw.Address != t.contract.Address() { t.lggr.Errorf("log address of 0x%x does not match configured contract address of 0x%x", raw.Address, t.contract.Address()) - t.lggr.ErrorIf(t.logBroadcaster.MarkConsumed(lb), "unable to mark consumed") + t.lggr.ErrorIf(t.logBroadcaster.MarkConsumed(t.ctx, lb), "unable to mark consumed") return } topics := raw.Topics if len(topics) == 0 { - t.lggr.ErrorIf(t.logBroadcaster.MarkConsumed(lb), "unable to mark consumed") + t.lggr.ErrorIf(t.logBroadcaster.MarkConsumed(t.ctx, lb), "unable to mark consumed") return } @@ -137,7 +137,7 @@ func (t *RequestRoundTracker) HandleLog(lb log.Broadcast) { rr, err = t.contractFilterer.ParseRoundRequested(raw) if err != nil { t.lggr.Errorw("could not parse round requested", "err", err) - t.lggr.ErrorIf(t.logBroadcaster.MarkConsumed(lb), "unable to mark consumed") + t.lggr.ErrorIf(t.logBroadcaster.MarkConsumed(t.ctx, lb), "unable to mark consumed") return } if IsLaterThan(raw, t.latestRoundRequested.Raw) { @@ -145,7 +145,7 @@ func (t *RequestRoundTracker) HandleLog(lb log.Broadcast) { if err = t.odb.SaveLatestRoundRequested(q, *rr); err != nil { return err } - return t.logBroadcaster.MarkConsumed(lb, pg.WithQueryer(q)) + return t.logBroadcaster.MarkConsumed(t.ctx, lb) }) if err != nil { t.lggr.Error(err) @@ -163,7 +163,7 @@ func (t *RequestRoundTracker) HandleLog(lb log.Broadcast) { t.lggr.Debugw("RequestRoundTracker: got unrecognised log topic", "topic", topics[0]) } if !consumed { - t.lggr.ErrorIf(t.logBroadcaster.MarkConsumed(lb), "unable to mark consumed") + t.lggr.ErrorIf(t.logBroadcaster.MarkConsumed(t.ctx, lb), "unable to mark consumed") } } diff --git a/core/services/synchronization/uni_client_integration_test.go b/core/services/synchronization/uni_client_integration_test.go deleted file mode 100644 index fcc0dc23717..00000000000 --- a/core/services/synchronization/uni_client_integration_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package synchronization - -import ( - "context" - "encoding/hex" - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/wsrpc" - - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" -) - -func TestUniClient(t *testing.T) { - t.Skip("Incomplete", "https://smartcontract-it.atlassian.net/browse/BCF-2729") - privKey, err := hex.DecodeString("TODO") - require.NoError(t, err) - pubKey, err := hex.DecodeString("TODO") - require.NoError(t, err) - t.Log(len(privKey), len(pubKey)) - lggr := logger.TestLogger(t) - c, err := wsrpc.DialUniWithContext(testutils.Context(t), - lggr, - "TODO", - privKey, - pubKey) - require.NoError(t, err) - t.Log(c) - client := telem.NewTelemClient(c) - ctx, cancel := context.WithTimeout(testutils.Context(t), 500*time.Millisecond) - resp, err := client.Telem(ctx, &telem.TelemRequest{ - Telemetry: []byte(`hello world`), - Address: "myaddress", - }) - cancel() - t.Log(resp, err) - require.NoError(t, c.Close()) -} diff --git a/core/services/vrf/delegate_test.go b/core/services/vrf/delegate_test.go index 29bbe41d288..adf54428b4e 100644 --- a/core/services/vrf/delegate_test.go +++ b/core/services/vrf/delegate_test.go @@ -406,8 +406,7 @@ func TestDelegate_InvalidLog(t *testing.T) { } db := pgtest.NewSqlxDB(t) - cfg := pgtest.NewQConfig(false) - txStore := txmgr.NewTxStore(db, logger.TestLogger(t), cfg) + txStore := txmgr.NewTxStore(db, logger.TestLogger(t)) txes, err := txStore.GetAllTxes(testutils.Context(t)) require.NoError(t, err) diff --git a/core/services/vrf/v1/integration_test.go b/core/services/vrf/v1/integration_test.go index b10ca160858..f68700a8af7 100644 --- a/core/services/vrf/v1/integration_test.go +++ b/core/services/vrf/v1/integration_test.go @@ -96,7 +96,7 @@ func TestIntegration_VRF_JPV2(t *testing.T) { // Ensure the eth transaction gets confirmed on chain. gomega.NewWithT(t).Eventually(func() bool { - orm := txmgr.NewTxStore(app.GetSqlxDB(), app.GetLogger(), app.GetConfig().Database()) + orm := txmgr.NewTxStore(app.GetSqlxDB(), app.GetLogger()) uc, err2 := orm.CountUnconfirmedTransactions(testutils.Context(t), key1.Address, testutils.SimulatedChainID) require.NoError(t, err2) return uc == 0 @@ -212,7 +212,7 @@ func TestIntegration_VRF_WithBHS(t *testing.T) { // Ensure the eth transaction gets confirmed on chain. gomega.NewWithT(t).Eventually(func() bool { - orm := txmgr.NewTxStore(app.GetSqlxDB(), app.GetLogger(), app.GetConfig().Database()) + orm := txmgr.NewTxStore(app.GetSqlxDB(), app.GetLogger()) uc, err2 := orm.CountUnconfirmedTransactions(testutils.Context(t), key.Address, testutils.SimulatedChainID) require.NoError(t, err2) return uc == 0 diff --git a/core/services/vrf/v1/listener_v1.go b/core/services/vrf/v1/listener_v1.go index a3240365a66..c57265634e5 100644 --- a/core/services/vrf/v1/listener_v1.go +++ b/core/services/vrf/v1/listener_v1.go @@ -311,6 +311,9 @@ func (lsn *Listener) RunLogListener(unsubscribes []func(), minConfs uint32) { } func (lsn *Listener) handleLog(lb log.Broadcast, minConfs uint32) { + ctx, cancel := lsn.ChStop.NewCtx() + defer cancel() + lggr := lsn.L.With( "log", lb.String(), "decodedLog", lb.DecodedLog(), @@ -323,7 +326,7 @@ func (lsn *Listener) handleLog(lb log.Broadcast, minConfs uint32) { if v, ok := lb.DecodedLog().(*solidity_vrf_coordinator_interface.VRFCoordinatorRandomnessRequestFulfilled); ok { lggr.Debugw("Got fulfillment log", "requestID", hex.EncodeToString(v.RequestId[:])) - if !lsn.shouldProcessLog(lb) { + if !lsn.shouldProcessLog(ctx, lb) { return } lsn.RespCountMu.Lock() @@ -333,17 +336,17 @@ func (lsn *Listener) handleLog(lb log.Broadcast, minConfs uint32) { reqID: v.RequestId, }) lsn.RespCountMu.Unlock() - lsn.markLogAsConsumed(lb) + lsn.markLogAsConsumed(ctx, lb) return } req, err := lsn.Coordinator.ParseRandomnessRequest(lb.RawLog()) if err != nil { lggr.Errorw("Failed to parse RandomnessRequest log", "err", err) - if !lsn.shouldProcessLog(lb) { + if !lsn.shouldProcessLog(ctx, lb) { return } - lsn.markLogAsConsumed(lb) + lsn.markLogAsConsumed(ctx, lb) return } @@ -366,8 +369,8 @@ func (lsn *Listener) handleLog(lb log.Broadcast, minConfs uint32) { "txHash", lb.RawLog().TxHash) } -func (lsn *Listener) shouldProcessLog(lb log.Broadcast) bool { - consumed, err := lsn.Chain.LogBroadcaster().WasAlreadyConsumed(lb) +func (lsn *Listener) shouldProcessLog(ctx context.Context, lb log.Broadcast) bool { + consumed, err := lsn.Chain.LogBroadcaster().WasAlreadyConsumed(ctx, lb) if err != nil { lsn.L.Errorw("Could not determine if log was already consumed", "err", err, "txHash", lb.RawLog().TxHash) // Do not process, let lb resend it as a retry mechanism. @@ -376,8 +379,8 @@ func (lsn *Listener) shouldProcessLog(lb log.Broadcast) bool { return !consumed } -func (lsn *Listener) markLogAsConsumed(lb log.Broadcast) { - err := lsn.Chain.LogBroadcaster().MarkConsumed(lb) +func (lsn *Listener) markLogAsConsumed(ctx context.Context, lb log.Broadcast) { + err := lsn.Chain.LogBroadcaster().MarkConsumed(ctx, lb) lsn.L.ErrorIf(err, fmt.Sprintf("Unable to mark log %v as consumed", lb.String())) } @@ -408,7 +411,7 @@ func (lsn *Listener) getConfirmedAt(req *solidity_vrf_coordinator_interface.VRFC func (lsn *Listener) ProcessRequest(ctx context.Context, req request) bool { // This check to see if the log was consumed needs to be in the same // goroutine as the mark consumed to avoid processing duplicates. - if !lsn.shouldProcessLog(req.lb) { + if !lsn.shouldProcessLog(ctx, req.lb) { return true } @@ -450,14 +453,14 @@ func (lsn *Listener) ProcessRequest(ctx context.Context, req request) bool { // If seedAndBlockNumber is zero then the response has been fulfilled // and we should skip it lggr.Infow("Request already fulfilled") - lsn.markLogAsConsumed(req.lb) + lsn.markLogAsConsumed(ctx, req.lb) return true } // Check if we can ignore the request due to its age. if time.Now().UTC().Sub(req.utcTimestamp) >= lsn.Job.VRFSpec.RequestTimeout { lggr.Infow("Request too old, dropping it") - lsn.markLogAsConsumed(req.lb) + lsn.markLogAsConsumed(ctx, req.lb) return true } @@ -485,7 +488,7 @@ func (lsn *Listener) ProcessRequest(ctx context.Context, req request) bool { // The VRF pipeline has no async tasks, so we don't need to check for `incomplete` if _, err = lsn.PipelineRunner.Run(ctx, run, lggr, true, func(tx pg.Queryer) error { // Always mark consumed regardless of whether the proof failed or not. - if err = lsn.Chain.LogBroadcaster().MarkConsumed(req.lb, pg.WithQueryer(tx)); err != nil { + if err = lsn.Chain.LogBroadcaster().MarkConsumed(ctx, req.lb); err != nil { lggr.Errorw("Failed mark consumed", "err", err) } return nil diff --git a/core/services/vrf/v2/bhs_feeder_test.go b/core/services/vrf/v2/bhs_feeder_test.go index 0ce674f5168..b39fd0dec7f 100644 --- a/core/services/vrf/v2/bhs_feeder_test.go +++ b/core/services/vrf/v2/bhs_feeder_test.go @@ -10,11 +10,11 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrftesthelpers" ) @@ -39,14 +39,14 @@ func TestStartHeartbeats(t *testing.T) { bhsKeyAddresses = append(bhsKeyAddresses, bhsKey.Address.String()) keys = append(keys, bhsKey) keySpecificOverrides = append(keySpecificOverrides, toml.KeySpecific{ - Key: ptr[ethkey.EIP55Address](bhsKey.EIP55Address), + Key: ptr[types.EIP55Address](bhsKey.EIP55Address), GasEstimator: toml.KeySpecificGasEstimator{PriceMax: gasLanePriceWei}, }) sendEth(t, ownerKey, uni.backend, bhsKey.Address, 10) } keySpecificOverrides = append(keySpecificOverrides, toml.KeySpecific{ // Gas lane. - Key: ptr[ethkey.EIP55Address](vrfKey.EIP55Address), + Key: ptr[types.EIP55Address](vrfKey.EIP55Address), GasEstimator: toml.KeySpecificGasEstimator{PriceMax: gasLanePriceWei}, }) diff --git a/core/services/vrf/v2/coordinator_v2x_interface.go b/core/services/vrf/v2/coordinator_v2x_interface.go index c99576d7558..9389f12b9f8 100644 --- a/core/services/vrf/v2/coordinator_v2x_interface.go +++ b/core/services/vrf/v2/coordinator_v2x_interface.go @@ -915,7 +915,7 @@ func (s *v2_5Subscription) NativeBalance() *big.Int { } func (s *v2_5Subscription) Owner() common.Address { - return s.event.Owner + return s.event.SubOwner } func (s *v2_5Subscription) Consumers() []common.Address { diff --git a/core/services/vrf/v2/integration_helpers_test.go b/core/services/vrf/v2/integration_helpers_test.go index 71724b928c1..f19f39f03f2 100644 --- a/core/services/vrf/v2/integration_helpers_test.go +++ b/core/services/vrf/v2/integration_helpers_test.go @@ -23,6 +23,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" v2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" evmutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_consumer_v2_upgradeable_example" @@ -67,11 +68,11 @@ func testSingleConsumerHappyPath( config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { simulatedOverrides(t, assets.GWei(10), toml.KeySpecific{ // Gas lane. - Key: ptr[ethkey.EIP55Address](key1.EIP55Address), + Key: ptr[types.EIP55Address](key1.EIP55Address), GasEstimator: toml.KeySpecificGasEstimator{PriceMax: gasLanePriceWei}, }, toml.KeySpecific{ // Gas lane. - Key: ptr[ethkey.EIP55Address](key2.EIP55Address), + Key: ptr[types.EIP55Address](key2.EIP55Address), GasEstimator: toml.KeySpecificGasEstimator{PriceMax: gasLanePriceWei}, })(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) @@ -1701,7 +1702,7 @@ func testMaliciousConsumer( // by the node. var attempts []txmgr.TxAttempt gomega.NewWithT(t).Eventually(func() bool { - attempts, _, err = app.TxmStorageService().TxAttempts(0, 1000) + attempts, _, err = app.TxmStorageService().TxAttempts(testutils.Context(t), 0, 1000) require.NoError(t, err) // It possible that we send the test request // before the job spawner has started the vrf services, which is fine diff --git a/core/services/vrf/v2/integration_v2_plus_test.go b/core/services/vrf/v2/integration_v2_plus_test.go index 22b10b61c84..bfec76afec3 100644 --- a/core/services/vrf/v2/integration_v2_plus_test.go +++ b/core/services/vrf/v2/integration_v2_plus_test.go @@ -948,7 +948,7 @@ func TestVRFV2PlusIntegration_MaxConsumersCost(t *testing.T) { uni.rootContractAddress, uni.coordinatorABI, "removeConsumer", subId, carolContractAddress) t.Log(estimate) - assert.Less(t, estimate, uint64(320000)) + assert.Less(t, estimate, uint64(540000)) estimate = estimateGas(t, uni.backend, carolContractAddress, uni.rootContractAddress, uni.coordinatorABI, "addConsumer", subId, testutils.NewAddress()) diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go index 3b7cdfa0a62..1a7c15a2508 100644 --- a/core/services/vrf/v2/integration_v2_test.go +++ b/core/services/vrf/v2/integration_v2_test.go @@ -67,7 +67,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -144,7 +143,7 @@ func makeTestTxm(t *testing.T, txStore txmgr.TestEvmTxStore, keyStore keystore.M _, _, evmConfig := txmgr.MakeTestConfigs(t) txmConfig := txmgr.NewEvmTxmConfig(evmConfig) txm := txmgr.NewEvmTxm(ec.ConfiguredChainID(), txmConfig, evmConfig.Transactions(), keyStore.Eth(), logger.TestLogger(t), nil, nil, - nil, txStore, nil, nil, nil, nil, nil) + nil, txStore, nil, nil, nil, nil) return txm } @@ -780,8 +779,7 @@ func assertNumRandomWords( } func mine(t *testing.T, requestID, subID *big.Int, backend *backends.SimulatedBackend, db *sqlx.DB, vrfVersion vrfcommon.Version, chainId *big.Int) bool { - cfg := pgtest.NewQConfig(false) - txstore := txmgr.NewTxStore(db, logger.TestLogger(t), cfg) + txstore := txmgr.NewTxStore(db, logger.TestLogger(t)) var metaField string if vrfVersion == vrfcommon.V2Plus { metaField = "GlobalSubId" @@ -808,8 +806,7 @@ func mine(t *testing.T, requestID, subID *big.Int, backend *backends.SimulatedBa func mineBatch(t *testing.T, requestIDs []*big.Int, subID *big.Int, backend *backends.SimulatedBackend, db *sqlx.DB, vrfVersion vrfcommon.Version, chainId *big.Int) bool { requestIDMap := map[string]bool{} - cfg := pgtest.NewQConfig(false) - txstore := txmgr.NewTxStore(db, logger.TestLogger(t), cfg) + txstore := txmgr.NewTxStore(db, logger.TestLogger(t)) var metaField string if vrfVersion == vrfcommon.V2Plus { metaField = "GlobalSubId" @@ -2046,9 +2043,9 @@ func TestFulfillmentCost(t *testing.T) { func TestStartingCountsV1(t *testing.T) { cfg, db := heavyweight.FullTestDBNoFixturesV2(t, nil) + ctx := testutils.Context(t) lggr := logger.TestLogger(t) - qCfg := pgtest.NewQConfig(false) - txStore := txmgr.NewTxStore(db, logger.TestLogger(t), qCfg) + txStore := txmgr.NewTxStore(db, logger.TestLogger(t)) ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg.Database()) ec := evmclimocks.NewClient(t) ec.On("ConfiguredChainID").Return(testutils.SimulatedChainID) @@ -2162,7 +2159,7 @@ func TestStartingCountsV1(t *testing.T) { } txList := append(confirmedTxes, unconfirmedTxes...) for i := range txList { - err = txStore.InsertTx(&txList[i]) + err = txStore.InsertTx(ctx, &txList[i]) require.NoError(t, err) } @@ -2197,7 +2194,7 @@ func TestStartingCountsV1(t *testing.T) { t.Log("tx attempt eth tx id: ", txAttempt.TxID) } for i := range txAttempts { - err = txStore.InsertTxAttempt(&txAttempts[i]) + err = txStore.InsertTxAttempt(ctx, &txAttempts[i]) require.NoError(t, err) } @@ -2212,7 +2209,7 @@ func TestStartingCountsV1(t *testing.T) { }) } for i := range receipts { - _, err = txStore.InsertReceipt(&receipts[i]) + _, err = txStore.InsertReceipt(ctx, &receipts[i]) require.NoError(t, err) } diff --git a/core/services/vrf/v2/listener_v2_log_listener.go b/core/services/vrf/v2/listener_v2_log_listener.go index e495eac5d8b..6fbe518411d 100644 --- a/core/services/vrf/v2/listener_v2_log_listener.go +++ b/core/services/vrf/v2/listener_v2_log_listener.go @@ -29,6 +29,7 @@ func (lsn *listenerV2) runLogListener( lastProcessedBlock int64 startingUp = true ) + filterName := lsn.getLogPollerFilterName() ctx, cancel := lsn.chStop.NewCtx() defer cancel() for { @@ -38,31 +39,30 @@ func (lsn *listenerV2) runLogListener( case <-ticker.C: start := time.Now() lsn.l.Debugw("log listener loop") - // Filter registration is idempotent, so we can just call it every time - // and retry on errors using the ticker. - err := lsn.chain.LogPoller().RegisterFilter(ctx, logpoller.Filter{ - Name: logpoller.FilterName( - "VRFListener", - "version", lsn.coordinator.Version(), - "keyhash", lsn.job.VRFSpec.PublicKey.MustHash(), - "coordinatorAddress", lsn.coordinator.Address()), - EventSigs: evmtypes.HashArray{ - lsn.coordinator.RandomWordsFulfilledTopic(), - lsn.coordinator.RandomWordsRequestedTopic(), - }, - Addresses: evmtypes.AddressArray{ - lsn.coordinator.Address(), - }, - }) - if err != nil { - lsn.l.Errorw("error registering filter in log poller, retrying", - "err", err, - "elapsed", time.Since(start)) - continue + + // If filter has not already been successfully registered, register it. + if !lsn.chain.LogPoller().HasFilter(filterName) { + err := lsn.chain.LogPoller().RegisterFilter(ctx, logpoller.Filter{ + Name: filterName, + EventSigs: evmtypes.HashArray{ + lsn.coordinator.RandomWordsFulfilledTopic(), + lsn.coordinator.RandomWordsRequestedTopic(), + }, + Addresses: evmtypes.AddressArray{ + lsn.coordinator.Address(), + }, + }) + if err != nil { + lsn.l.Errorw("error registering filter in log poller, retrying", + "err", err, + "elapsed", time.Since(start)) + continue + } } // on startup we want to initialize the last processed block if startingUp { + var err error lsn.l.Debugw("initializing last processed block on startup") lastProcessedBlock, err = lsn.initializeLastProcessedBlock(ctx) if err != nil { @@ -97,6 +97,14 @@ func (lsn *listenerV2) runLogListener( } } +func (lsn *listenerV2) getLogPollerFilterName() string { + return logpoller.FilterName( + "VRFListener", + "version", lsn.coordinator.Version(), + "keyhash", lsn.job.VRFSpec.PublicKey.MustHash(), + "coordinatorAddress", lsn.coordinator.Address()) +} + // initializeLastProcessedBlock returns the earliest block number that we need to // process requests for. This is the block number of the earliest unfulfilled request // or the latest finalized block, if there are no unfulfilled requests. diff --git a/core/services/vrf/v2/listener_v2_log_listener_test.go b/core/services/vrf/v2/listener_v2_log_listener_test.go index 81ec6473a92..15b0a5ecbe8 100644 --- a/core/services/vrf/v2/listener_v2_log_listener_test.go +++ b/core/services/vrf/v2/listener_v2_log_listener_test.go @@ -16,6 +16,8 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb" "github.com/jmoiron/sqlx" + "github.com/onsi/gomega" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -124,11 +126,13 @@ func setupVRFLogPollerListenerTH(t *testing.T, chain := evmmocks.NewChain(t) listener := &listenerV2{ - respCount: map[string]uint64{}, - job: j, - chain: chain, - l: logger.Sugared(lggr), - coordinator: coordinator, + respCount: map[string]uint64{}, + job: j, + chain: chain, + l: logger.Sugared(lggr), + coordinator: coordinator, + inflightCache: vrfcommon.NewInflightCache(10), + chStop: make(chan struct{}), } ctx := testutils.Context(t) @@ -228,6 +232,35 @@ func TestInitProcessedBlock_NoVRFReqs(t *testing.T) { require.Equal(t, int64(6), lastProcessedBlock) } +func TestLogPollerFilterRegistered(t *testing.T) { + t.Parallel() + // Instantiate listener. + th := setupVRFLogPollerListenerTH(t, false, 3, 3, 2, 1000, func(mockChain *evmmocks.Chain, th *vrfLogPollerListenerTH) { + mockChain.On("LogPoller").Maybe().Return(th.LogPoller) + }) + + // Run the log listener. This should register the log poller filter. + go th.Listener.runLogListener(time.Second, 1) + + // Wait for the log poller filter to be registered. + filterName := th.Listener.getLogPollerFilterName() + gomega.NewWithT(t).Eventually(func() bool { + return th.Listener.chain.LogPoller().HasFilter(filterName) + }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) + + // Once registered, expect the filter to stay registered. + gomega.NewWithT(t).Consistently(func() bool { + return th.Listener.chain.LogPoller().HasFilter(filterName) + }, 5*time.Second, 1*time.Second).Should(gomega.BeTrue()) + + // Close the listener to avoid an orphaned goroutine. + close(th.Listener.chStop) + + // Assert channel is closed. + _, ok := (<-th.Listener.chStop) + assert.False(t, ok) +} + func TestInitProcessedBlock_NoUnfulfilledVRFReqs(t *testing.T) { t.Parallel() diff --git a/core/services/vrf/v2/listener_v2_test.go b/core/services/vrf/v2/listener_v2_test.go index 465e3dcaca9..4e9e65bfafc 100644 --- a/core/services/vrf/v2/listener_v2_test.go +++ b/core/services/vrf/v2/listener_v2_test.go @@ -40,7 +40,7 @@ func makeTestTxm(t *testing.T, txStore txmgr.TestEvmTxStore, keyStore keystore.M ec := evmtest.NewEthClientMockWithDefaultChain(t) txmConfig := txmgr.NewEvmTxmConfig(evmConfig) txm := txmgr.NewEvmTxm(ec.ConfiguredChainID(), txmConfig, evmConfig.Transactions(), keyStore.Eth(), logger.TestLogger(t), nil, nil, - nil, txStore, nil, nil, nil, nil, nil) + nil, txStore, nil, nil, nil, nil) return txm } @@ -87,7 +87,7 @@ func addEthTx(t *testing.T, txStore txmgr.TestEvmTxStore, from common.Address, s MinConfirmations: clnull.Uint32{Uint32: 0}, PipelineTaskRunID: uuid.NullUUID{}, } - err = txStore.InsertTx(tx) + err = txStore.InsertTx(testutils.Context(t), tx) require.NoError(t, err) } @@ -118,7 +118,7 @@ func addConfirmedEthTx(t *testing.T, txStore txmgr.TestEvmTxStore, from common.A BroadcastAt: &now, InitialBroadcastAt: &now, } - err = txStore.InsertTx(tx) + err = txStore.InsertTx(testutils.Context(t), tx) require.NoError(t, err) } @@ -145,7 +145,7 @@ func addEthTxNativePayment(t *testing.T, txStore txmgr.TestEvmTxStore, from comm MinConfirmations: clnull.Uint32{Uint32: 0}, PipelineTaskRunID: uuid.NullUUID{}, } - err = txStore.InsertTx(tx) + err = txStore.InsertTx(testutils.Context(t), tx) require.NoError(t, err) } @@ -175,7 +175,7 @@ func addConfirmedEthTxNativePayment(t *testing.T, txStore txmgr.TestEvmTxStore, BroadcastAt: &now, InitialBroadcastAt: &now, } - err = txStore.InsertTx(tx) + err = txStore.InsertTx(testutils.Context(t), tx) require.NoError(t, err) } @@ -196,7 +196,7 @@ func testMaybeSubtractReservedLink(t *testing.T, vrfVersion vrfcommon.Version) { RequestedConfsDelay: 10, }).Toml()) require.NoError(t, err) - txstore := txmgr.NewTxStore(db, lggr, cfg) + txstore := txmgr.NewTxStore(db, lggr) txm := makeTestTxm(t, txstore, ks) chain := evmmocks.NewChain(t) chain.On("TxManager").Return(txm) @@ -278,7 +278,7 @@ func testMaybeSubtractReservedNative(t *testing.T, vrfVersion vrfcommon.Version) RequestedConfsDelay: 10, }).Toml()) require.NoError(t, err) - txstore := txmgr.NewTxStore(db, logger.TestLogger(t), cfg) + txstore := txmgr.NewTxStore(db, logger.TestLogger(t)) txm := makeTestTxm(t, txstore, ks) require.NoError(t, err) chain := evmmocks.NewChain(t) @@ -353,7 +353,7 @@ func TestMaybeSubtractReservedNativeV2(t *testing.T) { RequestedConfsDelay: 10, }).Toml()) require.NoError(t, err) - txstore := txmgr.NewTxStore(db, logger.TestLogger(t), cfg) + txstore := txmgr.NewTxStore(db, logger.TestLogger(t)) txm := makeTestTxm(t, txstore, ks) chain := evmmocks.NewChain(t) chain.On("TxManager").Return(txm).Maybe() diff --git a/core/services/webhook/delegate.go b/core/services/webhook/delegate.go index 999b041f308..0c08e992f32 100644 --- a/core/services/webhook/delegate.go +++ b/core/services/webhook/delegate.go @@ -9,6 +9,7 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -25,7 +26,7 @@ type ( } JobRunner interface { - RunJob(ctx context.Context, jobUUID uuid.UUID, requestBody string, meta pipeline.JSONSerializable) (int64, error) + RunJob(ctx context.Context, jobUUID uuid.UUID, requestBody string, meta jsonserializable.JSONSerializable) (int64, error) } ) @@ -151,7 +152,7 @@ func (r *webhookJobRunner) spec(externalJobID uuid.UUID) (registeredJob, bool) { var ErrJobNotExists = errors.New("job does not exist") -func (r *webhookJobRunner) RunJob(ctx context.Context, jobUUID uuid.UUID, requestBody string, meta pipeline.JSONSerializable) (int64, error) { +func (r *webhookJobRunner) RunJob(ctx context.Context, jobUUID uuid.UUID, requestBody string, meta jsonserializable.JSONSerializable) (int64, error) { spec, exists := r.spec(jobUUID) if !exists { return 0, ErrJobNotExists diff --git a/core/services/webhook/delegate_test.go b/core/services/webhook/delegate_test.go index c020f641615..64b6615642c 100644 --- a/core/services/webhook/delegate_test.go +++ b/core/services/webhook/delegate_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -34,7 +35,7 @@ func TestWebhookDelegate(t *testing.T) { } requestBody = "foo" - meta = pipeline.JSONSerializable{Val: "bar", Valid: true} + meta = jsonserializable.JSONSerializable{Val: "bar", Valid: true} vars = map[string]interface{}{ "jobSpec": map[string]interface{}{ "databaseID": spec.ID, diff --git a/core/services/workflows/delegate.go b/core/services/workflows/delegate.go index a54a33e9f0d..2c95b478709 100644 --- a/core/services/workflows/delegate.go +++ b/core/services/workflows/delegate.go @@ -15,6 +15,56 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) +const hardcodedWorkflow = ` +triggers: + - type: "on_mercury_report" + config: + feedlist: + - "0x1111111111111111111100000000000000000000000000000000000000000000" # ETHUSD + - "0x2222222222222222222200000000000000000000000000000000000000000000" # LINKUSD + - "0x3333333333333333333300000000000000000000000000000000000000000000" # BTCUSD + +consensus: + - type: "offchain_reporting" + ref: "evm_median" + inputs: + observations: + - "$(trigger.outputs)" + config: + aggregation_method: "data_feeds_2_0" + aggregation_config: + "0x1111111111111111111100000000000000000000000000000000000000000000": + deviation: "0.001" + heartbeat: "30m" + "0x2222222222222222222200000000000000000000000000000000000000000000": + deviation: "0.001" + heartbeat: "30m" + "0x3333333333333333333300000000000000000000000000000000000000000000": + deviation: "0.001" + heartbeat: "30m" + encoder: "EVM" + encoder_config: + abi: "mercury_reports bytes[]" + +targets: + - type: "write_polygon-testnet-mumbai" + inputs: + report: + - "$(evm_median.outputs.reports)" + config: + address: "0x3F3554832c636721F1fD1822Ccca0354576741Ef" + params: ["$(inputs.report)"] + abi: "receive(report bytes)" + - type: "write_ethereum-testnet-sepolia" + inputs: + report: + - "$(evm_median.outputs.reports)" + config: + address: "0x54e220867af6683aE6DcBF535B4f952cB5116510" + params: ["$(inputs.report)"] + abi: "receive(report bytes)" +` + type Delegate struct { registry types.CapabilitiesRegistry logger logger.Logger @@ -36,7 +86,12 @@ func (d *Delegate) OnDeleteJob(ctx context.Context, jb job.Job, q pg.Queryer) er // ServicesForSpec satisfies the job.Delegate interface. func (d *Delegate) ServicesForSpec(ctx context.Context, spec job.Job) ([]job.ServiceCtx, error) { - engine, err := NewEngine(d.logger, d.registry) + cfg := Config{ + Lggr: d.logger, + Spec: hardcodedWorkflow, + Registry: d.registry, + } + engine, err := NewEngine(cfg) if err != nil { return nil, err } diff --git a/core/services/workflows/engine.go b/core/services/workflows/engine.go index 3261bdd3fce..dfc2fb347ae 100644 --- a/core/services/workflows/engine.go +++ b/core/services/workflows/engine.go @@ -3,8 +3,11 @@ package workflows import ( "context" "fmt" + "sync" "time" + "github.com/google/uuid" + "github.com/smartcontractkit/chainlink-common/pkg/capabilities" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/types" @@ -19,100 +22,143 @@ const ( mockedTriggerID = "cccccccccc0000000000000000000000" ) +// Engine handles the lifecycle of a single workflow and its executions. type Engine struct { services.StateMachine - logger logger.Logger - registry types.CapabilitiesRegistry - trigger capabilities.TriggerCapability - consensus capabilities.ConsensusCapability - targets []capabilities.TargetCapability - workflow *Workflow - callbackCh chan capabilities.CapabilityResponse - cancel func() + logger logger.Logger + registry types.CapabilitiesRegistry + workflow *workflow + executionStates *inMemoryStore + pendingStepRequests chan stepRequest + triggerEvents chan capabilities.CapabilityResponse + newWorkerCh chan struct{} + stepUpdateCh chan stepState + wg sync.WaitGroup + stopCh services.StopChan + newWorkerTimeout time.Duration + + // Used for testing to wait for an execution to complete + xxxExecutionFinished chan string } func (e *Engine) Start(ctx context.Context) error { return e.StartOnce("Engine", func() error { // create a new context, since the one passed in via Start is short-lived. - ctx, cancel := context.WithCancel(context.Background()) - e.cancel = cancel + ctx, _ := e.stopCh.NewCtx() + + e.wg.Add(2) go e.init(ctx) - go e.triggerHandlerLoop(ctx) + go e.loop(ctx) + return nil }) } +// init does the following: +// +// 1. Resolves the underlying capability for each trigger +// 2. Registers each step's capability to this workflow +// 3. Registers for trigger events now that all capabilities are resolved +// +// Steps 1 and 2 are retried every 5 seconds until successful. func (e *Engine) init(ctx context.Context) { + defer e.wg.Done() + retrySec := 5 ticker := time.NewTicker(time.Duration(retrySec) * time.Second) defer ticker.Stop() - // Note: in our hardcoded workflow, there is only one trigger, - // and one consensus step. - trigger := e.workflow.Triggers[0] - consensus := e.workflow.Consensus[0] - - var err error + initSuccessful := true LOOP: for { select { case <-ctx.Done(): return case <-ticker.C: - e.trigger, err = e.registry.GetTrigger(ctx, trigger.Type) - if err != nil { - e.logger.Errorf("failed to get trigger capability: %s, retrying in %d seconds", err, retrySec) - break - } + // Resolve the underlying capability for each trigger + for _, t := range e.workflow.triggers { + tg, err := e.registry.GetTrigger(ctx, t.Type) + if err != nil { + initSuccessful = false + e.logger.Errorf("failed to get trigger capability: %s, retrying in %d seconds", err, retrySec) + continue + } - e.consensus, err = e.registry.GetConsensus(ctx, consensus.Type) - if err != nil { - e.logger.Errorf("failed to get consensus capability: %s, retrying in %d seconds", err, retrySec) - break + t.trigger = tg } - failed := false - e.targets = make([]capabilities.TargetCapability, len(e.workflow.Targets)) - for i, target := range e.workflow.Targets { - e.targets[i], err = e.registry.GetTarget(ctx, target.Type) - if err != nil { - e.logger.Errorf("failed to get target capability: %s, retrying in %d seconds", err, retrySec) - failed = true - break + + // Walk the graph and register each step's capability to this workflow + err := e.workflow.walkDo(keywordTrigger, func(s *step) error { + // The graph contains a dummy step for triggers, but + // we handle triggers separately since there might be more than one. + if s.Ref == keywordTrigger { + return nil + } + + // If the capability is already cached, that means we've already registered it + if s.capability != nil { + return nil + } + + cp, innerErr := e.registry.Get(ctx, s.Type) + if innerErr != nil { + return fmt.Errorf("failed to get capability with ref %s: %s, retrying in %d seconds", s.Type, innerErr, retrySec) } + + // We only need to configure actions, consensus and targets here, and + // they all satisfy the `CallbackExecutable` interface + cc, ok := cp.(capabilities.CallbackExecutable) + if !ok { + return fmt.Errorf("could not coerce capability %s to CallbackExecutable", s.Type) + } + + if s.config == nil { + configMap, ierr := values.NewMap(s.Config) + if ierr != nil { + return fmt.Errorf("failed to convert config to values.Map: %s", ierr) + } + s.config = configMap + } + + reg := capabilities.RegisterToWorkflowRequest{ + Metadata: capabilities.RegistrationMetadata{ + WorkflowID: mockedWorkflowID, + }, + Config: s.config, + } + + innerErr = cc.RegisterToWorkflow(ctx, reg) + if innerErr != nil { + return fmt.Errorf("failed to register to workflow: %+v", reg) + } + + s.capability = cc + return nil + }) + if err != nil { + initSuccessful = false + e.logger.Error(err) } - if !failed { + + if initSuccessful { break LOOP } } } - // we have all needed capabilities, now we can register for trigger events - err = e.registerTrigger(ctx) - if err != nil { - e.logger.Errorf("failed to register trigger: %s", err) - } - - // also register for consensus - cm, err := values.NewMap(consensus.Config) - if err != nil { - e.logger.Errorf("failed to convert config to values.Map: %s", err) - } - reg := capabilities.RegisterToWorkflowRequest{ - Metadata: capabilities.RegistrationMetadata{ - WorkflowID: mockedWorkflowID, - }, - Config: cm, - } - err = e.consensus.RegisterToWorkflow(ctx, reg) - if err != nil { - e.logger.Errorf("failed to register consensus: %s", err) + // We have all needed capabilities, now we can register for trigger events + for _, t := range e.workflow.triggers { + err := e.registerTrigger(ctx, t) + if err != nil { + e.logger.Errorf("failed to register trigger: %s", err) + } } e.logger.Info("engine initialized") } -func (e *Engine) registerTrigger(ctx context.Context) error { - trigger := e.workflow.Triggers[0] +// registerTrigger is used during the initialization phase to bind a trigger to this workflow +func (e *Engine) registerTrigger(ctx context.Context, t *triggerCapability) error { triggerInputs, err := values.NewMap( map[string]any{ "triggerId": mockedTriggerID, @@ -122,11 +168,13 @@ func (e *Engine) registerTrigger(ctx context.Context) error { return err } - tc, err := values.NewMap(trigger.Config) + tc, err := values.NewMap(t.Config) if err != nil { return err } + t.config = tc + triggerRegRequest := capabilities.CapabilityRequest{ Metadata: capabilities.RequestMetadata{ WorkflowID: mockedWorkflowID, @@ -134,204 +182,413 @@ func (e *Engine) registerTrigger(ctx context.Context) error { Config: tc, Inputs: triggerInputs, } - err = e.trigger.RegisterTrigger(ctx, e.callbackCh, triggerRegRequest) + err = t.trigger.RegisterTrigger(ctx, e.triggerEvents, triggerRegRequest) if err != nil { - return fmt.Errorf("failed to instantiate mercury_trigger, %s", err) + return fmt.Errorf("failed to instantiate trigger %s, %s", t.Type, err) } return nil } -func (e *Engine) triggerHandlerLoop(ctx context.Context) { +// loop is the synchronization goroutine for the engine, and is responsible for: +// - dispatching new workers up to the limit specified (default = 100) +// - starting a new execution when a trigger emits a message on `triggerEvents` +// - updating the `executionState` with the outcome of a `step`. +// +// Note: `executionState` is only mutated by this loop directly. +// +// This is important to avoid data races, and any accesses of `executionState` by any other +// goroutine should happen via a `stepRequest` message containing a copy of the latest +// `executionState`. +// +// This works because a worker thread for a given step will only +// be spun up once all dependent steps have completed (guaranteeing that the state associated +// with those dependent steps will no longer change). Therefore as long this worker thread only +// accesses data from dependent states, the data will never be stale. +func (e *Engine) loop(ctx context.Context) { + defer e.wg.Done() for { select { case <-ctx.Done(): + e.logger.Debugw("shutting down loop") return - case resp := <-e.callbackCh: - go e.handleExecution(ctx, resp) + case resp := <-e.triggerEvents: + if resp.Err != nil { + e.logger.Errorf("trigger event was an error; not executing", resp.Err) + continue + } + + err := e.startExecution(ctx, resp.Value) + if err != nil { + e.logger.Errorf("failed to start execution: %w", err) + } + case pendingStepRequest := <-e.pendingStepRequests: + // Wait for a new worker to be available before dispatching a new one. + // We'll do this up to newWorkerTimeout. If this expires, we'll put the + // message back on the queue and keep going. + t := time.NewTimer(e.newWorkerTimeout) + select { + case <-e.newWorkerCh: + e.wg.Add(1) + go e.workerForStepRequest(ctx, pendingStepRequest) + case <-t.C: + e.logger.Errorf("timed out when spinning off worker for pending step request %+v", pendingStepRequest) + e.pendingStepRequests <- pendingStepRequest + } + t.Stop() + case stepUpdate := <-e.stepUpdateCh: + // Executed synchronously to ensure we correctly schedule subsequent tasks. + err := e.handleStepUpdate(ctx, stepUpdate) + if err != nil { + e.logger.Errorf("failed to update step state: %+v, %s", stepUpdate, err) + } } } } -func (e *Engine) handleExecution(ctx context.Context, event capabilities.CapabilityResponse) { - e.logger.Debugw("executing on a trigger event", "event", event) - trigger := e.workflow.Triggers[0] - if event.Err != nil { - e.logger.Errorf("trigger event was an error; not executing", event.Err) - return - } - +// startExecution kicks off a new workflow execution when a trigger event is received. +func (e *Engine) startExecution(ctx context.Context, event values.Value) error { + executionID := uuid.New().String() + e.logger.Debugw("executing on a trigger event", "event", event, "executionID", executionID) ec := &executionState{ steps: map[string]*stepState{ - trigger.Ref: { + keywordTrigger: { outputs: &stepOutput{ - value: event.Value, + value: event, }, + status: statusCompleted, }, }, workflowID: mockedWorkflowID, - executionID: mockedExecutionID, + executionID: executionID, + status: statusStarted, + } + + err := e.executionStates.add(ctx, ec) + if err != nil { + return err + } + + // Find the tasks we need to fire when a trigger has fired and enqueue them. + // This consists of a) nodes without a dependency and b) nodes which depend + // on a trigger + triggerDependents, err := e.workflow.dependents(keywordTrigger) + if err != nil { + return err } - consensus := e.workflow.Consensus[0] - err := e.handleStep(ctx, ec, consensus) + for _, td := range triggerDependents { + e.queueIfReady(*ec, td) + } + + return nil +} + +func (e *Engine) handleStepUpdate(ctx context.Context, stepUpdate stepState) error { + state, err := e.executionStates.updateStep(ctx, &stepUpdate) if err != nil { - e.logger.Errorf("error in handleConsensus %v", err) - return + return err } - for _, trg := range e.workflow.Targets { - err := e.handleStep(ctx, ec, trg) + switch stepUpdate.status { + case statusCompleted: + stepDependents, err := e.workflow.dependents(stepUpdate.ref) if err != nil { - e.logger.Errorf("error in handleTargets %v", err) - return + return err + } + + // There are no steps left to process in the current path, so let's check if + // we've completed the workflow. + // If not, we'll check for any dependents that are ready to process. + if len(stepDependents) == 0 { + workflowCompleted := true + err := e.workflow.walkDo(keywordTrigger, func(s *step) error { + step, ok := state.steps[s.Ref] + // The step is missing from the state, + // which means it hasn't been processed yet. + // Let's mark `workflowCompleted` = false, and + // continue. + if !ok { + workflowCompleted = false + return nil + } + + switch step.status { + case statusCompleted, statusErrored: + default: + workflowCompleted = false + } + return nil + }) + if err != nil { + return err + } + + if workflowCompleted { + err := e.finishExecution(ctx, state.executionID, statusCompleted) + if err != nil { + return err + } + } + } + + for _, sd := range stepDependents { + e.queueIfReady(state, sd) + } + case statusErrored: + err := e.finishExecution(ctx, state.executionID, statusErrored) + if err != nil { + return err } } + + return nil } -func (e *Engine) handleStep(ctx context.Context, es *executionState, node Capability) error { - stepState := &stepState{ - outputs: &stepOutput{}, +func (e *Engine) queueIfReady(state executionState, step *step) { + // Check if all dependencies are completed for the current step + var waitingOnDependencies bool + for _, dr := range step.dependencies { + stepState, ok := state.steps[dr] + if !ok { + waitingOnDependencies = true + continue + } + + // Unless the dependency is complete, + // we'll mark waitingOnDependencies = true. + // This includes cases where one of the dependent + // steps has errored, since that means we shouldn't + // schedule the step for execution. + if stepState.status != statusCompleted { + waitingOnDependencies = true + } } - es.steps[node.Ref] = stepState - // Let's get the capability. If we fail here, we'll bail out - // and try to handle it at the next execution. - cp, err := e.registry.Get(ctx, node.Type) + // If all dependencies are completed, enqueue the step. + if !waitingOnDependencies { + e.logger.Debugw("step request enqueued", "ref", step.Ref, "state", copyState(state)) + e.pendingStepRequests <- stepRequest{ + state: copyState(state), + stepRef: step.Ref, + } + } +} + +func (e *Engine) finishExecution(ctx context.Context, executionID string, status string) error { + err := e.executionStates.updateStatus(ctx, executionID, status) if err != nil { return err } - api, ok := cp.(capabilities.CallbackExecutable) - if !ok { - return fmt.Errorf("capability %s must be an action, consensus or target", node.Type) + // Signal that an execution has finished in a + // non-blocking fashion. This is intended for + // testing purposes only. + select { + case e.xxxExecutionFinished <- executionID: + default: } - i, err := findAndInterpolateAllKeys(node.Inputs, es) - if err != nil { - return err + return nil +} + +func (e *Engine) workerForStepRequest(ctx context.Context, msg stepRequest) { + defer func() { e.newWorkerCh <- struct{}{} }() + defer e.wg.Done() + + e.logger.Debugw("executing on a step event", "stepRef", msg.stepRef, "executionID", msg.state.executionID) + stepState := &stepState{ + outputs: &stepOutput{}, + executionID: msg.state.executionID, + ref: msg.stepRef, } - inputs, err := values.NewMap(i.(map[string]any)) + inputs, outputs, err := e.executeStep(ctx, msg) if err != nil { - return err + e.logger.Errorf("error executing step request: %w", err, "executionID", msg.state.executionID, "stepRef", msg.stepRef) + stepState.outputs.err = err + stepState.status = statusErrored + } else { + e.logger.Debugw("step executed successfully", "executionID", msg.state.executionID, "stepRef", msg.stepRef, "outputs", outputs) + stepState.outputs.value = outputs + stepState.status = statusCompleted } stepState.inputs = inputs - config, err := values.NewMap(node.Config) + // Let's try and emit the stepUpdate. + // If the context is canceled, we'll just drop the update. + // This means the engine is shutting down and the + // receiving loop may not pick up any messages we emit. + // Note: When full persistence support is added, any hanging steps + // like this one will get picked up again and will be reprocessed. + select { + case <-ctx.Done(): + e.logger.Errorf("context canceled before step update could be issued", err, "executionID", msg.state.executionID, "stepRef", msg.stepRef) + case e.stepUpdateCh <- *stepState: + } +} + +// executeStep executes the referenced capability within a step and returns the result. +func (e *Engine) executeStep(ctx context.Context, msg stepRequest) (*values.Map, values.Value, error) { + step, err := e.workflow.Vertex(msg.stepRef) if err != nil { - return err + return nil, nil, err + } + + i, err := findAndInterpolateAllKeys(step.Inputs, msg.state) + if err != nil { + return nil, nil, err + } + + inputs, err := values.NewMap(i.(map[string]any)) + if err != nil { + return nil, nil, err } tr := capabilities.CapabilityRequest{ Inputs: inputs, - Config: config, + Config: step.config, Metadata: capabilities.RequestMetadata{ - WorkflowID: es.workflowID, - WorkflowExecutionID: es.executionID, + WorkflowID: msg.state.workflowID, + WorkflowExecutionID: msg.state.executionID, }, } - resp, err := capabilities.ExecuteSync(ctx, api, tr) + resp, err := capabilities.ExecuteSync(ctx, step.capability, tr) if err != nil { - stepState.outputs.err = err - return err + return inputs, nil, err } // `ExecuteSync` returns a `values.List` even if there was // just one return value. If that is the case, let's unwrap the // single value to make it easier to use in -- for example -- variable interpolation. if len(resp.Underlying) > 1 { - stepState.outputs.value = resp - } else { - stepState.outputs.value = resp.Underlying[0] + return inputs, resp, err } - return nil + return inputs, resp.Underlying[0], err +} + +func (e *Engine) deregisterTrigger(ctx context.Context, t *triggerCapability) error { + triggerInputs, err := values.NewMap( + map[string]any{ + "triggerId": mockedTriggerID, + }, + ) + if err != nil { + return err + } + deregRequest := capabilities.CapabilityRequest{ + Metadata: capabilities.RequestMetadata{ + WorkflowID: mockedWorkflowID, + }, + Inputs: triggerInputs, + Config: t.config, + } + return t.trigger.UnregisterTrigger(ctx, deregRequest) } func (e *Engine) Close() error { return e.StopOnce("Engine", func() error { - defer e.cancel() + ctx := context.Background() + // To shut down the engine, we'll start by deregistering + // any triggers to ensure no new executions are triggered, + // then we'll close down any background goroutines, + // and finally, we'll deregister any workflow steps. + for _, t := range e.workflow.triggers { + err := e.deregisterTrigger(ctx, t) + if err != nil { + return err + } + } - triggerInputs, err := values.NewMap( - map[string]any{ - "triggerId": mockedTriggerID, - }, - ) + close(e.stopCh) + e.wg.Wait() + + err := e.workflow.walkDo(keywordTrigger, func(s *step) error { + if s.Ref == keywordTrigger { + return nil + } + + reg := capabilities.UnregisterFromWorkflowRequest{ + Metadata: capabilities.RegistrationMetadata{ + WorkflowID: mockedWorkflowID, + }, + Config: s.config, + } + + innerErr := s.capability.UnregisterFromWorkflow(ctx, reg) + if innerErr != nil { + return fmt.Errorf("failed to unregister from workflow: %+v", reg) + } + + return nil + }) if err != nil { return err } - deregRequest := capabilities.CapabilityRequest{ - Metadata: capabilities.RequestMetadata{ - WorkflowID: mockedWorkflowID, - }, - Inputs: triggerInputs, - } - return e.trigger.UnregisterTrigger(context.Background(), deregRequest) + + return nil }) } -func NewEngine(lggr logger.Logger, registry types.CapabilitiesRegistry) (engine *Engine, err error) { - yamlWorkflowSpec := ` -triggers: - - type: "on_mercury_report" - ref: report_data - config: - feedlist: - - "0x1111111111111111111100000000000000000000000000000000000000000000" # ETHUSD - - "0x2222222222222222222200000000000000000000000000000000000000000000" # LINKUSD - - "0x3333333333333333333300000000000000000000000000000000000000000000" # BTCUSD - -consensus: - - type: "offchain_reporting" - ref: evm_median - inputs: - observations: - - $(report_data.outputs) - config: - aggregation_method: data_feeds_2_0 - aggregation_config: - 0x1111111111111111111100000000000000000000000000000000000000000000: - deviation: "0.001" - heartbeat: "30m" - 0x2222222222222222222200000000000000000000000000000000000000000000: - deviation: "0.001" - heartbeat: "30m" - 0x3333333333333333333300000000000000000000000000000000000000000000: - deviation: "0.001" - heartbeat: "30m" - encoder: EVM - encoder_config: - abi: "mercury_reports bytes[]" - -targets: - - type: write_polygon-testnet-mumbai - inputs: - report: - - $(evm_median.outputs.reports) - config: - address: "0x3F3554832c636721F1fD1822Ccca0354576741Ef" - params: [($inputs.report)] - abi: "receive(report bytes)" - - type: write_ethereum-testnet-sepolia - inputs: - report: - - $(evm_median.outputs.reports) - config: - address: "0x54e220867af6683aE6DcBF535B4f952cB5116510" - params: ["$(inputs.report)"] - abi: "receive(report bytes)" -` - - workflow, err := Parse(yamlWorkflowSpec) +type Config struct { + Spec string + Lggr logger.Logger + Registry types.CapabilitiesRegistry + MaxWorkerLimit int + QueueSize int + NewWorkerTimeout time.Duration +} + +const ( + defaultWorkerLimit = 100 + defaultQueueSize = 100000 + defaultNewWorkerTimeout = 2 * time.Second +) + +func NewEngine(cfg Config) (engine *Engine, err error) { + if cfg.MaxWorkerLimit == 0 { + cfg.MaxWorkerLimit = defaultWorkerLimit + } + + if cfg.QueueSize == 0 { + cfg.QueueSize = defaultQueueSize + } + + if cfg.NewWorkerTimeout == 0 { + cfg.NewWorkerTimeout = defaultNewWorkerTimeout + } + + // TODO: validation of the workflow spec + // We'll need to check, among other things: + // - that there are no step `ref` called `trigger` as this is reserved for any triggers + // - that there are no duplicate `ref`s + // - that the `ref` for any triggers is empty -- and filled in with `trigger` + // - etc. + + workflow, err := Parse(cfg.Spec) if err != nil { return nil, err } + + // Instantiate semaphore to put a limit on the number of workers + newWorkerCh := make(chan struct{}, cfg.MaxWorkerLimit) + for i := 0; i < cfg.MaxWorkerLimit; i++ { + newWorkerCh <- struct{}{} + } + engine = &Engine{ - logger: lggr.Named("WorkflowEngine"), - registry: registry, - workflow: workflow, - callbackCh: make(chan capabilities.CapabilityResponse), + logger: cfg.Lggr.Named("WorkflowEngine"), + registry: cfg.Registry, + workflow: workflow, + executionStates: newInMemoryStore(), + pendingStepRequests: make(chan stepRequest, cfg.QueueSize), + newWorkerCh: newWorkerCh, + stepUpdateCh: make(chan stepState), + triggerEvents: make(chan capabilities.CapabilityResponse), + stopCh: make(chan struct{}), + newWorkerTimeout: cfg.NewWorkerTimeout, + xxxExecutionFinished: make(chan string), } return engine, nil } diff --git a/core/services/workflows/engine_test.go b/core/services/workflows/engine_test.go index 74a2093c0d2..a87e841121d 100644 --- a/core/services/workflows/engine_test.go +++ b/core/services/workflows/engine_test.go @@ -2,6 +2,7 @@ package workflows import ( "context" + "errors" "testing" "github.com/shopspring/decimal" @@ -70,7 +71,98 @@ func TestEngineWithHardcodedWorkflow(t *testing.T) { ctx := testutils.Context(t) reg := coreCap.NewRegistry(logger.TestLogger(t)) - trigger := &mockTriggerCapability{ + trigger, cr := mockTrigger(t) + + require.NoError(t, reg.Add(ctx, trigger)) + require.NoError(t, reg.Add(ctx, mockConsensus())) + target1 := mockTarget() + require.NoError(t, reg.Add(ctx, target1)) + + target2 := newMockCapability( + capabilities.MustNewCapabilityInfo( + "write_ethereum-testnet-sepolia", + capabilities.CapabilityTypeTarget, + "a write capability targeting ethereum sepolia testnet", + "v1.0.0", + ), + func(req capabilities.CapabilityRequest) (capabilities.CapabilityResponse, error) { + list := req.Inputs.Underlying["report"].(*values.List) + return capabilities.CapabilityResponse{ + Value: list.Underlying[0], + }, nil + }, + ) + require.NoError(t, reg.Add(ctx, target2)) + + lggr := logger.TestLogger(t) + cfg := Config{ + Lggr: lggr, + Registry: reg, + Spec: hardcodedWorkflow, + } + eng, err := NewEngine(cfg) + require.NoError(t, err) + + err = eng.Start(ctx) + require.NoError(t, err) + defer eng.Close() + + eid := <-eng.xxxExecutionFinished + assert.Equal(t, cr, <-target1.response) + assert.Equal(t, cr, <-target2.response) + + state, err := eng.executionStates.get(ctx, eid) + require.NoError(t, err) + + assert.Equal(t, state.status, statusCompleted) +} + +const ( + simpleWorkflow = ` +triggers: + - type: "on_mercury_report" + config: + feedlist: + - "0x1111111111111111111100000000000000000000000000000000000000000000" # ETHUSD + - "0x2222222222222222222200000000000000000000000000000000000000000000" # LINKUSD + - "0x3333333333333333333300000000000000000000000000000000000000000000" # BTCUSD + +consensus: + - type: "offchain_reporting" + ref: "evm_median" + inputs: + observations: + - "$(trigger.outputs)" + config: + aggregation_method: "data_feeds_2_0" + aggregation_config: + "0x1111111111111111111100000000000000000000000000000000000000000000": + deviation: "0.001" + heartbeat: "30m" + "0x2222222222222222222200000000000000000000000000000000000000000000": + deviation: "0.001" + heartbeat: "30m" + "0x3333333333333333333300000000000000000000000000000000000000000000": + deviation: "0.001" + heartbeat: "30m" + encoder: "EVM" + encoder_config: + abi: "mercury_reports bytes[]" + +targets: + - type: "write_polygon-testnet-mumbai" + inputs: + report: + - "$(evm_median.outputs.reports)" + config: + address: "0x3F3554832c636721F1fD1822Ccca0354576741Ef" + params: ["$(inputs.report)"] + abi: "receive(report bytes)" +` +) + +func mockTrigger(t *testing.T) (capabilities.TriggerCapability, capabilities.CapabilityResponse) { + mt := &mockTriggerCapability{ CapabilityInfo: capabilities.MustNewCapabilityInfo( "on_mercury_report", capabilities.CapabilityTypeTrigger, @@ -78,9 +170,35 @@ func TestEngineWithHardcodedWorkflow(t *testing.T) { "v1.0.0", ), } - require.NoError(t, reg.Add(ctx, trigger)) + resp, err := values.NewMap(map[string]any{ + "123": decimal.NewFromFloat(1.00), + "456": decimal.NewFromFloat(1.25), + "789": decimal.NewFromFloat(1.50), + }) + require.NoError(t, err) + cr := capabilities.CapabilityResponse{ + Value: resp, + } + mt.triggerEvent = cr + return mt, cr +} - consensus := newMockCapability( +func mockFailingConsensus() *mockCapability { + return newMockCapability( + capabilities.MustNewCapabilityInfo( + "offchain_reporting", + capabilities.CapabilityTypeConsensus, + "an ocr3 consensus capability", + "v3.0.0", + ), + func(req capabilities.CapabilityRequest) (capabilities.CapabilityResponse, error) { + return capabilities.CapabilityResponse{}, errors.New("fatal consensus error") + }, + ) +} + +func mockConsensus() *mockCapability { + return newMockCapability( capabilities.MustNewCapabilityInfo( "offchain_reporting", capabilities.CapabilityTypeConsensus, @@ -103,9 +221,10 @@ func TestEngineWithHardcodedWorkflow(t *testing.T) { }, nil }, ) - require.NoError(t, reg.Add(ctx, consensus)) +} - target1 := newMockCapability( +func mockTarget() *mockCapability { + return newMockCapability( capabilities.MustNewCapabilityInfo( "write_polygon-testnet-mumbai", capabilities.CapabilityTypeTarget, @@ -119,42 +238,154 @@ func TestEngineWithHardcodedWorkflow(t *testing.T) { }, nil }, ) - require.NoError(t, reg.Add(ctx, target1)) +} - target2 := newMockCapability( +func TestEngine_ErrorsTheWorkflowIfAStepErrors(t *testing.T) { + ctx := testutils.Context(t) + reg := coreCap.NewRegistry(logger.TestLogger(t)) + + trigger, _ := mockTrigger(t) + + require.NoError(t, reg.Add(ctx, trigger)) + require.NoError(t, reg.Add(ctx, mockFailingConsensus())) + require.NoError(t, reg.Add(ctx, mockTarget())) + + cfg := Config{ + Lggr: logger.TestLogger(t), + Registry: reg, + Spec: simpleWorkflow, + } + eng, err := NewEngine(cfg) + require.NoError(t, err) + + err = eng.Start(ctx) + require.NoError(t, err) + defer eng.Close() + + eid := <-eng.xxxExecutionFinished + state, err := eng.executionStates.get(ctx, eid) + require.NoError(t, err) + + assert.Equal(t, state.status, statusErrored) + // evm_median is the ref of our failing consensus step + assert.Equal(t, state.steps["evm_median"].status, statusErrored) +} + +const ( + multiStepWorkflow = ` +triggers: + - type: "on_mercury_report" + config: + feedlist: + - "0x1111111111111111111100000000000000000000000000000000000000000000" # ETHUSD + - "0x2222222222222222222200000000000000000000000000000000000000000000" # LINKUSD + - "0x3333333333333333333300000000000000000000000000000000000000000000" # BTCUSD + +actions: + - type: "read_chain_action" + ref: "read_chain_action" + inputs: + action: + - "$(trigger.outputs)" + +consensus: + - type: "offchain_reporting" + ref: "evm_median" + inputs: + observations: + - "$(trigger.outputs)" + - "$(read_chain_action.outputs)" + config: + aggregation_method: "data_feeds_2_0" + aggregation_config: + "0x1111111111111111111100000000000000000000000000000000000000000000": + deviation: "0.001" + heartbeat: "30m" + "0x2222222222222222222200000000000000000000000000000000000000000000": + deviation: "0.001" + heartbeat: "30m" + "0x3333333333333333333300000000000000000000000000000000000000000000": + deviation: "0.001" + heartbeat: "30m" + encoder: "EVM" + encoder_config: + abi: "mercury_reports bytes[]" + +targets: + - type: "write_polygon-testnet-mumbai" + inputs: + report: + - "$(evm_median.outputs.reports)" + config: + address: "0x3F3554832c636721F1fD1822Ccca0354576741Ef" + params: ["$(inputs.report)"] + abi: "receive(report bytes)" +` +) + +func mockAction() (*mockCapability, values.Value) { + outputs := values.NewString("output") + return newMockCapability( capabilities.MustNewCapabilityInfo( - "write_ethereum-testnet-sepolia", - capabilities.CapabilityTypeTarget, - "a write capability targeting ethereum sepolia testnet", + "read_chain_action", + capabilities.CapabilityTypeAction, + "a read chain action", "v1.0.0", ), func(req capabilities.CapabilityRequest) (capabilities.CapabilityResponse, error) { - list := req.Inputs.Underlying["report"].(*values.List) + return capabilities.CapabilityResponse{ - Value: list.Underlying[0], + Value: outputs, }, nil }, - ) - require.NoError(t, reg.Add(ctx, target2)) + ), outputs +} - lggr := logger.TestLogger(t) - eng, err := NewEngine(lggr, reg) - require.NoError(t, err) +func TestEngine_MultiStepDependencies(t *testing.T) { + ctx := testutils.Context(t) + reg := coreCap.NewRegistry(logger.TestLogger(t)) - resp, err := values.NewMap(map[string]any{ - "123": decimal.NewFromFloat(1.00), - "456": decimal.NewFromFloat(1.25), - "789": decimal.NewFromFloat(1.50), - }) - require.NoError(t, err) - cr := capabilities.CapabilityResponse{ - Value: resp, + trigger, cr := mockTrigger(t) + + require.NoError(t, reg.Add(ctx, trigger)) + require.NoError(t, reg.Add(ctx, mockConsensus())) + require.NoError(t, reg.Add(ctx, mockTarget())) + + action, out := mockAction() + require.NoError(t, reg.Add(ctx, action)) + + cfg := Config{ + Lggr: logger.TestLogger(t), + Registry: reg, + Spec: multiStepWorkflow, } - trigger.triggerEvent = cr + eng, err := NewEngine(cfg) + require.NoError(t, err) err = eng.Start(ctx) require.NoError(t, err) defer eng.Close() - assert.Equal(t, cr, <-target1.response) - assert.Equal(t, cr, <-target2.response) + + eid := <-eng.xxxExecutionFinished + state, err := eng.executionStates.get(ctx, eid) + require.NoError(t, err) + + assert.Equal(t, state.status, statusCompleted) + + // The inputs to the consensus step should + // be the outputs of the two dependents. + inputs := state.steps["evm_median"].inputs + unw, err := values.Unwrap(inputs) + require.NoError(t, err) + + obs := unw.(map[string]any)["observations"] + assert.Len(t, obs, 2) + + tunw, err := values.Unwrap(cr.Value) + require.NoError(t, err) + assert.Equal(t, obs.([]any)[0], tunw) + + o, err := values.Unwrap(out) + require.NoError(t, err) + assert.Equal(t, obs.([]any)[1], o) } diff --git a/core/services/workflows/state.go b/core/services/workflows/state.go index e002fa90501..f70b4661897 100644 --- a/core/services/workflows/state.go +++ b/core/services/workflows/state.go @@ -9,12 +9,23 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/values" ) +const ( + statusStarted = "started" + statusErrored = "errored" + statusTimeout = "timeout" + statusCompleted = "completed" +) + type stepOutput struct { err error value values.Value } type stepState struct { + executionID string + ref string + status string + inputs *values.Map outputs *stepOutput } @@ -23,20 +34,64 @@ type executionState struct { steps map[string]*stepState executionID string workflowID string + + status string +} + +// copyState returns a deep copy of the input executionState +func copyState(es executionState) executionState { + steps := map[string]*stepState{} + for ref, step := range es.steps { + var mval *values.Map + if step.inputs != nil { + mp := values.Proto(step.inputs).GetMapValue() + mval = values.FromMapValueProto(mp) + } + + op := values.Proto(step.outputs.value) + copiedov := values.FromProto(op) + + newState := &stepState{ + executionID: step.executionID, + ref: step.ref, + status: step.status, + + outputs: &stepOutput{ + err: step.outputs.err, + value: copiedov, + }, + + inputs: mval, + } + + steps[ref] = newState + } + return executionState{ + executionID: es.executionID, + workflowID: es.workflowID, + status: es.status, + steps: steps, + } } // interpolateKey takes a multi-part, dot-separated key and attempts to replace // it with its corresponding value in `state`. -// A key is valid if: -// - it contains at least two parts, with the first part being the workflow step's `ref` variable, and the second being one of `inputs` or `outputs` -// - any subsequent parts will be processed as a list index (if the current element is a list) or a map key (if it's a map) -func interpolateKey(key string, state *executionState) (any, error) { +// +// A key is valid if it contains at least two parts, with: +// - the first part being the workflow step's `ref` variable +// - the second part being one of `inputs` or `outputs` +// +// If a key has more than two parts, then we traverse the parts +// to find the value we want to replace. +// We support traversing both nested maps and lists and any combination of the two. +func interpolateKey(key string, state executionState) (any, error) { parts := strings.Split(key, ".") if len(parts) < 2 { return "", fmt.Errorf("cannot interpolate %s: must have at least two parts", key) } + // lookup the step we want to get either input or output state from sc, ok := state.steps[parts[0]] if !ok { return "", fmt.Errorf("could not find ref `%s`", parts[0]) @@ -67,27 +122,23 @@ func interpolateKey(key string, state *executionState) (any, error) { case map[string]any: inner, ok := v[r] if !ok { - return "", fmt.Errorf("could not find ref part `%s` in `%+v`", r, v) + return "", fmt.Errorf("could not find ref part `%s` (ref: `%s`) in `%+v`", r, key, v) } val = inner case []any: - d, err := strconv.Atoi(r) + i, err := strconv.Atoi(r) if err != nil { - return "", fmt.Errorf("could not interpolate ref part `%s` in `%+v`: `%s` is not convertible to an int", r, v, r) - } - - if d > len(v)-1 { - return "", fmt.Errorf("could not interpolate ref part `%s` in `%+v`: cannot fetch index %d", r, v, d) + return "", fmt.Errorf("could not interpolate ref part `%s` (ref: `%s`) in `%+v`: `%s` is not convertible to an int", r, key, v, r) } - if d < 0 { - return "", fmt.Errorf("could not interpolate ref part `%s` in `%+v`: index %d must be a positive number", r, v, d) + if (i > len(v)-1) || (i < 0) { + return "", fmt.Errorf("could not interpolate ref part `%s` (ref: `%s`) in `%+v`: index out of bounds %d", r, key, v, i) } - val = v[d] + val = v[i] default: - return "", fmt.Errorf("could not interpolate ref part `%s` in `%+v`", r, val) + return "", fmt.Errorf("could not interpolate ref part `%s` (ref: `%s`) in `%+v`", r, key, val) } } @@ -100,17 +151,66 @@ var ( // findAndInterpolateAllKeys takes an `input` any value, and recursively // identifies any values that should be replaced from `state`. -// A value `v` should be replaced if it is wrapped as follows `$(v)`. -func findAndInterpolateAllKeys(input any, state *executionState) (any, error) { +// +// A value `v` should be replaced if it is wrapped as follows: `$(v)`. +func findAndInterpolateAllKeys(input any, state executionState) (any, error) { + return deepMap( + input, + func(el string) (any, error) { + matches := interpolationTokenRe.FindStringSubmatch(el) + if len(matches) < 2 { + return el, nil + } + + interpolatedVar := matches[1] + return interpolateKey(interpolatedVar, state) + }, + ) +} + +// findRefs takes an `inputs` map and returns a list of all the step references +// contained within it. +func findRefs(inputs map[string]any) ([]string, error) { + refs := []string{} + _, err := deepMap( + inputs, + // This function is called for each string in the map + // for each string, we iterate over each match of the interpolation token + // - if there are no matches, return no reference + // - if there is one match, return the reference + // - if there are multiple matches (in the case of a multi-part state reference), return just the step ref + func(el string) (any, error) { + matches := interpolationTokenRe.FindStringSubmatch(el) + if len(matches) < 2 { + return el, nil + } + + m := matches[1] + parts := strings.Split(m, ".") + if len(parts) < 1 { + return nil, fmt.Errorf("invalid ref %s", m) + } + + refs = append(refs, parts[0]) + return el, nil + }, + ) + return refs, err +} + +// deepMap recursively applies a transformation function +// over each string within: +// +// - a map[string]any +// - a []any +// - a string +func deepMap(input any, transform func(el string) (any, error)) (any, error) { + // in the case of a string, simply apply the transformation + // in the case of a map, recurse and apply the transformation to each value + // in the case of a list, recurse and apply the transformation to each element switch tv := input.(type) { case string: - matches := interpolationTokenRe.FindStringSubmatch(tv) - if len(matches) < 2 { - return tv, nil - } - - interpolatedVar := matches[1] - nv, err := interpolateKey(interpolatedVar, state) + nv, err := transform(tv) if err != nil { return nil, err } @@ -119,7 +219,7 @@ func findAndInterpolateAllKeys(input any, state *executionState) (any, error) { case map[string]any: nm := map[string]any{} for k, v := range tv { - nv, err := findAndInterpolateAllKeys(v, state) + nv, err := deepMap(v, transform) if err != nil { return nil, err } @@ -130,7 +230,7 @@ func findAndInterpolateAllKeys(input any, state *executionState) (any, error) { case []any: a := []any{} for _, el := range tv { - ne, err := findAndInterpolateAllKeys(el, state) + ne, err := deepMap(el, transform) if err != nil { return nil, err } @@ -140,5 +240,5 @@ func findAndInterpolateAllKeys(input any, state *executionState) (any, error) { return a, nil } - return nil, fmt.Errorf("cannot interpolate item %+v of type %T", input, input) + return nil, fmt.Errorf("cannot traverse item %+v of type %T", input, input) } diff --git a/core/services/workflows/state_test.go b/core/services/workflows/state_test.go index 9a0fadd02bd..9e69520c242 100644 --- a/core/services/workflows/state_test.go +++ b/core/services/workflows/state_test.go @@ -26,14 +26,14 @@ func TestInterpolateKey(t *testing.T) { testCases := []struct { name string key string - state *executionState + state executionState expected any errMsg string }{ { name: "digging into a string", key: "evm_median.outputs.reports", - state: &executionState{ + state: executionState{ steps: map[string]*stepState{ "evm_median": { outputs: &stepOutput{ @@ -42,12 +42,12 @@ func TestInterpolateKey(t *testing.T) { }, }, }, - errMsg: "could not interpolate ref part `reports` in ``", + errMsg: "could not interpolate ref part `reports` (ref: `evm_median.outputs.reports`) in ``", }, { name: "ref doesn't exist", key: "evm_median.outputs.reports", - state: &executionState{ + state: executionState{ steps: map[string]*stepState{}, }, errMsg: "could not find ref `evm_median`", @@ -55,7 +55,7 @@ func TestInterpolateKey(t *testing.T) { { name: "less than 2 parts", key: "evm_median", - state: &executionState{ + state: executionState{ steps: map[string]*stepState{}, }, errMsg: "must have at least two parts", @@ -63,7 +63,7 @@ func TestInterpolateKey(t *testing.T) { { name: "second part isn't `inputs` or `outputs`", key: "evm_median.foo", - state: &executionState{ + state: executionState{ steps: map[string]*stepState{ "evm_median": { outputs: &stepOutput{ @@ -77,7 +77,7 @@ func TestInterpolateKey(t *testing.T) { { name: "outputs has errored", key: "evm_median.outputs", - state: &executionState{ + state: executionState{ steps: map[string]*stepState{ "evm_median": { outputs: &stepOutput{ @@ -91,7 +91,7 @@ func TestInterpolateKey(t *testing.T) { { name: "digging into a recursive map", key: "evm_median.outputs.reports.inner", - state: &executionState{ + state: executionState{ steps: map[string]*stepState{ "evm_median": { outputs: &stepOutput{ @@ -105,7 +105,7 @@ func TestInterpolateKey(t *testing.T) { { name: "missing key in map", key: "evm_median.outputs.reports.missing", - state: &executionState{ + state: executionState{ steps: map[string]*stepState{ "evm_median": { outputs: &stepOutput{ @@ -114,12 +114,12 @@ func TestInterpolateKey(t *testing.T) { }, }, }, - errMsg: "could not find ref part `missing` in", + errMsg: "could not find ref part `missing` (ref: `evm_median.outputs.reports.missing`) in", }, { name: "digging into an array", key: "evm_median.outputs.reportsList.0", - state: &executionState{ + state: executionState{ steps: map[string]*stepState{ "evm_median": { outputs: &stepOutput{ @@ -133,7 +133,7 @@ func TestInterpolateKey(t *testing.T) { { name: "digging into an array that's too small", key: "evm_median.outputs.reportsList.2", - state: &executionState{ + state: executionState{ steps: map[string]*stepState{ "evm_median": { outputs: &stepOutput{ @@ -142,12 +142,12 @@ func TestInterpolateKey(t *testing.T) { }, }, }, - errMsg: "cannot fetch index 2", + errMsg: "index out of bounds 2", }, { name: "digging into an array with a string key", key: "evm_median.outputs.reportsList.notAString", - state: &executionState{ + state: executionState{ steps: map[string]*stepState{ "evm_median": { outputs: &stepOutput{ @@ -156,12 +156,12 @@ func TestInterpolateKey(t *testing.T) { }, }, }, - errMsg: "could not interpolate ref part `notAString` in `[listElement]`: `notAString` is not convertible to an int", + errMsg: "could not interpolate ref part `notAString` (ref: `evm_median.outputs.reportsList.notAString`) in `[listElement]`: `notAString` is not convertible to an int", }, { name: "digging into an array with a negative index", key: "evm_median.outputs.reportsList.-1", - state: &executionState{ + state: executionState{ steps: map[string]*stepState{ "evm_median": { outputs: &stepOutput{ @@ -170,12 +170,12 @@ func TestInterpolateKey(t *testing.T) { }, }, }, - errMsg: "could not interpolate ref part `-1` in `[listElement]`: index -1 must be a positive number", + errMsg: "could not interpolate ref part `-1` (ref: `evm_median.outputs.reportsList.-1`) in `[listElement]`: index out of bounds -1", }, { name: "empty element", key: "evm_median.outputs..notAString", - state: &executionState{ + state: executionState{ steps: map[string]*stepState{ "evm_median": { outputs: &stepOutput{ @@ -184,7 +184,7 @@ func TestInterpolateKey(t *testing.T) { }, }, }, - errMsg: "could not find ref part `` in", + errMsg: "could not find ref part `` (ref: `evm_median.outputs..notAString`) in", }, } @@ -205,7 +205,7 @@ func TestInterpolateInputsFromState(t *testing.T) { testCases := []struct { name string inputs map[string]any - state *executionState + state executionState expected any errMsg string }{ @@ -216,7 +216,7 @@ func TestInterpolateInputsFromState(t *testing.T) { "shouldinterpolate": "$(evm_median.outputs)", }, }, - state: &executionState{ + state: executionState{ steps: map[string]*stepState{ "evm_median": { outputs: &stepOutput{ @@ -236,7 +236,7 @@ func TestInterpolateInputsFromState(t *testing.T) { inputs: map[string]any{ "foo": "bar", }, - state: &executionState{ + state: executionState{ steps: map[string]*stepState{ "evm_median": { outputs: &stepOutput{ diff --git a/core/services/workflows/store.go b/core/services/workflows/store.go new file mode 100644 index 00000000000..d6ef72d39b9 --- /dev/null +++ b/core/services/workflows/store.go @@ -0,0 +1,70 @@ +package workflows + +import ( + "context" + "fmt" + "sync" +) + +// `inMemoryStore` is a temporary in-memory +// equivalent of the database table that should persist +// workflow progress. +type inMemoryStore struct { + idToState map[string]*executionState + mu sync.RWMutex +} + +func newInMemoryStore() *inMemoryStore { + return &inMemoryStore{idToState: map[string]*executionState{}} +} + +// add adds a new execution state under the given executionID +func (s *inMemoryStore) add(ctx context.Context, state *executionState) error { + s.mu.Lock() + defer s.mu.Unlock() + _, ok := s.idToState[state.executionID] + if ok { + return fmt.Errorf("execution ID %s already exists in store", state.executionID) + } + + s.idToState[state.executionID] = state + return nil +} + +// updateStep updates a step for the given executionID +func (s *inMemoryStore) updateStep(ctx context.Context, step *stepState) (executionState, error) { + s.mu.Lock() + defer s.mu.Unlock() + state, ok := s.idToState[step.executionID] + if !ok { + return executionState{}, fmt.Errorf("could not find execution %s", step.executionID) + } + + state.steps[step.ref] = step + return *state, nil +} + +// updateStatus updates the status for the given executionID +func (s *inMemoryStore) updateStatus(ctx context.Context, executionID string, status string) error { + s.mu.Lock() + defer s.mu.Unlock() + state, ok := s.idToState[executionID] + if !ok { + return fmt.Errorf("could not find execution %s", executionID) + } + + state.status = status + return nil +} + +// get gets the state for the given executionID +func (s *inMemoryStore) get(ctx context.Context, executionID string) (executionState, error) { + s.mu.RLock() + defer s.mu.RUnlock() + state, ok := s.idToState[executionID] + if !ok { + return executionState{}, fmt.Errorf("could not find execution %s", executionID) + } + + return *state, nil +} diff --git a/core/services/workflows/testdata/fixtures/workflows/marshalling/workflow_1.yaml b/core/services/workflows/testdata/fixtures/workflows/marshalling/workflow_1.yaml new file mode 100644 index 00000000000..0fab758ac44 --- /dev/null +++ b/core/services/workflows/testdata/fixtures/workflows/marshalling/workflow_1.yaml @@ -0,0 +1,88 @@ + triggers: + - type: on_mercury_report@1 + ref: report_data + config: + boolean_coercion: + bools: + - y + - n + - yes + - no + - Y + - N + - YES + - NO + - No + - Yes + - TRUE + - FALSE + - True + - False + - true + - false + strings: + - TruE + - FalsE + - "true" + - "false" + - "TRUE" + - "FALSE" + - t + - f + - "T" + - "F" + - "t" + - "f" + - "1" + - "0" + - "yes" + - "no" + - "y" + - "n" + - "YES" + - "NO" + - "Y" + - "N" + numbers: + - 1 + - 0 + feed_ids: + - 123 # ETHUSD + - 456 # LINKUSD + - 789 # USDBTC + + # no actions + + consensus: + - type: offchain_reporting@1 + inputs: + observations: + - triggers.report_data.outputs + config: + aggregation_method: data_feeds_2_0 + aggregation_config: + 123: # ETHUSD + deviation: "0.005" + heartbeat: 24h + test: + 456: # LINKUSD + deviation: "0.001" + heartbeat: 24h + 789: # USDBTC + deviation: "0.002" + heartbeat: 6h + encoder: EVM + encoder_config: + abi: "mercury_reports bytes[]" + + targets: + - type: write_polygon_mainnet@1 + inputs: + report: + - consensus.evm_median.outputs.report + config: + address: "0xaabbcc" + method: "updateFeedValues(report bytes, role uint8)" + params: [$(inputs.report), 1] + +# yaml-language-server: $schema=../workflow_schema.json diff --git a/core/services/workflows/testdata/fixtures/workflows/references/failing_1.yaml b/core/services/workflows/testdata/fixtures/workflows/references/failing_1.yaml new file mode 100644 index 00000000000..67d6890c47b --- /dev/null +++ b/core/services/workflows/testdata/fixtures/workflows/references/failing_1.yaml @@ -0,0 +1,15 @@ +triggers: +- type: trigger_test@1 + config: {} + +consensus: + - type: offchain_reporting@1 + ref: offchain_reporting=1 + config: {} + +targets: + - type: write_polygon_mainnet@1 + ref: write_polygon_mainnet_1 + config: {} + +# yaml-language-server: $schema=../workflow_schema.json diff --git a/core/services/workflows/testdata/fixtures/workflows/references/passing_1.yaml b/core/services/workflows/testdata/fixtures/workflows/references/passing_1.yaml new file mode 100644 index 00000000000..f8c7d20136e --- /dev/null +++ b/core/services/workflows/testdata/fixtures/workflows/references/passing_1.yaml @@ -0,0 +1,15 @@ +triggers: +- type: trigger_test@1 + config: {} + +consensus: + - type: offchain_reporting@1 + ref: offchain_reporting_1 + config: {} + +targets: + - type: write_polygon_mainnet@1 + ref: write_polygon_mainnet_1 + config: {} + +# yaml-language-server: $schema=../workflow_schema.json diff --git a/core/services/workflows/testdata/fixtures/workflows/versioning/failing_1.yaml b/core/services/workflows/testdata/fixtures/workflows/versioning/failing_1.yaml new file mode 100644 index 00000000000..b45676388c5 --- /dev/null +++ b/core/services/workflows/testdata/fixtures/workflows/versioning/failing_1.yaml @@ -0,0 +1,16 @@ +# Should fail since version is more specific than major +triggers: + - type: trigger_test@1.0 + config: {} + +consensus: + - type: offchain_reporting@1 + ref: offchain_reporting_1 + config: {} + +targets: + - type: write_polygon_mainnet@1 + ref: write_polygon_mainnet_1 + config: {} + +# yaml-language-server: $schema=../workflow_schema.json diff --git a/core/services/workflows/testdata/fixtures/workflows/versioning/failing_2.yaml b/core/services/workflows/testdata/fixtures/workflows/versioning/failing_2.yaml new file mode 100644 index 00000000000..c2a1872b4cf --- /dev/null +++ b/core/services/workflows/testdata/fixtures/workflows/versioning/failing_2.yaml @@ -0,0 +1,17 @@ + +# Should fail since version is more specific than major +triggers: + - type: trigger_test@1.0.0 + config: {} + +consensus: + - type: offchain_reporting@1 + ref: offchain_reporting_1 + config: {} + +targets: + - type: write_polygon_mainnet@1 + ref: write_polygon_mainnet_1 + config: {} + +# yaml-language-server: $schema=../workflow_schema.json diff --git a/core/services/workflows/testdata/fixtures/workflows/versioning/passing_1.yaml b/core/services/workflows/testdata/fixtures/workflows/versioning/passing_1.yaml new file mode 100644 index 00000000000..83bdcc610ef --- /dev/null +++ b/core/services/workflows/testdata/fixtures/workflows/versioning/passing_1.yaml @@ -0,0 +1,15 @@ + triggers: + - type: trigger_test@1 + config: {} + + consensus: + - type: offchain_reporting@1-beta.1 + ref: offchain_reporting_1 + config: {} + + targets: + - type: write_polygon_mainnet@1-alpha+sha246er3 + ref: write_polygon_mainnet_1 + config: {} + +# yaml-language-server: $schema=../workflow_schema.json diff --git a/core/services/workflows/testdata/fixtures/workflows/workflow_schema.json b/core/services/workflows/testdata/fixtures/workflows/workflow_schema.json new file mode 100644 index 00000000000..221e4582d19 --- /dev/null +++ b/core/services/workflows/testdata/fixtures/workflows/workflow_schema.json @@ -0,0 +1,66 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/smartcontractkit/chainlink/v2/core/services/workflows/workflow-spec", + "$ref": "#/$defs/workflowSpec", + "$defs": { + "stepDefinition": { + "properties": { + "type": { + "type": "string", + "pattern": "^[a-z0-9_\\-:]+@(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" + }, + "ref": { + "type": "string", + "pattern": "^[a-z0-9_]+$" + }, + "inputs": { + "type": "object" + }, + "config": { + "type": "object" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "type", + "config" + ] + }, + "workflowSpec": { + "properties": { + "triggers": { + "items": { + "$ref": "#/$defs/stepDefinition" + }, + "type": "array" + }, + "actions": { + "items": { + "$ref": "#/$defs/stepDefinition" + }, + "type": "array" + }, + "consensus": { + "items": { + "$ref": "#/$defs/stepDefinition" + }, + "type": "array" + }, + "targets": { + "items": { + "$ref": "#/$defs/stepDefinition" + }, + "type": "array" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "triggers", + "consensus", + "targets" + ] + } + } +} \ No newline at end of file diff --git a/core/services/workflows/workflow.go b/core/services/workflows/workflow.go index bf8394af610..11f655d36f9 100644 --- a/core/services/workflows/workflow.go +++ b/core/services/workflows/workflow.go @@ -1,23 +1,289 @@ package workflows -import "gopkg.in/yaml.v3" +import ( + "encoding/json" + "fmt" -type Capability struct { - Type string `yaml:"type"` - Ref string `yaml:"ref"` - Inputs map[string]any `yaml:"inputs"` - Config map[string]any `yaml:"config"` + "github.com/dominikbraun/graph" + "github.com/invopop/jsonschema" + "sigs.k8s.io/yaml" + + "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + "github.com/smartcontractkit/chainlink-common/pkg/values" +) + +type stepRequest struct { + stepRef string + state executionState +} + +// stepDefinition is the parsed representation of a step in a workflow. +// +// Within the workflow spec, they are called "Capability Properties". +type stepDefinition struct { + // A universally unique name for a capability will be defined under the “type” property. The uniqueness will, eventually, be enforced in the Capability Registry . Semver must be used to specify the version of the Capability at the end of the type field. Capability versions must be immutable. + // + // Initially, we will require major versions. This will ease upgrades early on while we develop the infrastructure. + // + // Eventually, we might support minor version and specific version pins. This will allow workflow authors to have flexibility when selecting the version, and node operators will be able to determine when they should update their capabilities. + // + // There are two ways to specify a type - using a string as a fully qualified ID or a structured table. When using a table, tags are ordered alphanumerically and joined into a string following a + // {type}:{tag1_key}_{tag1_value}:{tag2_key}_{tag2_value}@{version} + // pattern. + // + // The “type” supports [a-z0-9_-:] characters followed by an @ and [semver regex] at the end. + // + // Validation must throw an error if: + // + // Unsupported characters are used. + // (For Keystone only.) More specific than a major version is specified. + // + // Example (string) + // type: read_chain:chain_ethereum:network_mainnet@1 + // + // Example (table) + // + // type: + // name: read_chain + // version: 1 + // tags: + // chain: ethereum + // network: mainnet + // + // [semver regex]: https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string + Type string `json:"type" jsonschema:"required,pattern=^[a-z0-9_\\-:]+@(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$"` + + // Actions and Consensus capabilities have a required “ref” property that must be unique within a Workflow file (not universally) This property enables referencing outputs and is required because Actions and Consensus always need to be referenced in the following phases. Triggers can optionally specify if they need to be referenced. + // + // The “ref” supports [a-z0-9_] characters. + // + // Validation must throw an error if: + // - Unsupported characters are used. + // - The same “ref” appears in the workflow multiple times. + // - “ref” is used on a Target capability. + // - “ref” has a circular reference. + // + // NOTE: Should introduce a custom validator to cover trigger case + Ref string `json:"ref,omitempty" jsonschema:"pattern=^[a-z0-9_]+$"` + + // Capabilities can specify an additional optional ”inputs” property. It allows specifying a dependency on the result of one or more other capabilities. These are always runtime values that cannot be provided upfront. It takes a map of the argument name internal to the capability and an explicit reference to the values. + // + // References are specified using the [type].[ref].[path_to_value] pattern. + // + // The interpolation of “inputs” is allowed + // + // Validation must throw an error if: + // - Input reference cannot be resolved. + // - Input is defined on triggers + // NOTE: Should introduce a custom validator to cover trigger case + Inputs map[string]any `json:"inputs,omitempty"` + + // The configuration of a Capability will be done using the “config” property. Each capability is responsible for defining an external interface used during setup. This interface may be unique or identical, meaning multiple Capabilities might use the same configuration properties. + // + // The interpolation of “inputs” + // + // Interpolation of self inputs is allowed from within the “config” property. + // + // Example + // targets: + // - type: write_polygon_mainnet@1 + // inputs: + // report: + // - consensus.evm_median.outputs.report + // config: + // address: "0xaabbcc" + // method: "updateFeedValues(report bytes, role uint8)" + // params: [$(inputs.report), 1] + Config map[string]any `json:"config" jsonschema:"required"` +} + +// workflowSpec is the parsed representation of a workflow. +type workflowSpec struct { + // Triggers define a starting condition for the workflow, based on specific events or conditions. + Triggers []stepDefinition `json:"triggers" jsonschema:"required"` + // Actions represent a discrete operation within the workflow, potentially transforming input data. + Actions []stepDefinition `json:"actions,omitempty"` + // Consensus encapsulates the logic for aggregating and validating the results from various nodes. + Consensus []stepDefinition `json:"consensus" jsonschema:"required"` + // Targets represents the final step of the workflow, delivering the processed data to a specified location. + Targets []stepDefinition `json:"targets" jsonschema:"required"` +} + +func GenerateJsonSchema() ([]byte, error) { + schema := jsonschema.Reflect(&workflowSpec{}) + + return json.MarshalIndent(schema, "", " ") +} + +func (w *workflowSpec) steps() []stepDefinition { + s := []stepDefinition{} + s = append(s, w.Actions...) + s = append(s, w.Consensus...) + s = append(s, w.Targets...) + return s +} + +// workflow is a directed graph of nodes, where each node is a step. +// +// triggers are special steps that are stored separately, they're +// treated differently due to their nature of being the starting +// point of a workflow. +type workflow struct { + graph.Graph[string, *step] + + triggers []*triggerCapability + + spec *workflowSpec +} + +func (w *workflow) walkDo(start string, do func(s *step) error) error { + var outerErr error + err := graph.BFS(w.Graph, start, func(ref string) bool { + n, err := w.Graph.Vertex(ref) + if err != nil { + outerErr = err + return true + } + + err = do(n) + if err != nil { + outerErr = err + return true + } + + return false + }) + if err != nil { + return err + } + + return outerErr +} + +func (w *workflow) dependents(start string) ([]*step, error) { + steps := []*step{} + m, err := w.Graph.AdjacencyMap() + if err != nil { + return nil, err + } + + adj, ok := m[start] + if !ok { + return nil, fmt.Errorf("could not find step with ref %s", start) + } + + for adjacentRef := range adj { + n, err := w.Graph.Vertex(adjacentRef) + if err != nil { + return nil, err + } + + steps = append(steps, n) + } + + return steps, nil +} + +// step wraps a stepDefinition with additional context for dependencies and execution +type step struct { + stepDefinition + dependencies []string + capability capabilities.CallbackExecutable + config *values.Map } -type Workflow struct { - Triggers []Capability `yaml:"triggers"` - Actions []Capability `yaml:"actions"` - Consensus []Capability `yaml:"consensus"` - Targets []Capability `yaml:"targets"` +type triggerCapability struct { + stepDefinition + trigger capabilities.TriggerCapability + config *values.Map } -func Parse(yamlWorkflow string) (*Workflow, error) { - wf := &Workflow{} - err := yaml.Unmarshal([]byte(yamlWorkflow), wf) +const ( + keywordTrigger = "trigger" +) + +func Parse(yamlWorkflow string) (*workflow, error) { + spec := &workflowSpec{} + err := yaml.Unmarshal([]byte(yamlWorkflow), spec) + if err != nil { + return nil, err + } + + // Construct and validate the graph. We instantiate an + // empty graph with just one starting entry: `trigger`. + // This provides the starting point for our graph and + // points to all dependent steps. + // Note: all triggers are represented by a single step called + // `trigger`. This is because for workflows with multiple triggers + // only one trigger will have started the workflow. + stepHash := func(s *step) string { + return s.Ref + } + g := graph.New( + stepHash, + graph.PreventCycles(), + graph.Directed(), + ) + err = g.AddVertex(&step{ + stepDefinition: stepDefinition{Ref: keywordTrigger}, + }) + if err != nil { + return nil, err + } + + // Next, let's populate the other entries in the graph. + for _, s := range spec.steps() { + // TODO: The workflow format spec doesn't always require a `Ref` + // to be provided (triggers and targets don't have a `Ref` for example). + // To handle this, we default the `Ref` to the type, but ideally we + // should find a better long-term way to handle this. + if s.Ref == "" { + s.Ref = s.Type + } + + innerErr := g.AddVertex(&step{stepDefinition: s}) + if innerErr != nil { + return nil, fmt.Errorf("cannot add vertex %s: %w", s.Ref, innerErr) + } + } + + stepRefs, err := g.AdjacencyMap() + if err != nil { + return nil, err + } + + // Next, let's iterate over the steps and populate + // any edges. + for stepRef := range stepRefs { + step, innerErr := g.Vertex(stepRef) + if innerErr != nil { + return nil, innerErr + } + + refs, innerErr := findRefs(step.Inputs) + if innerErr != nil { + return nil, innerErr + } + step.dependencies = refs + + for _, r := range refs { + innerErr = g.AddEdge(r, step.Ref) + if innerErr != nil { + return nil, innerErr + } + } + } + + triggerSteps := []*triggerCapability{} + for _, t := range spec.Triggers { + triggerSteps = append(triggerSteps, &triggerCapability{ + stepDefinition: t, + }) + } + wf := &workflow{ + spec: spec, + Graph: g, + triggers: triggerSteps, + } return wf, err } diff --git a/core/services/workflows/workflow_test.go b/core/services/workflows/workflow_test.go new file mode 100644 index 00000000000..f6a2df38e1c --- /dev/null +++ b/core/services/workflows/workflow_test.go @@ -0,0 +1,383 @@ +package workflows + +import ( + "encoding/json" + "fmt" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/santhosh-tekuri/jsonschema/v5" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "sigs.k8s.io/yaml" +) + +var fixtureDir = "./testdata/fixtures/workflows/" + +// yamlFixtureReaderObj reads a yaml fixture file and returns the parsed object +func yamlFixtureReaderObj(t *testing.T, testCase string) func(name string) any { + testFixtureReader := yamlFixtureReaderBytes(t, testCase) + + return func(name string) any { + testFileBytes := testFixtureReader(name) + + var testFileYaml any + err := yaml.Unmarshal(testFileBytes, &testFileYaml) + require.NoError(t, err) + + return testFileYaml + } +} + +// yamlFixtureReaderBytes reads a yaml fixture file and returns the bytes +func yamlFixtureReaderBytes(t *testing.T, testCase string) func(name string) []byte { + return func(name string) []byte { + testFileBytes, err := os.ReadFile(fmt.Sprintf(fixtureDir+"%s/%s.yaml", testCase, name)) + require.NoError(t, err) + + return testFileBytes + } +} + +var transformJSON = cmp.FilterValues(func(x, y []byte) bool { + return json.Valid(x) && json.Valid(y) +}, cmp.Transformer("ParseJSON", func(in []byte) (out interface{}) { + if err := json.Unmarshal(in, &out); err != nil { + panic(err) // should never occur given previous filter to ensure valid JSON + } + return out +})) + +func TestWorkflowSpecMarshalling(t *testing.T) { + workflowBytes := yamlFixtureReaderBytes(t, "marshalling")("workflow_1") + + spec := workflowSpec{} + err := yaml.Unmarshal(workflowBytes, &spec) + require.NoError(t, err) + + // Test that our workflowSpec still keeps all of the original data + var rawSpec interface{} + err = yaml.Unmarshal(workflowBytes, &rawSpec) + require.NoError(t, err) + + workflowspecJson, err := json.MarshalIndent(spec, "", " ") + require.NoError(t, err) + rawWorkflowSpecJson, err := json.MarshalIndent(rawSpec, "", " ") + require.NoError(t, err) + + if diff := cmp.Diff(rawWorkflowSpecJson, workflowspecJson, transformJSON); diff != "" { + t.Errorf("ParseWorkflowWorkflowSpecFromString() mismatch (-want +got):\n%s", diff) + t.FailNow() + } + + // Spot check some fields + consensusConfig := spec.Consensus[0].Config + v, ok := consensusConfig["aggregation_config"] + require.True(t, ok, "expected aggregation_config to be present in consensus config") + + // the type of the keys present in v should be string rather than a number + // this is because JSON keys are always strings + _, ok = v.(map[string]any) + require.True(t, ok, "expected map[string]interface{} but got %T", v) + + // Make sure we dont have any weird type coercion with possible boolean values + booleanCoercions, ok := spec.Triggers[0].Config["boolean_coercion"].(map[string]any) + require.True(t, ok, "expected boolean_coercion to be present in triggers config") + + // check bools + bools, ok := booleanCoercions["bools"] + require.True(t, ok, "expected bools to be present in boolean_coercions") + for _, v := range bools.([]interface{}) { + _, ok = v.(bool) + require.True(t, ok, "expected bool but got %T", v) + } + + // check strings + strings, ok := booleanCoercions["strings"] + require.True(t, ok, "expected strings to be present in boolean_coercions") + for _, v := range strings.([]interface{}) { + _, ok = v.(string) + require.True(t, ok, "expected string but got %T", v) + } + + // check numbers + numbers, ok := booleanCoercions["numbers"] + require.True(t, ok, "expected numbers to be present in boolean_coercions") + for _, v := range numbers.([]interface{}) { + _, ok = v.(float64) + require.True(t, ok, "expected float64 but got %T", v) + } +} + +func TestJsonSchema(t *testing.T) { + t.Run("GenerateJsonSchema", func(t *testing.T) { + expectedSchemaPath := fixtureDir + "workflow_schema.json" + generatedSchema, err := GenerateJsonSchema() + require.NoError(t, err) + + // change this to update golden file + shouldUpdateSchema := false + if shouldUpdateSchema { + err = os.WriteFile(expectedSchemaPath, generatedSchema, 0600) + require.NoError(t, err) + } + + expectedSchema, err := os.ReadFile(expectedSchemaPath) + require.NoError(t, err) + diff := cmp.Diff(expectedSchema, generatedSchema, transformJSON) + if diff != "" { + t.Errorf("GenerateJsonSchema() mismatch (-want +got):\n%s", diff) + t.FailNow() + } + }) + + t.Run("ValidateJsonSchema", func(t *testing.T) { + generatedSchema, err := GenerateJsonSchema() + require.NoError(t, err) + + // test version regex + // for keystone, we should support major versions only along with prereleases and build metadata + t.Run("version", func(t *testing.T) { + readVersionFixture := yamlFixtureReaderObj(t, "versioning") + failingFixture1 := readVersionFixture("failing_1") + failingFixture2 := readVersionFixture("failing_2") + passingFixture1 := readVersionFixture("passing_1") + jsonSchema, err := jsonschema.CompileString("github.com/smartcontractkit/chainlink", string(generatedSchema)) + require.NoError(t, err) + + err = jsonSchema.Validate(failingFixture1) + require.Error(t, err) + + err = jsonSchema.Validate(failingFixture2) + require.Error(t, err) + + err = jsonSchema.Validate(passingFixture1) + require.NoError(t, err) + }) + + // test ref regex + t.Run("ref", func(t *testing.T) { + readRefFixture := yamlFixtureReaderObj(t, "references") + failingFixture1 := readRefFixture("failing_1") + passingFixture1 := readRefFixture("passing_1") + jsonSchema, err := jsonschema.CompileString("github.com/smartcontractkit/chainlink", string(generatedSchema)) + require.NoError(t, err) + + err = jsonSchema.Validate(failingFixture1) + require.Error(t, err) + + err = jsonSchema.Validate(passingFixture1) + require.NoError(t, err) + }) + }) +} + +func TestParse_Graph(t *testing.T) { + testCases := []struct { + name string + yaml string + graph map[string]map[string]struct{} + errMsg string + }{ + { + name: "basic example", + yaml: ` +triggers: + - type: "a-trigger" + +actions: + - type: "an-action" + ref: "an-action" + inputs: + trigger_output: $(trigger.outputs) + +consensus: + - type: "a-consensus" + ref: "a-consensus" + inputs: + trigger_output: $(trigger.outputs) + an-action_output: $(an-action.outputs) + +targets: + - type: "a-target" + ref: "a-target" + inputs: + consensus_output: $(a-consensus.outputs) +`, + graph: map[string]map[string]struct{}{ + keywordTrigger: { + "an-action": struct{}{}, + "a-consensus": struct{}{}, + }, + "an-action": { + "a-consensus": struct{}{}, + }, + "a-consensus": { + "a-target": struct{}{}, + }, + "a-target": {}, + }, + }, + { + name: "circular relationship", + yaml: ` +triggers: + - type: "a-trigger" + +actions: + - type: "an-action" + ref: "an-action" + inputs: + trigger_output: $(trigger.outputs) + output: $(a-second-action.outputs) + - type: "a-second-action" + ref: "a-second-action" + inputs: + output: $(an-action.outputs) + +consensus: + - type: "a-consensus" + ref: "a-consensus" + inputs: + trigger_output: $(trigger.outputs) + an-action_output: $(an-action.outputs) + +targets: + - type: "a-target" + ref: "a-target" + inputs: + consensus_output: $(a-consensus.outputs) +`, + errMsg: "edge would create a cycle", + }, + { + name: "indirect circular relationship", + yaml: ` +triggers: + - type: "a-trigger" + +actions: + - type: "an-action" + ref: "an-action" + inputs: + trigger_output: $(trigger.outputs) + action_output: $(a-third-action.outputs) + - type: "a-second-action" + ref: "a-second-action" + inputs: + output: $(an-action.outputs) + - type: "a-third-action" + ref: "a-third-action" + inputs: + output: $(a-second-action.outputs) + +consensus: + - type: "a-consensus" + ref: "a-consensus" + inputs: + trigger_output: $(trigger.outputs) + an-action_output: $(an-action.outputs) + +targets: + - type: "a-target" + ref: "a-target" + inputs: + consensus_output: $(a-consensus.outputs) +`, + errMsg: "edge would create a cycle", + }, + { + name: "relationship doesn't exist", + yaml: ` +triggers: + - type: "a-trigger" + +actions: + - type: "an-action" + ref: "an-action" + inputs: + trigger_output: $(trigger.outputs) + action_output: $(missing-action.outputs) + +consensus: + - type: "a-consensus" + ref: "a-consensus" + inputs: + an-action_output: $(an-action.outputs) + +targets: + - type: "a-target" + ref: "a-target" + inputs: + consensus_output: $(a-consensus.outputs) +`, + errMsg: "source vertex missing-action: vertex not found", + }, + { + name: "two trigger nodes", + yaml: ` +triggers: + - type: "a-trigger" + - type: "a-second-trigger" + +actions: + - type: "an-action" + ref: "an-action" + inputs: + trigger_output: $(trigger.outputs) + +consensus: + - type: "a-consensus" + ref: "a-consensus" + inputs: + an-action_output: $(an-action.outputs) + +targets: + - type: "a-target" + ref: "a-target" + inputs: + consensus_output: $(a-consensus.outputs) +`, + graph: map[string]map[string]struct{}{ + keywordTrigger: { + "an-action": struct{}{}, + }, + "an-action": { + "a-consensus": struct{}{}, + }, + "a-consensus": { + "a-target": struct{}{}, + }, + "a-target": {}, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(st *testing.T) { + wf, err := Parse(tc.yaml) + if tc.errMsg != "" { + assert.ErrorContains(st, err, tc.errMsg) + } else { + require.NoError(st, err) + + adjacencies, err := wf.AdjacencyMap() + require.NoError(t, err) + + got := map[string]map[string]struct{}{} + for k, v := range adjacencies { + if _, ok := got[k]; !ok { + got[k] = map[string]struct{}{} + } + for adj := range v { + got[k][adj] = struct{}{} + } + } + + assert.Equal(st, tc.graph, got, adjacencies) + } + }) + } +} diff --git a/core/store/migrate/migrations/0229_add_kv_store_job_fk_cascade_delete.sql b/core/store/migrate/migrations/0229_add_kv_store_job_fk_cascade_delete.sql new file mode 100644 index 00000000000..eb63539fae2 --- /dev/null +++ b/core/store/migrate/migrations/0229_add_kv_store_job_fk_cascade_delete.sql @@ -0,0 +1,23 @@ +-- +goose Up + +BEGIN; + +ALTER TABLE job_kv_store DROP CONSTRAINT job_kv_store_job_id_fkey; +ALTER TABLE job_kv_store + ADD CONSTRAINT job_kv_store_job_id_fkey + FOREIGN KEY (job_id) + REFERENCES jobs(id) + ON DELETE CASCADE; + +COMMIT; + +-- +goose Down +BEGIN; + +ALTER TABLE job_kv_store DROP CONSTRAINT job_kv_store_job_id_fkey; +ALTER TABLE job_kv_store + ADD CONSTRAINT job_kv_store_job_id_fkey + FOREIGN KEY (job_id) + REFERENCES jobs(id); + +COMMIT; diff --git a/core/store/migrate/migrations/0230_move_keyvalue_store_val_to_bytes.sql b/core/store/migrate/migrations/0230_move_keyvalue_store_val_to_bytes.sql new file mode 100644 index 00000000000..b75bd25e7f8 --- /dev/null +++ b/core/store/migrate/migrations/0230_move_keyvalue_store_val_to_bytes.sql @@ -0,0 +1,16 @@ +-- +goose Up + +-- Add a new bytea column +ALTER TABLE job_kv_store ADD COLUMN val_bytea bytea; + +-- Copy and convert the data from the jsonb column to the new bytea column +UPDATE job_kv_store SET val_bytea = convert_to(val::text, 'UTF8'); + +-- Drop the jsonb column +ALTER TABLE job_kv_store DROP COLUMN val; + +-- +goose Down +ALTER TABLE job_kv_store ADD COLUMN val jsonb; +-- Bytea data may not be convertable to jsonb, so just drop the column +ALTER TABLE job_kv_store DROP COLUMN val_bytea; + diff --git a/core/web/assets/index.html b/core/web/assets/index.html index 21811e104e8..c79e099904f 100644 --- a/core/web/assets/index.html +++ b/core/web/assets/index.html @@ -1 +1 @@ -Operator UIChainlink
\ No newline at end of file +Operator UIChainlink
\ No newline at end of file diff --git a/core/web/assets/index.html.gz b/core/web/assets/index.html.gz index 2067ae210af..520ebac6e87 100644 Binary files a/core/web/assets/index.html.gz and b/core/web/assets/index.html.gz differ diff --git a/core/web/assets/main.f42e73c0c7811e9907db.js b/core/web/assets/main.4a9b933093bb165fcc8f.js similarity index 93% rename from core/web/assets/main.f42e73c0c7811e9907db.js rename to core/web/assets/main.4a9b933093bb165fcc8f.js index 90276050fee..33f59a7826b 100644 --- a/core/web/assets/main.f42e73c0c7811e9907db.js +++ b/core/web/assets/main.4a9b933093bb165fcc8f.js @@ -184,4 +184,4 @@ object-assign */ Object.defineProperty(t,"__esModule",{value:!0}),"undefined"==typeof window||"function"!=typeof MessageChannel){var n,r,i,a,o,s=null,u=null,c=function(){if(null!==s)try{var e=t.unstable_now();s(!0,e),s=null}catch(n){throw setTimeout(c,0),n}},l=Date.now();t.unstable_now=function(){return Date.now()-l},n=function(e){null!==s?setTimeout(n,0,e):(s=e,setTimeout(c,0))},r=function(e,t){u=setTimeout(e,t)},i=function(){clearTimeout(u)},a=function(){return!1},o=t.unstable_forceFrameRate=function(){}}else{var f=window.performance,d=window.Date,h=window.setTimeout,p=window.clearTimeout;if("undefined"!=typeof console){var b=window.cancelAnimationFrame;"function"!=typeof window.requestAnimationFrame&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills"),"function"!=typeof b&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills")}if("object"==typeof f&&"function"==typeof f.now)t.unstable_now=function(){return f.now()};else{var m=d.now();t.unstable_now=function(){return d.now()-m}}var g=!1,v=null,y=-1,w=5,_=0;a=function(){return t.unstable_now()>=_},o=function(){},t.unstable_forceFrameRate=function(e){0>e||125M(o,n))void 0!==u&&0>M(u,o)?(e[r]=u,e[s]=n,r=s):(e[r]=o,e[a]=n,r=a);else if(void 0!==u&&0>M(u,n))e[r]=u,e[s]=n,r=s;else break a}}return t}return null}function M(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}var O=[],A=[],L=1,C=null,I=3,D=!1,N=!1,P=!1;function R(e){for(var t=x(A);null!==t;){if(null===t.callback)T(A);else if(t.startTime<=e)T(A),t.sortIndex=t.expirationTime,k(O,t);else break;t=x(A)}}function j(e){if(P=!1,R(e),!N){if(null!==x(O))N=!0,n(F);else{var t=x(A);null!==t&&r(j,t.startTime-e)}}}function F(e,n){N=!1,P&&(P=!1,i()),D=!0;var o=I;try{for(R(n),C=x(O);null!==C&&(!(C.expirationTime>n)||e&&!a());){var s=C.callback;if(null!==s){C.callback=null,I=C.priorityLevel;var u=s(C.expirationTime<=n);n=t.unstable_now(),"function"==typeof u?C.callback=u:C===x(O)&&T(O),R(n)}else T(O);C=x(O)}if(null!==C)var c=!0;else{var l=x(A);null!==l&&r(j,l.startTime-n),c=!1}return c}finally{C=null,I=o,D=!1}}function Y(e){switch(e){case 1:return -1;case 2:return 250;case 5:return 1073741823;case 4:return 1e4;default:return 5e3}}var B=o;t.unstable_ImmediatePriority=1,t.unstable_UserBlockingPriority=2,t.unstable_NormalPriority=3,t.unstable_IdlePriority=5,t.unstable_LowPriority=4,t.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=I;I=e;try{return t()}finally{I=n}},t.unstable_next=function(e){switch(I){case 1:case 2:case 3:var t=3;break;default:t=I}var n=I;I=t;try{return e()}finally{I=n}},t.unstable_scheduleCallback=function(e,a,o){var s=t.unstable_now();if("object"==typeof o&&null!==o){var u=o.delay;u="number"==typeof u&&0s?(e.sortIndex=u,k(A,e),null===x(O)&&e===x(A)&&(P?i():P=!0,r(j,u-s))):(e.sortIndex=o,k(O,e),N||D||(N=!0,n(F))),e},t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_wrapCallback=function(e){var t=I;return function(){var n=I;I=t;try{return e.apply(this,arguments)}finally{I=n}}},t.unstable_getCurrentPriorityLevel=function(){return I},t.unstable_shouldYield=function(){var e=t.unstable_now();R(e);var n=x(O);return n!==C&&null!==C&&null!==n&&null!==n.callback&&n.startTime<=e&&n.expirationTime>5==6?2:e>>4==14?3:e>>3==30?4:e>>6==2?-1:-2}function c(e,t,n){var r=t.length-1;if(r=0?(i>0&&(e.lastNeed=i-1),i):--r=0?(i>0&&(e.lastNeed=i-2),i):--r=0?(i>0&&(2===i?i=0:e.lastNeed=i-3),i):0}function l(e,t,n){if((192&t[0])!=128)return e.lastNeed=0,"�";if(e.lastNeed>1&&t.length>1){if((192&t[1])!=128)return e.lastNeed=1,"�";if(e.lastNeed>2&&t.length>2&&(192&t[2])!=128)return e.lastNeed=2,"�"}}function f(e){var t=this.lastTotal-this.lastNeed,n=l(this,e,t);return void 0!==n?n:this.lastNeed<=e.length?(e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):void(e.copy(this.lastChar,t,0,e.length),this.lastNeed-=e.length)}function d(e,t){var n=c(this,e,t);if(!this.lastNeed)return e.toString("utf8",t);this.lastTotal=n;var r=e.length-(n-this.lastNeed);return e.copy(this.lastChar,0,r),e.toString("utf8",t,r)}function h(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+"�":t}function p(e,t){if((e.length-t)%2==0){var n=e.toString("utf16le",t);if(n){var r=n.charCodeAt(n.length-1);if(r>=55296&&r<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],n.slice(0,-1)}return n}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",t,e.length-1)}function b(e){var t=e&&e.length?this.write(e):"";if(this.lastNeed){var n=this.lastTotal-this.lastNeed;return t+this.lastChar.toString("utf16le",0,n)}return t}function m(e,t){var n=(e.length-t)%3;return 0===n?e.toString("base64",t):(this.lastNeed=3-n,this.lastTotal=3,1===n?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",t,e.length-n))}function g(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+this.lastChar.toString("base64",0,3-this.lastNeed):t}function v(e){return e.toString(this.encoding)}function y(e){return e&&e.length?this.write(e):""}t.s=s,s.prototype.write=function(e){var t,n;if(0===e.length)return"";if(this.lastNeed){if(void 0===(t=this.fillLast(e)))return"";n=this.lastNeed,this.lastNeed=0}else n=0;return nOF});var r,i,a,o,s,u,c,l=n(67294),f=n.t(l,2),d=n(97779),h=n(47886),p=n(57209),b=n(32316),m=n(95880),g=n(17051),v=n(71381),y=n(81701),w=n(3022),_=n(60323),E=n(87591),S=n(25649),k=n(28902),x=n(71426),T=n(48884),M=n(94184),O=n.n(M),A=n(55977),L=n(73935),C=function(){if("undefined"!=typeof Map)return Map;function e(e,t){var n=-1;return e.some(function(e,r){return e[0]===t&&(n=r,!0)}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(t){var n=e(this.__entries__,t),r=this.__entries__[n];return r&&r[1]},t.prototype.set=function(t,n){var r=e(this.__entries__,t);~r?this.__entries__[r][1]=n:this.__entries__.push([t,n])},t.prototype.delete=function(t){var n=this.__entries__,r=e(n,t);~r&&n.splice(r,1)},t.prototype.has=function(t){return!!~e(this.__entries__,t)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(e,t){void 0===t&&(t=null);for(var n=0,r=this.__entries__;n0},e.prototype.connect_=function(){I&&!this.connected_&&(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),Y?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){I&&this.connected_&&(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(e){var t=e.propertyName,n=void 0===t?"":t;F.some(function(e){return!!~n.indexOf(e)})&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),U=function(e,t){for(var n=0,r=Object.keys(t);n0},e}(),er="undefined"!=typeof WeakMap?new WeakMap:new C,ei=function(){function e(t){if(!(this instanceof e))throw TypeError("Cannot call a class as a function.");if(!arguments.length)throw TypeError("1 argument required, but only 0 present.");var n=B.getInstance(),r=new en(t,n,this);er.set(this,r)}return e}();["observe","unobserve","disconnect"].forEach(function(e){ei.prototype[e]=function(){var t;return(t=er.get(this))[e].apply(t,arguments)}});var ea=void 0!==D.ResizeObserver?D.ResizeObserver:ei;let eo=ea;var es=function(e){var t=[],n=null,r=function(){for(var r=arguments.length,i=Array(r),a=0;a=t||n<0||f&&r>=a}function g(){var e=eb();if(m(e))return v(e);s=setTimeout(g,b(e))}function v(e){return(s=void 0,d&&r)?h(e):(r=i=void 0,o)}function y(){void 0!==s&&clearTimeout(s),c=0,r=u=i=s=void 0}function w(){return void 0===s?o:v(eb())}function _(){var e=eb(),n=m(e);if(r=arguments,i=this,u=e,n){if(void 0===s)return p(u);if(f)return clearTimeout(s),s=setTimeout(g,t),h(u)}return void 0===s&&(s=setTimeout(g,t)),o}return t=ez(t)||0,ed(n)&&(l=!!n.leading,a=(f="maxWait"in n)?eW(ez(n.maxWait)||0,t):a,d="trailing"in n?!!n.trailing:d),_.cancel=y,_.flush=w,_}let eq=eV;var eZ="Expected a function";function eX(e,t,n){var r=!0,i=!0;if("function"!=typeof e)throw TypeError(eZ);return ed(n)&&(r="leading"in n?!!n.leading:r,i="trailing"in n?!!n.trailing:i),eq(e,t,{leading:r,maxWait:t,trailing:i})}let eJ=eX;var eQ={debounce:eq,throttle:eJ},e1=function(e){return eQ[e]},e0=function(e){return"function"==typeof e},e2=function(){return"undefined"==typeof window},e3=function(e){return e instanceof Element||e instanceof HTMLDocument};function e4(e){return(e4="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function e5(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function e6(e,t){for(var n=0;ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&l.createElement(tG.Z,{variant:"indeterminate",classes:r}))};tK.propTypes={fetchCount:el().number.isRequired};let tV=(0,b.withStyles)(tW)(tK);var tq=n(5536);let tZ=n.p+"ba8bbf16ebf8e1d05bef.svg";function tX(){return(tX=Object.assign||function(e){for(var t=1;t120){for(var d=Math.floor(u/80),h=u%80,p=[],b=0;b0},name:{enumerable:!1},nodes:{enumerable:!1},source:{enumerable:!1},positions:{enumerable:!1},originalError:{enumerable:!1}}),null!=s&&s.stack)?(Object.defineProperty(nf(b),"stack",{value:s.stack,writable:!0,configurable:!0}),nl(b)):(Error.captureStackTrace?Error.captureStackTrace(nf(b),n):Object.defineProperty(nf(b),"stack",{value:Error().stack,writable:!0,configurable:!0}),b)}return ns(n,[{key:"toString",value:function(){return nw(this)}},{key:t4.YF,get:function(){return"Object"}}]),n}(nd(Error));function ny(e){return void 0===e||0===e.length?void 0:e}function nw(e){var t=e.message;if(e.nodes)for(var n=0,r=e.nodes;n",EOF:"",BANG:"!",DOLLAR:"$",AMP:"&",PAREN_L:"(",PAREN_R:")",SPREAD:"...",COLON:":",EQUALS:"=",AT:"@",BRACKET_L:"[",BRACKET_R:"]",BRACE_L:"{",PIPE:"|",BRACE_R:"}",NAME:"Name",INT:"Int",FLOAT:"Float",STRING:"String",BLOCK_STRING:"BlockString",COMMENT:"Comment"}),nx=n(10143),nT=Object.freeze({QUERY:"QUERY",MUTATION:"MUTATION",SUBSCRIPTION:"SUBSCRIPTION",FIELD:"FIELD",FRAGMENT_DEFINITION:"FRAGMENT_DEFINITION",FRAGMENT_SPREAD:"FRAGMENT_SPREAD",INLINE_FRAGMENT:"INLINE_FRAGMENT",VARIABLE_DEFINITION:"VARIABLE_DEFINITION",SCHEMA:"SCHEMA",SCALAR:"SCALAR",OBJECT:"OBJECT",FIELD_DEFINITION:"FIELD_DEFINITION",ARGUMENT_DEFINITION:"ARGUMENT_DEFINITION",INTERFACE:"INTERFACE",UNION:"UNION",ENUM:"ENUM",ENUM_VALUE:"ENUM_VALUE",INPUT_OBJECT:"INPUT_OBJECT",INPUT_FIELD_DEFINITION:"INPUT_FIELD_DEFINITION"}),nM=n(87392),nO=function(){function e(e){var t=new nS.WU(nk.SOF,0,0,0,0,null);this.source=e,this.lastToken=t,this.token=t,this.line=1,this.lineStart=0}var t=e.prototype;return t.advance=function(){return this.lastToken=this.token,this.token=this.lookahead()},t.lookahead=function(){var e,t=this.token;if(t.kind!==nk.EOF)do t=null!==(e=t.next)&&void 0!==e?e:t.next=nC(this,t);while(t.kind===nk.COMMENT)return t},e}();function nA(e){return e===nk.BANG||e===nk.DOLLAR||e===nk.AMP||e===nk.PAREN_L||e===nk.PAREN_R||e===nk.SPREAD||e===nk.COLON||e===nk.EQUALS||e===nk.AT||e===nk.BRACKET_L||e===nk.BRACKET_R||e===nk.BRACE_L||e===nk.PIPE||e===nk.BRACE_R}function nL(e){return isNaN(e)?nk.EOF:e<127?JSON.stringify(String.fromCharCode(e)):'"\\u'.concat(("00"+e.toString(16).toUpperCase()).slice(-4),'"')}function nC(e,t){for(var n=e.source,r=n.body,i=r.length,a=t.end;a31||9===a))return new nS.WU(nk.COMMENT,t,s,n,r,i,o.slice(t+1,s))}function nN(e,t,n,r,i,a){var o=e.body,s=n,u=t,c=!1;if(45===s&&(s=o.charCodeAt(++u)),48===s){if((s=o.charCodeAt(++u))>=48&&s<=57)throw n_(e,u,"Invalid number, unexpected digit after 0: ".concat(nL(s),"."))}else u=nP(e,u,s),s=o.charCodeAt(u);if(46===s&&(c=!0,s=o.charCodeAt(++u),u=nP(e,u,s),s=o.charCodeAt(u)),(69===s||101===s)&&(c=!0,(43===(s=o.charCodeAt(++u))||45===s)&&(s=o.charCodeAt(++u)),u=nP(e,u,s),s=o.charCodeAt(u)),46===s||nU(s))throw n_(e,u,"Invalid number, expected digit but got: ".concat(nL(s),"."));return new nS.WU(c?nk.FLOAT:nk.INT,t,u,r,i,a,o.slice(t,u))}function nP(e,t,n){var r=e.body,i=t,a=n;if(a>=48&&a<=57){do a=r.charCodeAt(++i);while(a>=48&&a<=57)return i}throw n_(e,i,"Invalid number, expected digit but got: ".concat(nL(a),"."))}function nR(e,t,n,r,i){for(var a=e.body,o=t+1,s=o,u=0,c="";o=48&&e<=57?e-48:e>=65&&e<=70?e-55:e>=97&&e<=102?e-87:-1}function nB(e,t,n,r,i){for(var a=e.body,o=a.length,s=t+1,u=0;s!==o&&!isNaN(u=a.charCodeAt(s))&&(95===u||u>=48&&u<=57||u>=65&&u<=90||u>=97&&u<=122);)++s;return new nS.WU(nk.NAME,t,s,n,r,i,a.slice(t,s))}function nU(e){return 95===e||e>=65&&e<=90||e>=97&&e<=122}function nH(e,t){return new n$(e,t).parseDocument()}var n$=function(){function e(e,t){var n=(0,nx.T)(e)?e:new nx.H(e);this._lexer=new nO(n),this._options=t}var t=e.prototype;return t.parseName=function(){var e=this.expectToken(nk.NAME);return{kind:nE.h.NAME,value:e.value,loc:this.loc(e)}},t.parseDocument=function(){var e=this._lexer.token;return{kind:nE.h.DOCUMENT,definitions:this.many(nk.SOF,this.parseDefinition,nk.EOF),loc:this.loc(e)}},t.parseDefinition=function(){if(this.peek(nk.NAME))switch(this._lexer.token.value){case"query":case"mutation":case"subscription":return this.parseOperationDefinition();case"fragment":return this.parseFragmentDefinition();case"schema":case"scalar":case"type":case"interface":case"union":case"enum":case"input":case"directive":return this.parseTypeSystemDefinition();case"extend":return this.parseTypeSystemExtension()}else if(this.peek(nk.BRACE_L))return this.parseOperationDefinition();else if(this.peekDescription())return this.parseTypeSystemDefinition();throw this.unexpected()},t.parseOperationDefinition=function(){var e,t=this._lexer.token;if(this.peek(nk.BRACE_L))return{kind:nE.h.OPERATION_DEFINITION,operation:"query",name:void 0,variableDefinitions:[],directives:[],selectionSet:this.parseSelectionSet(),loc:this.loc(t)};var n=this.parseOperationType();return this.peek(nk.NAME)&&(e=this.parseName()),{kind:nE.h.OPERATION_DEFINITION,operation:n,name:e,variableDefinitions:this.parseVariableDefinitions(),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}},t.parseOperationType=function(){var e=this.expectToken(nk.NAME);switch(e.value){case"query":return"query";case"mutation":return"mutation";case"subscription":return"subscription"}throw this.unexpected(e)},t.parseVariableDefinitions=function(){return this.optionalMany(nk.PAREN_L,this.parseVariableDefinition,nk.PAREN_R)},t.parseVariableDefinition=function(){var e=this._lexer.token;return{kind:nE.h.VARIABLE_DEFINITION,variable:this.parseVariable(),type:(this.expectToken(nk.COLON),this.parseTypeReference()),defaultValue:this.expectOptionalToken(nk.EQUALS)?this.parseValueLiteral(!0):void 0,directives:this.parseDirectives(!0),loc:this.loc(e)}},t.parseVariable=function(){var e=this._lexer.token;return this.expectToken(nk.DOLLAR),{kind:nE.h.VARIABLE,name:this.parseName(),loc:this.loc(e)}},t.parseSelectionSet=function(){var e=this._lexer.token;return{kind:nE.h.SELECTION_SET,selections:this.many(nk.BRACE_L,this.parseSelection,nk.BRACE_R),loc:this.loc(e)}},t.parseSelection=function(){return this.peek(nk.SPREAD)?this.parseFragment():this.parseField()},t.parseField=function(){var e,t,n=this._lexer.token,r=this.parseName();return this.expectOptionalToken(nk.COLON)?(e=r,t=this.parseName()):t=r,{kind:nE.h.FIELD,alias:e,name:t,arguments:this.parseArguments(!1),directives:this.parseDirectives(!1),selectionSet:this.peek(nk.BRACE_L)?this.parseSelectionSet():void 0,loc:this.loc(n)}},t.parseArguments=function(e){var t=e?this.parseConstArgument:this.parseArgument;return this.optionalMany(nk.PAREN_L,t,nk.PAREN_R)},t.parseArgument=function(){var e=this._lexer.token,t=this.parseName();return this.expectToken(nk.COLON),{kind:nE.h.ARGUMENT,name:t,value:this.parseValueLiteral(!1),loc:this.loc(e)}},t.parseConstArgument=function(){var e=this._lexer.token;return{kind:nE.h.ARGUMENT,name:this.parseName(),value:(this.expectToken(nk.COLON),this.parseValueLiteral(!0)),loc:this.loc(e)}},t.parseFragment=function(){var e=this._lexer.token;this.expectToken(nk.SPREAD);var t=this.expectOptionalKeyword("on");return!t&&this.peek(nk.NAME)?{kind:nE.h.FRAGMENT_SPREAD,name:this.parseFragmentName(),directives:this.parseDirectives(!1),loc:this.loc(e)}:{kind:nE.h.INLINE_FRAGMENT,typeCondition:t?this.parseNamedType():void 0,directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(e)}},t.parseFragmentDefinition=function(){var e,t=this._lexer.token;return(this.expectKeyword("fragment"),(null===(e=this._options)||void 0===e?void 0:e.experimentalFragmentVariables)===!0)?{kind:nE.h.FRAGMENT_DEFINITION,name:this.parseFragmentName(),variableDefinitions:this.parseVariableDefinitions(),typeCondition:(this.expectKeyword("on"),this.parseNamedType()),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}:{kind:nE.h.FRAGMENT_DEFINITION,name:this.parseFragmentName(),typeCondition:(this.expectKeyword("on"),this.parseNamedType()),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}},t.parseFragmentName=function(){if("on"===this._lexer.token.value)throw this.unexpected();return this.parseName()},t.parseValueLiteral=function(e){var t=this._lexer.token;switch(t.kind){case nk.BRACKET_L:return this.parseList(e);case nk.BRACE_L:return this.parseObject(e);case nk.INT:return this._lexer.advance(),{kind:nE.h.INT,value:t.value,loc:this.loc(t)};case nk.FLOAT:return this._lexer.advance(),{kind:nE.h.FLOAT,value:t.value,loc:this.loc(t)};case nk.STRING:case nk.BLOCK_STRING:return this.parseStringLiteral();case nk.NAME:switch(this._lexer.advance(),t.value){case"true":return{kind:nE.h.BOOLEAN,value:!0,loc:this.loc(t)};case"false":return{kind:nE.h.BOOLEAN,value:!1,loc:this.loc(t)};case"null":return{kind:nE.h.NULL,loc:this.loc(t)};default:return{kind:nE.h.ENUM,value:t.value,loc:this.loc(t)}}case nk.DOLLAR:if(!e)return this.parseVariable()}throw this.unexpected()},t.parseStringLiteral=function(){var e=this._lexer.token;return this._lexer.advance(),{kind:nE.h.STRING,value:e.value,block:e.kind===nk.BLOCK_STRING,loc:this.loc(e)}},t.parseList=function(e){var t=this,n=this._lexer.token,r=function(){return t.parseValueLiteral(e)};return{kind:nE.h.LIST,values:this.any(nk.BRACKET_L,r,nk.BRACKET_R),loc:this.loc(n)}},t.parseObject=function(e){var t=this,n=this._lexer.token,r=function(){return t.parseObjectField(e)};return{kind:nE.h.OBJECT,fields:this.any(nk.BRACE_L,r,nk.BRACE_R),loc:this.loc(n)}},t.parseObjectField=function(e){var t=this._lexer.token,n=this.parseName();return this.expectToken(nk.COLON),{kind:nE.h.OBJECT_FIELD,name:n,value:this.parseValueLiteral(e),loc:this.loc(t)}},t.parseDirectives=function(e){for(var t=[];this.peek(nk.AT);)t.push(this.parseDirective(e));return t},t.parseDirective=function(e){var t=this._lexer.token;return this.expectToken(nk.AT),{kind:nE.h.DIRECTIVE,name:this.parseName(),arguments:this.parseArguments(e),loc:this.loc(t)}},t.parseTypeReference=function(){var e,t=this._lexer.token;return(this.expectOptionalToken(nk.BRACKET_L)?(e=this.parseTypeReference(),this.expectToken(nk.BRACKET_R),e={kind:nE.h.LIST_TYPE,type:e,loc:this.loc(t)}):e=this.parseNamedType(),this.expectOptionalToken(nk.BANG))?{kind:nE.h.NON_NULL_TYPE,type:e,loc:this.loc(t)}:e},t.parseNamedType=function(){var e=this._lexer.token;return{kind:nE.h.NAMED_TYPE,name:this.parseName(),loc:this.loc(e)}},t.parseTypeSystemDefinition=function(){var e=this.peekDescription()?this._lexer.lookahead():this._lexer.token;if(e.kind===nk.NAME)switch(e.value){case"schema":return this.parseSchemaDefinition();case"scalar":return this.parseScalarTypeDefinition();case"type":return this.parseObjectTypeDefinition();case"interface":return this.parseInterfaceTypeDefinition();case"union":return this.parseUnionTypeDefinition();case"enum":return this.parseEnumTypeDefinition();case"input":return this.parseInputObjectTypeDefinition();case"directive":return this.parseDirectiveDefinition()}throw this.unexpected(e)},t.peekDescription=function(){return this.peek(nk.STRING)||this.peek(nk.BLOCK_STRING)},t.parseDescription=function(){if(this.peekDescription())return this.parseStringLiteral()},t.parseSchemaDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("schema");var n=this.parseDirectives(!0),r=this.many(nk.BRACE_L,this.parseOperationTypeDefinition,nk.BRACE_R);return{kind:nE.h.SCHEMA_DEFINITION,description:t,directives:n,operationTypes:r,loc:this.loc(e)}},t.parseOperationTypeDefinition=function(){var e=this._lexer.token,t=this.parseOperationType();this.expectToken(nk.COLON);var n=this.parseNamedType();return{kind:nE.h.OPERATION_TYPE_DEFINITION,operation:t,type:n,loc:this.loc(e)}},t.parseScalarTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("scalar");var n=this.parseName(),r=this.parseDirectives(!0);return{kind:nE.h.SCALAR_TYPE_DEFINITION,description:t,name:n,directives:r,loc:this.loc(e)}},t.parseObjectTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("type");var n=this.parseName(),r=this.parseImplementsInterfaces(),i=this.parseDirectives(!0),a=this.parseFieldsDefinition();return{kind:nE.h.OBJECT_TYPE_DEFINITION,description:t,name:n,interfaces:r,directives:i,fields:a,loc:this.loc(e)}},t.parseImplementsInterfaces=function(){var e;if(!this.expectOptionalKeyword("implements"))return[];if((null===(e=this._options)||void 0===e?void 0:e.allowLegacySDLImplementsInterfaces)===!0){var t=[];this.expectOptionalToken(nk.AMP);do t.push(this.parseNamedType());while(this.expectOptionalToken(nk.AMP)||this.peek(nk.NAME))return t}return this.delimitedMany(nk.AMP,this.parseNamedType)},t.parseFieldsDefinition=function(){var e;return(null===(e=this._options)||void 0===e?void 0:e.allowLegacySDLEmptyFields)===!0&&this.peek(nk.BRACE_L)&&this._lexer.lookahead().kind===nk.BRACE_R?(this._lexer.advance(),this._lexer.advance(),[]):this.optionalMany(nk.BRACE_L,this.parseFieldDefinition,nk.BRACE_R)},t.parseFieldDefinition=function(){var e=this._lexer.token,t=this.parseDescription(),n=this.parseName(),r=this.parseArgumentDefs();this.expectToken(nk.COLON);var i=this.parseTypeReference(),a=this.parseDirectives(!0);return{kind:nE.h.FIELD_DEFINITION,description:t,name:n,arguments:r,type:i,directives:a,loc:this.loc(e)}},t.parseArgumentDefs=function(){return this.optionalMany(nk.PAREN_L,this.parseInputValueDef,nk.PAREN_R)},t.parseInputValueDef=function(){var e,t=this._lexer.token,n=this.parseDescription(),r=this.parseName();this.expectToken(nk.COLON);var i=this.parseTypeReference();this.expectOptionalToken(nk.EQUALS)&&(e=this.parseValueLiteral(!0));var a=this.parseDirectives(!0);return{kind:nE.h.INPUT_VALUE_DEFINITION,description:n,name:r,type:i,defaultValue:e,directives:a,loc:this.loc(t)}},t.parseInterfaceTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("interface");var n=this.parseName(),r=this.parseImplementsInterfaces(),i=this.parseDirectives(!0),a=this.parseFieldsDefinition();return{kind:nE.h.INTERFACE_TYPE_DEFINITION,description:t,name:n,interfaces:r,directives:i,fields:a,loc:this.loc(e)}},t.parseUnionTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("union");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseUnionMemberTypes();return{kind:nE.h.UNION_TYPE_DEFINITION,description:t,name:n,directives:r,types:i,loc:this.loc(e)}},t.parseUnionMemberTypes=function(){return this.expectOptionalToken(nk.EQUALS)?this.delimitedMany(nk.PIPE,this.parseNamedType):[]},t.parseEnumTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("enum");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseEnumValuesDefinition();return{kind:nE.h.ENUM_TYPE_DEFINITION,description:t,name:n,directives:r,values:i,loc:this.loc(e)}},t.parseEnumValuesDefinition=function(){return this.optionalMany(nk.BRACE_L,this.parseEnumValueDefinition,nk.BRACE_R)},t.parseEnumValueDefinition=function(){var e=this._lexer.token,t=this.parseDescription(),n=this.parseName(),r=this.parseDirectives(!0);return{kind:nE.h.ENUM_VALUE_DEFINITION,description:t,name:n,directives:r,loc:this.loc(e)}},t.parseInputObjectTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("input");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseInputFieldsDefinition();return{kind:nE.h.INPUT_OBJECT_TYPE_DEFINITION,description:t,name:n,directives:r,fields:i,loc:this.loc(e)}},t.parseInputFieldsDefinition=function(){return this.optionalMany(nk.BRACE_L,this.parseInputValueDef,nk.BRACE_R)},t.parseTypeSystemExtension=function(){var e=this._lexer.lookahead();if(e.kind===nk.NAME)switch(e.value){case"schema":return this.parseSchemaExtension();case"scalar":return this.parseScalarTypeExtension();case"type":return this.parseObjectTypeExtension();case"interface":return this.parseInterfaceTypeExtension();case"union":return this.parseUnionTypeExtension();case"enum":return this.parseEnumTypeExtension();case"input":return this.parseInputObjectTypeExtension()}throw this.unexpected(e)},t.parseSchemaExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("schema");var t=this.parseDirectives(!0),n=this.optionalMany(nk.BRACE_L,this.parseOperationTypeDefinition,nk.BRACE_R);if(0===t.length&&0===n.length)throw this.unexpected();return{kind:nE.h.SCHEMA_EXTENSION,directives:t,operationTypes:n,loc:this.loc(e)}},t.parseScalarTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("scalar");var t=this.parseName(),n=this.parseDirectives(!0);if(0===n.length)throw this.unexpected();return{kind:nE.h.SCALAR_TYPE_EXTENSION,name:t,directives:n,loc:this.loc(e)}},t.parseObjectTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("type");var t=this.parseName(),n=this.parseImplementsInterfaces(),r=this.parseDirectives(!0),i=this.parseFieldsDefinition();if(0===n.length&&0===r.length&&0===i.length)throw this.unexpected();return{kind:nE.h.OBJECT_TYPE_EXTENSION,name:t,interfaces:n,directives:r,fields:i,loc:this.loc(e)}},t.parseInterfaceTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("interface");var t=this.parseName(),n=this.parseImplementsInterfaces(),r=this.parseDirectives(!0),i=this.parseFieldsDefinition();if(0===n.length&&0===r.length&&0===i.length)throw this.unexpected();return{kind:nE.h.INTERFACE_TYPE_EXTENSION,name:t,interfaces:n,directives:r,fields:i,loc:this.loc(e)}},t.parseUnionTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("union");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseUnionMemberTypes();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.UNION_TYPE_EXTENSION,name:t,directives:n,types:r,loc:this.loc(e)}},t.parseEnumTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("enum");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseEnumValuesDefinition();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.ENUM_TYPE_EXTENSION,name:t,directives:n,values:r,loc:this.loc(e)}},t.parseInputObjectTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("input");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseInputFieldsDefinition();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.INPUT_OBJECT_TYPE_EXTENSION,name:t,directives:n,fields:r,loc:this.loc(e)}},t.parseDirectiveDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("directive"),this.expectToken(nk.AT);var n=this.parseName(),r=this.parseArgumentDefs(),i=this.expectOptionalKeyword("repeatable");this.expectKeyword("on");var a=this.parseDirectiveLocations();return{kind:nE.h.DIRECTIVE_DEFINITION,description:t,name:n,arguments:r,repeatable:i,locations:a,loc:this.loc(e)}},t.parseDirectiveLocations=function(){return this.delimitedMany(nk.PIPE,this.parseDirectiveLocation)},t.parseDirectiveLocation=function(){var e=this._lexer.token,t=this.parseName();if(void 0!==nT[t.value])return t;throw this.unexpected(e)},t.loc=function(e){var t;if((null===(t=this._options)||void 0===t?void 0:t.noLocation)!==!0)return new nS.Ye(e,this._lexer.lastToken,this._lexer.source)},t.peek=function(e){return this._lexer.token.kind===e},t.expectToken=function(e){var t=this._lexer.token;if(t.kind===e)return this._lexer.advance(),t;throw n_(this._lexer.source,t.start,"Expected ".concat(nG(e),", found ").concat(nz(t),"."))},t.expectOptionalToken=function(e){var t=this._lexer.token;if(t.kind===e)return this._lexer.advance(),t},t.expectKeyword=function(e){var t=this._lexer.token;if(t.kind===nk.NAME&&t.value===e)this._lexer.advance();else throw n_(this._lexer.source,t.start,'Expected "'.concat(e,'", found ').concat(nz(t),"."))},t.expectOptionalKeyword=function(e){var t=this._lexer.token;return t.kind===nk.NAME&&t.value===e&&(this._lexer.advance(),!0)},t.unexpected=function(e){var t=null!=e?e:this._lexer.token;return n_(this._lexer.source,t.start,"Unexpected ".concat(nz(t),"."))},t.any=function(e,t,n){this.expectToken(e);for(var r=[];!this.expectOptionalToken(n);)r.push(t.call(this));return r},t.optionalMany=function(e,t,n){if(this.expectOptionalToken(e)){var r=[];do r.push(t.call(this));while(!this.expectOptionalToken(n))return r}return[]},t.many=function(e,t,n){this.expectToken(e);var r=[];do r.push(t.call(this));while(!this.expectOptionalToken(n))return r},t.delimitedMany=function(e,t){this.expectOptionalToken(e);var n=[];do n.push(t.call(this));while(this.expectOptionalToken(e))return n},e}();function nz(e){var t=e.value;return nG(e.kind)+(null!=t?' "'.concat(t,'"'):"")}function nG(e){return nA(e)?'"'.concat(e,'"'):e}var nW=new Map,nK=new Map,nV=!0,nq=!1;function nZ(e){return e.replace(/[\s,]+/g," ").trim()}function nX(e){return nZ(e.source.body.substring(e.start,e.end))}function nJ(e){var t=new Set,n=[];return e.definitions.forEach(function(e){if("FragmentDefinition"===e.kind){var r=e.name.value,i=nX(e.loc),a=nK.get(r);a&&!a.has(i)?nV&&console.warn("Warning: fragment with name "+r+" already exists.\ngraphql-tag enforces all fragment names across your application to be unique; read more about\nthis in the docs: http://dev.apollodata.com/core/fragments.html#unique-names"):a||nK.set(r,a=new Set),a.add(i),t.has(i)||(t.add(i),n.push(e))}else n.push(e)}),(0,t0.pi)((0,t0.pi)({},e),{definitions:n})}function nQ(e){var t=new Set(e.definitions);t.forEach(function(e){e.loc&&delete e.loc,Object.keys(e).forEach(function(n){var r=e[n];r&&"object"==typeof r&&t.add(r)})});var n=e.loc;return n&&(delete n.startToken,delete n.endToken),e}function n1(e){var t=nZ(e);if(!nW.has(t)){var n=nH(e,{experimentalFragmentVariables:nq,allowLegacyFragmentVariables:nq});if(!n||"Document"!==n.kind)throw Error("Not a valid GraphQL document.");nW.set(t,nQ(nJ(n)))}return nW.get(t)}function n0(e){for(var t=[],n=1;n, or pass an ApolloClient instance in via options.'):(0,n7.kG)(!!n,32),n}var rb=n(10542),rm=n(53712),rg=n(21436),rv=Object.prototype.hasOwnProperty;function ry(e,t){return void 0===t&&(t=Object.create(null)),rw(rp(t.client),e).useQuery(t)}function rw(e,t){var n=(0,l.useRef)();n.current&&e===n.current.client&&t===n.current.query||(n.current=new r_(e,t,n.current));var r=n.current,i=(0,l.useState)(0),a=(i[0],i[1]);return r.forceUpdate=function(){a(function(e){return e+1})},r}var r_=function(){function e(e,t,n){this.client=e,this.query=t,this.ssrDisabledResult=(0,rb.J)({loading:!0,data:void 0,error:void 0,networkStatus:rc.I.loading}),this.skipStandbyResult=(0,rb.J)({loading:!1,data:void 0,error:void 0,networkStatus:rc.I.ready}),this.toQueryResultCache=new(re.mr?WeakMap:Map),rh(t,r.Query);var i=n&&n.result,a=i&&i.data;a&&(this.previousData=a)}return e.prototype.forceUpdate=function(){__DEV__&&n7.kG.warn("Calling default no-op implementation of InternalState#forceUpdate")},e.prototype.executeQuery=function(e){var t,n=this;e.query&&Object.assign(this,{query:e.query}),this.watchQueryOptions=this.createWatchQueryOptions(this.queryHookOptions=e);var r=this.observable.reobserveAsConcast(this.getObsQueryOptions());return this.previousData=(null===(t=this.result)||void 0===t?void 0:t.data)||this.previousData,this.result=void 0,this.forceUpdate(),new Promise(function(e){var t;r.subscribe({next:function(e){t=e},error:function(){e(n.toQueryResult(n.observable.getCurrentResult()))},complete:function(){e(n.toQueryResult(t))}})})},e.prototype.useQuery=function(e){var t=this;this.renderPromises=(0,l.useContext)((0,rs.K)()).renderPromises,this.useOptions(e);var n=this.useObservableQuery(),r=rn((0,l.useCallback)(function(){if(t.renderPromises)return function(){};var e=function(){var e=t.result,r=n.getCurrentResult();!(e&&e.loading===r.loading&&e.networkStatus===r.networkStatus&&(0,ra.D)(e.data,r.data))&&t.setResult(r)},r=function(a){var o=n.last;i.unsubscribe();try{n.resetLastResults(),i=n.subscribe(e,r)}finally{n.last=o}if(!rv.call(a,"graphQLErrors"))throw a;var s=t.result;(!s||s&&s.loading||!(0,ra.D)(a,s.error))&&t.setResult({data:s&&s.data,error:a,loading:!1,networkStatus:rc.I.error})},i=n.subscribe(e,r);return function(){return setTimeout(function(){return i.unsubscribe()})}},[n,this.renderPromises,this.client.disableNetworkFetches,]),function(){return t.getCurrentResult()},function(){return t.getCurrentResult()});return this.unsafeHandlePartialRefetch(r),this.toQueryResult(r)},e.prototype.useOptions=function(t){var n,r=this.createWatchQueryOptions(this.queryHookOptions=t),i=this.watchQueryOptions;!(0,ra.D)(r,i)&&(this.watchQueryOptions=r,i&&this.observable&&(this.observable.reobserve(this.getObsQueryOptions()),this.previousData=(null===(n=this.result)||void 0===n?void 0:n.data)||this.previousData,this.result=void 0)),this.onCompleted=t.onCompleted||e.prototype.onCompleted,this.onError=t.onError||e.prototype.onError,(this.renderPromises||this.client.disableNetworkFetches)&&!1===this.queryHookOptions.ssr&&!this.queryHookOptions.skip?this.result=this.ssrDisabledResult:this.queryHookOptions.skip||"standby"===this.watchQueryOptions.fetchPolicy?this.result=this.skipStandbyResult:(this.result===this.ssrDisabledResult||this.result===this.skipStandbyResult)&&(this.result=void 0)},e.prototype.getObsQueryOptions=function(){var e=[],t=this.client.defaultOptions.watchQuery;return t&&e.push(t),this.queryHookOptions.defaultOptions&&e.push(this.queryHookOptions.defaultOptions),e.push((0,rm.o)(this.observable&&this.observable.options,this.watchQueryOptions)),e.reduce(ro.J)},e.prototype.createWatchQueryOptions=function(e){void 0===e&&(e={});var t,n=e.skip,r=Object.assign((e.ssr,e.onCompleted,e.onError,e.defaultOptions,(0,n8._T)(e,["skip","ssr","onCompleted","onError","defaultOptions"])),{query:this.query});if(this.renderPromises&&("network-only"===r.fetchPolicy||"cache-and-network"===r.fetchPolicy)&&(r.fetchPolicy="cache-first"),r.variables||(r.variables={}),n){var i=r.fetchPolicy,a=void 0===i?this.getDefaultFetchPolicy():i,o=r.initialFetchPolicy;Object.assign(r,{initialFetchPolicy:void 0===o?a:o,fetchPolicy:"standby"})}else r.fetchPolicy||(r.fetchPolicy=(null===(t=this.observable)||void 0===t?void 0:t.options.initialFetchPolicy)||this.getDefaultFetchPolicy());return r},e.prototype.getDefaultFetchPolicy=function(){var e,t;return(null===(e=this.queryHookOptions.defaultOptions)||void 0===e?void 0:e.fetchPolicy)||(null===(t=this.client.defaultOptions.watchQuery)||void 0===t?void 0:t.fetchPolicy)||"cache-first"},e.prototype.onCompleted=function(e){},e.prototype.onError=function(e){},e.prototype.useObservableQuery=function(){var e=this.observable=this.renderPromises&&this.renderPromises.getSSRObservable(this.watchQueryOptions)||this.observable||this.client.watchQuery(this.getObsQueryOptions());this.obsQueryFields=(0,l.useMemo)(function(){return{refetch:e.refetch.bind(e),reobserve:e.reobserve.bind(e),fetchMore:e.fetchMore.bind(e),updateQuery:e.updateQuery.bind(e),startPolling:e.startPolling.bind(e),stopPolling:e.stopPolling.bind(e),subscribeToMore:e.subscribeToMore.bind(e)}},[e]);var t=!(!1===this.queryHookOptions.ssr||this.queryHookOptions.skip);return this.renderPromises&&t&&(this.renderPromises.registerSSRObservable(e),e.getCurrentResult().loading&&this.renderPromises.addObservableQueryPromise(e)),e},e.prototype.setResult=function(e){var t=this.result;t&&t.data&&(this.previousData=t.data),this.result=e,this.forceUpdate(),this.handleErrorOrCompleted(e)},e.prototype.handleErrorOrCompleted=function(e){var t=this;if(!e.loading){var n=this.toApolloError(e);Promise.resolve().then(function(){n?t.onError(n):e.data&&t.onCompleted(e.data)}).catch(function(e){__DEV__&&n7.kG.warn(e)})}},e.prototype.toApolloError=function(e){return(0,rg.O)(e.errors)?new ru.cA({graphQLErrors:e.errors}):e.error},e.prototype.getCurrentResult=function(){return this.result||this.handleErrorOrCompleted(this.result=this.observable.getCurrentResult()),this.result},e.prototype.toQueryResult=function(e){var t=this.toQueryResultCache.get(e);if(t)return t;var n=e.data,r=(e.partial,(0,n8._T)(e,["data","partial"]));return this.toQueryResultCache.set(e,t=(0,n8.pi)((0,n8.pi)((0,n8.pi)({data:n},r),this.obsQueryFields),{client:this.client,observable:this.observable,variables:this.observable.variables,called:!this.queryHookOptions.skip,previousData:this.previousData})),!t.error&&(0,rg.O)(e.errors)&&(t.error=new ru.cA({graphQLErrors:e.errors})),t},e.prototype.unsafeHandlePartialRefetch=function(e){e.partial&&this.queryHookOptions.partialRefetch&&!e.loading&&(!e.data||0===Object.keys(e.data).length)&&"cache-only"!==this.observable.options.fetchPolicy&&(Object.assign(e,{loading:!0,networkStatus:rc.I.refetch}),this.observable.refetch())},e}();function rE(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]?arguments[0]:{};return ry(i$,e)},iG=function(){var e=iF(),t=parseInt(e.get("page")||"1",10),n=parseInt(e.get("per")||"50",10),r=iz({variables:{offset:(t-1)*n,limit:n},fetchPolicy:"network-only"}),i=r.data,a=r.loading,o=r.error;return a?l.createElement(ij,null):o?l.createElement(iN,{error:o}):i?l.createElement(iD,{chains:i.chains.results,page:t,pageSize:n,total:i.chains.metadata.total}):null},iW=n(67932),iK=n(8126),iV="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};function iq(e){if(iZ())return Intl.DateTimeFormat.supportedLocalesOf(e)[0]}function iZ(){return("undefined"==typeof Intl?"undefined":iV(Intl))==="object"&&"function"==typeof Intl.DateTimeFormat}var iX="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},iJ=function(){function e(e,t){for(var n=0;n=i.length)break;s=i[o++]}else{if((o=i.next()).done)break;s=o.value}var s,u=s;if((void 0===e?"undefined":iX(e))!=="object")return;e=e[u]}return e}},{key:"put",value:function(){for(var e=arguments.length,t=Array(e),n=0;n=o.length)break;c=o[u++]}else{if((u=o.next()).done)break;c=u.value}var c,l=c;"object"!==iX(a[l])&&(a[l]={}),a=a[l]}return a[i]=r}}]),e}();let i0=i1;var i2=new i0;function i3(e,t){if(!iZ())return function(e){return e.toString()};var n=i5(e),r=JSON.stringify(t),i=i2.get(String(n),r)||i2.put(String(n),r,new Intl.DateTimeFormat(n,t));return function(e){return i.format(e)}}var i4={};function i5(e){var t=e.toString();return i4[t]?i4[t]:i4[t]=iq(e)}var i6="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};function i9(e){return i8(e)?e:new Date(e)}function i8(e){return e instanceof Date||i7(e)}function i7(e){return(void 0===e?"undefined":i6(e))==="object"&&"function"==typeof e.getTime}var ae=n(54087),at=n.n(ae);function an(e,t){if(0===e.length)return 0;for(var n=0,r=e.length-1,i=void 0;n<=r;){var a=t(e[i=Math.floor((r+n)/2)]);if(0===a)return i;if(a<0){if((n=i+1)>r)return n}else if((r=i-1)=t.nextUpdateTime)ao(t,this.instances);else break}},scheduleNextTick:function(){var e=this;this.scheduledTick=at()(function(){e.tick(),e.scheduleNextTick()})},start:function(){this.scheduleNextTick()},stop:function(){at().cancel(this.scheduledTick)}};function aa(e){var t=ar(e.getNextValue(),2),n=t[0],r=t[1];e.setValue(n),e.nextUpdateTime=r}function ao(e,t){aa(e),au(t,e),as(t,e)}function as(e,t){var n=ac(e,t);e.splice(n,0,t)}function au(e,t){var n=e.indexOf(t);e.splice(n,1)}function ac(e,t){var n=t.nextUpdateTime;return an(e,function(e){return e.nextUpdateTime===n?0:e.nextUpdateTime>n?1:-1})}var al=(0,ec.oneOfType)([(0,ec.shape)({minTime:ec.number,formatAs:ec.string.isRequired}),(0,ec.shape)({test:ec.func,formatAs:ec.string.isRequired}),(0,ec.shape)({minTime:ec.number,format:ec.func.isRequired}),(0,ec.shape)({test:ec.func,format:ec.func.isRequired})]),af=(0,ec.oneOfType)([ec.string,(0,ec.shape)({steps:(0,ec.arrayOf)(al).isRequired,labels:(0,ec.oneOfType)([ec.string,(0,ec.arrayOf)(ec.string)]).isRequired,round:ec.string})]),ad=Object.assign||function(e){for(var t=1;t=0)&&Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}function ab(e){var t=e.date,n=e.future,r=e.timeStyle,i=e.round,a=e.minTimeLeft,o=e.tooltip,s=e.component,u=e.container,c=e.wrapperComponent,f=e.wrapperProps,d=e.locale,h=e.locales,p=e.formatVerboseDate,b=e.verboseDateFormat,m=e.updateInterval,g=e.tick,v=ap(e,["date","future","timeStyle","round","minTimeLeft","tooltip","component","container","wrapperComponent","wrapperProps","locale","locales","formatVerboseDate","verboseDateFormat","updateInterval","tick"]),y=(0,l.useMemo)(function(){return d&&(h=[d]),h.concat(iK.Z.getDefaultLocale())},[d,h]),w=(0,l.useMemo)(function(){return new iK.Z(y)},[y]);t=(0,l.useMemo)(function(){return i9(t)},[t]);var _=(0,l.useCallback)(function(){var e=Date.now(),o=void 0;if(n&&e>=t.getTime()&&(e=t.getTime(),o=!0),void 0!==a){var s=t.getTime()-1e3*a;e>s&&(e=s,o=!0)}var u=w.format(t,r,{getTimeToNextUpdate:!0,now:e,future:n,round:i}),c=ah(u,2),l=c[0],f=c[1];return f=o?av:m||f||6e4,[l,e+f]},[t,n,r,m,i,a,w]),E=(0,l.useRef)();E.current=_;var S=(0,l.useMemo)(_,[]),k=ah(S,2),x=k[0],T=k[1],M=(0,l.useState)(x),O=ah(M,2),A=O[0],L=O[1],C=ah((0,l.useState)(),2),I=C[0],D=C[1],N=(0,l.useRef)();(0,l.useEffect)(function(){if(g)return N.current=ai.add({getNextValue:function(){return E.current()},setValue:L,nextUpdateTime:T}),function(){return N.current.stop()}},[g]),(0,l.useEffect)(function(){if(N.current)N.current.forceUpdate();else{var e=_(),t=ah(e,1)[0];L(t)}},[_]),(0,l.useEffect)(function(){D(!0)},[]);var P=(0,l.useMemo)(function(){if("undefined"!=typeof window)return i3(y,b)},[y,b]),R=(0,l.useMemo)(function(){if("undefined"!=typeof window)return p?p(t):P(t)},[t,p,P]),j=l.createElement(s,ad({date:t,verboseDate:I?R:void 0,tooltip:o},v),A),F=c||u;return F?l.createElement(F,ad({},f,{verboseDate:I?R:void 0}),j):j}ab.propTypes={date:el().oneOfType([el().instanceOf(Date),el().number]).isRequired,locale:el().string,locales:el().arrayOf(el().string),future:el().bool,timeStyle:af,round:el().string,minTimeLeft:el().number,component:el().elementType.isRequired,tooltip:el().bool.isRequired,formatVerboseDate:el().func,verboseDateFormat:el().object,updateInterval:el().oneOfType([el().number,el().arrayOf(el().shape({threshold:el().number,interval:el().number.isRequired}))]),tick:el().bool,wrapperComponent:el().func,wrapperProps:el().object},ab.defaultProps={locales:[],component:ay,tooltip:!0,verboseDateFormat:{weekday:"long",day:"numeric",month:"long",year:"numeric",hour:"numeric",minute:"2-digit",second:"2-digit"},tick:!0},ab=l.memo(ab);let am=ab;var ag,av=31536e9;function ay(e){var t=e.date,n=e.verboseDate,r=e.tooltip,i=e.children,a=ap(e,["date","verboseDate","tooltip","children"]),o=(0,l.useMemo)(function(){return t.toISOString()},[t]);return l.createElement("time",ad({},a,{dateTime:o,title:r?n:void 0}),i)}ay.propTypes={date:el().instanceOf(Date).isRequired,verboseDate:el().string,tooltip:el().bool.isRequired,children:el().string.isRequired};var aw=n(30381),a_=n.n(aw),aE=n(31657);function aS(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function ak(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0?new ru.cA({graphQLErrors:i}):void 0;if(u===s.current.mutationId&&!c.ignoreResults){var f={called:!0,loading:!1,data:r,error:l,client:a};s.current.isMounted&&!(0,ra.D)(s.current.result,f)&&o(s.current.result=f)}var d=e.onCompleted||(null===(n=s.current.options)||void 0===n?void 0:n.onCompleted);return null==d||d(t.data,c),t}).catch(function(t){if(u===s.current.mutationId&&s.current.isMounted){var n,r={loading:!1,error:t,data:void 0,called:!0,client:a};(0,ra.D)(s.current.result,r)||o(s.current.result=r)}var i=e.onError||(null===(n=s.current.options)||void 0===n?void 0:n.onError);if(i)return i(t,c),{data:void 0,errors:t};throw t})},[]),c=(0,l.useCallback)(function(){s.current.isMounted&&o({called:!1,loading:!1,client:n})},[]);return(0,l.useEffect)(function(){return s.current.isMounted=!0,function(){s.current.isMounted=!1}},[]),[u,(0,n8.pi)({reset:c},a)]}var ou=n(59067),oc=n(28428),ol=n(11186),of=n(78513);function od(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var oh=function(e){return(0,b.createStyles)({paper:{display:"flex",margin:"".concat(2.5*e.spacing.unit,"px 0"),padding:"".concat(3*e.spacing.unit,"px ").concat(3.5*e.spacing.unit,"px")},content:{flex:1,width:"100%"},actions:od({marginTop:-(1.5*e.spacing.unit),marginLeft:-(4*e.spacing.unit)},e.breakpoints.up("sm"),{marginLeft:0,marginRight:-(1.5*e.spacing.unit)}),itemBlock:{border:"1px solid rgba(224, 224, 224, 1)",borderRadius:e.shape.borderRadius,padding:2*e.spacing.unit,marginTop:e.spacing.unit},itemBlockText:{overflowWrap:"anywhere"}})},op=(0,b.withStyles)(oh)(function(e){var t=e.actions,n=e.children,r=e.classes;return l.createElement(ia.default,{className:r.paper},l.createElement("div",{className:r.content},n),t&&l.createElement("div",{className:r.actions},t))}),ob=function(e){var t=e.title;return l.createElement(x.default,{variant:"subtitle2",gutterBottom:!0},t)},om=function(e){var t=e.children,n=e.value;return l.createElement(x.default,{variant:"body1",noWrap:!0},t||n)},og=(0,b.withStyles)(oh)(function(e){var t=e.children,n=e.classes,r=e.value;return l.createElement("div",{className:n.itemBlock},l.createElement(x.default,{variant:"body1",className:n.itemBlockText},t||r))});function ov(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]-1}let sZ=sq;function sX(e,t){var n=this.__data__,r=s$(n,e);return r<0?(++this.size,n.push([e,t])):n[r][1]=t,this}let sJ=sX;function sQ(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t-1&&e%1==0&&e-1&&e%1==0&&e<=cI}let cN=cD;var cP="[object Arguments]",cR="[object Array]",cj="[object Boolean]",cF="[object Date]",cY="[object Error]",cB="[object Function]",cU="[object Map]",cH="[object Number]",c$="[object Object]",cz="[object RegExp]",cG="[object Set]",cW="[object String]",cK="[object WeakMap]",cV="[object ArrayBuffer]",cq="[object DataView]",cZ="[object Float64Array]",cX="[object Int8Array]",cJ="[object Int16Array]",cQ="[object Int32Array]",c1="[object Uint8Array]",c0="[object Uint8ClampedArray]",c2="[object Uint16Array]",c3="[object Uint32Array]",c4={};function c5(e){return eD(e)&&cN(e.length)&&!!c4[eC(e)]}c4["[object Float32Array]"]=c4[cZ]=c4[cX]=c4[cJ]=c4[cQ]=c4[c1]=c4[c0]=c4[c2]=c4[c3]=!0,c4[cP]=c4[cR]=c4[cV]=c4[cj]=c4[cq]=c4[cF]=c4[cY]=c4[cB]=c4[cU]=c4[cH]=c4[c$]=c4[cz]=c4[cG]=c4[cW]=c4[cK]=!1;let c6=c5;function c9(e){return function(t){return e(t)}}let c8=c9;var c7=n(79730),le=c7.Z&&c7.Z.isTypedArray,lt=le?c8(le):c6;let ln=lt;var lr=Object.prototype.hasOwnProperty;function li(e,t){var n=cT(e),r=!n&&ck(e),i=!n&&!r&&(0,cM.Z)(e),a=!n&&!r&&!i&&ln(e),o=n||r||i||a,s=o?cm(e.length,String):[],u=s.length;for(var c in e)(t||lr.call(e,c))&&!(o&&("length"==c||i&&("offset"==c||"parent"==c)||a&&("buffer"==c||"byteLength"==c||"byteOffset"==c)||cC(c,u)))&&s.push(c);return s}let la=li;var lo=Object.prototype;function ls(e){var t=e&&e.constructor;return e===("function"==typeof t&&t.prototype||lo)}let lu=ls;var lc=sM(Object.keys,Object);let ll=lc;var lf=Object.prototype.hasOwnProperty;function ld(e){if(!lu(e))return ll(e);var t=[];for(var n in Object(e))lf.call(e,n)&&"constructor"!=n&&t.push(n);return t}let lh=ld;function lp(e){return null!=e&&cN(e.length)&&!ui(e)}let lb=lp;function lm(e){return lb(e)?la(e):lh(e)}let lg=lm;function lv(e,t){return e&&cp(t,lg(t),e)}let ly=lv;function lw(e){var t=[];if(null!=e)for(var n in Object(e))t.push(n);return t}let l_=lw;var lE=Object.prototype.hasOwnProperty;function lS(e){if(!ed(e))return l_(e);var t=lu(e),n=[];for(var r in e)"constructor"==r&&(t||!lE.call(e,r))||n.push(r);return n}let lk=lS;function lx(e){return lb(e)?la(e,!0):lk(e)}let lT=lx;function lM(e,t){return e&&cp(t,lT(t),e)}let lO=lM;var lA=n(42896);function lL(e,t){var n=-1,r=e.length;for(t||(t=Array(r));++n=0||(i[n]=e[n]);return i}function hc(e){if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}var hl=function(e){return Array.isArray(e)&&0===e.length},hf=function(e){return"function"==typeof e},hd=function(e){return null!==e&&"object"==typeof e},hh=function(e){return String(Math.floor(Number(e)))===e},hp=function(e){return"[object String]"===Object.prototype.toString.call(e)},hb=function(e){return 0===l.Children.count(e)},hm=function(e){return hd(e)&&hf(e.then)};function hg(e,t,n,r){void 0===r&&(r=0);for(var i=d8(t);e&&r=0?[]:{}}}return(0===a?e:i)[o[a]]===n?e:(void 0===n?delete i[o[a]]:i[o[a]]=n,0===a&&void 0===n&&delete r[o[a]],r)}function hy(e,t,n,r){void 0===n&&(n=new WeakMap),void 0===r&&(r={});for(var i=0,a=Object.keys(e);i0?t.map(function(t){return x(t,hg(e,t))}):[Promise.resolve("DO_NOT_DELETE_YOU_WILL_BE_FIRED")]).then(function(e){return e.reduce(function(e,n,r){return"DO_NOT_DELETE_YOU_WILL_BE_FIRED"===n||n&&(e=hv(e,t[r],n)),e},{})})},[x]),M=(0,l.useCallback)(function(e){return Promise.all([T(e),h.validationSchema?k(e):{},h.validate?S(e):{}]).then(function(e){var t=e[0],n=e[1],r=e[2];return sx.all([t,n,r],{arrayMerge:hC})})},[h.validate,h.validationSchema,T,S,k]),O=hP(function(e){return void 0===e&&(e=_.values),E({type:"SET_ISVALIDATING",payload:!0}),M(e).then(function(e){return v.current&&(E({type:"SET_ISVALIDATING",payload:!1}),sh()(_.errors,e)||E({type:"SET_ERRORS",payload:e})),e})});(0,l.useEffect)(function(){o&&!0===v.current&&sh()(p.current,h.initialValues)&&O(p.current)},[o,O]);var A=(0,l.useCallback)(function(e){var t=e&&e.values?e.values:p.current,n=e&&e.errors?e.errors:b.current?b.current:h.initialErrors||{},r=e&&e.touched?e.touched:m.current?m.current:h.initialTouched||{},i=e&&e.status?e.status:g.current?g.current:h.initialStatus;p.current=t,b.current=n,m.current=r,g.current=i;var a=function(){E({type:"RESET_FORM",payload:{isSubmitting:!!e&&!!e.isSubmitting,errors:n,touched:r,status:i,values:t,isValidating:!!e&&!!e.isValidating,submitCount:e&&e.submitCount&&"number"==typeof e.submitCount?e.submitCount:0}})};if(h.onReset){var o=h.onReset(_.values,V);hm(o)?o.then(a):a()}else a()},[h.initialErrors,h.initialStatus,h.initialTouched]);(0,l.useEffect)(function(){!0===v.current&&!sh()(p.current,h.initialValues)&&(c&&(p.current=h.initialValues,A()),o&&O(p.current))},[c,h.initialValues,A,o,O]),(0,l.useEffect)(function(){c&&!0===v.current&&!sh()(b.current,h.initialErrors)&&(b.current=h.initialErrors||hk,E({type:"SET_ERRORS",payload:h.initialErrors||hk}))},[c,h.initialErrors]),(0,l.useEffect)(function(){c&&!0===v.current&&!sh()(m.current,h.initialTouched)&&(m.current=h.initialTouched||hx,E({type:"SET_TOUCHED",payload:h.initialTouched||hx}))},[c,h.initialTouched]),(0,l.useEffect)(function(){c&&!0===v.current&&!sh()(g.current,h.initialStatus)&&(g.current=h.initialStatus,E({type:"SET_STATUS",payload:h.initialStatus}))},[c,h.initialStatus,h.initialTouched]);var L=hP(function(e){if(y.current[e]&&hf(y.current[e].validate)){var t=hg(_.values,e),n=y.current[e].validate(t);return hm(n)?(E({type:"SET_ISVALIDATING",payload:!0}),n.then(function(e){return e}).then(function(t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t}}),E({type:"SET_ISVALIDATING",payload:!1})})):(E({type:"SET_FIELD_ERROR",payload:{field:e,value:n}}),Promise.resolve(n))}return h.validationSchema?(E({type:"SET_ISVALIDATING",payload:!0}),k(_.values,e).then(function(e){return e}).then(function(t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t[e]}}),E({type:"SET_ISVALIDATING",payload:!1})})):Promise.resolve()}),C=(0,l.useCallback)(function(e,t){var n=t.validate;y.current[e]={validate:n}},[]),I=(0,l.useCallback)(function(e){delete y.current[e]},[]),D=hP(function(e,t){return E({type:"SET_TOUCHED",payload:e}),(void 0===t?i:t)?O(_.values):Promise.resolve()}),N=(0,l.useCallback)(function(e){E({type:"SET_ERRORS",payload:e})},[]),P=hP(function(e,t){var r=hf(e)?e(_.values):e;return E({type:"SET_VALUES",payload:r}),(void 0===t?n:t)?O(r):Promise.resolve()}),R=(0,l.useCallback)(function(e,t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t}})},[]),j=hP(function(e,t,r){return E({type:"SET_FIELD_VALUE",payload:{field:e,value:t}}),(void 0===r?n:r)?O(hv(_.values,e,t)):Promise.resolve()}),F=(0,l.useCallback)(function(e,t){var n,r=t,i=e;if(!hp(e)){e.persist&&e.persist();var a=e.target?e.target:e.currentTarget,o=a.type,s=a.name,u=a.id,c=a.value,l=a.checked,f=(a.outerHTML,a.options),d=a.multiple;r=t||s||u,i=/number|range/.test(o)?(n=parseFloat(c),isNaN(n)?"":n):/checkbox/.test(o)?hD(hg(_.values,r),l,c):d?hI(f):c}r&&j(r,i)},[j,_.values]),Y=hP(function(e){if(hp(e))return function(t){return F(t,e)};F(e)}),B=hP(function(e,t,n){return void 0===t&&(t=!0),E({type:"SET_FIELD_TOUCHED",payload:{field:e,value:t}}),(void 0===n?i:n)?O(_.values):Promise.resolve()}),U=(0,l.useCallback)(function(e,t){e.persist&&e.persist();var n,r=e.target,i=r.name,a=r.id;r.outerHTML,B(t||i||a,!0)},[B]),H=hP(function(e){if(hp(e))return function(t){return U(t,e)};U(e)}),$=(0,l.useCallback)(function(e){hf(e)?E({type:"SET_FORMIK_STATE",payload:e}):E({type:"SET_FORMIK_STATE",payload:function(){return e}})},[]),z=(0,l.useCallback)(function(e){E({type:"SET_STATUS",payload:e})},[]),G=(0,l.useCallback)(function(e){E({type:"SET_ISSUBMITTING",payload:e})},[]),W=hP(function(){return E({type:"SUBMIT_ATTEMPT"}),O().then(function(e){var t,n=e instanceof Error;if(!n&&0===Object.keys(e).length){try{if(void 0===(t=q()))return}catch(r){throw r}return Promise.resolve(t).then(function(e){return v.current&&E({type:"SUBMIT_SUCCESS"}),e}).catch(function(e){if(v.current)throw E({type:"SUBMIT_FAILURE"}),e})}if(v.current&&(E({type:"SUBMIT_FAILURE"}),n))throw e})}),K=hP(function(e){e&&e.preventDefault&&hf(e.preventDefault)&&e.preventDefault(),e&&e.stopPropagation&&hf(e.stopPropagation)&&e.stopPropagation(),W().catch(function(e){console.warn("Warning: An unhandled error was caught from submitForm()",e)})}),V={resetForm:A,validateForm:O,validateField:L,setErrors:N,setFieldError:R,setFieldTouched:B,setFieldValue:j,setStatus:z,setSubmitting:G,setTouched:D,setValues:P,setFormikState:$,submitForm:W},q=hP(function(){return f(_.values,V)}),Z=hP(function(e){e&&e.preventDefault&&hf(e.preventDefault)&&e.preventDefault(),e&&e.stopPropagation&&hf(e.stopPropagation)&&e.stopPropagation(),A()}),X=(0,l.useCallback)(function(e){return{value:hg(_.values,e),error:hg(_.errors,e),touched:!!hg(_.touched,e),initialValue:hg(p.current,e),initialTouched:!!hg(m.current,e),initialError:hg(b.current,e)}},[_.errors,_.touched,_.values]),J=(0,l.useCallback)(function(e){return{setValue:function(t,n){return j(e,t,n)},setTouched:function(t,n){return B(e,t,n)},setError:function(t){return R(e,t)}}},[j,B,R]),Q=(0,l.useCallback)(function(e){var t=hd(e),n=t?e.name:e,r=hg(_.values,n),i={name:n,value:r,onChange:Y,onBlur:H};if(t){var a=e.type,o=e.value,s=e.as,u=e.multiple;"checkbox"===a?void 0===o?i.checked=!!r:(i.checked=!!(Array.isArray(r)&&~r.indexOf(o)),i.value=o):"radio"===a?(i.checked=r===o,i.value=o):"select"===s&&u&&(i.value=i.value||[],i.multiple=!0)}return i},[H,Y,_.values]),ee=(0,l.useMemo)(function(){return!sh()(p.current,_.values)},[p.current,_.values]),et=(0,l.useMemo)(function(){return void 0!==s?ee?_.errors&&0===Object.keys(_.errors).length:!1!==s&&hf(s)?s(h):s:_.errors&&0===Object.keys(_.errors).length},[s,ee,_.errors,h]);return ho({},_,{initialValues:p.current,initialErrors:b.current,initialTouched:m.current,initialStatus:g.current,handleBlur:H,handleChange:Y,handleReset:Z,handleSubmit:K,resetForm:A,setErrors:N,setFormikState:$,setFieldTouched:B,setFieldValue:j,setFieldError:R,setStatus:z,setSubmitting:G,setTouched:D,setValues:P,submitForm:W,validateForm:O,validateField:L,isValid:et,dirty:ee,unregisterField:I,registerField:C,getFieldProps:Q,getFieldMeta:X,getFieldHelpers:J,validateOnBlur:i,validateOnChange:n,validateOnMount:o})}function hM(e){var t=hT(e),n=e.component,r=e.children,i=e.render,a=e.innerRef;return(0,l.useImperativeHandle)(a,function(){return t}),(0,l.createElement)(h_,{value:t},n?(0,l.createElement)(n,t):i?i(t):r?hf(r)?r(t):hb(r)?null:l.Children.only(r):null)}function hO(e){var t={};if(e.inner){if(0===e.inner.length)return hv(t,e.path,e.message);for(var n=e.inner,r=Array.isArray(n),i=0,n=r?n:n[Symbol.iterator]();;){if(r){if(i>=n.length)break;a=n[i++]}else{if((i=n.next()).done)break;a=i.value}var a,o=a;hg(t,o.path)||(t=hv(t,o.path,o.message))}}return t}function hA(e,t,n,r){void 0===n&&(n=!1),void 0===r&&(r={});var i=hL(e);return t[n?"validateSync":"validate"](i,{abortEarly:!1,context:r})}function hL(e){var t=Array.isArray(e)?[]:{};for(var n in e)if(Object.prototype.hasOwnProperty.call(e,n)){var r=String(n);!0===Array.isArray(e[r])?t[r]=e[r].map(function(e){return!0===Array.isArray(e)||sj(e)?hL(e):""!==e?e:void 0}):sj(e[r])?t[r]=hL(e[r]):t[r]=""!==e[r]?e[r]:void 0}return t}function hC(e,t,n){var r=e.slice();return t.forEach(function(t,i){if(void 0===r[i]){var a=!1!==n.clone&&n.isMergeableObject(t);r[i]=a?sx(Array.isArray(t)?[]:{},t,n):t}else n.isMergeableObject(t)?r[i]=sx(e[i],t,n):-1===e.indexOf(t)&&r.push(t)}),r}function hI(e){return Array.from(e).filter(function(e){return e.selected}).map(function(e){return e.value})}function hD(e,t,n){if("boolean"==typeof e)return Boolean(t);var r=[],i=!1,a=-1;if(Array.isArray(e))r=e,i=(a=e.indexOf(n))>=0;else if(!n||"true"==n||"false"==n)return Boolean(t);return t&&n&&!i?r.concat(n):i?r.slice(0,a).concat(r.slice(a+1)):r}var hN="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement?l.useLayoutEffect:l.useEffect;function hP(e){var t=(0,l.useRef)(e);return hN(function(){t.current=e}),(0,l.useCallback)(function(){for(var e=arguments.length,n=Array(e),r=0;re?t:e},0);return Array.from(ho({},e,{length:t+1}))};(function(e){function t(t){var n;return(n=e.call(this,t)||this).updateArrayField=function(e,t,r){var i=n.props,a=i.name;(0,i.formik.setFormikState)(function(n){var i="function"==typeof r?r:e,o="function"==typeof t?t:e,s=hv(n.values,a,e(hg(n.values,a))),u=r?i(hg(n.errors,a)):void 0,c=t?o(hg(n.touched,a)):void 0;return hl(u)&&(u=void 0),hl(c)&&(c=void 0),ho({},n,{values:s,errors:r?hv(n.errors,a,u):n.errors,touched:t?hv(n.touched,a,c):n.touched})})},n.push=function(e){return n.updateArrayField(function(t){return[].concat(hH(t),[ha(e)])},!1,!1)},n.handlePush=function(e){return function(){return n.push(e)}},n.swap=function(e,t){return n.updateArrayField(function(n){return hY(n,e,t)},!0,!0)},n.handleSwap=function(e,t){return function(){return n.swap(e,t)}},n.move=function(e,t){return n.updateArrayField(function(n){return hF(n,e,t)},!0,!0)},n.handleMove=function(e,t){return function(){return n.move(e,t)}},n.insert=function(e,t){return n.updateArrayField(function(n){return hB(n,e,t)},function(t){return hB(t,e,null)},function(t){return hB(t,e,null)})},n.handleInsert=function(e,t){return function(){return n.insert(e,t)}},n.replace=function(e,t){return n.updateArrayField(function(n){return hU(n,e,t)},!1,!1)},n.handleReplace=function(e,t){return function(){return n.replace(e,t)}},n.unshift=function(e){var t=-1;return n.updateArrayField(function(n){var r=n?[e].concat(n):[e];return t<0&&(t=r.length),r},function(e){var n=e?[null].concat(e):[null];return t<0&&(t=n.length),n},function(e){var n=e?[null].concat(e):[null];return t<0&&(t=n.length),n}),t},n.handleUnshift=function(e){return function(){return n.unshift(e)}},n.handleRemove=function(e){return function(){return n.remove(e)}},n.handlePop=function(){return function(){return n.pop()}},n.remove=n.remove.bind(hc(n)),n.pop=n.pop.bind(hc(n)),n}hs(t,e);var n=t.prototype;return n.componentDidUpdate=function(e){this.props.validateOnChange&&this.props.formik.validateOnChange&&!sh()(hg(e.formik.values,e.name),hg(this.props.formik.values,this.props.name))&&this.props.formik.validateForm(this.props.formik.values)},n.remove=function(e){var t;return this.updateArrayField(function(n){var r=n?hH(n):[];return t||(t=r[e]),hf(r.splice)&&r.splice(e,1),r},!0,!0),t},n.pop=function(){var e;return this.updateArrayField(function(t){var n=t;return e||(e=n&&n.pop&&n.pop()),n},!0,!0),e},n.render=function(){var e={push:this.push,pop:this.pop,swap:this.swap,move:this.move,insert:this.insert,replace:this.replace,unshift:this.unshift,remove:this.remove,handlePush:this.handlePush,handlePop:this.handlePop,handleSwap:this.handleSwap,handleMove:this.handleMove,handleInsert:this.handleInsert,handleReplace:this.handleReplace,handleUnshift:this.handleUnshift,handleRemove:this.handleRemove},t=this.props,n=t.component,r=t.render,i=t.children,a=t.name,o=hu(t.formik,["validate","validationSchema"]),s=ho({},e,{form:o,name:a});return n?(0,l.createElement)(n,s):r?r(s):i?"function"==typeof i?i(s):hb(i)?null:l.Children.only(i):null},t})(l.Component).defaultProps={validateOnChange:!0},l.Component,l.Component;var h$=n(24802),hz=n(71209),hG=n(91750),hW=n(11970),hK=n(4689),hV=n(67598),hq=function(){return(hq=Object.assign||function(e){for(var t,n=1,r=arguments.length;nt.indexOf(r)&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,r=Object.getOwnPropertySymbols(e);it.indexOf(r[i])&&(n[r[i]]=e[r[i]]);return n}function hX(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form,o=a.isSubmitting,s=a.touched,u=a.errors,c=e.onBlur,l=e.helperText,f=hZ(e,["disabled","field","form","onBlur","helperText"]),d=hg(u,i.name),h=hg(s,i.name)&&!!d;return hq(hq({variant:f.variant,error:h,helperText:h?d:l,disabled:null!=t?t:o,onBlur:null!=c?c:function(e){r(null!=e?e:i.name)}},i),f)}function hJ(e){var t=e.children,n=hZ(e,["children"]);return(0,l.createElement)(i_.Z,hq({},hX(n)),t)}function hQ(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form.isSubmitting,o=(e.type,e.onBlur),s=hZ(e,["disabled","field","form","type","onBlur"]);return hq(hq({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function h1(e){return(0,l.createElement)(h$.Z,hq({},hQ(e)))}function h0(e){var t,n=e.disabled,r=e.field,i=r.onBlur,a=hZ(r,["onBlur"]),o=e.form.isSubmitting,s=(e.type,e.onBlur),u=hZ(e,["disabled","field","form","type","onBlur"]);return hq(hq({disabled:null!=n?n:o,indeterminate:!Array.isArray(a.value)&&null==a.value,onBlur:null!=s?s:function(e){i(null!=e?e:a.name)}},a),u)}function h2(e){return(0,l.createElement)(hz.Z,hq({},h0(e)))}function h3(e){var t=e.Label,n=hZ(e,["Label"]);return(0,l.createElement)(hG.Z,hq({control:(0,l.createElement)(hz.Z,hq({},h0(n)))},t))}function h4(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form.isSubmitting,o=e.onBlur,s=hZ(e,["disabled","field","form","onBlur"]);return hq(hq({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function h5(e){return(0,l.createElement)(hW.default,hq({},h4(e)))}function h6(e){var t=e.field,n=t.onBlur,r=hZ(t,["onBlur"]),i=(e.form,e.onBlur),a=hZ(e,["field","form","onBlur"]);return hq(hq({onBlur:null!=i?i:function(e){n(null!=e?e:r.name)}},r),a)}function h9(e){return(0,l.createElement)(hK.Z,hq({},h6(e)))}function h8(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form.isSubmitting,o=e.onBlur,s=hZ(e,["disabled","field","form","onBlur"]);return hq(hq({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function h7(e){return(0,l.createElement)(hV.default,hq({},h8(e)))}hJ.displayName="FormikMaterialUITextField",h1.displayName="FormikMaterialUISwitch",h2.displayName="FormikMaterialUICheckbox",h3.displayName="FormikMaterialUICheckboxWithLabel",h5.displayName="FormikMaterialUISelect",h9.displayName="FormikMaterialUIRadioGroup",h7.displayName="FormikMaterialUIInputBase";try{a=Map}catch(pe){}try{o=Set}catch(pt){}function pn(e,t,n){if(!e||"object"!=typeof e||"function"==typeof e)return e;if(e.nodeType&&"cloneNode"in e)return e.cloneNode(!0);if(e instanceof Date)return new Date(e.getTime());if(e instanceof RegExp)return RegExp(e);if(Array.isArray(e))return e.map(pr);if(a&&e instanceof a)return new Map(Array.from(e.entries()));if(o&&e instanceof o)return new Set(Array.from(e.values()));if(e instanceof Object){t.push(e);var r=Object.create(e);for(var i in n.push(r),e){var s=t.findIndex(function(t){return t===e[i]});r[i]=s>-1?n[s]:pn(e[i],t,n)}return r}return e}function pr(e){return pn(e,[],[])}let pi=Object.prototype.toString,pa=Error.prototype.toString,po=RegExp.prototype.toString,ps="undefined"!=typeof Symbol?Symbol.prototype.toString:()=>"",pu=/^Symbol\((.*)\)(.*)$/;function pc(e){if(e!=+e)return"NaN";let t=0===e&&1/e<0;return t?"-0":""+e}function pl(e,t=!1){if(null==e||!0===e||!1===e)return""+e;let n=typeof e;if("number"===n)return pc(e);if("string"===n)return t?`"${e}"`:e;if("function"===n)return"[Function "+(e.name||"anonymous")+"]";if("symbol"===n)return ps.call(e).replace(pu,"Symbol($1)");let r=pi.call(e).slice(8,-1);return"Date"===r?isNaN(e.getTime())?""+e:e.toISOString(e):"Error"===r||e instanceof Error?"["+pa.call(e)+"]":"RegExp"===r?po.call(e):null}function pf(e,t){let n=pl(e,t);return null!==n?n:JSON.stringify(e,function(e,n){let r=pl(this[e],t);return null!==r?r:n},2)}let pd={default:"${path} is invalid",required:"${path} is a required field",oneOf:"${path} must be one of the following values: ${values}",notOneOf:"${path} must not be one of the following values: ${values}",notType({path:e,type:t,value:n,originalValue:r}){let i=null!=r&&r!==n,a=`${e} must be a \`${t}\` type, but the final value was: \`${pf(n,!0)}\``+(i?` (cast from the value \`${pf(r,!0)}\`).`:".");return null===n&&(a+='\n If "null" is intended as an empty value be sure to mark the schema as `.nullable()`'),a},defined:"${path} must be defined"},ph={length:"${path} must be exactly ${length} characters",min:"${path} must be at least ${min} characters",max:"${path} must be at most ${max} characters",matches:'${path} must match the following: "${regex}"',email:"${path} must be a valid email",url:"${path} must be a valid URL",uuid:"${path} must be a valid UUID",trim:"${path} must be a trimmed string",lowercase:"${path} must be a lowercase string",uppercase:"${path} must be a upper case string"},pp={min:"${path} must be greater than or equal to ${min}",max:"${path} must be less than or equal to ${max}",lessThan:"${path} must be less than ${less}",moreThan:"${path} must be greater than ${more}",positive:"${path} must be a positive number",negative:"${path} must be a negative number",integer:"${path} must be an integer"},pb={min:"${path} field must be later than ${min}",max:"${path} field must be at earlier than ${max}"},pm={isValue:"${path} field must be ${value}"},pg={noUnknown:"${path} field has unspecified keys: ${unknown}"},pv={min:"${path} field must have at least ${min} items",max:"${path} field must have less than or equal to ${max} items",length:"${path} must be have ${length} items"};Object.assign(Object.create(null),{mixed:pd,string:ph,number:pp,date:pb,object:pg,array:pv,boolean:pm});var py=n(18721),pw=n.n(py);let p_=e=>e&&e.__isYupSchema__;class pE{constructor(e,t){if(this.refs=e,this.refs=e,"function"==typeof t){this.fn=t;return}if(!pw()(t,"is"))throw TypeError("`is:` is required for `when()` conditions");if(!t.then&&!t.otherwise)throw TypeError("either `then:` or `otherwise:` is required for `when()` conditions");let{is:n,then:r,otherwise:i}=t,a="function"==typeof n?n:(...e)=>e.every(e=>e===n);this.fn=function(...e){let t=e.pop(),n=e.pop(),o=a(...e)?r:i;if(o)return"function"==typeof o?o(n):n.concat(o.resolve(t))}}resolve(e,t){let n=this.refs.map(e=>e.getValue(null==t?void 0:t.value,null==t?void 0:t.parent,null==t?void 0:t.context)),r=this.fn.apply(e,n.concat(e,t));if(void 0===r||r===e)return e;if(!p_(r))throw TypeError("conditions must return a schema object");return r.resolve(t)}}let pS=pE;function pk(e){return null==e?[]:[].concat(e)}function px(){return(px=Object.assign||function(e){for(var t=1;tpf(t[n])):"function"==typeof e?e(t):e}static isError(e){return e&&"ValidationError"===e.name}constructor(e,t,n,r){super(),this.name="ValidationError",this.value=t,this.path=n,this.type=r,this.errors=[],this.inner=[],pk(e).forEach(e=>{pM.isError(e)?(this.errors.push(...e.errors),this.inner=this.inner.concat(e.inner.length?e.inner:e)):this.errors.push(e)}),this.message=this.errors.length>1?`${this.errors.length} errors occurred`:this.errors[0],Error.captureStackTrace&&Error.captureStackTrace(this,pM)}}let pO=e=>{let t=!1;return(...n)=>{t||(t=!0,e(...n))}};function pA(e,t){let{endEarly:n,tests:r,args:i,value:a,errors:o,sort:s,path:u}=e,c=pO(t),l=r.length,f=[];if(o=o||[],!l)return o.length?c(new pM(o,a,u)):c(null,a);for(let d=0;d=0||(i[n]=e[n]);return i}function pj(e){function t(t,n){let{value:r,path:i="",label:a,options:o,originalValue:s,sync:u}=t,c=pR(t,["value","path","label","options","originalValue","sync"]),{name:l,test:f,params:d,message:h}=e,{parent:p,context:b}=o;function m(e){return pN.isRef(e)?e.getValue(r,p,b):e}function g(e={}){let t=pC()(pP({value:r,originalValue:s,label:a,path:e.path||i},d,e.params),m),n=new pM(pM.formatError(e.message||h,t),r,t.path,e.type||l);return n.params=t,n}let v=pP({path:i,parent:p,type:l,createError:g,resolve:m,options:o,originalValue:s},c);if(!u){try{Promise.resolve(f.call(v,r,v)).then(e=>{pM.isError(e)?n(e):e?n(null,e):n(g())})}catch(y){n(y)}return}let w;try{var _;if(w=f.call(v,r,v),"function"==typeof(null==(_=w)?void 0:_.then))throw Error(`Validation test of type: "${v.type}" returned a Promise during a synchronous validate. This test will finish after the validate call has returned`)}catch(E){n(E);return}pM.isError(w)?n(w):w?n(null,w):n(g())}return t.OPTIONS=e,t}pN.prototype.__isYupRef=!0;let pF=e=>e.substr(0,e.length-1).substr(1);function pY(e,t,n,r=n){let i,a,o;return t?((0,pI.forEach)(t,(s,u,c)=>{let l=u?pF(s):s;if((e=e.resolve({context:r,parent:i,value:n})).innerType){let f=c?parseInt(l,10):0;if(n&&f>=n.length)throw Error(`Yup.reach cannot resolve an array item at index: ${s}, in the path: ${t}. because there is no value at that index. `);i=n,n=n&&n[f],e=e.innerType}if(!c){if(!e.fields||!e.fields[l])throw Error(`The schema does not contain the path: ${t}. (failed at: ${o} which is a type: "${e._type}")`);i=n,n=n&&n[l],e=e.fields[l]}a=l,o=u?"["+s+"]":"."+s}),{schema:e,parent:i,parentPath:a}):{parent:i,parentPath:t,schema:e}}class pB{constructor(){this.list=new Set,this.refs=new Map}get size(){return this.list.size+this.refs.size}describe(){let e=[];for(let t of this.list)e.push(t);for(let[,n]of this.refs)e.push(n.describe());return e}toArray(){return Array.from(this.list).concat(Array.from(this.refs.values()))}add(e){pN.isRef(e)?this.refs.set(e.key,e):this.list.add(e)}delete(e){pN.isRef(e)?this.refs.delete(e.key):this.list.delete(e)}has(e,t){if(this.list.has(e))return!0;let n,r=this.refs.values();for(;!(n=r.next()).done;)if(t(n.value)===e)return!0;return!1}clone(){let e=new pB;return e.list=new Set(this.list),e.refs=new Map(this.refs),e}merge(e,t){let n=this.clone();return e.list.forEach(e=>n.add(e)),e.refs.forEach(e=>n.add(e)),t.list.forEach(e=>n.delete(e)),t.refs.forEach(e=>n.delete(e)),n}}function pU(){return(pU=Object.assign||function(e){for(var t=1;t{this.typeError(pd.notType)}),this.type=(null==e?void 0:e.type)||"mixed",this.spec=pU({strip:!1,strict:!1,abortEarly:!0,recursive:!0,nullable:!1,presence:"optional"},null==e?void 0:e.spec)}get _type(){return this.type}_typeCheck(e){return!0}clone(e){if(this._mutate)return e&&Object.assign(this.spec,e),this;let t=Object.create(Object.getPrototypeOf(this));return t.type=this.type,t._typeError=this._typeError,t._whitelistError=this._whitelistError,t._blacklistError=this._blacklistError,t._whitelist=this._whitelist.clone(),t._blacklist=this._blacklist.clone(),t.exclusiveTests=pU({},this.exclusiveTests),t.deps=[...this.deps],t.conditions=[...this.conditions],t.tests=[...this.tests],t.transforms=[...this.transforms],t.spec=pr(pU({},this.spec,e)),t}label(e){var t=this.clone();return t.spec.label=e,t}meta(...e){if(0===e.length)return this.spec.meta;let t=this.clone();return t.spec.meta=Object.assign(t.spec.meta||{},e[0]),t}withMutation(e){let t=this._mutate;this._mutate=!0;let n=e(this);return this._mutate=t,n}concat(e){if(!e||e===this)return this;if(e.type!==this.type&&"mixed"!==this.type)throw TypeError(`You cannot \`concat()\` schema's of different types: ${this.type} and ${e.type}`);let t=this,n=e.clone(),r=pU({},t.spec,n.spec);return n.spec=r,n._typeError||(n._typeError=t._typeError),n._whitelistError||(n._whitelistError=t._whitelistError),n._blacklistError||(n._blacklistError=t._blacklistError),n._whitelist=t._whitelist.merge(e._whitelist,e._blacklist),n._blacklist=t._blacklist.merge(e._blacklist,e._whitelist),n.tests=t.tests,n.exclusiveTests=t.exclusiveTests,n.withMutation(t=>{e.tests.forEach(e=>{t.test(e.OPTIONS)})}),n}isType(e){return!!this.spec.nullable&&null===e||this._typeCheck(e)}resolve(e){let t=this;if(t.conditions.length){let n=t.conditions;(t=t.clone()).conditions=[],t=(t=n.reduce((t,n)=>n.resolve(t,e),t)).resolve(e)}return t}cast(e,t={}){let n=this.resolve(pU({value:e},t)),r=n._cast(e,t);if(void 0!==e&&!1!==t.assert&&!0!==n.isType(r)){let i=pf(e),a=pf(r);throw TypeError(`The value of ${t.path||"field"} could not be cast to a value that satisfies the schema type: "${n._type}". attempted value: ${i} -`+(a!==i?`result of cast: ${a}`:""))}return r}_cast(e,t){let n=void 0===e?e:this.transforms.reduce((t,n)=>n.call(this,t,e,this),e);return void 0===n&&(n=this.getDefault()),n}_validate(e,t={},n){let{sync:r,path:i,from:a=[],originalValue:o=e,strict:s=this.spec.strict,abortEarly:u=this.spec.abortEarly}=t,c=e;s||(c=this._cast(c,pU({assert:!1},t)));let l={value:c,path:i,options:t,originalValue:o,schema:this,label:this.spec.label,sync:r,from:a},f=[];this._typeError&&f.push(this._typeError),this._whitelistError&&f.push(this._whitelistError),this._blacklistError&&f.push(this._blacklistError),pA({args:l,value:c,path:i,sync:r,tests:f,endEarly:u},e=>{if(e)return void n(e,c);pA({tests:this.tests,args:l,path:i,sync:r,value:c,endEarly:u},n)})}validate(e,t,n){let r=this.resolve(pU({},t,{value:e}));return"function"==typeof n?r._validate(e,t,n):new Promise((n,i)=>r._validate(e,t,(e,t)=>{e?i(e):n(t)}))}validateSync(e,t){let n;return this.resolve(pU({},t,{value:e}))._validate(e,pU({},t,{sync:!0}),(e,t)=>{if(e)throw e;n=t}),n}isValid(e,t){return this.validate(e,t).then(()=>!0,e=>{if(pM.isError(e))return!1;throw e})}isValidSync(e,t){try{return this.validateSync(e,t),!0}catch(n){if(pM.isError(n))return!1;throw n}}_getDefault(){let e=this.spec.default;return null==e?e:"function"==typeof e?e.call(this):pr(e)}getDefault(e){return this.resolve(e||{})._getDefault()}default(e){return 0===arguments.length?this._getDefault():this.clone({default:e})}strict(e=!0){var t=this.clone();return t.spec.strict=e,t}_isPresent(e){return null!=e}defined(e=pd.defined){return this.test({message:e,name:"defined",exclusive:!0,test:e=>void 0!==e})}required(e=pd.required){return this.clone({presence:"required"}).withMutation(t=>t.test({message:e,name:"required",exclusive:!0,test(e){return this.schema._isPresent(e)}}))}notRequired(){var e=this.clone({presence:"optional"});return e.tests=e.tests.filter(e=>"required"!==e.OPTIONS.name),e}nullable(e=!0){return this.clone({nullable:!1!==e})}transform(e){var t=this.clone();return t.transforms.push(e),t}test(...e){let t;if(void 0===(t=1===e.length?"function"==typeof e[0]?{test:e[0]}:e[0]:2===e.length?{name:e[0],test:e[1]}:{name:e[0],message:e[1],test:e[2]}).message&&(t.message=pd.default),"function"!=typeof t.test)throw TypeError("`test` is a required parameters");let n=this.clone(),r=pj(t),i=t.exclusive||t.name&&!0===n.exclusiveTests[t.name];if(t.exclusive&&!t.name)throw TypeError("Exclusive tests must provide a unique `name` identifying the test");return t.name&&(n.exclusiveTests[t.name]=!!t.exclusive),n.tests=n.tests.filter(e=>e.OPTIONS.name!==t.name||!i&&e.OPTIONS.test!==r.OPTIONS.test),n.tests.push(r),n}when(e,t){Array.isArray(e)||"string"==typeof e||(t=e,e=".");let n=this.clone(),r=pk(e).map(e=>new pN(e));return r.forEach(e=>{e.isSibling&&n.deps.push(e.key)}),n.conditions.push(new pS(r,t)),n}typeError(e){var t=this.clone();return t._typeError=pj({message:e,name:"typeError",test(e){return!!(void 0===e||this.schema.isType(e))||this.createError({params:{type:this.schema._type}})}}),t}oneOf(e,t=pd.oneOf){var n=this.clone();return e.forEach(e=>{n._whitelist.add(e),n._blacklist.delete(e)}),n._whitelistError=pj({message:t,name:"oneOf",test(e){if(void 0===e)return!0;let t=this.schema._whitelist;return!!t.has(e,this.resolve)||this.createError({params:{values:t.toArray().join(", ")}})}}),n}notOneOf(e,t=pd.notOneOf){var n=this.clone();return e.forEach(e=>{n._blacklist.add(e),n._whitelist.delete(e)}),n._blacklistError=pj({message:t,name:"notOneOf",test(e){let t=this.schema._blacklist;return!t.has(e,this.resolve)||this.createError({params:{values:t.toArray().join(", ")}})}}),n}strip(e=!0){let t=this.clone();return t.spec.strip=e,t}describe(){let e=this.clone(),{label:t,meta:n}=e.spec,r={meta:n,label:t,type:e.type,oneOf:e._whitelist.describe(),notOneOf:e._blacklist.describe(),tests:e.tests.map(e=>({name:e.OPTIONS.name,params:e.OPTIONS.params})).filter((e,t,n)=>n.findIndex(t=>t.name===e.name)===t)};return r}}for(let p$ of(pH.prototype.__isYupSchema__=!0,["validate","validateSync"]))pH.prototype[`${p$}At`]=function(e,t,n={}){let{parent:r,parentPath:i,schema:a}=pY(this,e,t,n.context);return a[p$](r&&r[i],pU({},n,{parent:r,path:e}))};for(let pz of["equals","is"])pH.prototype[pz]=pH.prototype.oneOf;for(let pG of["not","nope"])pH.prototype[pG]=pH.prototype.notOneOf;pH.prototype.optional=pH.prototype.notRequired;let pW=pH;function pK(){return new pW}pK.prototype=pW.prototype;let pV=e=>null==e;function pq(){return new pZ}class pZ extends pH{constructor(){super({type:"boolean"}),this.withMutation(()=>{this.transform(function(e){if(!this.isType(e)){if(/^(true|1)$/i.test(String(e)))return!0;if(/^(false|0)$/i.test(String(e)))return!1}return e})})}_typeCheck(e){return e instanceof Boolean&&(e=e.valueOf()),"boolean"==typeof e}isTrue(e=pm.isValue){return this.test({message:e,name:"is-value",exclusive:!0,params:{value:"true"},test:e=>pV(e)||!0===e})}isFalse(e=pm.isValue){return this.test({message:e,name:"is-value",exclusive:!0,params:{value:"false"},test:e=>pV(e)||!1===e})}}pq.prototype=pZ.prototype;let pX=/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i,pJ=/^((https?|ftp):)?\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i,pQ=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i,p1=e=>pV(e)||e===e.trim(),p0=({}).toString();function p2(){return new p3}class p3 extends pH{constructor(){super({type:"string"}),this.withMutation(()=>{this.transform(function(e){if(this.isType(e)||Array.isArray(e))return e;let t=null!=e&&e.toString?e.toString():e;return t===p0?e:t})})}_typeCheck(e){return e instanceof String&&(e=e.valueOf()),"string"==typeof e}_isPresent(e){return super._isPresent(e)&&!!e.length}length(e,t=ph.length){return this.test({message:t,name:"length",exclusive:!0,params:{length:e},test(t){return pV(t)||t.length===this.resolve(e)}})}min(e,t=ph.min){return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t.length>=this.resolve(e)}})}max(e,t=ph.max){return this.test({name:"max",exclusive:!0,message:t,params:{max:e},test(t){return pV(t)||t.length<=this.resolve(e)}})}matches(e,t){let n=!1,r,i;return t&&("object"==typeof t?{excludeEmptyString:n=!1,message:r,name:i}=t:r=t),this.test({name:i||"matches",message:r||ph.matches,params:{regex:e},test:t=>pV(t)||""===t&&n||-1!==t.search(e)})}email(e=ph.email){return this.matches(pX,{name:"email",message:e,excludeEmptyString:!0})}url(e=ph.url){return this.matches(pJ,{name:"url",message:e,excludeEmptyString:!0})}uuid(e=ph.uuid){return this.matches(pQ,{name:"uuid",message:e,excludeEmptyString:!1})}ensure(){return this.default("").transform(e=>null===e?"":e)}trim(e=ph.trim){return this.transform(e=>null!=e?e.trim():e).test({message:e,name:"trim",test:p1})}lowercase(e=ph.lowercase){return this.transform(e=>pV(e)?e:e.toLowerCase()).test({message:e,name:"string_case",exclusive:!0,test:e=>pV(e)||e===e.toLowerCase()})}uppercase(e=ph.uppercase){return this.transform(e=>pV(e)?e:e.toUpperCase()).test({message:e,name:"string_case",exclusive:!0,test:e=>pV(e)||e===e.toUpperCase()})}}p2.prototype=p3.prototype;let p4=e=>e!=+e;function p5(){return new p6}class p6 extends pH{constructor(){super({type:"number"}),this.withMutation(()=>{this.transform(function(e){let t=e;if("string"==typeof t){if(""===(t=t.replace(/\s/g,"")))return NaN;t=+t}return this.isType(t)?t:parseFloat(t)})})}_typeCheck(e){return e instanceof Number&&(e=e.valueOf()),"number"==typeof e&&!p4(e)}min(e,t=pp.min){return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t>=this.resolve(e)}})}max(e,t=pp.max){return this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(t){return pV(t)||t<=this.resolve(e)}})}lessThan(e,t=pp.lessThan){return this.test({message:t,name:"max",exclusive:!0,params:{less:e},test(t){return pV(t)||tthis.resolve(e)}})}positive(e=pp.positive){return this.moreThan(0,e)}negative(e=pp.negative){return this.lessThan(0,e)}integer(e=pp.integer){return this.test({name:"integer",message:e,test:e=>pV(e)||Number.isInteger(e)})}truncate(){return this.transform(e=>pV(e)?e:0|e)}round(e){var t,n=["ceil","floor","round","trunc"];if("trunc"===(e=(null==(t=e)?void 0:t.toLowerCase())||"round"))return this.truncate();if(-1===n.indexOf(e.toLowerCase()))throw TypeError("Only valid options for round() are: "+n.join(", "));return this.transform(t=>pV(t)?t:Math[e](t))}}p5.prototype=p6.prototype;var p9=/^(\d{4}|[+\-]\d{6})(?:-?(\d{2})(?:-?(\d{2}))?)?(?:[ T]?(\d{2}):?(\d{2})(?::?(\d{2})(?:[,\.](\d{1,}))?)?(?:(Z)|([+\-])(\d{2})(?::?(\d{2}))?)?)?$/;function p8(e){var t,n,r=[1,4,5,6,7,10,11],i=0;if(n=p9.exec(e)){for(var a,o=0;a=r[o];++o)n[a]=+n[a]||0;n[2]=(+n[2]||1)-1,n[3]=+n[3]||1,n[7]=n[7]?String(n[7]).substr(0,3):0,(void 0===n[8]||""===n[8])&&(void 0===n[9]||""===n[9])?t=+new Date(n[1],n[2],n[3],n[4],n[5],n[6],n[7]):("Z"!==n[8]&&void 0!==n[9]&&(i=60*n[10]+n[11],"+"===n[9]&&(i=0-i)),t=Date.UTC(n[1],n[2],n[3],n[4],n[5]+i,n[6],n[7]))}else t=Date.parse?Date.parse(e):NaN;return t}let p7=new Date(""),be=e=>"[object Date]"===Object.prototype.toString.call(e);function bt(){return new bn}class bn extends pH{constructor(){super({type:"date"}),this.withMutation(()=>{this.transform(function(e){return this.isType(e)?e:(e=p8(e),isNaN(e)?p7:new Date(e))})})}_typeCheck(e){return be(e)&&!isNaN(e.getTime())}prepareParam(e,t){let n;if(pN.isRef(e))n=e;else{let r=this.cast(e);if(!this._typeCheck(r))throw TypeError(`\`${t}\` must be a Date or a value that can be \`cast()\` to a Date`);n=r}return n}min(e,t=pb.min){let n=this.prepareParam(e,"min");return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(e){return pV(e)||e>=this.resolve(n)}})}max(e,t=pb.max){var n=this.prepareParam(e,"max");return this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(e){return pV(e)||e<=this.resolve(n)}})}}bn.INVALID_DATE=p7,bt.prototype=bn.prototype,bt.INVALID_DATE=p7;var br=n(11865),bi=n.n(br),ba=n(68929),bo=n.n(ba),bs=n(67523),bu=n.n(bs),bc=n(94633),bl=n.n(bc);function bf(e,t=[]){let n=[],r=[];function i(e,i){var a=(0,pI.split)(e)[0];~r.indexOf(a)||r.push(a),~t.indexOf(`${i}-${a}`)||n.push([i,a])}for(let a in e)if(pw()(e,a)){let o=e[a];~r.indexOf(a)||r.push(a),pN.isRef(o)&&o.isSibling?i(o.path,a):p_(o)&&"deps"in o&&o.deps.forEach(e=>i(e,a))}return bl().array(r,n).reverse()}function bd(e,t){let n=1/0;return e.some((e,r)=>{var i;if((null==(i=t.path)?void 0:i.indexOf(e))!==-1)return n=r,!0}),n}function bh(e){return(t,n)=>bd(e,t)-bd(e,n)}function bp(){return(bp=Object.assign||function(e){for(var t=1;t"[object Object]"===Object.prototype.toString.call(e);function bm(e,t){let n=Object.keys(e.fields);return Object.keys(t).filter(e=>-1===n.indexOf(e))}let bg=bh([]);class bv extends pH{constructor(e){super({type:"object"}),this.fields=Object.create(null),this._sortErrors=bg,this._nodes=[],this._excludedEdges=[],this.withMutation(()=>{this.transform(function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(t){e=null}return this.isType(e)?e:null}),e&&this.shape(e)})}_typeCheck(e){return bb(e)||"function"==typeof e}_cast(e,t={}){var n;let r=super._cast(e,t);if(void 0===r)return this.getDefault();if(!this._typeCheck(r))return r;let i=this.fields,a=null!=(n=t.stripUnknown)?n:this.spec.noUnknown,o=this._nodes.concat(Object.keys(r).filter(e=>-1===this._nodes.indexOf(e))),s={},u=bp({},t,{parent:s,__validating:t.__validating||!1}),c=!1;for(let l of o){let f=i[l],d=pw()(r,l);if(f){let h,p=r[l];u.path=(t.path?`${t.path}.`:"")+l;let b="spec"in(f=f.resolve({value:p,context:t.context,parent:s}))?f.spec:void 0,m=null==b?void 0:b.strict;if(null==b?void 0:b.strip){c=c||l in r;continue}void 0!==(h=t.__validating&&m?r[l]:f.cast(r[l],u))&&(s[l]=h)}else d&&!a&&(s[l]=r[l]);s[l]!==r[l]&&(c=!0)}return c?s:r}_validate(e,t={},n){let r=[],{sync:i,from:a=[],originalValue:o=e,abortEarly:s=this.spec.abortEarly,recursive:u=this.spec.recursive}=t;a=[{schema:this,value:o},...a],t.__validating=!0,t.originalValue=o,t.from=a,super._validate(e,t,(e,c)=>{if(e){if(!pM.isError(e)||s)return void n(e,c);r.push(e)}if(!u||!bb(c)){n(r[0]||null,c);return}o=o||c;let l=this._nodes.map(e=>(n,r)=>{let i=-1===e.indexOf(".")?(t.path?`${t.path}.`:"")+e:`${t.path||""}["${e}"]`,s=this.fields[e];if(s&&"validate"in s){s.validate(c[e],bp({},t,{path:i,from:a,strict:!0,parent:c,originalValue:o[e]}),r);return}r(null)});pA({sync:i,tests:l,value:c,errors:r,endEarly:s,sort:this._sortErrors,path:t.path},n)})}clone(e){let t=super.clone(e);return t.fields=bp({},this.fields),t._nodes=this._nodes,t._excludedEdges=this._excludedEdges,t._sortErrors=this._sortErrors,t}concat(e){let t=super.concat(e),n=t.fields;for(let[r,i]of Object.entries(this.fields)){let a=n[r];void 0===a?n[r]=i:a instanceof pH&&i instanceof pH&&(n[r]=i.concat(a))}return t.withMutation(()=>t.shape(n))}getDefaultFromShape(){let e={};return this._nodes.forEach(t=>{let n=this.fields[t];e[t]="default"in n?n.getDefault():void 0}),e}_getDefault(){return"default"in this.spec?super._getDefault():this._nodes.length?this.getDefaultFromShape():void 0}shape(e,t=[]){let n=this.clone(),r=Object.assign(n.fields,e);if(n.fields=r,n._sortErrors=bh(Object.keys(r)),t.length){Array.isArray(t[0])||(t=[t]);let i=t.map(([e,t])=>`${e}-${t}`);n._excludedEdges=n._excludedEdges.concat(i)}return n._nodes=bf(r,n._excludedEdges),n}pick(e){let t={};for(let n of e)this.fields[n]&&(t[n]=this.fields[n]);return this.clone().withMutation(e=>(e.fields={},e.shape(t)))}omit(e){let t=this.clone(),n=t.fields;for(let r of(t.fields={},e))delete n[r];return t.withMutation(()=>t.shape(n))}from(e,t,n){let r=(0,pI.getter)(e,!0);return this.transform(i=>{if(null==i)return i;let a=i;return pw()(i,e)&&(a=bp({},i),n||delete a[e],a[t]=r(i)),a})}noUnknown(e=!0,t=pg.noUnknown){"string"==typeof e&&(t=e,e=!0);let n=this.test({name:"noUnknown",exclusive:!0,message:t,test(t){if(null==t)return!0;let n=bm(this.schema,t);return!e||0===n.length||this.createError({params:{unknown:n.join(", ")}})}});return n.spec.noUnknown=e,n}unknown(e=!0,t=pg.noUnknown){return this.noUnknown(!e,t)}transformKeys(e){return this.transform(t=>t&&bu()(t,(t,n)=>e(n)))}camelCase(){return this.transformKeys(bo())}snakeCase(){return this.transformKeys(bi())}constantCase(){return this.transformKeys(e=>bi()(e).toUpperCase())}describe(){let e=super.describe();return e.fields=pC()(this.fields,e=>e.describe()),e}}function by(e){return new bv(e)}function bw(){return(bw=Object.assign||function(e){for(var t=1;t{this.transform(function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(t){e=null}return this.isType(e)?e:null})})}_typeCheck(e){return Array.isArray(e)}get _subType(){return this.innerType}_cast(e,t){let n=super._cast(e,t);if(!this._typeCheck(n)||!this.innerType)return n;let r=!1,i=n.map((e,n)=>{let i=this.innerType.cast(e,bw({},t,{path:`${t.path||""}[${n}]`}));return i!==e&&(r=!0),i});return r?i:n}_validate(e,t={},n){var r,i;let a=[],o=t.sync,s=t.path,u=this.innerType,c=null!=(r=t.abortEarly)?r:this.spec.abortEarly,l=null!=(i=t.recursive)?i:this.spec.recursive,f=null!=t.originalValue?t.originalValue:e;super._validate(e,t,(e,r)=>{if(e){if(!pM.isError(e)||c)return void n(e,r);a.push(e)}if(!l||!u||!this._typeCheck(r)){n(a[0]||null,r);return}f=f||r;let i=Array(r.length);for(let d=0;du.validate(h,b,t)}pA({sync:o,path:s,value:r,errors:a,endEarly:c,tests:i},n)})}clone(e){let t=super.clone(e);return t.innerType=this.innerType,t}concat(e){let t=super.concat(e);return t.innerType=this.innerType,e.innerType&&(t.innerType=t.innerType?t.innerType.concat(e.innerType):e.innerType),t}of(e){let t=this.clone();if(!p_(e))throw TypeError("`array.of()` sub-schema must be a valid yup schema not: "+pf(e));return t.innerType=e,t}length(e,t=pv.length){return this.test({message:t,name:"length",exclusive:!0,params:{length:e},test(t){return pV(t)||t.length===this.resolve(e)}})}min(e,t){return t=t||pv.min,this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t.length>=this.resolve(e)}})}max(e,t){return t=t||pv.max,this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(t){return pV(t)||t.length<=this.resolve(e)}})}ensure(){return this.default(()=>[]).transform((e,t)=>this._typeCheck(e)?e:null==t?[]:[].concat(t))}compact(e){let t=e?(t,n,r)=>!e(t,n,r):e=>!!e;return this.transform(e=>null!=e?e.filter(t):e)}describe(){let e=super.describe();return this.innerType&&(e.innerType=this.innerType.describe()),e}nullable(e=!0){return super.nullable(e)}defined(){return super.defined()}required(e){return super.required(e)}}b_.prototype=bE.prototype;var bS=by().shape({name:p2().required("Required"),url:p2().required("Required")}),bk=function(e){var t=e.initialValues,n=e.onSubmit,r=e.submitButtonText,i=e.nameDisabled,a=void 0!==i&&i;return l.createElement(hM,{initialValues:t,validationSchema:bS,onSubmit:n},function(e){var t=e.isSubmitting;return l.createElement(l.Fragment,null,l.createElement(hj,{"data-testid":"bridge-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(hR,{component:hJ,id:"name",name:"name",label:"Name",disabled:a,required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"name-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(hR,{component:hJ,id:"url",name:"url",label:"Bridge URL",placeholder:"https://",required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"url-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:7},l.createElement(hR,{component:hJ,id:"minimumContractPayment",name:"minimumContractPayment",label:"Minimum Contract Payment",placeholder:"0",fullWidth:!0,inputProps:{min:0},FormHelperTextProps:{"data-testid":"minimumContractPayment-helper-text"}})),l.createElement(d.Z,{item:!0,xs:7},l.createElement(hR,{component:hJ,id:"confirmations",name:"confirmations",label:"Confirmations",placeholder:"0",type:"number",fullWidth:!0,inputProps:{min:0},FormHelperTextProps:{"data-testid":"confirmations-helper-text"}})))),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ox.default,{variant:"contained",color:"primary",type:"submit",disabled:t,size:"large"},r)))))})},bx=function(e){var t=e.bridge,n=e.onSubmit,r={name:t.name,url:t.url,minimumContractPayment:t.minimumContractPayment,confirmations:t.confirmations};return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:40},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Edit Bridge",action:l.createElement(aL.Z,{component:tz,href:"/bridges/".concat(t.id)},"Cancel")}),l.createElement(aK.Z,null,l.createElement(bk,{nameDisabled:!0,initialValues:r,onSubmit:n,submitButtonText:"Save Bridge"}))))))};function bT(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]&&arguments[0],t=e?function(){return l.createElement(x.default,{variant:"body1"},"Loading...")}:function(){return null};return{isLoading:e,LoadingPlaceholder:t}},ml=n(76023);function mf(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=0||(i[n]=e[n]);return i}function mB(e,t){if(null==e)return{};var n,r,i=mY(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function mU(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n=4?[e[0],e[1],e[2],e[3],"".concat(e[0],".").concat(e[1]),"".concat(e[0],".").concat(e[2]),"".concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[0]),"".concat(e[1],".").concat(e[2]),"".concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[1]),"".concat(e[2],".").concat(e[3]),"".concat(e[3],".").concat(e[0]),"".concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[0]),"".concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[1],".").concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[2],".").concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[3],".").concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[2],".").concat(e[1],".").concat(e[0])]:void 0}var mX={};function mJ(e){if(0===e.length||1===e.length)return e;var t=e.join(".");return mX[t]||(mX[t]=mZ(e)),mX[t]}function mQ(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0;return mJ(e.filter(function(e){return"token"!==e})).reduce(function(e,t){return mV({},e,n[t])},t)}function m1(e){return e.join(" ")}function m0(e,t){var n=0;return function(r){return n+=1,r.map(function(r,i){return m2({node:r,stylesheet:e,useInlineStyles:t,key:"code-segment-".concat(n,"-").concat(i)})})}}function m2(e){var t=e.node,n=e.stylesheet,r=e.style,i=void 0===r?{}:r,a=e.useInlineStyles,o=e.key,s=t.properties,u=t.type,c=t.tagName,f=t.value;if("text"===u)return f;if(c){var d,h=m0(n,a);if(a){var p=Object.keys(n).reduce(function(e,t){return t.split(".").forEach(function(t){e.includes(t)||e.push(t)}),e},[]),b=s.className&&s.className.includes("token")?["token"]:[],m=s.className&&b.concat(s.className.filter(function(e){return!p.includes(e)}));d=mV({},s,{className:m1(m)||void 0,style:mQ(s.className,Object.assign({},s.style,i),n)})}else d=mV({},s,{className:m1(s.className)});var g=h(t.children);return l.createElement(c,mq({key:o},d),g)}}let m3=function(e,t){return -1!==e.listLanguages().indexOf(t)};var m4=/\n/g;function m5(e){return e.match(m4)}function m6(e){var t=e.lines,n=e.startingLineNumber,r=e.style;return t.map(function(e,t){var i=t+n;return l.createElement("span",{key:"line-".concat(t),className:"react-syntax-highlighter-line-number",style:"function"==typeof r?r(i):r},"".concat(i,"\n"))})}function m9(e){var t=e.codeString,n=e.codeStyle,r=e.containerStyle,i=void 0===r?{float:"left",paddingRight:"10px"}:r,a=e.numberStyle,o=void 0===a?{}:a,s=e.startingLineNumber;return l.createElement("code",{style:Object.assign({},n,i)},m6({lines:t.replace(/\n$/,"").split("\n"),style:o,startingLineNumber:s}))}function m8(e){return"".concat(e.toString().length,".25em")}function m7(e,t){return{type:"element",tagName:"span",properties:{key:"line-number--".concat(e),className:["comment","linenumber","react-syntax-highlighter-line-number"],style:t},children:[{type:"text",value:e}]}}function ge(e,t,n){var r,i={display:"inline-block",minWidth:m8(n),paddingRight:"1em",textAlign:"right",userSelect:"none"};return mV({},i,"function"==typeof e?e(t):e)}function gt(e){var t=e.children,n=e.lineNumber,r=e.lineNumberStyle,i=e.largestLineNumber,a=e.showInlineLineNumbers,o=e.lineProps,s=void 0===o?{}:o,u=e.className,c=void 0===u?[]:u,l=e.showLineNumbers,f=e.wrapLongLines,d="function"==typeof s?s(n):s;if(d.className=c,n&&a){var h=ge(r,n,i);t.unshift(m7(n,h))}return f&l&&(d.style=mV({},d.style,{display:"flex"})),{type:"element",tagName:"span",properties:d,children:t}}function gn(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],r=0;r2&&void 0!==arguments[2]?arguments[2]:[];return gt({children:e,lineNumber:t,lineNumberStyle:s,largestLineNumber:o,showInlineLineNumbers:i,lineProps:n,className:a,showLineNumbers:r,wrapLongLines:u})}function b(e,t){if(r&&t&&i){var n=ge(s,t,o);e.unshift(m7(t,n))}return e}function m(e,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];return t||r.length>0?p(e,n,r):b(e,n)}for(var g=function(){var e=l[h],t=e.children[0].value;if(m5(t)){var n=t.split("\n");n.forEach(function(t,i){var o=r&&f.length+a,s={type:"text",value:"".concat(t,"\n")};if(0===i){var u=l.slice(d+1,h).concat(gt({children:[s],className:e.properties.className})),c=m(u,o);f.push(c)}else if(i===n.length-1){if(l[h+1]&&l[h+1].children&&l[h+1].children[0]){var p={type:"text",value:"".concat(t)},b=gt({children:[p],className:e.properties.className});l.splice(h+1,0,b)}else{var g=[s],v=m(g,o,e.properties.className);f.push(v)}}else{var y=[s],w=m(y,o,e.properties.className);f.push(w)}}),d=h}h++};h code[class*="language-"]':{background:"#f5f2f0",padding:".1em",borderRadius:".3em",whiteSpace:"normal"},comment:{color:"slategray"},prolog:{color:"slategray"},doctype:{color:"slategray"},cdata:{color:"slategray"},punctuation:{color:"#999"},namespace:{Opacity:".7"},property:{color:"#905"},tag:{color:"#905"},boolean:{color:"#905"},number:{color:"#905"},constant:{color:"#905"},symbol:{color:"#905"},deleted:{color:"#905"},selector:{color:"#690"},"attr-name":{color:"#690"},string:{color:"#690"},char:{color:"#690"},builtin:{color:"#690"},inserted:{color:"#690"},operator:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},entity:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)",cursor:"help"},url:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".language-css .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".style .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},atrule:{color:"#07a"},"attr-value":{color:"#07a"},keyword:{color:"#07a"},function:{color:"#DD4A68"},"class-name":{color:"#DD4A68"},regex:{color:"#e90"},important:{color:"#e90",fontWeight:"bold"},variable:{color:"#e90"},bold:{fontWeight:"bold"},italic:{fontStyle:"italic"}};var gc=n(98695),gl=n.n(gc);let gf=["abap","abnf","actionscript","ada","agda","al","antlr4","apacheconf","apl","applescript","aql","arduino","arff","asciidoc","asm6502","aspnet","autohotkey","autoit","bash","basic","batch","bbcode","birb","bison","bnf","brainfuck","brightscript","bro","bsl","c","cil","clike","clojure","cmake","coffeescript","concurnas","cpp","crystal","csharp","csp","css-extras","css","cypher","d","dart","dax","dhall","diff","django","dns-zone-file","docker","ebnf","editorconfig","eiffel","ejs","elixir","elm","erb","erlang","etlua","excel-formula","factor","firestore-security-rules","flow","fortran","fsharp","ftl","gcode","gdscript","gedcom","gherkin","git","glsl","gml","go","graphql","groovy","haml","handlebars","haskell","haxe","hcl","hlsl","hpkp","hsts","http","ichigojam","icon","iecst","ignore","inform7","ini","io","j","java","javadoc","javadoclike","javascript","javastacktrace","jolie","jq","js-extras","js-templates","jsdoc","json","json5","jsonp","jsstacktrace","jsx","julia","keyman","kotlin","latex","latte","less","lilypond","liquid","lisp","livescript","llvm","lolcode","lua","makefile","markdown","markup-templating","markup","matlab","mel","mizar","mongodb","monkey","moonscript","n1ql","n4js","nand2tetris-hdl","naniscript","nasm","neon","nginx","nim","nix","nsis","objectivec","ocaml","opencl","oz","parigp","parser","pascal","pascaligo","pcaxis","peoplecode","perl","php-extras","php","phpdoc","plsql","powerquery","powershell","processing","prolog","properties","protobuf","pug","puppet","pure","purebasic","purescript","python","q","qml","qore","r","racket","reason","regex","renpy","rest","rip","roboconf","robotframework","ruby","rust","sas","sass","scala","scheme","scss","shell-session","smali","smalltalk","smarty","sml","solidity","solution-file","soy","sparql","splunk-spl","sqf","sql","stan","stylus","swift","t4-cs","t4-templating","t4-vb","tap","tcl","textile","toml","tsx","tt2","turtle","twig","typescript","typoscript","unrealscript","vala","vbnet","velocity","verilog","vhdl","vim","visual-basic","warpscript","wasm","wiki","xeora","xml-doc","xojo","xquery","yaml","yang","zig"];var gd=gs(gl(),gu);gd.supportedLanguages=gf;let gh=gd;var gp=n(64566);function gb(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function gm(){var e=gb(["\n query FetchConfigV2 {\n configv2 {\n user\n effective\n }\n }\n"]);return gm=function(){return e},e}var gg=n0(gm()),gv=function(e){var t=e.children;return l.createElement(ii.Z,null,l.createElement(ie.default,{component:"th",scope:"row",colSpan:3},t))},gy=function(){return l.createElement(gv,null,"...")},gw=function(e){var t=e.children;return l.createElement(gv,null,t)},g_=function(e){var t=e.loading,n=e.toml,r=e.error,i=void 0===r?"":r,a=e.title,o=e.expanded;if(i)return l.createElement(gw,null,i);if(t)return l.createElement(gy,null);a||(a="TOML");var s={display:"block"};return l.createElement(x.default,null,l.createElement(mR.Z,{defaultExpanded:o},l.createElement(mj.Z,{expandIcon:l.createElement(gp.Z,null)},a),l.createElement(mF.Z,{style:s},l.createElement(gh,{language:"toml",style:gu},n))))},gE=function(){var e=ry(gg,{fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return(null==t?void 0:t.configv2.effective)=="N/A"?l.createElement(l.Fragment,null,l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"TOML Configuration"}),l.createElement(g_,{title:"V2 config dump:",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.user,showHead:!0})))):l.createElement(l.Fragment,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"TOML Configuration"}),l.createElement(g_,{title:"User specified:",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.user,showHead:!0,expanded:!0}),l.createElement(g_,{title:"Effective (with defaults):",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.effective,showHead:!0})))))},gS=n(34823),gk=function(e){return(0,b.createStyles)({cell:{paddingTop:1.5*e.spacing.unit,paddingBottom:1.5*e.spacing.unit}})},gx=(0,b.withStyles)(gk)(function(e){var t=e.classes,n=(0,A.I0)();(0,l.useEffect)(function(){n((0,ty.DQ)())});var r=(0,A.v9)(gS.N,A.wU);return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Node"}),l.createElement(r8.Z,null,l.createElement(r7.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,{className:t.cell},l.createElement(x.default,null,"Version"),l.createElement(x.default,{variant:"subtitle1",color:"textSecondary"},r.version))),l.createElement(ii.Z,null,l.createElement(ie.default,{className:t.cell},l.createElement(x.default,null,"SHA"),l.createElement(x.default,{variant:"subtitle1",color:"textSecondary"},r.commitSHA))))))}),gT=function(){return l.createElement(iv,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,sm:12,md:8},l.createElement(d.Z,{container:!0},l.createElement(gE,null))),l.createElement(d.Z,{item:!0,sm:12,md:4},l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gx,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(mP,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(mS,null))))))},gM=function(){return l.createElement(gT,null)},gO=function(){return l.createElement(gM,null)},gA=n(44431),gL=1e18,gC=function(e){return new gA.BigNumber(e).dividedBy(gL).toFixed(8)},gI=function(e){var t=e.keys,n=e.chainID,r=e.hideHeaderTitle;return l.createElement(l.Fragment,null,l.createElement(sf.Z,{title:!r&&"Account Balances",subheader:"Chain ID "+n}),l.createElement(aK.Z,null,l.createElement(w.default,{dense:!1,disablePadding:!0},t&&t.map(function(e,r){return l.createElement(l.Fragment,null,l.createElement(_.default,{disableGutters:!0,key:["acc-balance",n.toString(),r.toString()].join("-")},l.createElement(E.Z,{primary:l.createElement(l.Fragment,null,l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ob,{title:"Address"}),l.createElement(om,{value:e.address})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(ob,{title:"Native Token Balance"}),l.createElement(om,{value:e.ethBalance||"--"})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(ob,{title:"LINK Balance"}),l.createElement(om,{value:e.linkBalance?gC(e.linkBalance):"--"}))))})),r+1s&&l.createElement(gU.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,{className:r.footer},l.createElement(aL.Z,{href:"/runs",component:tz},"View More"))))))});function vn(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vr(){var e=vn(["\n ","\n query FetchRecentJobRuns($offset: Int, $limit: Int) {\n jobRuns(offset: $offset, limit: $limit) {\n results {\n ...RecentJobRunsPayload_ResultsFields\n }\n metadata {\n total\n }\n }\n }\n"]);return vr=function(){return e},e}var vi=5,va=n0(vr(),g7),vo=function(){var e=ry(va,{variables:{offset:0,limit:vi},fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return l.createElement(vt,{data:t,errorMsg:null==r?void 0:r.message,loading:n,maxRunsSize:vi})},vs=function(e){return(0,b.createStyles)({style:{textAlign:"center",padding:2.5*e.spacing.unit,position:"fixed",left:"0",bottom:"0",width:"100%",borderRadius:0},bareAnchor:{color:e.palette.common.black,textDecoration:"none"}})},vu=(0,b.withStyles)(vs)(function(e){var t=e.classes,n=(0,A.v9)(gS.N,A.wU),r=(0,A.I0)();return(0,l.useEffect)(function(){r((0,ty.DQ)())}),l.createElement(ia.default,{className:t.style},l.createElement(x.default,null,"Chainlink Node ",n.version," at commit"," ",l.createElement("a",{target:"_blank",rel:"noopener noreferrer",href:"https://github.com/smartcontractkit/chainlink/commit/".concat(n.commitSHA),className:t.bareAnchor},n.commitSHA)))}),vc=function(e){return(0,b.createStyles)({cell:{borderColor:e.palette.divider,borderTop:"1px solid",borderBottom:"none",paddingTop:2*e.spacing.unit,paddingBottom:2*e.spacing.unit,paddingLeft:2*e.spacing.unit},block:{display:"block"},overflowEllipsis:{textOverflow:"ellipsis",overflow:"hidden"}})},vl=(0,b.withStyles)(vc)(function(e){var t=e.classes,n=e.job;return l.createElement(ii.Z,null,l.createElement(ie.default,{scope:"row",className:t.cell},l.createElement(d.Z,{container:!0,spacing:0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ip,{href:"/jobs/".concat(n.id),classes:{linkContent:t.block}},l.createElement(x.default,{className:t.overflowEllipsis,variant:"body1",component:"span",color:"primary"},n.name||n.id))),l.createElement(d.Z,{item:!0,xs:12},l.createElement(x.default,{variant:"body1",color:"textSecondary"},"Created ",l.createElement(aA,{tooltip:!0},n.createdAt))))))});function vf(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vd(){var e=vf(["\n fragment RecentJobsPayload_ResultsFields on Job {\n id\n name\n createdAt\n }\n"]);return vd=function(){return e},e}var vh=n0(vd()),vp=function(){return(0,b.createStyles)({cardHeader:{borderBottom:0},table:{tableLayout:"fixed"}})},vb=(0,b.withStyles)(vp)(function(e){var t,n,r=e.classes,i=e.data,a=e.errorMsg,o=e.loading;return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Recent Jobs",className:r.cardHeader}),l.createElement(r8.Z,{className:r.table},l.createElement(r7.Z,null,l.createElement(gz,{visible:o}),l.createElement(gG,{visible:(null===(t=null==i?void 0:i.jobs.results)||void 0===t?void 0:t.length)===0},"No recently created jobs"),l.createElement(gH,{msg:a}),null===(n=null==i?void 0:i.jobs.results)||void 0===n?void 0:n.map(function(e,t){return l.createElement(vl,{job:e,key:t})}))))});function vm(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vg(){var e=vm(["\n ","\n query FetchRecentJobs($offset: Int, $limit: Int) {\n jobs(offset: $offset, limit: $limit) {\n results {\n ...RecentJobsPayload_ResultsFields\n }\n }\n }\n"]);return vg=function(){return e},e}var vv=5,vy=n0(vg(),vh),vw=function(){var e=ry(vy,{variables:{offset:0,limit:vv},fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return l.createElement(vb,{data:t,errorMsg:null==r?void 0:r.message,loading:n})},v_=function(){return l.createElement(iv,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:8},l.createElement(vo,null)),l.createElement(d.Z,{item:!0,xs:4},l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gB,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(vw,null))))),l.createElement(vu,null))},vE=function(){return l.createElement(v_,null)},vS=function(){return l.createElement(vE,null)},vk=n(87239),vx=function(e){switch(e){case"DirectRequestSpec":return"Direct Request";case"FluxMonitorSpec":return"Flux Monitor";default:return e.replace(/Spec$/,"")}},vT=n(5022),vM=n(78718),vO=n.n(vM);function vA(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1?t-1:0),r=1;r1?t-1:0),r=1;re.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&n.map(function(e){return l.createElement(ii.Z,{key:e.id,style:{cursor:"pointer"},onClick:function(){return r.push("/runs/".concat(e.id))}},l.createElement(ie.default,{className:t.idCell,scope:"row"},l.createElement("div",{className:t.runDetails},l.createElement(x.default,{variant:"h5",color:"primary",component:"span"},e.id))),l.createElement(ie.default,{className:t.stampCell},l.createElement(x.default,{variant:"body1",color:"textSecondary",className:t.stamp},"Created ",l.createElement(aA,{tooltip:!0},e.createdAt))),l.createElement(ie.default,{className:t.statusCell,scope:"row"},l.createElement(x.default,{variant:"body1",className:O()(t.status,yp(t,e.status))},e.status.toLowerCase())))})))}),ym=n(16839),yg=n.n(ym);function yv(e){var t=e.replace(/\w+\s*=\s*<([^>]|[\r\n])*>/g,""),n=yg().read(t),r=n.edges();return n.nodes().map(function(e){var t={id:e,parentIds:r.filter(function(t){return t.w===e}).map(function(e){return e.v})};return Object.keys(n.node(e)).length>0&&(t.attributes=n.node(e)),t})}var yy=n(94164),yw=function(e){var t=e.data,n=[];return(null==t?void 0:t.attributes)&&Object.keys(t.attributes).forEach(function(e){var r;n.push(l.createElement("div",{key:e},l.createElement(x.default,{variant:"body1",color:"textSecondary",component:"div"},l.createElement("b",null,e,":")," ",null===(r=t.attributes)||void 0===r?void 0:r[e])))}),l.createElement("div",null,t&&l.createElement(x.default,{variant:"body1",color:"textPrimary"},l.createElement("b",null,t.id)),n)},y_=n(73343),yE=n(3379),yS=n.n(yE);function yk(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);nwindow.innerWidth?u-r.getBoundingClientRect().width-a:u+a,n=c+r.getBoundingClientRect().height+i>window.innerHeight?c-r.getBoundingClientRect().height-a:c+a,r.style.opacity=String(1),r.style.top="".concat(n,"px"),r.style.left="".concat(t,"px"),r.style.zIndex=String(1)}},h=function(e){var t=document.getElementById("tooltip-d3-chart-".concat(e));t&&(t.style.opacity=String(0),t.style.zIndex=String(-1))};return l.createElement("div",{style:{fontFamily:"sans-serif",fontWeight:"normal"}},l.createElement(yy.kJ,{id:"task-list-graph-d3",data:i,config:s,onMouseOverNode:d,onMouseOutNode:h},"D3 chart"),n.map(function(e){return l.createElement("div",{key:"d3-tooltip-key-".concat(e.id),id:"tooltip-d3-chart-".concat(e.id),style:{position:"absolute",opacity:"0",border:"1px solid rgba(0, 0, 0, 0.1)",padding:y_.r.spacing.unit,background:"white",borderRadius:5,zIndex:-1,inlineSize:"min-content"}},l.createElement(yw,{data:e}))}))};function yC(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);nyB&&l.createElement("div",{className:t.runDetails},l.createElement(aL.Z,{href:"/jobs/".concat(n.id,"/runs"),component:tz},"View more")))),l.createElement(d.Z,{item:!0,xs:12,sm:6},l.createElement(yY,{observationSource:n.observationSource})))});function y$(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]?arguments[0]:"";try{return vT.parse(e),!0}catch(t){return!1}})}),wK=function(e){var t=e.initialValues,n=e.onSubmit,r=e.onTOMLChange;return l.createElement(hM,{initialValues:t,validationSchema:wW,onSubmit:n},function(e){var t=e.isSubmitting,n=e.values;return r&&r(n.toml),l.createElement(hj,{"data-testid":"job-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12},l.createElement(hR,{component:hJ,id:"toml",name:"toml",label:"Job Spec (TOML)",required:!0,fullWidth:!0,multiline:!0,rows:10,rowsMax:25,variant:"outlined",autoComplete:"off",FormHelperTextProps:{"data-testid":"toml-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ox.default,{variant:"contained",color:"primary",type:"submit",disabled:t,size:"large"},"Create Job"))))})},wV=n(50109),wq="persistSpec";function wZ(e){var t=e.query,n=new URLSearchParams(t).get("definition");return n?(wV.t8(wq,n),{toml:n}):{toml:wV.U2(wq)||""}}var wX=function(e){var t=e.onSubmit,n=e.onTOMLChange,r=wZ({query:(0,h.TH)().search}),i=function(e){var t=e.replace(/[\u200B-\u200D\uFEFF]/g,"");wV.t8("".concat(wq),t),n&&n(t)};return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"New Job"}),l.createElement(aK.Z,null,l.createElement(wK,{initialValues:r,onSubmit:t,onTOMLChange:i})))};function wJ(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n1&&void 0!==arguments[1]?arguments[1]:{},n=t.start,r=void 0===n?6:n,i=t.end,a=void 0===i?4:i;return e.substring(0,r)+"..."+e.substring(e.length-a)}function _O(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(_K,e)},_q=function(){var e=_V({fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error,i=e.refetch;return l.createElement(_H,{loading:n,data:t,errorMsg:null==r?void 0:r.message,refetch:i})},_Z=function(e){var t=e.csaKey;return l.createElement(ii.Z,{hover:!0},l.createElement(ie.default,null,l.createElement(x.default,{variant:"body1"},t.publicKey," ",l.createElement(_T,{data:t.publicKey}))))};function _X(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function _J(){var e=_X(["\n fragment CSAKeysPayload_ResultsFields on CSAKey {\n id\n publicKey\n }\n"]);return _J=function(){return e},e}var _Q=n0(_J()),_1=function(e){var t,n,r,i=e.data,a=e.errorMsg,o=e.loading,s=e.onCreate;return l.createElement(r9.Z,null,l.createElement(sf.Z,{action:(null===(t=null==i?void 0:i.csaKeys.results)||void 0===t?void 0:t.length)===0&&l.createElement(ox.default,{variant:"outlined",color:"primary",onClick:s},"New CSA Key"),title:"CSA Key",subheader:"Manage your CSA Key"}),l.createElement(r8.Z,null,l.createElement(it.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,null,"Public Key"))),l.createElement(r7.Z,null,l.createElement(gz,{visible:o}),l.createElement(gG,{visible:(null===(n=null==i?void 0:i.csaKeys.results)||void 0===n?void 0:n.length)===0}),l.createElement(gH,{msg:a}),null===(r=null==i?void 0:i.csaKeys.results)||void 0===r?void 0:r.map(function(e,t){return l.createElement(_Z,{csaKey:e,key:t})}))))};function _0(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(EO,e)};function EL(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(EQ,e)},E4=function(){return os(E1)},E5=function(){return os(E0)},E6=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return ry(E2,e)};function E9(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(SV,e)};function SZ(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function kq(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}var kZ=function(e){var t=e.run,n=l.useMemo(function(){var e=t.inputs,n=t.outputs,r=t.taskRuns,i=kV(t,["inputs","outputs","taskRuns"]),a={};try{a=JSON.parse(e)}catch(o){a={}}return kK(kG({},i),{inputs:a,outputs:n,taskRuns:r})},[t]);return l.createElement(r9.Z,null,l.createElement(aK.Z,null,l.createElement(k$,{object:n})))};function kX(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function kJ(e){for(var t=1;t0&&l.createElement(ki,{errors:t.allErrors})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(h.rs,null,l.createElement(h.AW,{path:"".concat(n,"/json")},l.createElement(kZ,{run:t})),l.createElement(h.AW,{path:n},t.taskRuns.length>0&&l.createElement(kP,{taskRuns:t.taskRuns,observationSource:t.job.observationSource}))))))))};function k9(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function k8(){var e=k9(["\n ","\n query FetchJobRun($id: ID!) {\n jobRun(id: $id) {\n __typename\n ... on JobRun {\n ...JobRunPayload_Fields\n }\n ... on NotFoundError {\n message\n }\n }\n }\n"]);return k8=function(){return e},e}var k7=n0(k8(),k5),xe=function(){var e=ry(k7,{variables:{id:(0,h.UO)().id}}),t=e.data,n=e.loading,r=e.error;if(n)return l.createElement(ij,null);if(r)return l.createElement(iN,{error:r});var i=null==t?void 0:t.jobRun;switch(null==i?void 0:i.__typename){case"JobRun":return l.createElement(k6,{run:i});case"NotFoundError":return l.createElement(oo,null);default:return null}};function xt(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xn(){var e=xt(["\n fragment JobRunsPayload_ResultsFields on JobRun {\n id\n allErrors\n createdAt\n finishedAt\n status\n job {\n id\n }\n }\n"]);return xn=function(){return e},e}var xr=n0(xn()),xi=function(e){var t=e.loading,n=e.data,r=e.page,i=e.pageSize,a=(0,h.k6)(),o=l.useMemo(function(){return null==n?void 0:n.jobRuns.results.map(function(e){var t,n=e.allErrors,r=e.id,i=e.createdAt;return{id:r,createdAt:i,errors:n,finishedAt:e.finishedAt,status:e.status}})},[n]);return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:12},l.createElement(iw,null,"Job Runs")),t&&l.createElement(ij,null),n&&o&&l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(yb,{runs:o}),l.createElement(ir.Z,{component:"div",count:n.jobRuns.metadata.total,rowsPerPage:i,rowsPerPageOptions:[i],page:r-1,onChangePage:function(e,t){a.push("/runs?page=".concat(t+1,"&per=").concat(i))},onChangeRowsPerPage:function(){},backIconButtonProps:{"aria-label":"prev-page"},nextIconButtonProps:{"aria-label":"next-page"}})))))};function xa(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xo(){var e=xa(["\n ","\n query FetchJobRuns($offset: Int, $limit: Int) {\n jobRuns(offset: $offset, limit: $limit) {\n results {\n ...JobRunsPayload_ResultsFields\n }\n metadata {\n total\n }\n }\n }\n"]);return xo=function(){return e},e}var xs=n0(xo(),xr),xu=function(){var e=iF(),t=parseInt(e.get("page")||"1",10),n=parseInt(e.get("per")||"25",10),r=ry(xs,{variables:{offset:(t-1)*n,limit:n},fetchPolicy:"cache-and-network"}),i=r.data,a=r.loading,o=r.error;return o?l.createElement(iN,{error:o}):l.createElement(xi,{loading:a,data:i,page:t,pageSize:n})},xc=function(){var e=(0,h.$B)().path;return l.createElement(h.rs,null,l.createElement(h.AW,{exact:!0,path:e},l.createElement(xu,null)),l.createElement(h.AW,{path:"".concat(e,"/:id")},l.createElement(xe,null)))},xl=by().shape({name:p2().required("Required"),uri:p2().required("Required"),publicKey:p2().required("Required")}),xf=function(e){var t=e.initialValues,n=e.onSubmit;return l.createElement(hM,{initialValues:t,validationSchema:xl,onSubmit:n},function(e){var t=e.isSubmitting,n=e.submitForm;return l.createElement(hj,{"data-testid":"feeds-manager-form"},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"name",name:"name",label:"Name",required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"name-helper-text"}})),l.createElement(d.Z,{item:!0,xs:!1,md:6}),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"uri",name:"uri",label:"URI",required:!0,fullWidth:!0,helperText:"Provided by the Feeds Manager operator",FormHelperTextProps:{"data-testid":"uri-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"publicKey",name:"publicKey",label:"Public Key",required:!0,fullWidth:!0,helperText:"Provided by the Feeds Manager operator",FormHelperTextProps:{"data-testid":"publicKey-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(ox.default,{variant:"contained",color:"primary",disabled:t,onClick:n},"Submit"))))})},xd=function(e){var t=e.data,n=e.onSubmit,r={name:t.name,uri:t.uri,publicKey:t.publicKey};return l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Edit Feeds Manager"}),l.createElement(aK.Z,null,l.createElement(xf,{initialValues:r,onSubmit:n})))))};function xh(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xp(){var e=xh(["\n query FetchFeedsManagers {\n feedsManagers {\n results {\n __typename\n id\n name\n uri\n publicKey\n isConnectionActive\n createdAt\n }\n }\n }\n"]);return xp=function(){return e},e}var xb=n0(xp()),xm=function(){return ry(xb)};function xg(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(xZ,e)};function xJ(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0?n.feedsManagers.results[0]:void 0;return n&&a?l.createElement(TH,{manager:a}):l.createElement(h.l_,{to:{pathname:"/feeds_manager/new",state:{from:e}}})},Tz={name:"Chainlink Feeds Manager",uri:"",publicKey:""},TG=function(e){var t=e.onSubmit;return l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Register Feeds Manager"}),l.createElement(aK.Z,null,l.createElement(xf,{initialValues:Tz,onSubmit:t})))))};function TW(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);nt.version?e:t})},[o]),g=l.useMemo(function(){return Mp(o).sort(function(e,t){return t.version-e.version})},[o]),v=function(e,t,n){switch(e){case"PENDING":return l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"text",color:"secondary",onClick:function(){return b("reject",t)}},"Reject"),m.id===t&&"DELETED"!==n.status&&"REVOKED"!==n.status&&l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("approve",t)}},"Approve"),m.id===t&&"DELETED"===n.status&&n.pendingUpdate&&l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("cancel",t)}},"Cancel"),l.createElement(x.default,{color:"error"},"This proposal was deleted. Cancel the spec to delete any running jobs")));case"APPROVED":return l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"contained",onClick:function(){return b("cancel",t)}},"Cancel"),"DELETED"===n.status&&n.pendingUpdate&&l.createElement(x.default,{color:"error"},"This proposal was deleted. Cancel the spec to delete any running jobs"));case"CANCELLED":if(m.id===t&&"DELETED"!==n.status&&"REVOKED"!==n.status)return l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("approve",t)}},"Approve");return null;default:return null}};return l.createElement("div",null,g.map(function(e,n){return l.createElement(mR.Z,{defaultExpanded:0===n,key:n},l.createElement(mj.Z,{expandIcon:l.createElement(gp.Z,null)},l.createElement(x.default,{className:t.versionText},"Version ",e.version),l.createElement(Eu.Z,{label:e.status,color:"APPROVED"===e.status?"primary":"default",variant:"REJECTED"===e.status||"CANCELLED"===e.status?"outlined":"default"}),l.createElement("div",{className:t.proposedAtContainer},l.createElement(x.default,null,"Proposed ",l.createElement(aA,{tooltip:!0},e.createdAt)))),l.createElement(mF.Z,{className:t.expansionPanelDetails},l.createElement("div",{className:t.actions},l.createElement("div",{className:t.editContainer},0===n&&("PENDING"===e.status||"CANCELLED"===e.status)&&"DELETED"!==s.status&&"REVOKED"!==s.status&&l.createElement(ox.default,{variant:"contained",onClick:function(){return p(!0)}},"Edit")),l.createElement("div",{className:t.actionsContainer},v(e.status,e.id,s))),l.createElement(gh,{language:"toml",style:gu,"data-testid":"codeblock"},e.definition)))}),l.createElement(oI,{open:null!=c,title:c?My[c.action].title:"",body:c?My[c.action].body:"",onConfirm:function(){if(c){switch(c.action){case"approve":n(c.id);break;case"cancel":r(c.id);break;case"reject":i(c.id)}f(null)}},cancelButtonText:"Cancel",onCancel:function(){return f(null)}}),l.createElement(Mi,{open:h,onClose:function(){return p(!1)},initialValues:{definition:m.definition,id:m.id},onSubmit:a}))});function M_(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function ME(){var e=M_(["\n ","\n fragment JobProposalPayloadFields on JobProposal {\n id\n externalJobID\n remoteUUID\n jobID\n specs {\n ...JobProposal_SpecsFields\n }\n status\n pendingUpdate\n }\n"]);return ME=function(){return e},e}var MS=n0(ME(),Mg),Mk=function(e){var t=e.onApprove,n=e.onCancel,r=e.onReject,i=e.onUpdateSpec,a=e.proposal;return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:9},l.createElement(iw,null,"Job Proposal #",a.id))),l.createElement(T8,{proposal:a}),l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:9},l.createElement(TU,null,"Specs"))),l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:12},l.createElement(Mw,{proposal:a,specs:a.specs,onReject:r,onApprove:t,onCancel:n,onUpdateSpec:i}))))};function Mx(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);nU,tA:()=>$,KL:()=>H,Iw:()=>V,DQ:()=>W,cB:()=>T,LO:()=>M,t5:()=>k,qt:()=>x,Jc:()=>C,L7:()=>Y,EO:()=>B});var r,i,a=n(66289),o=n(41800),s=n.n(o),u=n(67932);(i=r||(r={})).IN_PROGRESS="in_progress",i.PENDING_INCOMING_CONFIRMATIONS="pending_incoming_confirmations",i.PENDING_CONNECTION="pending_connection",i.PENDING_BRIDGE="pending_bridge",i.PENDING_SLEEP="pending_sleep",i.ERRORED="errored",i.COMPLETED="completed";var c=n(87013),l=n(19084),f=n(34823);function d(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]j,v2:()=>F});var r=n(66289);function i(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var a="/sessions",o="/sessions",s=function e(t){var n=this;i(this,e),this.api=t,this.createSession=function(e){return n.create(e)},this.destroySession=function(){return n.destroy()},this.create=this.api.createResource(a),this.destroy=this.api.deleteResource(o)};function u(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var c="/v2/bulk_delete_runs",l=function e(t){var n=this;u(this,e),this.api=t,this.bulkDeleteJobRuns=function(e){return n.destroy(e)},this.destroy=this.api.deleteResource(c)};function f(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var d="/v2/chains/evm",h="".concat(d,"/:id"),p=function e(t){var n=this;f(this,e),this.api=t,this.getChains=function(){return n.index()},this.createChain=function(e){return n.create(e)},this.destroyChain=function(e){return n.destroy(void 0,{id:e})},this.updateChain=function(e,t){return n.update(t,{id:e})},this.index=this.api.fetchResource(d),this.create=this.api.createResource(d),this.destroy=this.api.deleteResource(h),this.update=this.api.updateResource(h)};function b(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var m="/v2/keys/evm/chain",g=function e(t){var n=this;b(this,e),this.api=t,this.chain=function(e){var t=new URLSearchParams;t.append("address",e.address),t.append("evmChainID",e.evmChainID),null!==e.nextNonce&&t.append("nextNonce",e.nextNonce),null!==e.abandon&&t.append("abandon",String(e.abandon)),null!==e.enabled&&t.append("enabled",String(e.enabled));var r=m+"?"+t.toString();return n.api.createResource(r)()}};function v(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var y="/v2/jobs",w="".concat(y,"/:specId/runs"),_=function e(t){var n=this;v(this,e),this.api=t,this.createJobRunV2=function(e,t){return n.post(t,{specId:e})},this.post=this.api.createResource(w,!0)};function E(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var S="/v2/log",k=function e(t){var n=this;E(this,e),this.api=t,this.getLogConfig=function(){return n.show()},this.updateLogConfig=function(e){return n.update(e)},this.show=this.api.fetchResource(S),this.update=this.api.updateResource(S)};function x(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var T="/v2/nodes",M=function e(t){var n=this;x(this,e),this.api=t,this.getNodes=function(){return n.index()},this.createNode=function(e){return n.create(e)},this.index=this.api.fetchResource(T),this.create=this.api.createResource(T)};function O(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var A="/v2/enroll_webauthn",L=function e(t){var n=this;O(this,e),this.api=t,this.beginKeyRegistration=function(e){return n.create(e)},this.finishKeyRegistration=function(e){return n.put(e)},this.create=this.api.fetchResource(A),this.put=this.api.createResource(A)};function C(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var I="/v2/build_info",D=function e(t){var n=this;C(this,e),this.api=t,this.show=function(){return n.api.GET(I)()}};function N(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var P=function e(t){N(this,e),this.api=t,this.buildInfo=new D(this.api),this.bulkDeleteRuns=new l(this.api),this.chains=new p(this.api),this.logConfig=new k(this.api),this.nodes=new M(this.api),this.jobs=new _(this.api),this.webauthn=new L(this.api),this.evmKeys=new g(this.api)},R=new r.V0({base:void 0}),j=new s(R),F=new P(R)},1398(e,t,n){"use strict";n.d(t,{Z:()=>d});var r=n(67294),i=n(32316),a=n(83638),o=n(94184),s=n.n(o);function u(){return(u=Object.assign||function(e){for(var t=1;tc});var r=n(67294),i=n(32316);function a(){return(a=Object.assign||function(e){for(var t=1;tx,jK:()=>v});var r=n(67294),i=n(55977),a=n(45697),o=n.n(a),s=n(82204),u=n(71426),c=n(94184),l=n.n(c),f=n(32316),d=function(e){var t=e.palette.success||{},n=e.palette.warning||{};return{base:{paddingLeft:5*e.spacing.unit,paddingRight:5*e.spacing.unit},success:{backgroundColor:t.main,color:t.contrastText},error:{backgroundColor:e.palette.error.dark,color:e.palette.error.contrastText},warning:{backgroundColor:n.contrastText,color:n.main}}},h=function(e){var t,n=e.success,r=e.error,i=e.warning,a=e.classes,o=e.className;return n?t=a.success:r?t=a.error:i&&(t=a.warning),l()(a.base,o,t)},p=function(e){return r.createElement(s.Z,{className:h(e),square:!0},r.createElement(u.default,{variant:"body2",color:"inherit",component:"div"},e.children))};p.defaultProps={success:!1,error:!1,warning:!1},p.propTypes={success:o().bool,error:o().bool,warning:o().bool};let b=(0,f.withStyles)(d)(p);var m=function(){return r.createElement(r.Fragment,null,"Unhandled error. Please help us by opening a"," ",r.createElement("a",{href:"https://github.com/smartcontractkit/chainlink/issues/new"},"bug report"))};let g=m;function v(e){return"string"==typeof e?e:e.component?e.component(e.props):r.createElement(g,null)}function y(e,t){var n;return n="string"==typeof e?e:e.component?e.component(e.props):r.createElement(g,null),r.createElement("p",{key:t},n)}var w=function(e){var t=e.notifications;return r.createElement(b,{error:!0},t.map(y))},_=function(e){var t=e.notifications;return r.createElement(b,{success:!0},t.map(y))},E=function(e){var t=e.errors,n=e.successes;return r.createElement("div",null,(null==t?void 0:t.length)>0&&r.createElement(w,{notifications:t}),n.length>0&&r.createElement(_,{notifications:n}))},S=function(e){return{errors:e.notifications.errors,successes:e.notifications.successes}},k=(0,i.$j)(S)(E);let x=k},9409(e,t,n){"use strict";n.d(t,{ZP:()=>j});var r=n(67294),i=n(55977),a=n(47886),o=n(32316),s=n(1398),u=n(82204),c=n(30060),l=n(71426),f=n(60520),d=n(97779),h=n(57209),p=n(26842),b=n(3950),m=n(5536),g=n(45697),v=n.n(g);let y=n.p+"9f6d832ef97e8493764e.svg";function w(){return(w=Object.assign||function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&_.map(function(e,t){return r.createElement(d.Z,{item:!0,xs:12,key:t},r.createElement(u.Z,{raised:!1,className:v.error},r.createElement(c.Z,null,r.createElement(l.default,{variant:"body1",className:v.errorText},(0,b.jK)(e)))))}),r.createElement(d.Z,{item:!0,xs:12},r.createElement(f.Z,{id:"email",label:"Email",margin:"normal",value:n,onChange:m("email"),error:_.length>0,variant:"outlined",fullWidth:!0})),r.createElement(d.Z,{item:!0,xs:12},r.createElement(f.Z,{id:"password",label:"Password",type:"password",autoComplete:"password",margin:"normal",value:h,onChange:m("password"),error:_.length>0,variant:"outlined",fullWidth:!0})),r.createElement(d.Z,{item:!0,xs:12},r.createElement(d.Z,{container:!0,spacing:0,justify:"center"},r.createElement(d.Z,{item:!0},r.createElement(s.Z,{type:"submit",variant:"primary"},"Access Account")))),y&&r.createElement(l.default,{variant:"body1",color:"textSecondary"},"Signing in...")))))))},P=function(e){return{fetching:e.authentication.fetching,authenticated:e.authentication.allowed,errors:e.notifications.errors}},R=(0,i.$j)(P,x({submitSignIn:p.L7}))(N);let j=(0,h.wU)(e)((0,o.withStyles)(D)(R))},16353(e,t,n){"use strict";n.d(t,{ZP:()=>H,rH:()=>U});var r,i=n(55977),a=n(15857),o=n(9541),s=n(19084);function u(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:h,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.Mk.RECEIVE_SIGNOUT_SUCCESS:case s.Mk.RECEIVE_SIGNIN_SUCCESS:var n={allowed:t.authenticated};return o.Ks(n),f(c({},e,n),{errors:[]});case s.Mk.RECEIVE_SIGNIN_FAIL:var r={allowed:!1};return o.Ks(r),f(c({},e,r),{errors:[]});case s.Mk.RECEIVE_SIGNIN_ERROR:case s.Mk.RECEIVE_SIGNOUT_ERROR:var i={allowed:!1};return o.Ks(i),f(c({},e,i),{errors:t.errors||[]});default:return e}};let b=p;function m(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function g(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:_,t=arguments.length>1?arguments[1]:void 0;return t.type?t.type.startsWith(r.REQUEST)?y(g({},e),{count:e.count+1}):t.type.startsWith(r.RECEIVE)?y(g({},e),{count:Math.max(e.count-1,0)}):t.type.startsWith(r.RESPONSE)?y(g({},e),{count:Math.max(e.count-1,0)}):t.type===s.di.REDIRECT?y(g({},e),{count:0}):e:e};let S=E;function k(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function x(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:O,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.di.MATCH_ROUTE:return M(x({},O),{currentUrl:t.pathname});case s.Ih.NOTIFY_SUCCESS:var n={component:t.component,props:t.props};return M(x({},e),{successes:[n],errors:[]});case s.Ih.NOTIFY_SUCCESS_MSG:return M(x({},e),{successes:[t.msg],errors:[]});case s.Ih.NOTIFY_ERROR:var r=t.error.errors,i=null==r?void 0:r.map(function(e){return L(t,e)});return M(x({},e),{successes:[],errors:i});case s.Ih.NOTIFY_ERROR_MSG:return M(x({},e),{successes:[],errors:[t.msg]});case s.Mk.RECEIVE_SIGNIN_FAIL:return M(x({},e),{successes:[],errors:["Your email or password is incorrect. Please try again"]});default:return e}};function L(e,t){return{component:e.component,props:{msg:t.detail}}}let C=A;function I(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function D(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:R,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.di.REDIRECT:return P(D({},e),{to:t.to});case s.di.MATCH_ROUTE:return P(D({},e),{to:void 0});default:return e}};let F=j;var Y=n(87013),B=(0,a.UY)({authentication:b,fetching:S,notifications:C,redirect:F,buildInfo:Y.Z});B(void 0,{type:"INITIAL_STATE"});var U=i.v9;let H=B},19084(e,t,n){"use strict";var r,i,a,o,s,u,c,l,f,d;n.d(t,{Ih:()=>i,Mk:()=>a,Y0:()=>s,di:()=>r,jp:()=>o}),n(67294),(u=r||(r={})).REDIRECT="REDIRECT",u.MATCH_ROUTE="MATCH_ROUTE",(c=i||(i={})).NOTIFY_SUCCESS="NOTIFY_SUCCESS",c.NOTIFY_SUCCESS_MSG="NOTIFY_SUCCESS_MSG",c.NOTIFY_ERROR="NOTIFY_ERROR",c.NOTIFY_ERROR_MSG="NOTIFY_ERROR_MSG",(l=a||(a={})).REQUEST_SIGNIN="REQUEST_SIGNIN",l.RECEIVE_SIGNIN_SUCCESS="RECEIVE_SIGNIN_SUCCESS",l.RECEIVE_SIGNIN_FAIL="RECEIVE_SIGNIN_FAIL",l.RECEIVE_SIGNIN_ERROR="RECEIVE_SIGNIN_ERROR",l.RECEIVE_SIGNOUT_SUCCESS="RECEIVE_SIGNOUT_SUCCESS",l.RECEIVE_SIGNOUT_ERROR="RECEIVE_SIGNOUT_ERROR",(f=o||(o={})).RECEIVE_CREATE_ERROR="RECEIVE_CREATE_ERROR",f.RECEIVE_CREATE_SUCCESS="RECEIVE_CREATE_SUCCESS",f.RECEIVE_DELETE_ERROR="RECEIVE_DELETE_ERROR",f.RECEIVE_DELETE_SUCCESS="RECEIVE_DELETE_SUCCESS",f.RECEIVE_UPDATE_ERROR="RECEIVE_UPDATE_ERROR",f.RECEIVE_UPDATE_SUCCESS="RECEIVE_UPDATE_SUCCESS",f.REQUEST_CREATE="REQUEST_CREATE",f.REQUEST_DELETE="REQUEST_DELETE",f.REQUEST_UPDATE="REQUEST_UPDATE",f.UPSERT_CONFIGURATION="UPSERT_CONFIGURATION",f.UPSERT_JOB_RUN="UPSERT_JOB_RUN",f.UPSERT_JOB_RUNS="UPSERT_JOB_RUNS",f.UPSERT_TRANSACTION="UPSERT_TRANSACTION",f.UPSERT_TRANSACTIONS="UPSERT_TRANSACTIONS",f.UPSERT_BUILD_INFO="UPSERT_BUILD_INFO",(d=s||(s={})).FETCH_BUILD_INFO_REQUESTED="FETCH_BUILD_INFO_REQUESTED",d.FETCH_BUILD_INFO_SUCCEEDED="FETCH_BUILD_INFO_SUCCEEDED",d.FETCH_BUILD_INFO_FAILED="FETCH_BUILD_INFO_FAILED"},87013(e,t,n){"use strict";n.d(t,{Y:()=>o,Z:()=>u});var r=n(19084);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:o,t=arguments.length>1?arguments[1]:void 0;return t.type===r.Y0.FETCH_BUILD_INFO_SUCCEEDED?a({},t.buildInfo):e};let u=s},34823(e,t,n){"use strict";n.d(t,{N:()=>r});var r=function(e){return e.buildInfo}},73343(e,t,n){"use strict";n.d(t,{r:()=>u});var r=n(19350),i=n(32316),a=n(59114),o=n(5324),s={props:{MuiGrid:{spacing:3*o.default.unit},MuiCardHeader:{titleTypographyProps:{color:"secondary"}}},palette:{action:{hoverOpacity:.3},primary:{light:"#E5F1FF",main:"#3c40c6",contrastText:"#fff"},secondary:{main:"#3d5170"},success:{light:"#e8faf1",main:r.ek.A700,dark:r.ek[700],contrastText:r.y0.white},warning:{light:"#FFFBF1",main:"#fff6b6",contrastText:"#fad27a"},error:{light:"#ffdada",main:"#f44336",dark:"#d32f2f",contrastText:"#fff"},background:{default:"#f5f6f8",appBar:"#3c40c6"},text:{primary:(0,a.darken)(r.BA.A700,.7),secondary:"#818ea3"},listPendingStatus:{background:"#fef7e5",color:"#fecb4c"},listCompletedStatus:{background:"#e9faf2",color:"#4ed495"}},shape:{borderRadius:o.default.unit},overrides:{MuiButton:{root:{borderRadius:o.default.unit/2,textTransform:"none"},sizeLarge:{padding:void 0,fontSize:void 0,paddingTop:o.default.unit,paddingBottom:o.default.unit,paddingLeft:5*o.default.unit,paddingRight:5*o.default.unit}},MuiTableCell:{body:{fontSize:"1rem"},head:{fontSize:"1rem",fontWeight:400}},MuiCardHeader:{root:{borderBottom:"1px solid rgba(0, 0, 0, 0.12)"},action:{marginTop:-2,marginRight:0,"& >*":{marginLeft:2*o.default.unit}},subheader:{marginTop:.5*o.default.unit}}},typography:{useNextVariants:!0,fontFamily:"-apple-system,BlinkMacSystemFont,Roboto,Helvetica,Arial,sans-serif",button:{textTransform:"none",fontSize:"1.2em"},body1:{fontSize:"1.0rem",fontWeight:400,lineHeight:"1.46429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},body2:{fontSize:"1.0rem",fontWeight:500,lineHeight:"1.71429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},body1Next:{color:"rgb(29, 29, 29)",fontWeight:400,fontSize:"1rem",lineHeight:1.5,letterSpacing:-.4},body2Next:{color:"rgb(29, 29, 29)",fontWeight:400,fontSize:"0.875rem",lineHeight:1.5,letterSpacing:-.4},display1:{color:"#818ea3",fontSize:"2.125rem",fontWeight:400,lineHeight:"1.20588em",letterSpacing:-.4},display2:{color:"#818ea3",fontSize:"2.8125rem",fontWeight:400,lineHeight:"1.13333em",marginLeft:"-.02em",letterSpacing:-.4},display3:{color:"#818ea3",fontSize:"3.5rem",fontWeight:400,lineHeight:"1.30357em",marginLeft:"-.02em",letterSpacing:-.4},display4:{fontSize:14,fontWeightLight:300,fontWeightMedium:500,fontWeightRegular:400,letterSpacing:-.4},h1:{color:"rgb(29, 29, 29)",fontSize:"6rem",fontWeight:300,lineHeight:1},h2:{color:"rgb(29, 29, 29)",fontSize:"3.75rem",fontWeight:300,lineHeight:1},h3:{color:"rgb(29, 29, 29)",fontSize:"3rem",fontWeight:400,lineHeight:1.04},h4:{color:"rgb(29, 29, 29)",fontSize:"2.125rem",fontWeight:400,lineHeight:1.17},h5:{color:"rgb(29, 29, 29)",fontSize:"1.5rem",fontWeight:400,lineHeight:1.33,letterSpacing:-.4},h6:{fontSize:"0.8rem",fontWeight:450,lineHeight:"1.71429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},subheading:{color:"rgb(29, 29, 29)",fontSize:"1rem",fontWeight:400,lineHeight:"1.5em",letterSpacing:-.4},subtitle1:{color:"rgb(29, 29, 29)",fontSize:"1rem",fontWeight:400,lineHeight:1.75,letterSpacing:-.4},subtitle2:{color:"rgb(29, 29, 29)",fontSize:"0.875rem",fontWeight:500,lineHeight:1.57,letterSpacing:-.4}},shadows:["none","0px 1px 3px 0px rgba(0, 0, 0, 0.1),0px 1px 1px 0px rgba(0, 0, 0, 0.04),0px 2px 1px -1px rgba(0, 0, 0, 0.02)","0px 1px 5px 0px rgba(0, 0, 0, 0.1),0px 2px 2px 0px rgba(0, 0, 0, 0.04),0px 3px 1px -2px rgba(0, 0, 0, 0.02)","0px 1px 8px 0px rgba(0, 0, 0, 0.1),0px 3px 4px 0px rgba(0, 0, 0, 0.04),0px 3px 3px -2px rgba(0, 0, 0, 0.02)","0px 2px 4px -1px rgba(0, 0, 0, 0.1),0px 4px 5px 0px rgba(0, 0, 0, 0.04),0px 1px 10px 0px rgba(0, 0, 0, 0.02)","0px 3px 5px -1px rgba(0, 0, 0, 0.1),0px 5px 8px 0px rgba(0, 0, 0, 0.04),0px 1px 14px 0px rgba(0, 0, 0, 0.02)","0px 3px 5px -1px rgba(0, 0, 0, 0.1),0px 6px 10px 0px rgba(0, 0, 0, 0.04),0px 1px 18px 0px rgba(0, 0, 0, 0.02)","0px 4px 5px -2px rgba(0, 0, 0, 0.1),0px 7px 10px 1px rgba(0, 0, 0, 0.04),0px 2px 16px 1px rgba(0, 0, 0, 0.02)","0px 5px 5px -3px rgba(0, 0, 0, 0.1),0px 8px 10px 1px rgba(0, 0, 0, 0.04),0px 3px 14px 2px rgba(0, 0, 0, 0.02)","0px 5px 6px -3px rgba(0, 0, 0, 0.1),0px 9px 12px 1px rgba(0, 0, 0, 0.04),0px 3px 16px 2px rgba(0, 0, 0, 0.02)","0px 6px 6px -3px rgba(0, 0, 0, 0.1),0px 10px 14px 1px rgba(0, 0, 0, 0.04),0px 4px 18px 3px rgba(0, 0, 0, 0.02)","0px 6px 7px -4px rgba(0, 0, 0, 0.1),0px 11px 15px 1px rgba(0, 0, 0, 0.04),0px 4px 20px 3px rgba(0, 0, 0, 0.02)","0px 7px 8px -4px rgba(0, 0, 0, 0.1),0px 12px 17px 2px rgba(0, 0, 0, 0.04),0px 5px 22px 4px rgba(0, 0, 0, 0.02)","0px 7px 8px -4px rgba(0, 0, 0, 0.1),0px 13px 19px 2px rgba(0, 0, 0, 0.04),0px 5px 24px 4px rgba(0, 0, 0, 0.02)","0px 7px 9px -4px rgba(0, 0, 0, 0.1),0px 14px 21px 2px rgba(0, 0, 0, 0.04),0px 5px 26px 4px rgba(0, 0, 0, 0.02)","0px 8px 9px -5px rgba(0, 0, 0, 0.1),0px 15px 22px 2px rgba(0, 0, 0, 0.04),0px 6px 28px 5px rgba(0, 0, 0, 0.02)","0px 8px 10px -5px rgba(0, 0, 0, 0.1),0px 16px 24px 2px rgba(0, 0, 0, 0.04),0px 6px 30px 5px rgba(0, 0, 0, 0.02)","0px 8px 11px -5px rgba(0, 0, 0, 0.1),0px 17px 26px 2px rgba(0, 0, 0, 0.04),0px 6px 32px 5px rgba(0, 0, 0, 0.02)","0px 9px 11px -5px rgba(0, 0, 0, 0.1),0px 18px 28px 2px rgba(0, 0, 0, 0.04),0px 7px 34px 6px rgba(0, 0, 0, 0.02)","0px 9px 12px -6px rgba(0, 0, 0, 0.1),0px 19px 29px 2px rgba(0, 0, 0, 0.04),0px 7px 36px 6px rgba(0, 0, 0, 0.02)","0px 10px 13px -6px rgba(0, 0, 0, 0.1),0px 20px 31px 3px rgba(0, 0, 0, 0.04),0px 8px 38px 7px rgba(0, 0, 0, 0.02)","0px 10px 13px -6px rgba(0, 0, 0, 0.1),0px 21px 33px 3px rgba(0, 0, 0, 0.04),0px 8px 40px 7px rgba(0, 0, 0, 0.02)","0px 10px 14px -6px rgba(0, 0, 0, 0.1),0px 22px 35px 3px rgba(0, 0, 0, 0.04),0px 8px 42px 7px rgba(0, 0, 0, 0.02)","0px 11px 14px -7px rgba(0, 0, 0, 0.1),0px 23px 36px 3px rgba(0, 0, 0, 0.04),0px 9px 44px 8px rgba(0, 0, 0, 0.02)","0px 11px 15px -7px rgba(0, 0, 0, 0.1),0px 24px 38px 3px rgba(0, 0, 0, 0.04),0px 9px 46px 8px rgba(0, 0, 0, 0.02)",]},u=(0,i.createMuiTheme)(s)},66289(e,t,n){"use strict";function r(e){if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function i(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function a(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(e){return!1}}function o(e,t,n){return(o=a()?Reflect.construct:function(e,t,n){var r=[null];r.push.apply(r,t);var i=new(Function.bind.apply(e,r));return n&&f(i,n.prototype),i}).apply(null,arguments)}function s(e){return(s=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function u(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&f(e,t)}function c(e){return -1!==Function.toString.call(e).indexOf("[native code]")}function l(e,t){return t&&("object"===p(t)||"function"==typeof t)?t:r(e)}function f(e,t){return(f=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}n.d(t,{V0:()=>B,_7:()=>v});var d,h,p=function(e){return e&&"undefined"!=typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};function b(e){var t="function"==typeof Map?new Map:void 0;return(b=function(e){if(null===e||!c(e))return e;if("function"!=typeof e)throw TypeError("Super expression must either be null or a function");if(void 0!==t){if(t.has(e))return t.get(e);t.set(e,n)}function n(){return o(e,arguments,s(this).constructor)}return n.prototype=Object.create(e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),f(n,e)})(e)}function m(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}function g(e){var t=m();return function(){var n,r=s(e);if(t){var i=s(this).constructor;n=Reflect.construct(r,arguments,i)}else n=r.apply(this,arguments);return l(this,n)}}var v=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"AuthenticationError(".concat(e.statusText,")"))).errors=[{status:e.status,detail:e},],r}return n}(b(Error)),y=function(e){u(n,e);var t=g(n);function n(e){var r,a=e.errors;return i(this,n),(r=t.call(this,"BadRequestError")).errors=a,r}return n}(b(Error)),w=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"UnprocessableEntityError")).errors=e,r}return n}(b(Error)),_=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"ServerError")).errors=e,r}return n}(b(Error)),E=function(e){u(n,e);var t=g(n);function n(e){var r,a=e.errors;return i(this,n),(r=t.call(this,"ConflictError")).errors=a,r}return n}(b(Error)),S=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"UnknownResponseError(".concat(e.statusText,")"))).errors=[{status:e.status,detail:e.statusText},],r}return n}(b(Error));function k(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:2e4;return Promise.race([fetch(e,t),new Promise(function(e,t){return setTimeout(function(){return t(Error("timeout"))},n)}),])}function x(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=200&&e.status<300))return[3,2];return[2,e.json()];case 2:if(400!==e.status)return[3,3];return[2,e.json().then(function(e){throw new y(e)})];case 3:if(401!==e.status)return[3,4];throw new v(e);case 4:if(422!==e.status)return[3,6];return[4,$(e)];case 5:throw n=i.sent(),new w(n);case 6:if(409!==e.status)return[3,7];return[2,e.json().then(function(e){throw new E(e)})];case 7:if(!(e.status>=500))return[3,9];return[4,$(e)];case 8:throw r=i.sent(),new _(r);case 9:throw new S(e);case 10:return[2]}})})).apply(this,arguments)}function $(e){return z.apply(this,arguments)}function z(){return(z=j(function(e){return Y(this,function(t){return[2,e.json().then(function(t){return t.errors?t.errors.map(function(t){return{status:e.status,detail:t.detail}}):G(e)}).catch(function(){return G(e)})]})})).apply(this,arguments)}function G(e){return[{status:e.status,detail:e.statusText},]}},50109(e,t,n){"use strict";n.d(t,{LK:()=>o,U2:()=>i,eT:()=>s,t8:()=>a});var r=n(12795);function i(e){return r.ZP.getItem("chainlink.".concat(e))}function a(e,t){r.ZP.setItem("chainlink.".concat(e),t)}function o(e){var t=i(e),n={};if(t)try{return JSON.parse(t)}catch(r){}return n}function s(e,t){a(e,JSON.stringify(t))}},9541(e,t,n){"use strict";n.d(t,{Ks:()=>u,Tp:()=>a,iR:()=>o,pm:()=>s});var r=n(50109),i="persistURL";function a(){return r.U2(i)||""}function o(e){r.t8(i,e)}function s(){return r.LK("authentication")}function u(e){r.eT("authentication",e)}},67121(e,t,n){"use strict";function r(e){var t,n=e.Symbol;return"function"==typeof n?n.observable?t=n.observable:(t=n("observable"),n.observable=t):t="@@observable",t}n.r(t),n.d(t,{default:()=>o}),e=n.hmd(e),i="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==n.g?n.g:e;var i,a=r(i);let o=a},2177(e,t,n){"use strict";n.d(t,{Z:()=>o});var r=!0,i="Invariant failed";function a(e,t){if(!e){if(r)throw Error(i);throw Error(i+": "+(t||""))}}let o=a},11742(e){e.exports=function(){var e=document.getSelection();if(!e.rangeCount)return function(){};for(var t=document.activeElement,n=[],r=0;ri,pi:()=>a});var r=function(e,t){return(r=Object.setPrototypeOf||({__proto__:[]})instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])})(e,t)};function i(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}var a=function(){return(a=Object.assign||function(e){for(var t,n=1,r=arguments.length;nr})},94927(e,t,n){function r(e,t){if(i("noDeprecation"))return e;var n=!1;function r(){if(!n){if(i("throwDeprecation"))throw Error(t);i("traceDeprecation")?console.trace(t):console.warn(t),n=!0}return e.apply(this,arguments)}return r}function i(e){try{if(!n.g.localStorage)return!1}catch(t){return!1}var r=n.g.localStorage[e];return null!=r&&"true"===String(r).toLowerCase()}e.exports=r},42473(e){"use strict";var t=function(){};e.exports=t},84763(e){e.exports=Worker},47529(e){e.exports=n;var t=Object.prototype.hasOwnProperty;function n(){for(var e={},n=0;nr,O:()=>a}),(i=r||(r={}))[i.loading=1]="loading",i[i.setVariables=2]="setVariables",i[i.fetchMore=3]="fetchMore",i[i.refetch=4]="refetch",i[i.poll=6]="poll",i[i.ready=7]="ready",i[i.error=8]="error"},30990(e,t,n){"use strict";n.d(t,{MS:()=>s,YG:()=>a,cA:()=>c,ls:()=>o});var r=n(23564);n(83952);var i=n(13154),a=Symbol();function o(e){return!!e.extensions&&Array.isArray(e.extensions[a])}function s(e){return e.hasOwnProperty("graphQLErrors")}var u=function(e){var t=(0,r.ev)((0,r.ev)((0,r.ev)([],e.graphQLErrors,!0),e.clientErrors,!0),e.protocolErrors,!0);return e.networkError&&t.push(e.networkError),t.map(function(e){return(0,i.s)(e)&&e.message||"Error message not found."}).join("\n")},c=function(e){function t(n){var r=n.graphQLErrors,i=n.protocolErrors,a=n.clientErrors,o=n.networkError,s=n.errorMessage,c=n.extraInfo,l=e.call(this,s)||this;return l.name="ApolloError",l.graphQLErrors=r||[],l.protocolErrors=i||[],l.clientErrors=a||[],l.networkError=o||null,l.message=s||u(l),l.extraInfo=c,l.__proto__=t.prototype,l}return(0,r.ZT)(t,e),t}(Error)},85317(e,t,n){"use strict";n.d(t,{K:()=>a});var r=n(67294),i=n(30320).aS?Symbol.for("__APOLLO_CONTEXT__"):"__APOLLO_CONTEXT__";function a(){var e=r.createContext[i];return e||(Object.defineProperty(r.createContext,i,{value:e=r.createContext({}),enumerable:!1,writable:!1,configurable:!0}),e.displayName="ApolloContext"),e}},21436(e,t,n){"use strict";n.d(t,{O:()=>i,k:()=>r});var r=Array.isArray;function i(e){return Array.isArray(e)&&e.length>0}},30320(e,t,n){"use strict";n.d(t,{DN:()=>s,JC:()=>l,aS:()=>o,mr:()=>i,sy:()=>a});var r=n(83952),i="function"==typeof WeakMap&&"ReactNative"!==(0,r.wY)(function(){return navigator.product}),a="function"==typeof WeakSet,o="function"==typeof Symbol&&"function"==typeof Symbol.for,s=o&&Symbol.asyncIterator,u="function"==typeof(0,r.wY)(function(){return window.document.createElement}),c=(0,r.wY)(function(){return navigator.userAgent.indexOf("jsdom")>=0})||!1,l=u&&!c},53712(e,t,n){"use strict";function r(){for(var e=[],t=0;tr})},10542(e,t,n){"use strict";n.d(t,{J:()=>o}),n(83952);var r=n(13154);function i(e){var t=new Set([e]);return t.forEach(function(e){(0,r.s)(e)&&a(e)===e&&Object.getOwnPropertyNames(e).forEach(function(n){(0,r.s)(e[n])&&t.add(e[n])})}),e}function a(e){if(__DEV__&&!Object.isFrozen(e))try{Object.freeze(e)}catch(t){if(t instanceof TypeError)return null;throw t}return e}function o(e){return __DEV__&&i(e),e}},14012(e,t,n){"use strict";n.d(t,{J:()=>a});var r=n(23564),i=n(53712);function a(e,t){return(0,i.o)(e,t,t.variables&&{variables:(0,r.pi)((0,r.pi)({},e&&e.variables),t.variables)})}},13154(e,t,n){"use strict";function r(e){return null!==e&&"object"==typeof e}n.d(t,{s:()=>r})},83952(e,t,n){"use strict";n.d(t,{ej:()=>u,kG:()=>c,wY:()=>h});var r,i=n(70655),a="Invariant Violation",o=Object.setPrototypeOf,s=void 0===o?function(e,t){return e.__proto__=t,e}:o,u=function(e){function t(n){void 0===n&&(n=a);var r=e.call(this,"number"==typeof n?a+": "+n+" (see https://github.com/apollographql/invariant-packages)":n)||this;return r.framesToPop=1,r.name=a,s(r,t.prototype),r}return(0,i.ZT)(t,e),t}(Error);function c(e,t){if(!e)throw new u(t)}var l=["debug","log","warn","error","silent"],f=l.indexOf("log");function d(e){return function(){if(l.indexOf(e)>=f)return(console[e]||console.log).apply(console,arguments)}}function h(e){try{return e()}catch(t){}}(r=c||(c={})).debug=d("debug"),r.log=d("log"),r.warn=d("warn"),r.error=d("error");let p=h(function(){return globalThis})||h(function(){return window})||h(function(){return self})||h(function(){return global})||h(function(){return h.constructor("return this")()});var b="__",m=[b,b].join("DEV");function g(){try{return Boolean(__DEV__)}catch(e){return Object.defineProperty(p,m,{value:"production"!==h(function(){return"production"}),enumerable:!1,configurable:!0,writable:!0}),p[m]}}let v=g();function y(e){try{return e()}catch(t){}}var w=y(function(){return globalThis})||y(function(){return window})||y(function(){return self})||y(function(){return global})||y(function(){return y.constructor("return this")()}),_=!1;function E(){!w||y(function(){return"production"})||y(function(){return process})||(Object.defineProperty(w,"process",{value:{env:{NODE_ENV:"production"}},configurable:!0,enumerable:!1,writable:!0}),_=!0)}function S(){_&&(delete w.process,_=!1)}E();var k=n(10143);function x(){return k.H,S()}function T(){__DEV__?c("boolean"==typeof v,v):c("boolean"==typeof v,39)}x(),T()},87462(e,t,n){"use strict";function r(){return(r=Object.assign||function(e){for(var t=1;tr})},25821(e,t,n){"use strict";n.d(t,{Z:()=>s});var r=n(45695);function i(e){return(i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}var a=10,o=2;function s(e){return u(e,[])}function u(e,t){switch(i(e)){case"string":return JSON.stringify(e);case"function":return e.name?"[function ".concat(e.name,"]"):"[function]";case"object":if(null===e)return"null";return c(e,t);default:return String(e)}}function c(e,t){if(-1!==t.indexOf(e))return"[Circular]";var n=[].concat(t,[e]),r=d(e);if(void 0!==r){var i=r.call(e);if(i!==e)return"string"==typeof i?i:u(i,n)}else if(Array.isArray(e))return f(e,n);return l(e,n)}function l(e,t){var n=Object.keys(e);return 0===n.length?"{}":t.length>o?"["+h(e)+"]":"{ "+n.map(function(n){var r=u(e[n],t);return n+": "+r}).join(", ")+" }"}function f(e,t){if(0===e.length)return"[]";if(t.length>o)return"[Array]";for(var n=Math.min(a,e.length),r=e.length-n,i=[],s=0;s1&&i.push("... ".concat(r," more items")),"["+i.join(", ")+"]"}function d(e){var t=e[String(r.Z)];return"function"==typeof t?t:"function"==typeof e.inspect?e.inspect:void 0}function h(e){var t=Object.prototype.toString.call(e).replace(/^\[object /,"").replace(/]$/,"");if("Object"===t&&"function"==typeof e.constructor){var n=e.constructor.name;if("string"==typeof n&&""!==n)return n}return t}},45695(e,t,n){"use strict";n.d(t,{Z:()=>i});var r="function"==typeof Symbol&&"function"==typeof Symbol.for?Symbol.for("nodejs.util.inspect.custom"):void 0;let i=r},25217(e,t,n){"use strict";function r(e,t){if(!Boolean(e))throw Error(null!=t?t:"Unexpected invariant triggered.")}n.d(t,{Ye:()=>o,WU:()=>s,UG:()=>u});var i=n(45695);function a(e){var t=e.prototype.toJSON;"function"==typeof t||r(0),e.prototype.inspect=t,i.Z&&(e.prototype[i.Z]=t)}var o=function(){function e(e,t,n){this.start=e.start,this.end=t.end,this.startToken=e,this.endToken=t,this.source=n}return e.prototype.toJSON=function(){return{start:this.start,end:this.end}},e}();a(o);var s=function(){function e(e,t,n,r,i,a,o){this.kind=e,this.start=t,this.end=n,this.line=r,this.column=i,this.value=o,this.prev=a,this.next=null}return e.prototype.toJSON=function(){return{kind:this.kind,value:this.value,line:this.line,column:this.column}},e}();function u(e){return null!=e&&"string"==typeof e.kind}a(s)},87392(e,t,n){"use strict";function r(e){var t=e.split(/\r\n|[\n\r]/g),n=a(e);if(0!==n)for(var r=1;ro&&i(t[s-1]);)--s;return t.slice(o,s).join("\n")}function i(e){for(var t=0;t1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],r=-1===e.indexOf("\n"),i=" "===e[0]||" "===e[0],a='"'===e[e.length-1],o="\\"===e[e.length-1],s=!r||a||o||n,u="";return s&&!(r&&i)&&(u+="\n"+t),u+=t?e.replace(/\n/g,"\n"+t):e,s&&(u+="\n"),'"""'+u.replace(/"""/g,'\\"""')+'"""'}n.d(t,{LZ:()=>o,W7:()=>r})},97359(e,t,n){"use strict";n.d(t,{h:()=>r});var r=Object.freeze({NAME:"Name",DOCUMENT:"Document",OPERATION_DEFINITION:"OperationDefinition",VARIABLE_DEFINITION:"VariableDefinition",SELECTION_SET:"SelectionSet",FIELD:"Field",ARGUMENT:"Argument",FRAGMENT_SPREAD:"FragmentSpread",INLINE_FRAGMENT:"InlineFragment",FRAGMENT_DEFINITION:"FragmentDefinition",VARIABLE:"Variable",INT:"IntValue",FLOAT:"FloatValue",STRING:"StringValue",BOOLEAN:"BooleanValue",NULL:"NullValue",ENUM:"EnumValue",LIST:"ListValue",OBJECT:"ObjectValue",OBJECT_FIELD:"ObjectField",DIRECTIVE:"Directive",NAMED_TYPE:"NamedType",LIST_TYPE:"ListType",NON_NULL_TYPE:"NonNullType",SCHEMA_DEFINITION:"SchemaDefinition",OPERATION_TYPE_DEFINITION:"OperationTypeDefinition",SCALAR_TYPE_DEFINITION:"ScalarTypeDefinition",OBJECT_TYPE_DEFINITION:"ObjectTypeDefinition",FIELD_DEFINITION:"FieldDefinition",INPUT_VALUE_DEFINITION:"InputValueDefinition",INTERFACE_TYPE_DEFINITION:"InterfaceTypeDefinition",UNION_TYPE_DEFINITION:"UnionTypeDefinition",ENUM_TYPE_DEFINITION:"EnumTypeDefinition",ENUM_VALUE_DEFINITION:"EnumValueDefinition",INPUT_OBJECT_TYPE_DEFINITION:"InputObjectTypeDefinition",DIRECTIVE_DEFINITION:"DirectiveDefinition",SCHEMA_EXTENSION:"SchemaExtension",SCALAR_TYPE_EXTENSION:"ScalarTypeExtension",OBJECT_TYPE_EXTENSION:"ObjectTypeExtension",INTERFACE_TYPE_EXTENSION:"InterfaceTypeExtension",UNION_TYPE_EXTENSION:"UnionTypeExtension",ENUM_TYPE_EXTENSION:"EnumTypeExtension",INPUT_OBJECT_TYPE_EXTENSION:"InputObjectTypeExtension"})},10143(e,t,n){"use strict";n.d(t,{H:()=>c,T:()=>l});var r=n(99763),i=n(25821);function a(e,t){if(!Boolean(e))throw Error(t)}let o=function(e,t){return e instanceof t};function s(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:"GraphQL request",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{line:1,column:1};"string"==typeof e||a(0,"Body must be a string. Received: ".concat((0,i.Z)(e),".")),this.body=e,this.name=t,this.locationOffset=n,this.locationOffset.line>0||a(0,"line in locationOffset is 1-indexed and must be positive."),this.locationOffset.column>0||a(0,"column in locationOffset is 1-indexed and must be positive.")}return u(e,[{key:r.YF,get:function(){return"Source"}}]),e}();function l(e){return o(e,c)}},99763(e,t,n){"use strict";n.d(t,{YF:()=>r});var r="function"==typeof Symbol&&null!=Symbol.toStringTag?Symbol.toStringTag:"@@toStringTag"},37452(e){"use strict";e.exports=JSON.parse('{"AElig":"\xc6","AMP":"&","Aacute":"\xc1","Acirc":"\xc2","Agrave":"\xc0","Aring":"\xc5","Atilde":"\xc3","Auml":"\xc4","COPY":"\xa9","Ccedil":"\xc7","ETH":"\xd0","Eacute":"\xc9","Ecirc":"\xca","Egrave":"\xc8","Euml":"\xcb","GT":">","Iacute":"\xcd","Icirc":"\xce","Igrave":"\xcc","Iuml":"\xcf","LT":"<","Ntilde":"\xd1","Oacute":"\xd3","Ocirc":"\xd4","Ograve":"\xd2","Oslash":"\xd8","Otilde":"\xd5","Ouml":"\xd6","QUOT":"\\"","REG":"\xae","THORN":"\xde","Uacute":"\xda","Ucirc":"\xdb","Ugrave":"\xd9","Uuml":"\xdc","Yacute":"\xdd","aacute":"\xe1","acirc":"\xe2","acute":"\xb4","aelig":"\xe6","agrave":"\xe0","amp":"&","aring":"\xe5","atilde":"\xe3","auml":"\xe4","brvbar":"\xa6","ccedil":"\xe7","cedil":"\xb8","cent":"\xa2","copy":"\xa9","curren":"\xa4","deg":"\xb0","divide":"\xf7","eacute":"\xe9","ecirc":"\xea","egrave":"\xe8","eth":"\xf0","euml":"\xeb","frac12":"\xbd","frac14":"\xbc","frac34":"\xbe","gt":">","iacute":"\xed","icirc":"\xee","iexcl":"\xa1","igrave":"\xec","iquest":"\xbf","iuml":"\xef","laquo":"\xab","lt":"<","macr":"\xaf","micro":"\xb5","middot":"\xb7","nbsp":"\xa0","not":"\xac","ntilde":"\xf1","oacute":"\xf3","ocirc":"\xf4","ograve":"\xf2","ordf":"\xaa","ordm":"\xba","oslash":"\xf8","otilde":"\xf5","ouml":"\xf6","para":"\xb6","plusmn":"\xb1","pound":"\xa3","quot":"\\"","raquo":"\xbb","reg":"\xae","sect":"\xa7","shy":"\xad","sup1":"\xb9","sup2":"\xb2","sup3":"\xb3","szlig":"\xdf","thorn":"\xfe","times":"\xd7","uacute":"\xfa","ucirc":"\xfb","ugrave":"\xf9","uml":"\xa8","uuml":"\xfc","yacute":"\xfd","yen":"\xa5","yuml":"\xff"}')},93580(e){"use strict";e.exports=JSON.parse('{"0":"�","128":"€","130":"‚","131":"ƒ","132":"„","133":"…","134":"†","135":"‡","136":"ˆ","137":"‰","138":"Š","139":"‹","140":"Œ","142":"Ž","145":"‘","146":"’","147":"“","148":"”","149":"•","150":"–","151":"—","152":"˜","153":"™","154":"š","155":"›","156":"œ","158":"ž","159":"Ÿ"}')},67946(e){"use strict";e.exports=JSON.parse('{"locale":"en","long":{"year":{"previous":"last year","current":"this year","next":"next year","past":{"one":"{0} year ago","other":"{0} years ago"},"future":{"one":"in {0} year","other":"in {0} years"}},"quarter":{"previous":"last quarter","current":"this quarter","next":"next quarter","past":{"one":"{0} quarter ago","other":"{0} quarters ago"},"future":{"one":"in {0} quarter","other":"in {0} quarters"}},"month":{"previous":"last month","current":"this month","next":"next month","past":{"one":"{0} month ago","other":"{0} months ago"},"future":{"one":"in {0} month","other":"in {0} months"}},"week":{"previous":"last week","current":"this week","next":"next week","past":{"one":"{0} week ago","other":"{0} weeks ago"},"future":{"one":"in {0} week","other":"in {0} weeks"}},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":{"one":"{0} hour ago","other":"{0} hours ago"},"future":{"one":"in {0} hour","other":"in {0} hours"}},"minute":{"current":"this minute","past":{"one":"{0} minute ago","other":"{0} minutes ago"},"future":{"one":"in {0} minute","other":"in {0} minutes"}},"second":{"current":"now","past":{"one":"{0} second ago","other":"{0} seconds ago"},"future":{"one":"in {0} second","other":"in {0} seconds"}}},"short":{"year":{"previous":"last yr.","current":"this yr.","next":"next yr.","past":"{0} yr. ago","future":"in {0} yr."},"quarter":{"previous":"last qtr.","current":"this qtr.","next":"next qtr.","past":{"one":"{0} qtr. ago","other":"{0} qtrs. ago"},"future":{"one":"in {0} qtr.","other":"in {0} qtrs."}},"month":{"previous":"last mo.","current":"this mo.","next":"next mo.","past":"{0} mo. ago","future":"in {0} mo."},"week":{"previous":"last wk.","current":"this wk.","next":"next wk.","past":"{0} wk. ago","future":"in {0} wk."},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":"{0} hr. ago","future":"in {0} hr."},"minute":{"current":"this minute","past":"{0} min. ago","future":"in {0} min."},"second":{"current":"now","past":"{0} sec. ago","future":"in {0} sec."}},"narrow":{"year":{"previous":"last yr.","current":"this yr.","next":"next yr.","past":"{0} yr. ago","future":"in {0} yr."},"quarter":{"previous":"last qtr.","current":"this qtr.","next":"next qtr.","past":{"one":"{0} qtr. ago","other":"{0} qtrs. ago"},"future":{"one":"in {0} qtr.","other":"in {0} qtrs."}},"month":{"previous":"last mo.","current":"this mo.","next":"next mo.","past":"{0} mo. ago","future":"in {0} mo."},"week":{"previous":"last wk.","current":"this wk.","next":"next wk.","past":"{0} wk. ago","future":"in {0} wk."},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":"{0} hr. ago","future":"in {0} hr."},"minute":{"current":"this minute","past":"{0} min. ago","future":"in {0} min."},"second":{"current":"now","past":"{0} sec. ago","future":"in {0} sec."}},"now":{"now":{"current":"now","future":"in a moment","past":"just now"}},"mini":{"year":"{0}yr","month":"{0}mo","week":"{0}wk","day":"{0}d","hour":"{0}h","minute":"{0}m","second":"{0}s","now":"now"},"short-time":{"year":"{0} yr.","month":"{0} mo.","week":"{0} wk.","day":{"one":"{0} day","other":"{0} days"},"hour":"{0} hr.","minute":"{0} min.","second":"{0} sec."},"long-time":{"year":{"one":"{0} year","other":"{0} years"},"month":{"one":"{0} month","other":"{0} months"},"week":{"one":"{0} week","other":"{0} weeks"},"day":{"one":"{0} day","other":"{0} days"},"hour":{"one":"{0} hour","other":"{0} hours"},"minute":{"one":"{0} minute","other":"{0} minutes"},"second":{"one":"{0} second","other":"{0} seconds"}}}')}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={id:e,loaded:!1,exports:{}};return __webpack_modules__[e].call(n.exports,n,n.exports,__webpack_require__),n.loaded=!0,n.exports}__webpack_require__.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return __webpack_require__.d(t,{a:t}),t},(()=>{var e,t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__;__webpack_require__.t=function(n,r){if(1&r&&(n=this(n)),8&r||"object"==typeof n&&n&&(4&r&&n.__esModule||16&r&&"function"==typeof n.then))return n;var i=Object.create(null);__webpack_require__.r(i);var a={};e=e||[null,t({}),t([]),t(t)];for(var o=2&r&&n;"object"==typeof o&&!~e.indexOf(o);o=t(o))Object.getOwnPropertyNames(o).forEach(e=>a[e]=()=>n[e]);return a.default=()=>n,__webpack_require__.d(i,a),i}})(),__webpack_require__.d=(e,t)=>{for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),__webpack_require__.hmd=e=>((e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set(){throw Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e),__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},__webpack_require__.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),__webpack_require__.p="/assets/",__webpack_require__.nc=void 0;var __webpack_exports__={};(()=>{"use strict";var e,t,n,r,i=__webpack_require__(32316),a=__webpack_require__(8126),o=__webpack_require__(5690),s=__webpack_require__(30381),u=__webpack_require__.n(s),c=__webpack_require__(67294),l=__webpack_require__(73935),f=__webpack_require__.n(l),d=__webpack_require__(57209),h=__webpack_require__(55977),p=__webpack_require__(15857),b=__webpack_require__(28500);function m(e){return function(t){var n=t.dispatch,r=t.getState;return function(t){return function(i){return"function"==typeof i?i(n,r,e):t(i)}}}}var g=m();g.withExtraArgument=m;let v=g;var y=__webpack_require__(76489);function w(e){return function(t){return function(n){return function(r){n(r);var i=e||document&&document.cookie||"",a=t.getState();if("MATCH_ROUTE"===r.type&&"/signin"!==a.notifications.currentUrl){var o=(0,y.Q)(i);if(o.explorer)try{var s=JSON.parse(o.explorer);if("error"===s.status){var u=_(s.url);n({type:"NOTIFY_ERROR_MSG",msg:u})}}catch(c){n({type:"NOTIFY_ERROR_MSG",msg:"Invalid explorer status"})}}}}}}function _(e){var t="Can't connect to explorer: ".concat(e);return e.match(/^wss?:.+/)?t:"".concat(t,". You must use a websocket.")}var E=__webpack_require__(16353);function S(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n=e.length?{done:!0}:{done:!1,value:e[r++]}}}throw TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function ei(e,t){if(e){if("string"==typeof e)return ea(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);if("Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return ea(e,t)}}function ea(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1,i=!1,a=arguments[1],o=a;return new n(function(n){return t.subscribe({next:function(t){var a=!i;if(i=!0,!a||r)try{o=e(o,t)}catch(s){return n.error(s)}else o=t},error:function(e){n.error(e)},complete:function(){if(!i&&!r)return n.error(TypeError("Cannot reduce an empty sequence"));n.next(o),n.complete()}})})},t.concat=function(){for(var e=this,t=arguments.length,n=Array(t),r=0;r=0&&i.splice(e,1),o()}});i.push(s)},error:function(e){r.error(e)},complete:function(){o()}});function o(){a.closed&&0===i.length&&r.complete()}return function(){i.forEach(function(e){return e.unsubscribe()}),a.unsubscribe()}})},t[ed]=function(){return this},e.from=function(t){var n="function"==typeof this?this:e;if(null==t)throw TypeError(t+" is not an object");var r=ep(t,ed);if(r){var i=r.call(t);if(Object(i)!==i)throw TypeError(i+" is not an object");return em(i)&&i.constructor===n?i:new n(function(e){return i.subscribe(e)})}if(ec("iterator")&&(r=ep(t,ef)))return new n(function(e){ev(function(){if(!e.closed){for(var n,i=er(r.call(t));!(n=i()).done;){var a=n.value;if(e.next(a),e.closed)return}e.complete()}})});if(Array.isArray(t))return new n(function(e){ev(function(){if(!e.closed){for(var n=0;n0))return n.connection.key;var r=n.connection.filter?n.connection.filter:[];r.sort();var i={};return r.forEach(function(e){i[e]=t[e]}),"".concat(n.connection.key,"(").concat(eV(i),")")}var a=e;if(t){var o=eV(t);a+="(".concat(o,")")}return n&&Object.keys(n).forEach(function(e){-1===eW.indexOf(e)&&(n[e]&&Object.keys(n[e]).length?a+="@".concat(e,"(").concat(eV(n[e]),")"):a+="@".concat(e))}),a},{setStringify:function(e){var t=eV;return eV=e,t}}),eV=function(e){return JSON.stringify(e,eq)};function eq(e,t){return(0,eO.s)(t)&&!Array.isArray(t)&&(t=Object.keys(t).sort().reduce(function(e,n){return e[n]=t[n],e},{})),t}function eZ(e,t){if(e.arguments&&e.arguments.length){var n={};return e.arguments.forEach(function(e){var r;return ez(n,e.name,e.value,t)}),n}return null}function eX(e){return e.alias?e.alias.value:e.name.value}function eJ(e,t,n){for(var r,i=0,a=t.selections;it.indexOf(i))throw __DEV__?new Q.ej("illegal argument: ".concat(i)):new Q.ej(27)}return e}function tt(e,t){return t?t(e):eT.of()}function tn(e){return"function"==typeof e?new ta(e):e}function tr(e){return e.request.length<=1}var ti=function(e){function t(t,n){var r=e.call(this,t)||this;return r.link=n,r}return(0,en.ZT)(t,e),t}(Error),ta=function(){function e(e){e&&(this.request=e)}return e.empty=function(){return new e(function(){return eT.of()})},e.from=function(t){return 0===t.length?e.empty():t.map(tn).reduce(function(e,t){return e.concat(t)})},e.split=function(t,n,r){var i=tn(n),a=tn(r||new e(tt));return new e(tr(i)&&tr(a)?function(e){return t(e)?i.request(e)||eT.of():a.request(e)||eT.of()}:function(e,n){return t(e)?i.request(e,n)||eT.of():a.request(e,n)||eT.of()})},e.execute=function(e,t){return e.request(eM(t.context,e7(te(t))))||eT.of()},e.concat=function(t,n){var r=tn(t);if(tr(r))return __DEV__&&Q.kG.warn(new ti("You are calling concat on a terminating link, which will have no effect",r)),r;var i=tn(n);return new e(tr(i)?function(e){return r.request(e,function(e){return i.request(e)||eT.of()})||eT.of()}:function(e,t){return r.request(e,function(e){return i.request(e,t)||eT.of()})||eT.of()})},e.prototype.split=function(t,n,r){return this.concat(e.split(t,n,r||new e(tt)))},e.prototype.concat=function(t){return e.concat(this,t)},e.prototype.request=function(e,t){throw __DEV__?new Q.ej("request is not implemented"):new Q.ej(22)},e.prototype.onError=function(e,t){if(t&&t.error)return t.error(e),!1;throw e},e.prototype.setOnError=function(e){return this.onError=e,this},e}(),to=__webpack_require__(25821),ts=__webpack_require__(25217),tu={Name:[],Document:["definitions"],OperationDefinition:["name","variableDefinitions","directives","selectionSet"],VariableDefinition:["variable","type","defaultValue","directives"],Variable:["name"],SelectionSet:["selections"],Field:["alias","name","arguments","directives","selectionSet"],Argument:["name","value"],FragmentSpread:["name","directives"],InlineFragment:["typeCondition","directives","selectionSet"],FragmentDefinition:["name","variableDefinitions","typeCondition","directives","selectionSet"],IntValue:[],FloatValue:[],StringValue:[],BooleanValue:[],NullValue:[],EnumValue:[],ListValue:["values"],ObjectValue:["fields"],ObjectField:["name","value"],Directive:["name","arguments"],NamedType:["name"],ListType:["type"],NonNullType:["type"],SchemaDefinition:["description","directives","operationTypes"],OperationTypeDefinition:["type"],ScalarTypeDefinition:["description","name","directives"],ObjectTypeDefinition:["description","name","interfaces","directives","fields"],FieldDefinition:["description","name","arguments","type","directives"],InputValueDefinition:["description","name","type","defaultValue","directives"],InterfaceTypeDefinition:["description","name","interfaces","directives","fields"],UnionTypeDefinition:["description","name","directives","types"],EnumTypeDefinition:["description","name","directives","values"],EnumValueDefinition:["description","name","directives"],InputObjectTypeDefinition:["description","name","directives","fields"],DirectiveDefinition:["description","name","arguments","locations"],SchemaExtension:["directives","operationTypes"],ScalarTypeExtension:["name","directives"],ObjectTypeExtension:["name","interfaces","directives","fields"],InterfaceTypeExtension:["name","interfaces","directives","fields"],UnionTypeExtension:["name","directives","types"],EnumTypeExtension:["name","directives","values"],InputObjectTypeExtension:["name","directives","fields"]},tc=Object.freeze({});function tl(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:tu,r=void 0,i=Array.isArray(e),a=[e],o=-1,s=[],u=void 0,c=void 0,l=void 0,f=[],d=[],h=e;do{var p,b=++o===a.length,m=b&&0!==s.length;if(b){if(c=0===d.length?void 0:f[f.length-1],u=l,l=d.pop(),m){if(i)u=u.slice();else{for(var g={},v=0,y=Object.keys(u);v1)for(var r=new tB,i=1;i=0;--a){var o=i[a],s=isNaN(+o)?{}:[];s[o]=t,t=s}n=r.merge(n,t)}),n}var tW=Object.prototype.hasOwnProperty;function tK(e,t){var n,r,i,a,o;return(0,en.mG)(this,void 0,void 0,function(){var s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T,M,O,A;return(0,en.Jh)(this,function(L){switch(L.label){case 0:if(void 0===TextDecoder)throw Error("TextDecoder must be defined in the environment: please import a polyfill.");s=new TextDecoder("utf-8"),u=null===(n=e.headers)||void 0===n?void 0:n.get("content-type"),c="boundary=",l=(null==u?void 0:u.includes(c))?null==u?void 0:u.substring((null==u?void 0:u.indexOf(c))+c.length).replace(/['"]/g,"").replace(/\;(.*)/gm,"").trim():"-",f="\r\n--".concat(l),d="",h=tI(e),p=!0,L.label=1;case 1:if(!p)return[3,3];return[4,h.next()];case 2:for(m=(b=L.sent()).value,g=b.done,v="string"==typeof m?m:s.decode(m),y=d.length-f.length+1,p=!g,d+=v,w=d.indexOf(f,y);w>-1;){if(_=void 0,_=(O=[d.slice(0,w),d.slice(w+f.length),])[0],d=O[1],E=_.indexOf("\r\n\r\n"),(k=(S=tV(_.slice(0,E)))["content-type"])&&-1===k.toLowerCase().indexOf("application/json"))throw Error("Unsupported patch content type: application/json is required.");if(x=_.slice(E))try{T=tq(e,x),Object.keys(T).length>1||"data"in T||"incremental"in T||"errors"in T||"payload"in T?tz(T)?(M={},"payload"in T&&(M=(0,en.pi)({},T.payload)),"errors"in T&&(M=(0,en.pi)((0,en.pi)({},M),{extensions:(0,en.pi)((0,en.pi)({},"extensions"in M?M.extensions:null),((A={})[tN.YG]=T.errors,A))})),null===(r=t.next)||void 0===r||r.call(t,M)):null===(i=t.next)||void 0===i||i.call(t,T):1===Object.keys(T).length&&"hasNext"in T&&!T.hasNext&&(null===(a=t.complete)||void 0===a||a.call(t))}catch(C){tZ(C,t)}w=d.indexOf(f)}return[3,1];case 3:return null===(o=t.complete)||void 0===o||o.call(t),[2]}})})}function tV(e){var t={};return e.split("\n").forEach(function(e){var n=e.indexOf(":");if(n>-1){var r=e.slice(0,n).trim().toLowerCase(),i=e.slice(n+1).trim();t[r]=i}}),t}function tq(e,t){e.status>=300&&tD(e,function(){try{return JSON.parse(t)}catch(e){return t}}(),"Response not successful: Received status code ".concat(e.status));try{return JSON.parse(t)}catch(n){var r=n;throw r.name="ServerParseError",r.response=e,r.statusCode=e.status,r.bodyText=t,r}}function tZ(e,t){var n,r;"AbortError"!==e.name&&(e.result&&e.result.errors&&e.result.data&&(null===(n=t.next)||void 0===n||n.call(t,e.result)),null===(r=t.error)||void 0===r||r.call(t,e))}function tX(e,t,n){tJ(t)(e).then(function(e){var t,r;null===(t=n.next)||void 0===t||t.call(n,e),null===(r=n.complete)||void 0===r||r.call(n)}).catch(function(e){return tZ(e,n)})}function tJ(e){return function(t){return t.text().then(function(e){return tq(t,e)}).then(function(n){return t.status>=300&&tD(t,n,"Response not successful: Received status code ".concat(t.status)),Array.isArray(n)||tW.call(n,"data")||tW.call(n,"errors")||tD(t,n,"Server response was missing for query '".concat(Array.isArray(e)?e.map(function(e){return e.operationName}):e.operationName,"'.")),n})}}var tQ=function(e){if(!e&&"undefined"==typeof fetch)throw __DEV__?new Q.ej("\n\"fetch\" has not been found globally and no fetcher has been configured. To fix this, install a fetch package (like https://www.npmjs.com/package/cross-fetch), instantiate the fetcher, and pass it into your HttpLink constructor. For example:\n\nimport fetch from 'cross-fetch';\nimport { ApolloClient, HttpLink } from '@apollo/client';\nconst client = new ApolloClient({\n link: new HttpLink({ uri: '/graphql', fetch })\n});\n "):new Q.ej(23)},t1=__webpack_require__(87392);function t0(e){return tl(e,{leave:t3})}var t2=80,t3={Name:function(e){return e.value},Variable:function(e){return"$"+e.name},Document:function(e){return t5(e.definitions,"\n\n")+"\n"},OperationDefinition:function(e){var t=e.operation,n=e.name,r=t9("(",t5(e.variableDefinitions,", "),")"),i=t5(e.directives," "),a=e.selectionSet;return n||i||r||"query"!==t?t5([t,t5([n,r]),i,a]," "):a},VariableDefinition:function(e){var t=e.variable,n=e.type,r=e.defaultValue,i=e.directives;return t+": "+n+t9(" = ",r)+t9(" ",t5(i," "))},SelectionSet:function(e){return t6(e.selections)},Field:function(e){var t=e.alias,n=e.name,r=e.arguments,i=e.directives,a=e.selectionSet,o=t9("",t,": ")+n,s=o+t9("(",t5(r,", "),")");return s.length>t2&&(s=o+t9("(\n",t8(t5(r,"\n")),"\n)")),t5([s,t5(i," "),a]," ")},Argument:function(e){var t;return e.name+": "+e.value},FragmentSpread:function(e){var t;return"..."+e.name+t9(" ",t5(e.directives," "))},InlineFragment:function(e){var t=e.typeCondition,n=e.directives,r=e.selectionSet;return t5(["...",t9("on ",t),t5(n," "),r]," ")},FragmentDefinition:function(e){var t=e.name,n=e.typeCondition,r=e.variableDefinitions,i=e.directives,a=e.selectionSet;return"fragment ".concat(t).concat(t9("(",t5(r,", "),")")," ")+"on ".concat(n," ").concat(t9("",t5(i," ")," "))+a},IntValue:function(e){return e.value},FloatValue:function(e){return e.value},StringValue:function(e,t){var n=e.value;return e.block?(0,t1.LZ)(n,"description"===t?"":" "):JSON.stringify(n)},BooleanValue:function(e){return e.value?"true":"false"},NullValue:function(){return"null"},EnumValue:function(e){return e.value},ListValue:function(e){return"["+t5(e.values,", ")+"]"},ObjectValue:function(e){return"{"+t5(e.fields,", ")+"}"},ObjectField:function(e){var t;return e.name+": "+e.value},Directive:function(e){var t;return"@"+e.name+t9("(",t5(e.arguments,", "),")")},NamedType:function(e){return e.name},ListType:function(e){return"["+e.type+"]"},NonNullType:function(e){return e.type+"!"},SchemaDefinition:t4(function(e){var t=e.directives,n=e.operationTypes;return t5(["schema",t5(t," "),t6(n)]," ")}),OperationTypeDefinition:function(e){var t;return e.operation+": "+e.type},ScalarTypeDefinition:t4(function(e){var t;return t5(["scalar",e.name,t5(e.directives," ")]," ")}),ObjectTypeDefinition:t4(function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["type",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")}),FieldDefinition:t4(function(e){var t=e.name,n=e.arguments,r=e.type,i=e.directives;return t+(ne(n)?t9("(\n",t8(t5(n,"\n")),"\n)"):t9("(",t5(n,", "),")"))+": "+r+t9(" ",t5(i," "))}),InputValueDefinition:t4(function(e){var t=e.name,n=e.type,r=e.defaultValue,i=e.directives;return t5([t+": "+n,t9("= ",r),t5(i," ")]," ")}),InterfaceTypeDefinition:t4(function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["interface",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")}),UnionTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.types;return t5(["union",t,t5(n," "),r&&0!==r.length?"= "+t5(r," | "):""]," ")}),EnumTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.values;return t5(["enum",t,t5(n," "),t6(r)]," ")}),EnumValueDefinition:t4(function(e){var t;return t5([e.name,t5(e.directives," ")]," ")}),InputObjectTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.fields;return t5(["input",t,t5(n," "),t6(r)]," ")}),DirectiveDefinition:t4(function(e){var t=e.name,n=e.arguments,r=e.repeatable,i=e.locations;return"directive @"+t+(ne(n)?t9("(\n",t8(t5(n,"\n")),"\n)"):t9("(",t5(n,", "),")"))+(r?" repeatable":"")+" on "+t5(i," | ")}),SchemaExtension:function(e){var t=e.directives,n=e.operationTypes;return t5(["extend schema",t5(t," "),t6(n)]," ")},ScalarTypeExtension:function(e){var t;return t5(["extend scalar",e.name,t5(e.directives," ")]," ")},ObjectTypeExtension:function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["extend type",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")},InterfaceTypeExtension:function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["extend interface",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")},UnionTypeExtension:function(e){var t=e.name,n=e.directives,r=e.types;return t5(["extend union",t,t5(n," "),r&&0!==r.length?"= "+t5(r," | "):""]," ")},EnumTypeExtension:function(e){var t=e.name,n=e.directives,r=e.values;return t5(["extend enum",t,t5(n," "),t6(r)]," ")},InputObjectTypeExtension:function(e){var t=e.name,n=e.directives,r=e.fields;return t5(["extend input",t,t5(n," "),t6(r)]," ")}};function t4(e){return function(t){return t5([t.description,e(t)],"\n")}}function t5(e){var t,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return null!==(t=null==e?void 0:e.filter(function(e){return e}).join(n))&&void 0!==t?t:""}function t6(e){return t9("{\n",t8(t5(e,"\n")),"\n}")}function t9(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";return null!=t&&""!==t?e+t+n:""}function t8(e){return t9(" ",e.replace(/\n/g,"\n "))}function t7(e){return -1!==e.indexOf("\n")}function ne(e){return null!=e&&e.some(t7)}var nt,nn,nr,ni={http:{includeQuery:!0,includeExtensions:!1,preserveHeaderCase:!1},headers:{accept:"*/*","content-type":"application/json"},options:{method:"POST"}},na=function(e,t){return t(e)};function no(e,t){for(var n=[],r=2;rObject.create(null),{forEach:nv,slice:ny}=Array.prototype,{hasOwnProperty:nw}=Object.prototype;class n_{constructor(e=!0,t=ng){this.weakness=e,this.makeData=t}lookup(...e){return this.lookupArray(e)}lookupArray(e){let t=this;return nv.call(e,e=>t=t.getChildTrie(e)),nw.call(t,"data")?t.data:t.data=this.makeData(ny.call(e))}peek(...e){return this.peekArray(e)}peekArray(e){let t=this;for(let n=0,r=e.length;t&&n=0;--o)t.definitions[o].kind===nL.h.OPERATION_DEFINITION&&++a;var s=nN(e),u=e.some(function(e){return e.remove}),c=function(e){return u&&e&&e.some(s)},l=new Map,f=!1,d={enter:function(e){if(c(e.directives))return f=!0,null}},h=tl(t,{Field:d,InlineFragment:d,VariableDefinition:{enter:function(){return!1}},Variable:{enter:function(e,t,n,r,a){var o=i(a);o&&o.variables.add(e.name.value)}},FragmentSpread:{enter:function(e,t,n,r,a){if(c(e.directives))return f=!0,null;var o=i(a);o&&o.fragmentSpreads.add(e.name.value)}},FragmentDefinition:{enter:function(e,t,n,r){l.set(JSON.stringify(r),e)},leave:function(e,t,n,i){return e===l.get(JSON.stringify(i))?e:a>0&&e.selectionSet.selections.every(function(e){return e.kind===nL.h.FIELD&&"__typename"===e.name.value})?(r(e.name.value).removed=!0,f=!0,null):void 0}},Directive:{leave:function(e){if(s(e))return f=!0,null}}});if(!f)return t;var p=function(e){return e.transitiveVars||(e.transitiveVars=new Set(e.variables),e.removed||e.fragmentSpreads.forEach(function(t){p(r(t)).transitiveVars.forEach(function(t){e.transitiveVars.add(t)})})),e},b=new Set;h.definitions.forEach(function(e){e.kind===nL.h.OPERATION_DEFINITION?p(n(e.name&&e.name.value)).fragmentSpreads.forEach(function(e){b.add(e)}):e.kind!==nL.h.FRAGMENT_DEFINITION||0!==a||r(e.name.value).removed||b.add(e.name.value)}),b.forEach(function(e){p(r(e)).fragmentSpreads.forEach(function(e){b.add(e)})});var m=function(e){return!!(!b.has(e)||r(e).removed)},g={enter:function(e){if(m(e.name.value))return null}};return nD(tl(h,{FragmentSpread:g,FragmentDefinition:g,OperationDefinition:{leave:function(e){if(e.variableDefinitions){var t=p(n(e.name&&e.name.value)).transitiveVars;if(t.size0},t.prototype.tearDownQuery=function(){this.isTornDown||(this.concast&&this.observer&&(this.concast.removeObserver(this.observer),delete this.concast,delete this.observer),this.stopPolling(),this.subscriptions.forEach(function(e){return e.unsubscribe()}),this.subscriptions.clear(),this.queryManager.stopQuery(this.queryId),this.observers.clear(),this.isTornDown=!0)},t}(eT);function n4(e){var t=e.options,n=t.fetchPolicy,r=t.nextFetchPolicy;return"cache-and-network"===n||"network-only"===n?e.reobserve({fetchPolicy:"cache-first",nextFetchPolicy:function(){return(this.nextFetchPolicy=r,"function"==typeof r)?r.apply(this,arguments):n}}):e.reobserve()}function n5(e){__DEV__&&Q.kG.error("Unhandled error",e.message,e.stack)}function n6(e){__DEV__&&e&&__DEV__&&Q.kG.debug("Missing cache result fields: ".concat(JSON.stringify(e)),e)}function n9(e){return"network-only"===e||"no-cache"===e||"standby"===e}nK(n3);function n8(e){return e.kind===nL.h.FIELD||e.kind===nL.h.FRAGMENT_SPREAD||e.kind===nL.h.INLINE_FRAGMENT}function n7(e){return e.kind===Kind.SCALAR_TYPE_DEFINITION||e.kind===Kind.OBJECT_TYPE_DEFINITION||e.kind===Kind.INTERFACE_TYPE_DEFINITION||e.kind===Kind.UNION_TYPE_DEFINITION||e.kind===Kind.ENUM_TYPE_DEFINITION||e.kind===Kind.INPUT_OBJECT_TYPE_DEFINITION}function re(e){return e.kind===Kind.SCALAR_TYPE_EXTENSION||e.kind===Kind.OBJECT_TYPE_EXTENSION||e.kind===Kind.INTERFACE_TYPE_EXTENSION||e.kind===Kind.UNION_TYPE_EXTENSION||e.kind===Kind.ENUM_TYPE_EXTENSION||e.kind===Kind.INPUT_OBJECT_TYPE_EXTENSION}var rt=function(){return Object.create(null)},rn=Array.prototype,rr=rn.forEach,ri=rn.slice,ra=function(){function e(e,t){void 0===e&&(e=!0),void 0===t&&(t=rt),this.weakness=e,this.makeData=t}return e.prototype.lookup=function(){for(var e=[],t=0;tclass{constructor(){this.id=["slot",rc++,Date.now(),Math.random().toString(36).slice(2),].join(":")}hasValue(){for(let e=rs;e;e=e.parent)if(this.id in e.slots){let t=e.slots[this.id];if(t===ru)break;return e!==rs&&(rs.slots[this.id]=t),!0}return rs&&(rs.slots[this.id]=ru),!1}getValue(){if(this.hasValue())return rs.slots[this.id]}withValue(e,t,n,r){let i={__proto__:null,[this.id]:e},a=rs;rs={parent:a,slots:i};try{return t.apply(r,n)}finally{rs=a}}static bind(e){let t=rs;return function(){let n=rs;try{return rs=t,e.apply(this,arguments)}finally{rs=n}}}static noContext(e,t,n){if(!rs)return e.apply(n,t);{let r=rs;try{return rs=null,e.apply(n,t)}finally{rs=r}}}};function rf(e){try{return e()}catch(t){}}let rd="@wry/context:Slot",rh=rf(()=>globalThis)||rf(()=>global)||Object.create(null),rp=rh,rb=rp[rd]||Array[rd]||function(e){try{Object.defineProperty(rp,rd,{value:e,enumerable:!1,writable:!1,configurable:!0})}finally{return e}}(rl()),{bind:rm,noContext:rg}=rb;function rv(){}var ry=function(){function e(e,t){void 0===e&&(e=1/0),void 0===t&&(t=rv),this.max=e,this.dispose=t,this.map=new Map,this.newest=null,this.oldest=null}return e.prototype.has=function(e){return this.map.has(e)},e.prototype.get=function(e){var t=this.getNode(e);return t&&t.value},e.prototype.getNode=function(e){var t=this.map.get(e);if(t&&t!==this.newest){var n=t.older,r=t.newer;r&&(r.older=n),n&&(n.newer=r),t.older=this.newest,t.older.newer=t,t.newer=null,this.newest=t,t===this.oldest&&(this.oldest=r)}return t},e.prototype.set=function(e,t){var n=this.getNode(e);return n?n.value=t:(n={key:e,value:t,newer:null,older:this.newest},this.newest&&(this.newest.newer=n),this.newest=n,this.oldest=this.oldest||n,this.map.set(e,n),n.value)},e.prototype.clean=function(){for(;this.oldest&&this.map.size>this.max;)this.delete(this.oldest.key)},e.prototype.delete=function(e){var t=this.map.get(e);return!!t&&(t===this.newest&&(this.newest=t.older),t===this.oldest&&(this.oldest=t.newer),t.newer&&(t.newer.older=t.older),t.older&&(t.older.newer=t.newer),this.map.delete(e),this.dispose(t.value,e),!0)},e}(),rw=new rb,r_=Object.prototype.hasOwnProperty,rE=void 0===(n=Array.from)?function(e){var t=[];return e.forEach(function(e){return t.push(e)}),t}:n;function rS(e){var t=e.unsubscribe;"function"==typeof t&&(e.unsubscribe=void 0,t())}var rk=[],rx=100;function rT(e,t){if(!e)throw Error(t||"assertion failure")}function rM(e,t){var n=e.length;return n>0&&n===t.length&&e[n-1]===t[n-1]}function rO(e){switch(e.length){case 0:throw Error("unknown value");case 1:return e[0];case 2:throw e[1]}}function rA(e){return e.slice(0)}var rL=function(){function e(t){this.fn=t,this.parents=new Set,this.childValues=new Map,this.dirtyChildren=null,this.dirty=!0,this.recomputing=!1,this.value=[],this.deps=null,++e.count}return e.prototype.peek=function(){if(1===this.value.length&&!rN(this))return rC(this),this.value[0]},e.prototype.recompute=function(e){return rT(!this.recomputing,"already recomputing"),rC(this),rN(this)?rI(this,e):rO(this.value)},e.prototype.setDirty=function(){this.dirty||(this.dirty=!0,this.value.length=0,rR(this),rS(this))},e.prototype.dispose=function(){var e=this;this.setDirty(),rH(this),rF(this,function(t,n){t.setDirty(),r$(t,e)})},e.prototype.forget=function(){this.dispose()},e.prototype.dependOn=function(e){e.add(this),this.deps||(this.deps=rk.pop()||new Set),this.deps.add(e)},e.prototype.forgetDeps=function(){var e=this;this.deps&&(rE(this.deps).forEach(function(t){return t.delete(e)}),this.deps.clear(),rk.push(this.deps),this.deps=null)},e.count=0,e}();function rC(e){var t=rw.getValue();if(t)return e.parents.add(t),t.childValues.has(e)||t.childValues.set(e,[]),rN(e)?rY(t,e):rB(t,e),t}function rI(e,t){return rH(e),rw.withValue(e,rD,[e,t]),rz(e,t)&&rP(e),rO(e.value)}function rD(e,t){e.recomputing=!0,e.value.length=0;try{e.value[0]=e.fn.apply(null,t)}catch(n){e.value[1]=n}e.recomputing=!1}function rN(e){return e.dirty||!!(e.dirtyChildren&&e.dirtyChildren.size)}function rP(e){e.dirty=!1,!rN(e)&&rj(e)}function rR(e){rF(e,rY)}function rj(e){rF(e,rB)}function rF(e,t){var n=e.parents.size;if(n)for(var r=rE(e.parents),i=0;i0&&e.childValues.forEach(function(t,n){r$(e,n)}),e.forgetDeps(),rT(null===e.dirtyChildren)}function r$(e,t){t.parents.delete(e),e.childValues.delete(t),rU(e,t)}function rz(e,t){if("function"==typeof e.subscribe)try{rS(e),e.unsubscribe=e.subscribe.apply(null,t)}catch(n){return e.setDirty(),!1}return!0}var rG={setDirty:!0,dispose:!0,forget:!0};function rW(e){var t=new Map,n=e&&e.subscribe;function r(e){var r=rw.getValue();if(r){var i=t.get(e);i||t.set(e,i=new Set),r.dependOn(i),"function"==typeof n&&(rS(i),i.unsubscribe=n(e))}}return r.dirty=function(e,n){var r=t.get(e);if(r){var i=n&&r_.call(rG,n)?n:"setDirty";rE(r).forEach(function(e){return e[i]()}),t.delete(e),rS(r)}},r}function rK(){var e=new ra("function"==typeof WeakMap);return function(){return e.lookupArray(arguments)}}var rV=rK(),rq=new Set;function rZ(e,t){void 0===t&&(t=Object.create(null));var n=new ry(t.max||65536,function(e){return e.dispose()}),r=t.keyArgs,i=t.makeCacheKey||rK(),a=function(){var a=i.apply(null,r?r.apply(null,arguments):arguments);if(void 0===a)return e.apply(null,arguments);var o=n.get(a);o||(n.set(a,o=new rL(e)),o.subscribe=t.subscribe,o.forget=function(){return n.delete(a)});var s=o.recompute(Array.prototype.slice.call(arguments));return n.set(a,o),rq.add(n),rw.hasValue()||(rq.forEach(function(e){return e.clean()}),rq.clear()),s};function o(e){var t=n.get(e);t&&t.setDirty()}function s(e){var t=n.get(e);if(t)return t.peek()}function u(e){return n.delete(e)}return Object.defineProperty(a,"size",{get:function(){return n.map.size},configurable:!1,enumerable:!1}),a.dirtyKey=o,a.dirty=function(){o(i.apply(null,arguments))},a.peekKey=s,a.peek=function(){return s(i.apply(null,arguments))},a.forgetKey=u,a.forget=function(){return u(i.apply(null,arguments))},a.makeCacheKey=i,a.getKey=r?function(){return i.apply(null,r.apply(null,arguments))}:i,Object.freeze(a)}var rX=new rb,rJ=new WeakMap;function rQ(e){var t=rJ.get(e);return t||rJ.set(e,t={vars:new Set,dep:rW()}),t}function r1(e){rQ(e).vars.forEach(function(t){return t.forgetCache(e)})}function r0(e){rQ(e).vars.forEach(function(t){return t.attachCache(e)})}function r2(e){var t=new Set,n=new Set,r=function(a){if(arguments.length>0){if(e!==a){e=a,t.forEach(function(e){rQ(e).dep.dirty(r),r3(e)});var o=Array.from(n);n.clear(),o.forEach(function(t){return t(e)})}}else{var s=rX.getValue();s&&(i(s),rQ(s).dep(r))}return e};r.onNextChange=function(e){return n.add(e),function(){n.delete(e)}};var i=r.attachCache=function(e){return t.add(e),rQ(e).vars.add(r),r};return r.forgetCache=function(e){return t.delete(e)},r}function r3(e){e.broadcastWatches&&e.broadcastWatches()}var r4=function(){function e(e){var t=e.cache,n=e.client,r=e.resolvers,i=e.fragmentMatcher;this.selectionsToResolveCache=new WeakMap,this.cache=t,n&&(this.client=n),r&&this.addResolvers(r),i&&this.setFragmentMatcher(i)}return e.prototype.addResolvers=function(e){var t=this;this.resolvers=this.resolvers||{},Array.isArray(e)?e.forEach(function(e){t.resolvers=tj(t.resolvers,e)}):this.resolvers=tj(this.resolvers,e)},e.prototype.setResolvers=function(e){this.resolvers={},this.addResolvers(e)},e.prototype.getResolvers=function(){return this.resolvers||{}},e.prototype.runResolvers=function(e){var t=e.document,n=e.remoteResult,r=e.context,i=e.variables,a=e.onlyRunForcedResolvers,o=void 0!==a&&a;return(0,en.mG)(this,void 0,void 0,function(){return(0,en.Jh)(this,function(e){return t?[2,this.resolveDocument(t,n.data,r,i,this.fragmentMatcher,o).then(function(e){return(0,en.pi)((0,en.pi)({},n),{data:e.result})})]:[2,n]})})},e.prototype.setFragmentMatcher=function(e){this.fragmentMatcher=e},e.prototype.getFragmentMatcher=function(){return this.fragmentMatcher},e.prototype.clientQuery=function(e){return tb(["client"],e)&&this.resolvers?e:null},e.prototype.serverQuery=function(e){return n$(e)},e.prototype.prepareContext=function(e){var t=this.cache;return(0,en.pi)((0,en.pi)({},e),{cache:t,getCacheKey:function(e){return t.identify(e)}})},e.prototype.addExportedVariables=function(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),(0,en.mG)(this,void 0,void 0,function(){return(0,en.Jh)(this,function(r){return e?[2,this.resolveDocument(e,this.buildRootValueFromCache(e,t)||{},this.prepareContext(n),t).then(function(e){return(0,en.pi)((0,en.pi)({},t),e.exportedVariables)})]:[2,(0,en.pi)({},t)]})})},e.prototype.shouldForceResolvers=function(e){var t=!1;return tl(e,{Directive:{enter:function(e){if("client"===e.name.value&&e.arguments&&(t=e.arguments.some(function(e){return"always"===e.name.value&&"BooleanValue"===e.value.kind&&!0===e.value.value})))return tc}}}),t},e.prototype.buildRootValueFromCache=function(e,t){return this.cache.diff({query:nH(e),variables:t,returnPartialData:!0,optimistic:!1}).result},e.prototype.resolveDocument=function(e,t,n,r,i,a){return void 0===n&&(n={}),void 0===r&&(r={}),void 0===i&&(i=function(){return!0}),void 0===a&&(a=!1),(0,en.mG)(this,void 0,void 0,function(){var o,s,u,c,l,f,d,h,p,b,m;return(0,en.Jh)(this,function(g){return o=e9(e),s=e4(e),u=eL(s),c=this.collectSelectionsToResolve(o,u),f=(l=o.operation)?l.charAt(0).toUpperCase()+l.slice(1):"Query",d=this,h=d.cache,p=d.client,b={fragmentMap:u,context:(0,en.pi)((0,en.pi)({},n),{cache:h,client:p}),variables:r,fragmentMatcher:i,defaultOperationType:f,exportedVariables:{},selectionsToResolve:c,onlyRunForcedResolvers:a},m=!1,[2,this.resolveSelectionSet(o.selectionSet,m,t,b).then(function(e){return{result:e,exportedVariables:b.exportedVariables}})]})})},e.prototype.resolveSelectionSet=function(e,t,n,r){return(0,en.mG)(this,void 0,void 0,function(){var i,a,o,s,u,c=this;return(0,en.Jh)(this,function(l){return i=r.fragmentMap,a=r.context,o=r.variables,s=[n],u=function(e){return(0,en.mG)(c,void 0,void 0,function(){var u,c;return(0,en.Jh)(this,function(l){return(t||r.selectionsToResolve.has(e))&&td(e,o)?eQ(e)?[2,this.resolveField(e,t,n,r).then(function(t){var n;void 0!==t&&s.push(((n={})[eX(e)]=t,n))})]:(e1(e)?u=e:(u=i[e.name.value],__DEV__?(0,Q.kG)(u,"No fragment named ".concat(e.name.value)):(0,Q.kG)(u,11)),u&&u.typeCondition&&(c=u.typeCondition.name.value,r.fragmentMatcher(n,c,a)))?[2,this.resolveSelectionSet(u.selectionSet,t,n,r).then(function(e){s.push(e)})]:[2]:[2]})})},[2,Promise.all(e.selections.map(u)).then(function(){return tF(s)})]})})},e.prototype.resolveField=function(e,t,n,r){return(0,en.mG)(this,void 0,void 0,function(){var i,a,o,s,u,c,l,f,d,h=this;return(0,en.Jh)(this,function(p){return n?(i=r.variables,a=e.name.value,o=eX(e),s=a!==o,c=Promise.resolve(u=n[o]||n[a]),(!r.onlyRunForcedResolvers||this.shouldForceResolvers(e))&&(l=n.__typename||r.defaultOperationType,(f=this.resolvers&&this.resolvers[l])&&(d=f[s?a:o])&&(c=Promise.resolve(rX.withValue(this.cache,d,[n,eZ(e,i),r.context,{field:e,fragmentMap:r.fragmentMap},])))),[2,c.then(function(n){if(void 0===n&&(n=u),e.directives&&e.directives.forEach(function(e){"export"===e.name.value&&e.arguments&&e.arguments.forEach(function(e){"as"===e.name.value&&"StringValue"===e.value.kind&&(r.exportedVariables[e.value.value]=n)})}),!e.selectionSet||null==n)return n;var i,a,o=null!==(a=null===(i=e.directives)||void 0===i?void 0:i.some(function(e){return"client"===e.name.value}))&&void 0!==a&&a;return Array.isArray(n)?h.resolveSubSelectedArray(e,t||o,n,r):e.selectionSet?h.resolveSelectionSet(e.selectionSet,t||o,n,r):void 0})]):[2,null]})})},e.prototype.resolveSubSelectedArray=function(e,t,n,r){var i=this;return Promise.all(n.map(function(n){return null===n?null:Array.isArray(n)?i.resolveSubSelectedArray(e,t,n,r):e.selectionSet?i.resolveSelectionSet(e.selectionSet,t,n,r):void 0}))},e.prototype.collectSelectionsToResolve=function(e,t){var n=function(e){return!Array.isArray(e)},r=this.selectionsToResolveCache;function i(e){if(!r.has(e)){var a=new Set;r.set(e,a),tl(e,{Directive:function(e,t,r,i,o){"client"===e.name.value&&o.forEach(function(e){n(e)&&n8(e)&&a.add(e)})},FragmentSpread:function(e,r,o,s,u){var c=t[e.name.value];__DEV__?(0,Q.kG)(c,"No fragment named ".concat(e.name.value)):(0,Q.kG)(c,12);var l=i(c);l.size>0&&(u.forEach(function(e){n(e)&&n8(e)&&a.add(e)}),a.add(e),l.forEach(function(e){a.add(e)}))}})}return r.get(e)}return i(e)},e}(),r5=new(t_.mr?WeakMap:Map);function r6(e,t){var n=e[t];"function"==typeof n&&(e[t]=function(){return r5.set(e,(r5.get(e)+1)%1e15),n.apply(this,arguments)})}function r9(e){e.notifyTimeout&&(clearTimeout(e.notifyTimeout),e.notifyTimeout=void 0)}var r8=function(){function e(e,t){void 0===t&&(t=e.generateQueryId()),this.queryId=t,this.listeners=new Set,this.document=null,this.lastRequestId=1,this.subscriptions=new Set,this.stopped=!1,this.dirty=!1,this.observableQuery=null;var n=this.cache=e.cache;r5.has(n)||(r5.set(n,0),r6(n,"evict"),r6(n,"modify"),r6(n,"reset"))}return e.prototype.init=function(e){var t=e.networkStatus||nZ.I.loading;return this.variables&&this.networkStatus!==nZ.I.loading&&!(0,nm.D)(this.variables,e.variables)&&(t=nZ.I.setVariables),(0,nm.D)(e.variables,this.variables)||(this.lastDiff=void 0),Object.assign(this,{document:e.document,variables:e.variables,networkError:null,graphQLErrors:this.graphQLErrors||[],networkStatus:t}),e.observableQuery&&this.setObservableQuery(e.observableQuery),e.lastRequestId&&(this.lastRequestId=e.lastRequestId),this},e.prototype.reset=function(){r9(this),this.dirty=!1},e.prototype.getDiff=function(e){void 0===e&&(e=this.variables);var t=this.getDiffOptions(e);if(this.lastDiff&&(0,nm.D)(t,this.lastDiff.options))return this.lastDiff.diff;this.updateWatch(this.variables=e);var n=this.observableQuery;if(n&&"no-cache"===n.options.fetchPolicy)return{complete:!1};var r=this.cache.diff(t);return this.updateLastDiff(r,t),r},e.prototype.updateLastDiff=function(e,t){this.lastDiff=e?{diff:e,options:t||this.getDiffOptions()}:void 0},e.prototype.getDiffOptions=function(e){var t;return void 0===e&&(e=this.variables),{query:this.document,variables:e,returnPartialData:!0,optimistic:!0,canonizeResults:null===(t=this.observableQuery)||void 0===t?void 0:t.options.canonizeResults}},e.prototype.setDiff=function(e){var t=this,n=this.lastDiff&&this.lastDiff.diff;this.updateLastDiff(e),this.dirty||(0,nm.D)(n&&n.result,e&&e.result)||(this.dirty=!0,this.notifyTimeout||(this.notifyTimeout=setTimeout(function(){return t.notify()},0)))},e.prototype.setObservableQuery=function(e){var t=this;e!==this.observableQuery&&(this.oqListener&&this.listeners.delete(this.oqListener),this.observableQuery=e,e?(e.queryInfo=this,this.listeners.add(this.oqListener=function(){t.getDiff().fromOptimisticTransaction?e.observe():n4(e)})):delete this.oqListener)},e.prototype.notify=function(){var e=this;r9(this),this.shouldNotify()&&this.listeners.forEach(function(t){return t(e)}),this.dirty=!1},e.prototype.shouldNotify=function(){if(!this.dirty||!this.listeners.size)return!1;if((0,nZ.O)(this.networkStatus)&&this.observableQuery){var e=this.observableQuery.options.fetchPolicy;if("cache-only"!==e&&"cache-and-network"!==e)return!1}return!0},e.prototype.stop=function(){if(!this.stopped){this.stopped=!0,this.reset(),this.cancel(),this.cancel=e.prototype.cancel,this.subscriptions.forEach(function(e){return e.unsubscribe()});var t=this.observableQuery;t&&t.stopPolling()}},e.prototype.cancel=function(){},e.prototype.updateWatch=function(e){var t=this;void 0===e&&(e=this.variables);var n=this.observableQuery;if(!n||"no-cache"!==n.options.fetchPolicy){var r=(0,en.pi)((0,en.pi)({},this.getDiffOptions(e)),{watcher:this,callback:function(e){return t.setDiff(e)}});this.lastWatch&&(0,nm.D)(r,this.lastWatch)||(this.cancel(),this.cancel=this.cache.watch(this.lastWatch=r))}},e.prototype.resetLastWrite=function(){this.lastWrite=void 0},e.prototype.shouldWrite=function(e,t){var n=this.lastWrite;return!(n&&n.dmCount===r5.get(this.cache)&&(0,nm.D)(t,n.variables)&&(0,nm.D)(e.data,n.result.data))},e.prototype.markResult=function(e,t,n,r){var i=this,a=new tB,o=(0,tP.O)(e.errors)?e.errors.slice(0):[];if(this.reset(),"incremental"in e&&(0,tP.O)(e.incremental)){var s=tG(this.getDiff().result,e);e.data=s}else if("hasNext"in e&&e.hasNext){var u=this.getDiff();e.data=a.merge(u.result,e.data)}this.graphQLErrors=o,"no-cache"===n.fetchPolicy?this.updateLastDiff({result:e.data,complete:!0},this.getDiffOptions(n.variables)):0!==r&&(r7(e,n.errorPolicy)?this.cache.performTransaction(function(a){if(i.shouldWrite(e,n.variables))a.writeQuery({query:t,data:e.data,variables:n.variables,overwrite:1===r}),i.lastWrite={result:e,variables:n.variables,dmCount:r5.get(i.cache)};else if(i.lastDiff&&i.lastDiff.diff.complete){e.data=i.lastDiff.diff.result;return}var o=i.getDiffOptions(n.variables),s=a.diff(o);i.stopped||i.updateWatch(n.variables),i.updateLastDiff(s,o),s.complete&&(e.data=s.result)}):this.lastWrite=void 0)},e.prototype.markReady=function(){return this.networkError=null,this.networkStatus=nZ.I.ready},e.prototype.markError=function(e){return this.networkStatus=nZ.I.error,this.lastWrite=void 0,this.reset(),e.graphQLErrors&&(this.graphQLErrors=e.graphQLErrors),e.networkError&&(this.networkError=e.networkError),e},e}();function r7(e,t){void 0===t&&(t="none");var n="ignore"===t||"all"===t,r=!nO(e);return!r&&n&&e.data&&(r=!0),r}var ie=Object.prototype.hasOwnProperty,it=function(){function e(e){var t=e.cache,n=e.link,r=e.defaultOptions,i=e.queryDeduplication,a=void 0!==i&&i,o=e.onBroadcast,s=e.ssrMode,u=void 0!==s&&s,c=e.clientAwareness,l=void 0===c?{}:c,f=e.localState,d=e.assumeImmutableResults;this.clientAwareness={},this.queries=new Map,this.fetchCancelFns=new Map,this.transformCache=new(t_.mr?WeakMap:Map),this.queryIdCounter=1,this.requestIdCounter=1,this.mutationIdCounter=1,this.inFlightLinkObservables=new Map,this.cache=t,this.link=n,this.defaultOptions=r||Object.create(null),this.queryDeduplication=a,this.clientAwareness=l,this.localState=f||new r4({cache:t}),this.ssrMode=u,this.assumeImmutableResults=!!d,(this.onBroadcast=o)&&(this.mutationStore=Object.create(null))}return e.prototype.stop=function(){var e=this;this.queries.forEach(function(t,n){e.stopQueryNoBroadcast(n)}),this.cancelPendingFetches(__DEV__?new Q.ej("QueryManager stopped while query was in flight"):new Q.ej(14))},e.prototype.cancelPendingFetches=function(e){this.fetchCancelFns.forEach(function(t){return t(e)}),this.fetchCancelFns.clear()},e.prototype.mutate=function(e){var t,n,r=e.mutation,i=e.variables,a=e.optimisticResponse,o=e.updateQueries,s=e.refetchQueries,u=void 0===s?[]:s,c=e.awaitRefetchQueries,l=void 0!==c&&c,f=e.update,d=e.onQueryUpdated,h=e.fetchPolicy,p=void 0===h?(null===(t=this.defaultOptions.mutate)||void 0===t?void 0:t.fetchPolicy)||"network-only":h,b=e.errorPolicy,m=void 0===b?(null===(n=this.defaultOptions.mutate)||void 0===n?void 0:n.errorPolicy)||"none":b,g=e.keepRootFields,v=e.context;return(0,en.mG)(this,void 0,void 0,function(){var e,t,n,s,c,h;return(0,en.Jh)(this,function(b){switch(b.label){case 0:if(__DEV__?(0,Q.kG)(r,"mutation option is required. You must specify your GraphQL document in the mutation option."):(0,Q.kG)(r,15),__DEV__?(0,Q.kG)("network-only"===p||"no-cache"===p,"Mutations support only 'network-only' or 'no-cache' fetchPolicy strings. The default `network-only` behavior automatically writes mutation results to the cache. Passing `no-cache` skips the cache write."):(0,Q.kG)("network-only"===p||"no-cache"===p,16),e=this.generateMutationId(),n=(t=this.transform(r)).document,s=t.hasClientExports,r=this.cache.transformForLink(n),i=this.getVariables(r,i),!s)return[3,2];return[4,this.localState.addExportedVariables(r,i,v)];case 1:i=b.sent(),b.label=2;case 2:return c=this.mutationStore&&(this.mutationStore[e]={mutation:r,variables:i,loading:!0,error:null}),a&&this.markMutationOptimistic(a,{mutationId:e,document:r,variables:i,fetchPolicy:p,errorPolicy:m,context:v,updateQueries:o,update:f,keepRootFields:g}),this.broadcastQueries(),h=this,[2,new Promise(function(t,n){return nM(h.getObservableFromLink(r,(0,en.pi)((0,en.pi)({},v),{optimisticResponse:a}),i,!1),function(t){if(nO(t)&&"none"===m)throw new tN.cA({graphQLErrors:nA(t)});c&&(c.loading=!1,c.error=null);var n=(0,en.pi)({},t);return"function"==typeof u&&(u=u(n)),"ignore"===m&&nO(n)&&delete n.errors,h.markMutationResult({mutationId:e,result:n,document:r,variables:i,fetchPolicy:p,errorPolicy:m,context:v,update:f,updateQueries:o,awaitRefetchQueries:l,refetchQueries:u,removeOptimistic:a?e:void 0,onQueryUpdated:d,keepRootFields:g})}).subscribe({next:function(e){h.broadcastQueries(),"hasNext"in e&&!1!==e.hasNext||t(e)},error:function(t){c&&(c.loading=!1,c.error=t),a&&h.cache.removeOptimistic(e),h.broadcastQueries(),n(t instanceof tN.cA?t:new tN.cA({networkError:t}))}})})]}})})},e.prototype.markMutationResult=function(e,t){var n=this;void 0===t&&(t=this.cache);var r=e.result,i=[],a="no-cache"===e.fetchPolicy;if(!a&&r7(r,e.errorPolicy)){if(tU(r)||i.push({result:r.data,dataId:"ROOT_MUTATION",query:e.document,variables:e.variables}),tU(r)&&(0,tP.O)(r.incremental)){var o=t.diff({id:"ROOT_MUTATION",query:this.transform(e.document).asQuery,variables:e.variables,optimistic:!1,returnPartialData:!0}),s=void 0;o.result&&(s=tG(o.result,r)),void 0!==s&&(r.data=s,i.push({result:s,dataId:"ROOT_MUTATION",query:e.document,variables:e.variables}))}var u=e.updateQueries;u&&this.queries.forEach(function(e,a){var o=e.observableQuery,s=o&&o.queryName;if(s&&ie.call(u,s)){var c,l=u[s],f=n.queries.get(a),d=f.document,h=f.variables,p=t.diff({query:d,variables:h,returnPartialData:!0,optimistic:!1}),b=p.result;if(p.complete&&b){var m=l(b,{mutationResult:r,queryName:d&&e3(d)||void 0,queryVariables:h});m&&i.push({result:m,dataId:"ROOT_QUERY",query:d,variables:h})}}})}if(i.length>0||e.refetchQueries||e.update||e.onQueryUpdated||e.removeOptimistic){var c=[];if(this.refetchQueries({updateCache:function(t){a||i.forEach(function(e){return t.write(e)});var o=e.update,s=!t$(r)||tU(r)&&!r.hasNext;if(o){if(!a){var u=t.diff({id:"ROOT_MUTATION",query:n.transform(e.document).asQuery,variables:e.variables,optimistic:!1,returnPartialData:!0});u.complete&&("incremental"in(r=(0,en.pi)((0,en.pi)({},r),{data:u.result}))&&delete r.incremental,"hasNext"in r&&delete r.hasNext)}s&&o(t,r,{context:e.context,variables:e.variables})}a||e.keepRootFields||!s||t.modify({id:"ROOT_MUTATION",fields:function(e,t){var n=t.fieldName,r=t.DELETE;return"__typename"===n?e:r}})},include:e.refetchQueries,optimistic:!1,removeOptimistic:e.removeOptimistic,onQueryUpdated:e.onQueryUpdated||null}).forEach(function(e){return c.push(e)}),e.awaitRefetchQueries||e.onQueryUpdated)return Promise.all(c).then(function(){return r})}return Promise.resolve(r)},e.prototype.markMutationOptimistic=function(e,t){var n=this,r="function"==typeof e?e(t.variables):e;return this.cache.recordOptimisticTransaction(function(e){try{n.markMutationResult((0,en.pi)((0,en.pi)({},t),{result:{data:r}}),e)}catch(i){__DEV__&&Q.kG.error(i)}},t.mutationId)},e.prototype.fetchQuery=function(e,t,n){return this.fetchQueryObservable(e,t,n).promise},e.prototype.getQueryStore=function(){var e=Object.create(null);return this.queries.forEach(function(t,n){e[n]={variables:t.variables,networkStatus:t.networkStatus,networkError:t.networkError,graphQLErrors:t.graphQLErrors}}),e},e.prototype.resetErrors=function(e){var t=this.queries.get(e);t&&(t.networkError=void 0,t.graphQLErrors=[])},e.prototype.transform=function(e){var t=this.transformCache;if(!t.has(e)){var n=this.cache.transformDocument(e),r=nY(n),i=this.localState.clientQuery(n),a=r&&this.localState.serverQuery(r),o={document:n,hasClientExports:tm(n),hasForcedResolvers:this.localState.shouldForceResolvers(n),clientQuery:i,serverQuery:a,defaultVars:e8(e2(n)),asQuery:(0,en.pi)((0,en.pi)({},n),{definitions:n.definitions.map(function(e){return"OperationDefinition"===e.kind&&"query"!==e.operation?(0,en.pi)((0,en.pi)({},e),{operation:"query"}):e})})},s=function(e){e&&!t.has(e)&&t.set(e,o)};s(e),s(n),s(i),s(a)}return t.get(e)},e.prototype.getVariables=function(e,t){return(0,en.pi)((0,en.pi)({},this.transform(e).defaultVars),t)},e.prototype.watchQuery=function(e){void 0===(e=(0,en.pi)((0,en.pi)({},e),{variables:this.getVariables(e.query,e.variables)})).notifyOnNetworkStatusChange&&(e.notifyOnNetworkStatusChange=!1);var t=new r8(this),n=new n3({queryManager:this,queryInfo:t,options:e});return this.queries.set(n.queryId,t),t.init({document:n.query,observableQuery:n,variables:n.variables}),n},e.prototype.query=function(e,t){var n=this;return void 0===t&&(t=this.generateQueryId()),__DEV__?(0,Q.kG)(e.query,"query option is required. You must specify your GraphQL document in the query option."):(0,Q.kG)(e.query,17),__DEV__?(0,Q.kG)("Document"===e.query.kind,'You must wrap the query string in a "gql" tag.'):(0,Q.kG)("Document"===e.query.kind,18),__DEV__?(0,Q.kG)(!e.returnPartialData,"returnPartialData option only supported on watchQuery."):(0,Q.kG)(!e.returnPartialData,19),__DEV__?(0,Q.kG)(!e.pollInterval,"pollInterval option only supported on watchQuery."):(0,Q.kG)(!e.pollInterval,20),this.fetchQuery(t,e).finally(function(){return n.stopQuery(t)})},e.prototype.generateQueryId=function(){return String(this.queryIdCounter++)},e.prototype.generateRequestId=function(){return this.requestIdCounter++},e.prototype.generateMutationId=function(){return String(this.mutationIdCounter++)},e.prototype.stopQueryInStore=function(e){this.stopQueryInStoreNoBroadcast(e),this.broadcastQueries()},e.prototype.stopQueryInStoreNoBroadcast=function(e){var t=this.queries.get(e);t&&t.stop()},e.prototype.clearStore=function(e){return void 0===e&&(e={discardWatches:!0}),this.cancelPendingFetches(__DEV__?new Q.ej("Store reset while query was in flight (not completed in link chain)"):new Q.ej(21)),this.queries.forEach(function(e){e.observableQuery?e.networkStatus=nZ.I.loading:e.stop()}),this.mutationStore&&(this.mutationStore=Object.create(null)),this.cache.reset(e)},e.prototype.getObservableQueries=function(e){var t=this;void 0===e&&(e="active");var n=new Map,r=new Map,i=new Set;return Array.isArray(e)&&e.forEach(function(e){"string"==typeof e?r.set(e,!1):eN(e)?r.set(t.transform(e).document,!1):(0,eO.s)(e)&&e.query&&i.add(e)}),this.queries.forEach(function(t,i){var a=t.observableQuery,o=t.document;if(a){if("all"===e){n.set(i,a);return}var s=a.queryName;if("standby"===a.options.fetchPolicy||"active"===e&&!a.hasObservers())return;("active"===e||s&&r.has(s)||o&&r.has(o))&&(n.set(i,a),s&&r.set(s,!0),o&&r.set(o,!0))}}),i.size&&i.forEach(function(e){var r=nG("legacyOneTimeQuery"),i=t.getQuery(r).init({document:e.query,variables:e.variables}),a=new n3({queryManager:t,queryInfo:i,options:(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"network-only"})});(0,Q.kG)(a.queryId===r),i.setObservableQuery(a),n.set(r,a)}),__DEV__&&r.size&&r.forEach(function(e,t){!e&&__DEV__&&Q.kG.warn("Unknown query ".concat("string"==typeof t?"named ":"").concat(JSON.stringify(t,null,2)," requested in refetchQueries options.include array"))}),n},e.prototype.reFetchObservableQueries=function(e){var t=this;void 0===e&&(e=!1);var n=[];return this.getObservableQueries(e?"all":"active").forEach(function(r,i){var a=r.options.fetchPolicy;r.resetLastResults(),(e||"standby"!==a&&"cache-only"!==a)&&n.push(r.refetch()),t.getQuery(i).setDiff(null)}),this.broadcastQueries(),Promise.all(n)},e.prototype.setObservableQuery=function(e){this.getQuery(e.queryId).setObservableQuery(e)},e.prototype.startGraphQLSubscription=function(e){var t=this,n=e.query,r=e.fetchPolicy,i=e.errorPolicy,a=e.variables,o=e.context,s=void 0===o?{}:o;n=this.transform(n).document,a=this.getVariables(n,a);var u=function(e){return t.getObservableFromLink(n,s,e).map(function(a){"no-cache"!==r&&(r7(a,i)&&t.cache.write({query:n,result:a.data,dataId:"ROOT_SUBSCRIPTION",variables:e}),t.broadcastQueries());var o=nO(a),s=(0,tN.ls)(a);if(o||s){var u={};throw o&&(u.graphQLErrors=a.errors),s&&(u.protocolErrors=a.extensions[tN.YG]),new tN.cA(u)}return a})};if(this.transform(n).hasClientExports){var c=this.localState.addExportedVariables(n,a,s).then(u);return new eT(function(e){var t=null;return c.then(function(n){return t=n.subscribe(e)},e.error),function(){return t&&t.unsubscribe()}})}return u(a)},e.prototype.stopQuery=function(e){this.stopQueryNoBroadcast(e),this.broadcastQueries()},e.prototype.stopQueryNoBroadcast=function(e){this.stopQueryInStoreNoBroadcast(e),this.removeQuery(e)},e.prototype.removeQuery=function(e){this.fetchCancelFns.delete(e),this.queries.has(e)&&(this.getQuery(e).stop(),this.queries.delete(e))},e.prototype.broadcastQueries=function(){this.onBroadcast&&this.onBroadcast(),this.queries.forEach(function(e){return e.notify()})},e.prototype.getLocalState=function(){return this.localState},e.prototype.getObservableFromLink=function(e,t,n,r){var i,a,o=this;void 0===r&&(r=null!==(i=null==t?void 0:t.queryDeduplication)&&void 0!==i?i:this.queryDeduplication);var s=this.transform(e).serverQuery;if(s){var u=this,c=u.inFlightLinkObservables,l=u.link,f={query:s,variables:n,operationName:e3(s)||void 0,context:this.prepareContext((0,en.pi)((0,en.pi)({},t),{forceFetch:!r}))};if(t=f.context,r){var d=c.get(s)||new Map;c.set(s,d);var h=nx(n);if(!(a=d.get(h))){var p=new nq([np(l,f)]);d.set(h,a=p),p.beforeNext(function(){d.delete(h)&&d.size<1&&c.delete(s)})}}else a=new nq([np(l,f)])}else a=new nq([eT.of({data:{}})]),t=this.prepareContext(t);var b=this.transform(e).clientQuery;return b&&(a=nM(a,function(e){return o.localState.runResolvers({document:b,remoteResult:e,context:t,variables:n})})),a},e.prototype.getResultsFromLink=function(e,t,n){var r=e.lastRequestId=this.generateRequestId(),i=this.cache.transformForLink(this.transform(e.document).document);return nM(this.getObservableFromLink(i,n.context,n.variables),function(a){var o=nA(a),s=o.length>0;if(r>=e.lastRequestId){if(s&&"none"===n.errorPolicy)throw e.markError(new tN.cA({graphQLErrors:o}));e.markResult(a,i,n,t),e.markReady()}var u={data:a.data,loading:!1,networkStatus:nZ.I.ready};return s&&"ignore"!==n.errorPolicy&&(u.errors=o,u.networkStatus=nZ.I.error),u},function(t){var n=(0,tN.MS)(t)?t:new tN.cA({networkError:t});throw r>=e.lastRequestId&&e.markError(n),n})},e.prototype.fetchQueryObservable=function(e,t,n){return this.fetchConcastWithInfo(e,t,n).concast},e.prototype.fetchConcastWithInfo=function(e,t,n){var r,i,a=this;void 0===n&&(n=nZ.I.loading);var o=this.transform(t.query).document,s=this.getVariables(o,t.variables),u=this.getQuery(e),c=this.defaultOptions.watchQuery,l=t.fetchPolicy,f=void 0===l?c&&c.fetchPolicy||"cache-first":l,d=t.errorPolicy,h=void 0===d?c&&c.errorPolicy||"none":d,p=t.returnPartialData,b=void 0!==p&&p,m=t.notifyOnNetworkStatusChange,g=void 0!==m&&m,v=t.context,y=void 0===v?{}:v,w=Object.assign({},t,{query:o,variables:s,fetchPolicy:f,errorPolicy:h,returnPartialData:b,notifyOnNetworkStatusChange:g,context:y}),_=function(e){w.variables=e;var r=a.fetchQueryByPolicy(u,w,n);return"standby"!==w.fetchPolicy&&r.sources.length>0&&u.observableQuery&&u.observableQuery.applyNextFetchPolicy("after-fetch",t),r},E=function(){return a.fetchCancelFns.delete(e)};if(this.fetchCancelFns.set(e,function(e){E(),setTimeout(function(){return r.cancel(e)})}),this.transform(w.query).hasClientExports)r=new nq(this.localState.addExportedVariables(w.query,w.variables,w.context).then(_).then(function(e){return e.sources})),i=!0;else{var S=_(w.variables);i=S.fromLink,r=new nq(S.sources)}return r.promise.then(E,E),{concast:r,fromLink:i}},e.prototype.refetchQueries=function(e){var t=this,n=e.updateCache,r=e.include,i=e.optimistic,a=void 0!==i&&i,o=e.removeOptimistic,s=void 0===o?a?nG("refetchQueries"):void 0:o,u=e.onQueryUpdated,c=new Map;r&&this.getObservableQueries(r).forEach(function(e,n){c.set(n,{oq:e,lastDiff:t.getQuery(n).getDiff()})});var l=new Map;return n&&this.cache.batch({update:n,optimistic:a&&s||!1,removeOptimistic:s,onWatchUpdated:function(e,t,n){var r=e.watcher instanceof r8&&e.watcher.observableQuery;if(r){if(u){c.delete(r.queryId);var i=u(r,t,n);return!0===i&&(i=r.refetch()),!1!==i&&l.set(r,i),i}null!==u&&c.set(r.queryId,{oq:r,lastDiff:n,diff:t})}}}),c.size&&c.forEach(function(e,n){var r,i=e.oq,a=e.lastDiff,o=e.diff;if(u){if(!o){var s=i.queryInfo;s.reset(),o=s.getDiff()}r=u(i,o,a)}u&&!0!==r||(r=i.refetch()),!1!==r&&l.set(i,r),n.indexOf("legacyOneTimeQuery")>=0&&t.stopQueryNoBroadcast(n)}),s&&this.cache.removeOptimistic(s),l},e.prototype.fetchQueryByPolicy=function(e,t,n){var r=this,i=t.query,a=t.variables,o=t.fetchPolicy,s=t.refetchWritePolicy,u=t.errorPolicy,c=t.returnPartialData,l=t.context,f=t.notifyOnNetworkStatusChange,d=e.networkStatus;e.init({document:this.transform(i).document,variables:a,networkStatus:n});var h=function(){return e.getDiff(a)},p=function(t,n){void 0===n&&(n=e.networkStatus||nZ.I.loading);var o=t.result;!__DEV__||c||(0,nm.D)(o,{})||n6(t.missing);var s=function(e){return eT.of((0,en.pi)({data:e,loading:(0,nZ.O)(n),networkStatus:n},t.complete?null:{partial:!0}))};return o&&r.transform(i).hasForcedResolvers?r.localState.runResolvers({document:i,remoteResult:{data:o},context:l,variables:a,onlyRunForcedResolvers:!0}).then(function(e){return s(e.data||void 0)}):"none"===u&&n===nZ.I.refetch&&Array.isArray(t.missing)?s(void 0):s(o)},b="no-cache"===o?0:n===nZ.I.refetch&&"merge"!==s?1:2,m=function(){return r.getResultsFromLink(e,b,{variables:a,context:l,fetchPolicy:o,errorPolicy:u})},g=f&&"number"==typeof d&&d!==n&&(0,nZ.O)(n);switch(o){default:case"cache-first":var v=h();if(v.complete)return{fromLink:!1,sources:[p(v,e.markReady())]};if(c||g)return{fromLink:!0,sources:[p(v),m()]};return{fromLink:!0,sources:[m()]};case"cache-and-network":var v=h();if(v.complete||c||g)return{fromLink:!0,sources:[p(v),m()]};return{fromLink:!0,sources:[m()]};case"cache-only":return{fromLink:!1,sources:[p(h(),e.markReady())]};case"network-only":if(g)return{fromLink:!0,sources:[p(h()),m()]};return{fromLink:!0,sources:[m()]};case"no-cache":if(g)return{fromLink:!0,sources:[p(e.getDiff()),m(),]};return{fromLink:!0,sources:[m()]};case"standby":return{fromLink:!1,sources:[]}}},e.prototype.getQuery=function(e){return e&&!this.queries.has(e)&&this.queries.set(e,new r8(this,e)),this.queries.get(e)},e.prototype.prepareContext=function(e){void 0===e&&(e={});var t=this.localState.prepareContext(e);return(0,en.pi)((0,en.pi)({},t),{clientAwareness:this.clientAwareness})},e}(),ir=__webpack_require__(14012),ii=!1,ia=function(){function e(e){var t=this;this.resetStoreCallbacks=[],this.clearStoreCallbacks=[];var n=e.uri,r=e.credentials,i=e.headers,a=e.cache,o=e.ssrMode,s=void 0!==o&&o,u=e.ssrForceFetchDelay,c=void 0===u?0:u,l=e.connectToDevTools,f=void 0===l?"object"==typeof window&&!window.__APOLLO_CLIENT__&&__DEV__:l,d=e.queryDeduplication,h=void 0===d||d,p=e.defaultOptions,b=e.assumeImmutableResults,m=void 0!==b&&b,g=e.resolvers,v=e.typeDefs,y=e.fragmentMatcher,w=e.name,_=e.version,E=e.link;if(E||(E=n?new nh({uri:n,credentials:r,headers:i}):ta.empty()),!a)throw __DEV__?new Q.ej("To initialize Apollo Client, you must specify a 'cache' property in the options object. \nFor more information, please visit: https://go.apollo.dev/c/docs"):new Q.ej(9);if(this.link=E,this.cache=a,this.disableNetworkFetches=s||c>0,this.queryDeduplication=h,this.defaultOptions=p||Object.create(null),this.typeDefs=v,c&&setTimeout(function(){return t.disableNetworkFetches=!1},c),this.watchQuery=this.watchQuery.bind(this),this.query=this.query.bind(this),this.mutate=this.mutate.bind(this),this.resetStore=this.resetStore.bind(this),this.reFetchObservableQueries=this.reFetchObservableQueries.bind(this),f&&"object"==typeof window&&(window.__APOLLO_CLIENT__=this),!ii&&f&&__DEV__&&(ii=!0,"undefined"!=typeof window&&window.document&&window.top===window.self&&!window.__APOLLO_DEVTOOLS_GLOBAL_HOOK__)){var S=window.navigator,k=S&&S.userAgent,x=void 0;"string"==typeof k&&(k.indexOf("Chrome/")>-1?x="https://chrome.google.com/webstore/detail/apollo-client-developer-t/jdkknkkbebbapilgoeccciglkfbmbnfm":k.indexOf("Firefox/")>-1&&(x="https://addons.mozilla.org/en-US/firefox/addon/apollo-developer-tools/")),x&&__DEV__&&Q.kG.log("Download the Apollo DevTools for a better development experience: "+x)}this.version=nb,this.localState=new r4({cache:a,client:this,resolvers:g,fragmentMatcher:y}),this.queryManager=new it({cache:this.cache,link:this.link,defaultOptions:this.defaultOptions,queryDeduplication:h,ssrMode:s,clientAwareness:{name:w,version:_},localState:this.localState,assumeImmutableResults:m,onBroadcast:f?function(){t.devToolsHookCb&&t.devToolsHookCb({action:{},state:{queries:t.queryManager.getQueryStore(),mutations:t.queryManager.mutationStore||{}},dataWithOptimisticResults:t.cache.extract(!0)})}:void 0})}return e.prototype.stop=function(){this.queryManager.stop()},e.prototype.watchQuery=function(e){return this.defaultOptions.watchQuery&&(e=(0,ir.J)(this.defaultOptions.watchQuery,e)),this.disableNetworkFetches&&("network-only"===e.fetchPolicy||"cache-and-network"===e.fetchPolicy)&&(e=(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"cache-first"})),this.queryManager.watchQuery(e)},e.prototype.query=function(e){return this.defaultOptions.query&&(e=(0,ir.J)(this.defaultOptions.query,e)),__DEV__?(0,Q.kG)("cache-and-network"!==e.fetchPolicy,"The cache-and-network fetchPolicy does not work with client.query, because client.query can only return a single result. Please use client.watchQuery to receive multiple results from the cache and the network, or consider using a different fetchPolicy, such as cache-first or network-only."):(0,Q.kG)("cache-and-network"!==e.fetchPolicy,10),this.disableNetworkFetches&&"network-only"===e.fetchPolicy&&(e=(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"cache-first"})),this.queryManager.query(e)},e.prototype.mutate=function(e){return this.defaultOptions.mutate&&(e=(0,ir.J)(this.defaultOptions.mutate,e)),this.queryManager.mutate(e)},e.prototype.subscribe=function(e){return this.queryManager.startGraphQLSubscription(e)},e.prototype.readQuery=function(e,t){return void 0===t&&(t=!1),this.cache.readQuery(e,t)},e.prototype.readFragment=function(e,t){return void 0===t&&(t=!1),this.cache.readFragment(e,t)},e.prototype.writeQuery=function(e){var t=this.cache.writeQuery(e);return!1!==e.broadcast&&this.queryManager.broadcastQueries(),t},e.prototype.writeFragment=function(e){var t=this.cache.writeFragment(e);return!1!==e.broadcast&&this.queryManager.broadcastQueries(),t},e.prototype.__actionHookForDevTools=function(e){this.devToolsHookCb=e},e.prototype.__requestRaw=function(e){return np(this.link,e)},e.prototype.resetStore=function(){var e=this;return Promise.resolve().then(function(){return e.queryManager.clearStore({discardWatches:!1})}).then(function(){return Promise.all(e.resetStoreCallbacks.map(function(e){return e()}))}).then(function(){return e.reFetchObservableQueries()})},e.prototype.clearStore=function(){var e=this;return Promise.resolve().then(function(){return e.queryManager.clearStore({discardWatches:!0})}).then(function(){return Promise.all(e.clearStoreCallbacks.map(function(e){return e()}))})},e.prototype.onResetStore=function(e){var t=this;return this.resetStoreCallbacks.push(e),function(){t.resetStoreCallbacks=t.resetStoreCallbacks.filter(function(t){return t!==e})}},e.prototype.onClearStore=function(e){var t=this;return this.clearStoreCallbacks.push(e),function(){t.clearStoreCallbacks=t.clearStoreCallbacks.filter(function(t){return t!==e})}},e.prototype.reFetchObservableQueries=function(e){return this.queryManager.reFetchObservableQueries(e)},e.prototype.refetchQueries=function(e){var t=this.queryManager.refetchQueries(e),n=[],r=[];t.forEach(function(e,t){n.push(t),r.push(e)});var i=Promise.all(r);return i.queries=n,i.results=r,i.catch(function(e){__DEV__&&Q.kG.debug("In client.refetchQueries, Promise.all promise rejected with error ".concat(e))}),i},e.prototype.getObservableQueries=function(e){return void 0===e&&(e="active"),this.queryManager.getObservableQueries(e)},e.prototype.extract=function(e){return this.cache.extract(e)},e.prototype.restore=function(e){return this.cache.restore(e)},e.prototype.addResolvers=function(e){this.localState.addResolvers(e)},e.prototype.setResolvers=function(e){this.localState.setResolvers(e)},e.prototype.getResolvers=function(){return this.localState.getResolvers()},e.prototype.setLocalStateFragmentMatcher=function(e){this.localState.setFragmentMatcher(e)},e.prototype.setLink=function(e){this.link=this.queryManager.link=e},e}(),io=function(){function e(){this.getFragmentDoc=rZ(eA)}return e.prototype.batch=function(e){var t,n=this,r="string"==typeof e.optimistic?e.optimistic:!1===e.optimistic?null:void 0;return this.performTransaction(function(){return t=e.update(n)},r),t},e.prototype.recordOptimisticTransaction=function(e,t){this.performTransaction(e,t)},e.prototype.transformDocument=function(e){return e},e.prototype.transformForLink=function(e){return e},e.prototype.identify=function(e){},e.prototype.gc=function(){return[]},e.prototype.modify=function(e){return!1},e.prototype.readQuery=function(e,t){return void 0===t&&(t=!!e.optimistic),this.read((0,en.pi)((0,en.pi)({},e),{rootId:e.id||"ROOT_QUERY",optimistic:t}))},e.prototype.readFragment=function(e,t){return void 0===t&&(t=!!e.optimistic),this.read((0,en.pi)((0,en.pi)({},e),{query:this.getFragmentDoc(e.fragment,e.fragmentName),rootId:e.id,optimistic:t}))},e.prototype.writeQuery=function(e){var t=e.id,n=e.data,r=(0,en._T)(e,["id","data"]);return this.write(Object.assign(r,{dataId:t||"ROOT_QUERY",result:n}))},e.prototype.writeFragment=function(e){var t=e.id,n=e.data,r=e.fragment,i=e.fragmentName,a=(0,en._T)(e,["id","data","fragment","fragmentName"]);return this.write(Object.assign(a,{query:this.getFragmentDoc(r,i),dataId:t,result:n}))},e.prototype.updateQuery=function(e,t){return this.batch({update:function(n){var r=n.readQuery(e),i=t(r);return null==i?r:(n.writeQuery((0,en.pi)((0,en.pi)({},e),{data:i})),i)}})},e.prototype.updateFragment=function(e,t){return this.batch({update:function(n){var r=n.readFragment(e),i=t(r);return null==i?r:(n.writeFragment((0,en.pi)((0,en.pi)({},e),{data:i})),i)}})},e}(),is=function(e){function t(n,r,i,a){var o,s=e.call(this,n)||this;if(s.message=n,s.path=r,s.query=i,s.variables=a,Array.isArray(s.path)){s.missing=s.message;for(var u=s.path.length-1;u>=0;--u)s.missing=((o={})[s.path[u]]=s.missing,o)}else s.missing=s.path;return s.__proto__=t.prototype,s}return(0,en.ZT)(t,e),t}(Error),iu=__webpack_require__(10542),ic=Object.prototype.hasOwnProperty;function il(e){return null==e}function id(e,t){var n=e.__typename,r=e.id,i=e._id;if("string"==typeof n&&(t&&(t.keyObject=il(r)?il(i)?void 0:{_id:i}:{id:r}),il(r)&&!il(i)&&(r=i),!il(r)))return"".concat(n,":").concat("number"==typeof r||"string"==typeof r?r:JSON.stringify(r))}var ih={dataIdFromObject:id,addTypename:!0,resultCaching:!0,canonizeResults:!1};function ip(e){return(0,n1.o)(ih,e)}function ib(e){var t=e.canonizeResults;return void 0===t?ih.canonizeResults:t}function im(e,t){return eD(t)?e.get(t.__ref,"__typename"):t&&t.__typename}var ig=/^[_a-z][_0-9a-z]*/i;function iv(e){var t=e.match(ig);return t?t[0]:e}function iy(e,t,n){return!!(0,eO.s)(t)&&((0,tP.k)(t)?t.every(function(t){return iy(e,t,n)}):e.selections.every(function(e){if(eQ(e)&&td(e,n)){var r=eX(e);return ic.call(t,r)&&(!e.selectionSet||iy(e.selectionSet,t[r],n))}return!0}))}function iw(e){return(0,eO.s)(e)&&!eD(e)&&!(0,tP.k)(e)}function i_(){return new tB}function iE(e,t){var n=eL(e4(e));return{fragmentMap:n,lookupFragment:function(e){var r=n[e];return!r&&t&&(r=t.lookup(e)),r||null}}}var iS=Object.create(null),ik=function(){return iS},ix=Object.create(null),iT=function(){function e(e,t){var n=this;this.policies=e,this.group=t,this.data=Object.create(null),this.rootIds=Object.create(null),this.refs=Object.create(null),this.getFieldValue=function(e,t){return(0,iu.J)(eD(e)?n.get(e.__ref,t):e&&e[t])},this.canRead=function(e){return eD(e)?n.has(e.__ref):"object"==typeof e},this.toReference=function(e,t){if("string"==typeof e)return eI(e);if(eD(e))return e;var r=n.policies.identify(e)[0];if(r){var i=eI(r);return t&&n.merge(r,e),i}}}return e.prototype.toObject=function(){return(0,en.pi)({},this.data)},e.prototype.has=function(e){return void 0!==this.lookup(e,!0)},e.prototype.get=function(e,t){if(this.group.depend(e,t),ic.call(this.data,e)){var n=this.data[e];if(n&&ic.call(n,t))return n[t]}return"__typename"===t&&ic.call(this.policies.rootTypenamesById,e)?this.policies.rootTypenamesById[e]:this instanceof iL?this.parent.get(e,t):void 0},e.prototype.lookup=function(e,t){return(t&&this.group.depend(e,"__exists"),ic.call(this.data,e))?this.data[e]:this instanceof iL?this.parent.lookup(e,t):this.policies.rootTypenamesById[e]?Object.create(null):void 0},e.prototype.merge=function(e,t){var n,r=this;eD(e)&&(e=e.__ref),eD(t)&&(t=t.__ref);var i="string"==typeof e?this.lookup(n=e):e,a="string"==typeof t?this.lookup(n=t):t;if(a){__DEV__?(0,Q.kG)("string"==typeof n,"store.merge expects a string ID"):(0,Q.kG)("string"==typeof n,1);var o=new tB(iI).merge(i,a);if(this.data[n]=o,o!==i&&(delete this.refs[n],this.group.caching)){var s=Object.create(null);i||(s.__exists=1),Object.keys(a).forEach(function(e){if(!i||i[e]!==o[e]){s[e]=1;var t=iv(e);t===e||r.policies.hasKeyArgs(o.__typename,t)||(s[t]=1),void 0!==o[e]||r instanceof iL||delete o[e]}}),s.__typename&&!(i&&i.__typename)&&this.policies.rootTypenamesById[n]===o.__typename&&delete s.__typename,Object.keys(s).forEach(function(e){return r.group.dirty(n,e)})}}},e.prototype.modify=function(e,t){var n=this,r=this.lookup(e);if(r){var i=Object.create(null),a=!1,o=!0,s={DELETE:iS,INVALIDATE:ix,isReference:eD,toReference:this.toReference,canRead:this.canRead,readField:function(t,r){return n.policies.readField("string"==typeof t?{fieldName:t,from:r||eI(e)}:t,{store:n})}};if(Object.keys(r).forEach(function(u){var c=iv(u),l=r[u];if(void 0!==l){var f="function"==typeof t?t:t[u]||t[c];if(f){var d=f===ik?iS:f((0,iu.J)(l),(0,en.pi)((0,en.pi)({},s),{fieldName:c,storeFieldName:u,storage:n.getStorage(e,u)}));d===ix?n.group.dirty(e,u):(d===iS&&(d=void 0),d!==l&&(i[u]=d,a=!0,l=d))}void 0!==l&&(o=!1)}}),a)return this.merge(e,i),o&&(this instanceof iL?this.data[e]=void 0:delete this.data[e],this.group.dirty(e,"__exists")),!0}return!1},e.prototype.delete=function(e,t,n){var r,i=this.lookup(e);if(i){var a=this.getFieldValue(i,"__typename"),o=t&&n?this.policies.getStoreFieldName({typename:a,fieldName:t,args:n}):t;return this.modify(e,o?((r={})[o]=ik,r):ik)}return!1},e.prototype.evict=function(e,t){var n=!1;return e.id&&(ic.call(this.data,e.id)&&(n=this.delete(e.id,e.fieldName,e.args)),this instanceof iL&&this!==t&&(n=this.parent.evict(e,t)||n),(e.fieldName||n)&&this.group.dirty(e.id,e.fieldName||"__exists")),n},e.prototype.clear=function(){this.replace(null)},e.prototype.extract=function(){var e=this,t=this.toObject(),n=[];return this.getRootIdSet().forEach(function(t){ic.call(e.policies.rootTypenamesById,t)||n.push(t)}),n.length&&(t.__META={extraRootIds:n.sort()}),t},e.prototype.replace=function(e){var t=this;if(Object.keys(this.data).forEach(function(n){e&&ic.call(e,n)||t.delete(n)}),e){var n=e.__META,r=(0,en._T)(e,["__META"]);Object.keys(r).forEach(function(e){t.merge(e,r[e])}),n&&n.extraRootIds.forEach(this.retain,this)}},e.prototype.retain=function(e){return this.rootIds[e]=(this.rootIds[e]||0)+1},e.prototype.release=function(e){if(this.rootIds[e]>0){var t=--this.rootIds[e];return t||delete this.rootIds[e],t}return 0},e.prototype.getRootIdSet=function(e){return void 0===e&&(e=new Set),Object.keys(this.rootIds).forEach(e.add,e),this instanceof iL?this.parent.getRootIdSet(e):Object.keys(this.policies.rootTypenamesById).forEach(e.add,e),e},e.prototype.gc=function(){var e=this,t=this.getRootIdSet(),n=this.toObject();t.forEach(function(r){ic.call(n,r)&&(Object.keys(e.findChildRefIds(r)).forEach(t.add,t),delete n[r])});var r=Object.keys(n);if(r.length){for(var i=this;i instanceof iL;)i=i.parent;r.forEach(function(e){return i.delete(e)})}return r},e.prototype.findChildRefIds=function(e){if(!ic.call(this.refs,e)){var t=this.refs[e]=Object.create(null),n=this.data[e];if(!n)return t;var r=new Set([n]);r.forEach(function(e){eD(e)&&(t[e.__ref]=!0),(0,eO.s)(e)&&Object.keys(e).forEach(function(t){var n=e[t];(0,eO.s)(n)&&r.add(n)})})}return this.refs[e]},e.prototype.makeCacheKey=function(){return this.group.keyMaker.lookupArray(arguments)},e}(),iM=function(){function e(e,t){void 0===t&&(t=null),this.caching=e,this.parent=t,this.d=null,this.resetCaching()}return e.prototype.resetCaching=function(){this.d=this.caching?rW():null,this.keyMaker=new n_(t_.mr)},e.prototype.depend=function(e,t){if(this.d){this.d(iO(e,t));var n=iv(t);n!==t&&this.d(iO(e,n)),this.parent&&this.parent.depend(e,t)}},e.prototype.dirty=function(e,t){this.d&&this.d.dirty(iO(e,t),"__exists"===t?"forget":"setDirty")},e}();function iO(e,t){return t+"#"+e}function iA(e,t){iD(e)&&e.group.depend(t,"__exists")}!function(e){var t=function(e){function t(t){var n=t.policies,r=t.resultCaching,i=void 0===r||r,a=t.seed,o=e.call(this,n,new iM(i))||this;return o.stump=new iC(o),o.storageTrie=new n_(t_.mr),a&&o.replace(a),o}return(0,en.ZT)(t,e),t.prototype.addLayer=function(e,t){return this.stump.addLayer(e,t)},t.prototype.removeLayer=function(){return this},t.prototype.getStorage=function(){return this.storageTrie.lookupArray(arguments)},t}(e);e.Root=t}(iT||(iT={}));var iL=function(e){function t(t,n,r,i){var a=e.call(this,n.policies,i)||this;return a.id=t,a.parent=n,a.replay=r,a.group=i,r(a),a}return(0,en.ZT)(t,e),t.prototype.addLayer=function(e,n){return new t(e,this,n,this.group)},t.prototype.removeLayer=function(e){var t=this,n=this.parent.removeLayer(e);return e===this.id?(this.group.caching&&Object.keys(this.data).forEach(function(e){var r=t.data[e],i=n.lookup(e);i?r?r!==i&&Object.keys(r).forEach(function(n){(0,nm.D)(r[n],i[n])||t.group.dirty(e,n)}):(t.group.dirty(e,"__exists"),Object.keys(i).forEach(function(n){t.group.dirty(e,n)})):t.delete(e)}),n):n===this.parent?this:n.addLayer(this.id,this.replay)},t.prototype.toObject=function(){return(0,en.pi)((0,en.pi)({},this.parent.toObject()),this.data)},t.prototype.findChildRefIds=function(t){var n=this.parent.findChildRefIds(t);return ic.call(this.data,t)?(0,en.pi)((0,en.pi)({},n),e.prototype.findChildRefIds.call(this,t)):n},t.prototype.getStorage=function(){for(var e=this.parent;e.parent;)e=e.parent;return e.getStorage.apply(e,arguments)},t}(iT),iC=function(e){function t(t){return e.call(this,"EntityStore.Stump",t,function(){},new iM(t.group.caching,t.group))||this}return(0,en.ZT)(t,e),t.prototype.removeLayer=function(){return this},t.prototype.merge=function(){return this.parent.merge.apply(this.parent,arguments)},t}(iL);function iI(e,t,n){var r=e[n],i=t[n];return(0,nm.D)(r,i)?r:i}function iD(e){return!!(e instanceof iT&&e.group.caching)}function iN(e){return[e.selectionSet,e.objectOrReference,e.context,e.context.canonizeResults,]}var iP=function(){function e(e){var t=this;this.knownResults=new(t_.mr?WeakMap:Map),this.config=(0,n1.o)(e,{addTypename:!1!==e.addTypename,canonizeResults:ib(e)}),this.canon=e.canon||new nk,this.executeSelectionSet=rZ(function(e){var n,r=e.context.canonizeResults,i=iN(e);i[3]=!r;var a=(n=t.executeSelectionSet).peek.apply(n,i);return a?r?(0,en.pi)((0,en.pi)({},a),{result:t.canon.admit(a.result)}):a:(iA(e.context.store,e.enclosingRef.__ref),t.execSelectionSetImpl(e))},{max:this.config.resultCacheMaxSize,keyArgs:iN,makeCacheKey:function(e,t,n,r){if(iD(n.store))return n.store.makeCacheKey(e,eD(t)?t.__ref:t,n.varString,r)}}),this.executeSubSelectedArray=rZ(function(e){return iA(e.context.store,e.enclosingRef.__ref),t.execSubSelectedArrayImpl(e)},{max:this.config.resultCacheMaxSize,makeCacheKey:function(e){var t=e.field,n=e.array,r=e.context;if(iD(r.store))return r.store.makeCacheKey(t,n,r.varString)}})}return e.prototype.resetCanon=function(){this.canon=new nk},e.prototype.diffQueryAgainstStore=function(e){var t,n=e.store,r=e.query,i=e.rootId,a=void 0===i?"ROOT_QUERY":i,o=e.variables,s=e.returnPartialData,u=void 0===s||s,c=e.canonizeResults,l=void 0===c?this.config.canonizeResults:c,f=this.config.cache.policies;o=(0,en.pi)((0,en.pi)({},e8(e5(r))),o);var d=eI(a),h=this.executeSelectionSet({selectionSet:e9(r).selectionSet,objectOrReference:d,enclosingRef:d,context:(0,en.pi)({store:n,query:r,policies:f,variables:o,varString:nx(o),canonizeResults:l},iE(r,this.config.fragments))});if(h.missing&&(t=[new is(iR(h.missing),h.missing,r,o)],!u))throw t[0];return{result:h.result,complete:!t,missing:t}},e.prototype.isFresh=function(e,t,n,r){if(iD(r.store)&&this.knownResults.get(e)===n){var i=this.executeSelectionSet.peek(n,t,r,this.canon.isKnown(e));if(i&&e===i.result)return!0}return!1},e.prototype.execSelectionSetImpl=function(e){var t,n=this,r=e.selectionSet,i=e.objectOrReference,a=e.enclosingRef,o=e.context;if(eD(i)&&!o.policies.rootTypenamesById[i.__ref]&&!o.store.has(i.__ref))return{result:this.canon.empty,missing:"Dangling reference to missing ".concat(i.__ref," object")};var s=o.variables,u=o.policies,c=o.store.getFieldValue(i,"__typename"),l=[],f=new tB;function d(e,n){var r;return e.missing&&(t=f.merge(t,((r={})[n]=e.missing,r))),e.result}this.config.addTypename&&"string"==typeof c&&!u.rootIdsByTypename[c]&&l.push({__typename:c});var h=new Set(r.selections);h.forEach(function(e){var r,p;if(td(e,s)){if(eQ(e)){var b=u.readField({fieldName:e.name.value,field:e,variables:o.variables,from:i},o),m=eX(e);void 0===b?nj.added(e)||(t=f.merge(t,((r={})[m]="Can't find field '".concat(e.name.value,"' on ").concat(eD(i)?i.__ref+" object":"object "+JSON.stringify(i,null,2)),r))):(0,tP.k)(b)?b=d(n.executeSubSelectedArray({field:e,array:b,enclosingRef:a,context:o}),m):e.selectionSet?null!=b&&(b=d(n.executeSelectionSet({selectionSet:e.selectionSet,objectOrReference:b,enclosingRef:eD(b)?b:a,context:o}),m)):o.canonizeResults&&(b=n.canon.pass(b)),void 0!==b&&l.push(((p={})[m]=b,p))}else{var g=eC(e,o.lookupFragment);if(!g&&e.kind===nL.h.FRAGMENT_SPREAD)throw __DEV__?new Q.ej("No fragment named ".concat(e.name.value)):new Q.ej(5);g&&u.fragmentMatches(g,c)&&g.selectionSet.selections.forEach(h.add,h)}}});var p={result:tF(l),missing:t},b=o.canonizeResults?this.canon.admit(p):(0,iu.J)(p);return b.result&&this.knownResults.set(b.result,r),b},e.prototype.execSubSelectedArrayImpl=function(e){var t,n=this,r=e.field,i=e.array,a=e.enclosingRef,o=e.context,s=new tB;function u(e,n){var r;return e.missing&&(t=s.merge(t,((r={})[n]=e.missing,r))),e.result}return r.selectionSet&&(i=i.filter(o.store.canRead)),i=i.map(function(e,t){return null===e?null:(0,tP.k)(e)?u(n.executeSubSelectedArray({field:r,array:e,enclosingRef:a,context:o}),t):r.selectionSet?u(n.executeSelectionSet({selectionSet:r.selectionSet,objectOrReference:e,enclosingRef:eD(e)?e:a,context:o}),t):(__DEV__&&ij(o.store,r,e),e)}),{result:o.canonizeResults?this.canon.admit(i):i,missing:t}},e}();function iR(e){try{JSON.stringify(e,function(e,t){if("string"==typeof t)throw t;return t})}catch(t){return t}}function ij(e,t,n){if(!t.selectionSet){var r=new Set([n]);r.forEach(function(n){(0,eO.s)(n)&&(__DEV__?(0,Q.kG)(!eD(n),"Missing selection set for object of type ".concat(im(e,n)," returned for query field ").concat(t.name.value)):(0,Q.kG)(!eD(n),6),Object.values(n).forEach(r.add,r))})}}function iF(e){var t=nG("stringifyForDisplay");return JSON.stringify(e,function(e,n){return void 0===n?t:n}).split(JSON.stringify(t)).join("")}var iY=Object.create(null);function iB(e){var t=JSON.stringify(e);return iY[t]||(iY[t]=Object.create(null))}function iU(e){var t=iB(e);return t.keyFieldsFn||(t.keyFieldsFn=function(t,n){var r=function(e,t){return n.readField(t,e)},i=n.keyObject=i$(e,function(e){var i=iW(n.storeObject,e,r);return void 0===i&&t!==n.storeObject&&ic.call(t,e[0])&&(i=iW(t,e,iG)),__DEV__?(0,Q.kG)(void 0!==i,"Missing field '".concat(e.join("."),"' while extracting keyFields from ").concat(JSON.stringify(t))):(0,Q.kG)(void 0!==i,2),i});return"".concat(n.typename,":").concat(JSON.stringify(i))})}function iH(e){var t=iB(e);return t.keyArgsFn||(t.keyArgsFn=function(t,n){var r=n.field,i=n.variables,a=n.fieldName,o=JSON.stringify(i$(e,function(e){var n=e[0],a=n.charAt(0);if("@"===a){if(r&&(0,tP.O)(r.directives)){var o=n.slice(1),s=r.directives.find(function(e){return e.name.value===o}),u=s&&eZ(s,i);return u&&iW(u,e.slice(1))}return}if("$"===a){var c=n.slice(1);if(i&&ic.call(i,c)){var l=e.slice(0);return l[0]=c,iW(i,l)}return}if(t)return iW(t,e)}));return(t||"{}"!==o)&&(a+=":"+o),a})}function i$(e,t){var n=new tB;return iz(e).reduce(function(e,r){var i,a=t(r);if(void 0!==a){for(var o=r.length-1;o>=0;--o)a=((i={})[r[o]]=a,i);e=n.merge(e,a)}return e},Object.create(null))}function iz(e){var t=iB(e);if(!t.paths){var n=t.paths=[],r=[];e.forEach(function(t,i){(0,tP.k)(t)?(iz(t).forEach(function(e){return n.push(r.concat(e))}),r.length=0):(r.push(t),(0,tP.k)(e[i+1])||(n.push(r.slice(0)),r.length=0))})}return t.paths}function iG(e,t){return e[t]}function iW(e,t,n){return n=n||iG,iK(t.reduce(function e(t,r){return(0,tP.k)(t)?t.map(function(t){return e(t,r)}):t&&n(t,r)},e))}function iK(e){return(0,eO.s)(e)?(0,tP.k)(e)?e.map(iK):i$(Object.keys(e).sort(),function(t){return iW(e,t)}):e}function iV(e){return void 0!==e.args?e.args:e.field?eZ(e.field,e.variables):null}eK.setStringify(nx);var iq=function(){},iZ=function(e,t){return t.fieldName},iX=function(e,t,n){return(0,n.mergeObjects)(e,t)},iJ=function(e,t){return t},iQ=function(){function e(e){this.config=e,this.typePolicies=Object.create(null),this.toBeAdded=Object.create(null),this.supertypeMap=new Map,this.fuzzySubtypes=new Map,this.rootIdsByTypename=Object.create(null),this.rootTypenamesById=Object.create(null),this.usingPossibleTypes=!1,this.config=(0,en.pi)({dataIdFromObject:id},e),this.cache=this.config.cache,this.setRootTypename("Query"),this.setRootTypename("Mutation"),this.setRootTypename("Subscription"),e.possibleTypes&&this.addPossibleTypes(e.possibleTypes),e.typePolicies&&this.addTypePolicies(e.typePolicies)}return e.prototype.identify=function(e,t){var n,r,i=this,a=t&&(t.typename||(null===(n=t.storeObject)||void 0===n?void 0:n.__typename))||e.__typename;if(a===this.rootTypenamesById.ROOT_QUERY)return["ROOT_QUERY"];for(var o=t&&t.storeObject||e,s=(0,en.pi)((0,en.pi)({},t),{typename:a,storeObject:o,readField:t&&t.readField||function(){var e=i0(arguments,o);return i.readField(e,{store:i.cache.data,variables:e.variables})}}),u=a&&this.getTypePolicy(a),c=u&&u.keyFn||this.config.dataIdFromObject;c;){var l=c((0,en.pi)((0,en.pi)({},e),o),s);if((0,tP.k)(l))c=iU(l);else{r=l;break}}return r=r?String(r):void 0,s.keyObject?[r,s.keyObject]:[r]},e.prototype.addTypePolicies=function(e){var t=this;Object.keys(e).forEach(function(n){var r=e[n],i=r.queryType,a=r.mutationType,o=r.subscriptionType,s=(0,en._T)(r,["queryType","mutationType","subscriptionType"]);i&&t.setRootTypename("Query",n),a&&t.setRootTypename("Mutation",n),o&&t.setRootTypename("Subscription",n),ic.call(t.toBeAdded,n)?t.toBeAdded[n].push(s):t.toBeAdded[n]=[s]})},e.prototype.updateTypePolicy=function(e,t){var n=this,r=this.getTypePolicy(e),i=t.keyFields,a=t.fields;function o(e,t){e.merge="function"==typeof t?t:!0===t?iX:!1===t?iJ:e.merge}o(r,t.merge),r.keyFn=!1===i?iq:(0,tP.k)(i)?iU(i):"function"==typeof i?i:r.keyFn,a&&Object.keys(a).forEach(function(t){var r=n.getFieldPolicy(e,t,!0),i=a[t];if("function"==typeof i)r.read=i;else{var s=i.keyArgs,u=i.read,c=i.merge;r.keyFn=!1===s?iZ:(0,tP.k)(s)?iH(s):"function"==typeof s?s:r.keyFn,"function"==typeof u&&(r.read=u),o(r,c)}r.read&&r.merge&&(r.keyFn=r.keyFn||iZ)})},e.prototype.setRootTypename=function(e,t){void 0===t&&(t=e);var n="ROOT_"+e.toUpperCase(),r=this.rootTypenamesById[n];t!==r&&(__DEV__?(0,Q.kG)(!r||r===e,"Cannot change root ".concat(e," __typename more than once")):(0,Q.kG)(!r||r===e,3),r&&delete this.rootIdsByTypename[r],this.rootIdsByTypename[t]=n,this.rootTypenamesById[n]=t)},e.prototype.addPossibleTypes=function(e){var t=this;this.usingPossibleTypes=!0,Object.keys(e).forEach(function(n){t.getSupertypeSet(n,!0),e[n].forEach(function(e){t.getSupertypeSet(e,!0).add(n);var r=e.match(ig);r&&r[0]===e||t.fuzzySubtypes.set(e,RegExp(e))})})},e.prototype.getTypePolicy=function(e){var t=this;if(!ic.call(this.typePolicies,e)){var n=this.typePolicies[e]=Object.create(null);n.fields=Object.create(null);var r=this.supertypeMap.get(e);r&&r.size&&r.forEach(function(e){var r=t.getTypePolicy(e),i=r.fields;Object.assign(n,(0,en._T)(r,["fields"])),Object.assign(n.fields,i)})}var i=this.toBeAdded[e];return i&&i.length&&i.splice(0).forEach(function(n){t.updateTypePolicy(e,n)}),this.typePolicies[e]},e.prototype.getFieldPolicy=function(e,t,n){if(e){var r=this.getTypePolicy(e).fields;return r[t]||n&&(r[t]=Object.create(null))}},e.prototype.getSupertypeSet=function(e,t){var n=this.supertypeMap.get(e);return!n&&t&&this.supertypeMap.set(e,n=new Set),n},e.prototype.fragmentMatches=function(e,t,n,r){var i=this;if(!e.typeCondition)return!0;if(!t)return!1;var a=e.typeCondition.name.value;if(t===a)return!0;if(this.usingPossibleTypes&&this.supertypeMap.has(a))for(var o=this.getSupertypeSet(t,!0),s=[o],u=function(e){var t=i.getSupertypeSet(e,!1);t&&t.size&&0>s.indexOf(t)&&s.push(t)},c=!!(n&&this.fuzzySubtypes.size),l=!1,f=0;f1?a:t}:(r=(0,en.pi)({},i),ic.call(r,"from")||(r.from=t)),__DEV__&&void 0===r.from&&__DEV__&&Q.kG.warn("Undefined 'from' passed to readField with arguments ".concat(iF(Array.from(e)))),void 0===r.variables&&(r.variables=n),r}function i2(e){return function(t,n){if((0,tP.k)(t)||(0,tP.k)(n))throw __DEV__?new Q.ej("Cannot automatically merge arrays"):new Q.ej(4);if((0,eO.s)(t)&&(0,eO.s)(n)){var r=e.getFieldValue(t,"__typename"),i=e.getFieldValue(n,"__typename");if(r&&i&&r!==i)return n;if(eD(t)&&iw(n))return e.merge(t.__ref,n),t;if(iw(t)&&eD(n))return e.merge(t,n.__ref),n;if(iw(t)&&iw(n))return(0,en.pi)((0,en.pi)({},t),n)}return n}}function i3(e,t,n){var r="".concat(t).concat(n),i=e.flavors.get(r);return i||e.flavors.set(r,i=e.clientOnly===t&&e.deferred===n?e:(0,en.pi)((0,en.pi)({},e),{clientOnly:t,deferred:n})),i}var i4=function(){function e(e,t,n){this.cache=e,this.reader=t,this.fragments=n}return e.prototype.writeToStore=function(e,t){var n=this,r=t.query,i=t.result,a=t.dataId,o=t.variables,s=t.overwrite,u=e2(r),c=i_();o=(0,en.pi)((0,en.pi)({},e8(u)),o);var l=(0,en.pi)((0,en.pi)({store:e,written:Object.create(null),merge:function(e,t){return c.merge(e,t)},variables:o,varString:nx(o)},iE(r,this.fragments)),{overwrite:!!s,incomingById:new Map,clientOnly:!1,deferred:!1,flavors:new Map}),f=this.processSelectionSet({result:i||Object.create(null),dataId:a,selectionSet:u.selectionSet,mergeTree:{map:new Map},context:l});if(!eD(f))throw __DEV__?new Q.ej("Could not identify object ".concat(JSON.stringify(i))):new Q.ej(7);return l.incomingById.forEach(function(t,r){var i=t.storeObject,a=t.mergeTree,o=t.fieldNodeSet,s=eI(r);if(a&&a.map.size){var u=n.applyMerges(a,s,i,l);if(eD(u))return;i=u}if(__DEV__&&!l.overwrite){var c=Object.create(null);o.forEach(function(e){e.selectionSet&&(c[e.name.value]=!0)});var f=function(e){return!0===c[iv(e)]},d=function(e){var t=a&&a.map.get(e);return Boolean(t&&t.info&&t.info.merge)};Object.keys(i).forEach(function(e){f(e)&&!d(e)&&at(s,i,e,l.store)})}e.merge(r,i)}),e.retain(f.__ref),f},e.prototype.processSelectionSet=function(e){var t=this,n=e.dataId,r=e.result,i=e.selectionSet,a=e.context,o=e.mergeTree,s=this.cache.policies,u=Object.create(null),c=n&&s.rootTypenamesById[n]||eJ(r,i,a.fragmentMap)||n&&a.store.get(n,"__typename");"string"==typeof c&&(u.__typename=c);var l=function(){var e=i0(arguments,u,a.variables);if(eD(e.from)){var t=a.incomingById.get(e.from.__ref);if(t){var n=s.readField((0,en.pi)((0,en.pi)({},e),{from:t.storeObject}),a);if(void 0!==n)return n}}return s.readField(e,a)},f=new Set;this.flattenFields(i,r,a,c).forEach(function(e,n){var i,a=r[eX(n)];if(f.add(n),void 0!==a){var d=s.getStoreFieldName({typename:c,fieldName:n.name.value,field:n,variables:e.variables}),h=i6(o,d),p=t.processFieldValue(a,n,n.selectionSet?i3(e,!1,!1):e,h),b=void 0;n.selectionSet&&(eD(p)||iw(p))&&(b=l("__typename",p));var m=s.getMergeFunction(c,n.name.value,b);m?h.info={field:n,typename:c,merge:m}:i7(o,d),u=e.merge(u,((i={})[d]=p,i))}else __DEV__&&!e.clientOnly&&!e.deferred&&!nj.added(n)&&!s.getReadFunction(c,n.name.value)&&__DEV__&&Q.kG.error("Missing field '".concat(eX(n),"' while writing result ").concat(JSON.stringify(r,null,2)).substring(0,1e3))});try{var d=s.identify(r,{typename:c,selectionSet:i,fragmentMap:a.fragmentMap,storeObject:u,readField:l}),h=d[0],p=d[1];n=n||h,p&&(u=a.merge(u,p))}catch(b){if(!n)throw b}if("string"==typeof n){var m=eI(n),g=a.written[n]||(a.written[n]=[]);if(g.indexOf(i)>=0||(g.push(i),this.reader&&this.reader.isFresh(r,m,i,a)))return m;var v=a.incomingById.get(n);return v?(v.storeObject=a.merge(v.storeObject,u),v.mergeTree=i9(v.mergeTree,o),f.forEach(function(e){return v.fieldNodeSet.add(e)})):a.incomingById.set(n,{storeObject:u,mergeTree:i8(o)?void 0:o,fieldNodeSet:f}),m}return u},e.prototype.processFieldValue=function(e,t,n,r){var i=this;return t.selectionSet&&null!==e?(0,tP.k)(e)?e.map(function(e,a){var o=i.processFieldValue(e,t,n,i6(r,a));return i7(r,a),o}):this.processSelectionSet({result:e,selectionSet:t.selectionSet,context:n,mergeTree:r}):__DEV__?nJ(e):e},e.prototype.flattenFields=function(e,t,n,r){void 0===r&&(r=eJ(t,e,n.fragmentMap));var i=new Map,a=this.cache.policies,o=new n_(!1);return function e(s,u){var c=o.lookup(s,u.clientOnly,u.deferred);c.visited||(c.visited=!0,s.selections.forEach(function(o){if(td(o,n.variables)){var s=u.clientOnly,c=u.deferred;if(!(s&&c)&&(0,tP.O)(o.directives)&&o.directives.forEach(function(e){var t=e.name.value;if("client"===t&&(s=!0),"defer"===t){var r=eZ(e,n.variables);r&&!1===r.if||(c=!0)}}),eQ(o)){var l=i.get(o);l&&(s=s&&l.clientOnly,c=c&&l.deferred),i.set(o,i3(n,s,c))}else{var f=eC(o,n.lookupFragment);if(!f&&o.kind===nL.h.FRAGMENT_SPREAD)throw __DEV__?new Q.ej("No fragment named ".concat(o.name.value)):new Q.ej(8);f&&a.fragmentMatches(f,r,t,n.variables)&&e(f.selectionSet,i3(n,s,c))}}}))}(e,n),i},e.prototype.applyMerges=function(e,t,n,r,i){var a=this;if(e.map.size&&!eD(n)){var o,s,u=!(0,tP.k)(n)&&(eD(t)||iw(t))?t:void 0,c=n;u&&!i&&(i=[eD(u)?u.__ref:u]);var l=function(e,t){return(0,tP.k)(e)?"number"==typeof t?e[t]:void 0:r.store.getFieldValue(e,String(t))};e.map.forEach(function(e,t){var n=l(u,t),o=l(c,t);if(void 0!==o){i&&i.push(t);var f=a.applyMerges(e,n,o,r,i);f!==o&&(s=s||new Map).set(t,f),i&&(0,Q.kG)(i.pop()===t)}}),s&&(n=(0,tP.k)(c)?c.slice(0):(0,en.pi)({},c),s.forEach(function(e,t){n[t]=e}))}return e.info?this.cache.policies.runMergeFunction(t,n,e.info,r,i&&(o=r.store).getStorage.apply(o,i)):n},e}(),i5=[];function i6(e,t){var n=e.map;return n.has(t)||n.set(t,i5.pop()||{map:new Map}),n.get(t)}function i9(e,t){if(e===t||!t||i8(t))return e;if(!e||i8(e))return t;var n=e.info&&t.info?(0,en.pi)((0,en.pi)({},e.info),t.info):e.info||t.info,r=e.map.size&&t.map.size,i=r?new Map:e.map.size?e.map:t.map,a={info:n,map:i};if(r){var o=new Set(t.map.keys());e.map.forEach(function(e,n){a.map.set(n,i9(e,t.map.get(n))),o.delete(n)}),o.forEach(function(n){a.map.set(n,i9(t.map.get(n),e.map.get(n)))})}return a}function i8(e){return!e||!(e.info||e.map.size)}function i7(e,t){var n=e.map,r=n.get(t);r&&i8(r)&&(i5.push(r),n.delete(t))}var ae=new Set;function at(e,t,n,r){var i=function(e){var t=r.getFieldValue(e,n);return"object"==typeof t&&t},a=i(e);if(a){var o=i(t);if(!(!o||eD(a)||(0,nm.D)(a,o)||Object.keys(a).every(function(e){return void 0!==r.getFieldValue(o,e)}))){var s=r.getFieldValue(e,"__typename")||r.getFieldValue(t,"__typename"),u=iv(n),c="".concat(s,".").concat(u);if(!ae.has(c)){ae.add(c);var l=[];(0,tP.k)(a)||(0,tP.k)(o)||[a,o].forEach(function(e){var t=r.getFieldValue(e,"__typename");"string"!=typeof t||l.includes(t)||l.push(t)}),__DEV__&&Q.kG.warn("Cache data may be lost when replacing the ".concat(u," field of a ").concat(s," object.\n\nThis could cause additional (usually avoidable) network requests to fetch data that were otherwise cached.\n\nTo address this problem (which is not a bug in Apollo Client), ").concat(l.length?"either ensure all objects of type "+l.join(" and ")+" have an ID or a custom merge function, or ":"","define a custom merge function for the ").concat(c," field, so InMemoryCache can safely merge these objects:\n\n existing: ").concat(JSON.stringify(a).slice(0,1e3),"\n incoming: ").concat(JSON.stringify(o).slice(0,1e3),"\n\nFor more information about these options, please refer to the documentation:\n\n * Ensuring entity objects have IDs: https://go.apollo.dev/c/generating-unique-identifiers\n * Defining custom merge functions: https://go.apollo.dev/c/merging-non-normalized-objects\n"))}}}}var an=function(e){function t(t){void 0===t&&(t={});var n=e.call(this)||this;return n.watches=new Set,n.typenameDocumentCache=new Map,n.makeVar=r2,n.txCount=0,n.config=ip(t),n.addTypename=!!n.config.addTypename,n.policies=new iQ({cache:n,dataIdFromObject:n.config.dataIdFromObject,possibleTypes:n.config.possibleTypes,typePolicies:n.config.typePolicies}),n.init(),n}return(0,en.ZT)(t,e),t.prototype.init=function(){var e=this.data=new iT.Root({policies:this.policies,resultCaching:this.config.resultCaching});this.optimisticData=e.stump,this.resetResultCache()},t.prototype.resetResultCache=function(e){var t=this,n=this.storeReader,r=this.config.fragments;this.storeWriter=new i4(this,this.storeReader=new iP({cache:this,addTypename:this.addTypename,resultCacheMaxSize:this.config.resultCacheMaxSize,canonizeResults:ib(this.config),canon:e?void 0:n&&n.canon,fragments:r}),r),this.maybeBroadcastWatch=rZ(function(e,n){return t.broadcastWatch(e,n)},{max:this.config.resultCacheMaxSize,makeCacheKey:function(e){var n=e.optimistic?t.optimisticData:t.data;if(iD(n)){var r=e.optimistic,i=e.id,a=e.variables;return n.makeCacheKey(e.query,e.callback,nx({optimistic:r,id:i,variables:a}))}}}),new Set([this.data.group,this.optimisticData.group,]).forEach(function(e){return e.resetCaching()})},t.prototype.restore=function(e){return this.init(),e&&this.data.replace(e),this},t.prototype.extract=function(e){return void 0===e&&(e=!1),(e?this.optimisticData:this.data).extract()},t.prototype.read=function(e){var t=e.returnPartialData,n=void 0!==t&&t;try{return this.storeReader.diffQueryAgainstStore((0,en.pi)((0,en.pi)({},e),{store:e.optimistic?this.optimisticData:this.data,config:this.config,returnPartialData:n})).result||null}catch(r){if(r instanceof is)return null;throw r}},t.prototype.write=function(e){try{return++this.txCount,this.storeWriter.writeToStore(this.data,e)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.modify=function(e){if(ic.call(e,"id")&&!e.id)return!1;var t=e.optimistic?this.optimisticData:this.data;try{return++this.txCount,t.modify(e.id||"ROOT_QUERY",e.fields)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.diff=function(e){return this.storeReader.diffQueryAgainstStore((0,en.pi)((0,en.pi)({},e),{store:e.optimistic?this.optimisticData:this.data,rootId:e.id||"ROOT_QUERY",config:this.config}))},t.prototype.watch=function(e){var t=this;return this.watches.size||r0(this),this.watches.add(e),e.immediate&&this.maybeBroadcastWatch(e),function(){t.watches.delete(e)&&!t.watches.size&&r1(t),t.maybeBroadcastWatch.forget(e)}},t.prototype.gc=function(e){nx.reset();var t=this.optimisticData.gc();return e&&!this.txCount&&(e.resetResultCache?this.resetResultCache(e.resetResultIdentities):e.resetResultIdentities&&this.storeReader.resetCanon()),t},t.prototype.retain=function(e,t){return(t?this.optimisticData:this.data).retain(e)},t.prototype.release=function(e,t){return(t?this.optimisticData:this.data).release(e)},t.prototype.identify=function(e){if(eD(e))return e.__ref;try{return this.policies.identify(e)[0]}catch(t){__DEV__&&Q.kG.warn(t)}},t.prototype.evict=function(e){if(!e.id){if(ic.call(e,"id"))return!1;e=(0,en.pi)((0,en.pi)({},e),{id:"ROOT_QUERY"})}try{return++this.txCount,this.optimisticData.evict(e,this.data)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.reset=function(e){var t=this;return this.init(),nx.reset(),e&&e.discardWatches?(this.watches.forEach(function(e){return t.maybeBroadcastWatch.forget(e)}),this.watches.clear(),r1(this)):this.broadcastWatches(),Promise.resolve()},t.prototype.removeOptimistic=function(e){var t=this.optimisticData.removeLayer(e);t!==this.optimisticData&&(this.optimisticData=t,this.broadcastWatches())},t.prototype.batch=function(e){var t,n=this,r=e.update,i=e.optimistic,a=void 0===i||i,o=e.removeOptimistic,s=e.onWatchUpdated,u=function(e){var i=n,a=i.data,o=i.optimisticData;++n.txCount,e&&(n.data=n.optimisticData=e);try{return t=r(n)}finally{--n.txCount,n.data=a,n.optimisticData=o}},c=new Set;return s&&!this.txCount&&this.broadcastWatches((0,en.pi)((0,en.pi)({},e),{onWatchUpdated:function(e){return c.add(e),!1}})),"string"==typeof a?this.optimisticData=this.optimisticData.addLayer(a,u):!1===a?u(this.data):u(),"string"==typeof o&&(this.optimisticData=this.optimisticData.removeLayer(o)),s&&c.size?(this.broadcastWatches((0,en.pi)((0,en.pi)({},e),{onWatchUpdated:function(e,t){var n=s.call(this,e,t);return!1!==n&&c.delete(e),n}})),c.size&&c.forEach(function(e){return n.maybeBroadcastWatch.dirty(e)})):this.broadcastWatches(e),t},t.prototype.performTransaction=function(e,t){return this.batch({update:e,optimistic:t||null!==t})},t.prototype.transformDocument=function(e){if(this.addTypename){var t=this.typenameDocumentCache.get(e);return t||(t=nj(e),this.typenameDocumentCache.set(e,t),this.typenameDocumentCache.set(t,t)),t}return e},t.prototype.transformForLink=function(e){var t=this.config.fragments;return t?t.transform(e):e},t.prototype.broadcastWatches=function(e){var t=this;this.txCount||this.watches.forEach(function(n){return t.maybeBroadcastWatch(n,e)})},t.prototype.broadcastWatch=function(e,t){var n=e.lastDiff,r=this.diff(e);(!t||(e.optimistic&&"string"==typeof t.optimistic&&(r.fromOptimisticTransaction=!0),!t.onWatchUpdated||!1!==t.onWatchUpdated.call(this,e,r,n)))&&(n&&(0,nm.D)(n.result,r.result)||e.callback(e.lastDiff=r,n))},t}(io),ar={possibleTypes:{ApproveJobProposalSpecPayload:["ApproveJobProposalSpecSuccess","JobAlreadyExistsError","NotFoundError"],BridgePayload:["Bridge","NotFoundError"],CancelJobProposalSpecPayload:["CancelJobProposalSpecSuccess","NotFoundError"],ChainPayload:["Chain","NotFoundError"],CreateAPITokenPayload:["CreateAPITokenSuccess","InputErrors"],CreateBridgePayload:["CreateBridgeSuccess"],CreateCSAKeyPayload:["CSAKeyExistsError","CreateCSAKeySuccess"],CreateFeedsManagerChainConfigPayload:["CreateFeedsManagerChainConfigSuccess","InputErrors","NotFoundError"],CreateFeedsManagerPayload:["CreateFeedsManagerSuccess","InputErrors","NotFoundError","SingleFeedsManagerError"],CreateJobPayload:["CreateJobSuccess","InputErrors"],CreateOCR2KeyBundlePayload:["CreateOCR2KeyBundleSuccess"],CreateOCRKeyBundlePayload:["CreateOCRKeyBundleSuccess"],CreateP2PKeyPayload:["CreateP2PKeySuccess"],DeleteAPITokenPayload:["DeleteAPITokenSuccess","InputErrors"],DeleteBridgePayload:["DeleteBridgeConflictError","DeleteBridgeInvalidNameError","DeleteBridgeSuccess","NotFoundError"],DeleteCSAKeyPayload:["DeleteCSAKeySuccess","NotFoundError"],DeleteFeedsManagerChainConfigPayload:["DeleteFeedsManagerChainConfigSuccess","NotFoundError"],DeleteJobPayload:["DeleteJobSuccess","NotFoundError"],DeleteOCR2KeyBundlePayload:["DeleteOCR2KeyBundleSuccess","NotFoundError"],DeleteOCRKeyBundlePayload:["DeleteOCRKeyBundleSuccess","NotFoundError"],DeleteP2PKeyPayload:["DeleteP2PKeySuccess","NotFoundError"],DeleteVRFKeyPayload:["DeleteVRFKeySuccess","NotFoundError"],DismissJobErrorPayload:["DismissJobErrorSuccess","NotFoundError"],Error:["CSAKeyExistsError","DeleteBridgeConflictError","DeleteBridgeInvalidNameError","InputError","JobAlreadyExistsError","NotFoundError","RunJobCannotRunError","SingleFeedsManagerError"],EthTransactionPayload:["EthTransaction","NotFoundError"],FeaturesPayload:["Features"],FeedsManagerPayload:["FeedsManager","NotFoundError"],GetSQLLoggingPayload:["SQLLogging"],GlobalLogLevelPayload:["GlobalLogLevel"],JobPayload:["Job","NotFoundError"],JobProposalPayload:["JobProposal","NotFoundError"],JobRunPayload:["JobRun","NotFoundError"],JobSpec:["BlockHeaderFeederSpec","BlockhashStoreSpec","BootstrapSpec","CronSpec","DirectRequestSpec","FluxMonitorSpec","GatewaySpec","KeeperSpec","OCR2Spec","OCRSpec","VRFSpec","WebhookSpec"],NodePayload:["Node","NotFoundError"],PaginatedPayload:["BridgesPayload","ChainsPayload","EthTransactionAttemptsPayload","EthTransactionsPayload","JobRunsPayload","JobsPayload","NodesPayload"],RejectJobProposalSpecPayload:["NotFoundError","RejectJobProposalSpecSuccess"],RunJobPayload:["NotFoundError","RunJobCannotRunError","RunJobSuccess"],SetGlobalLogLevelPayload:["InputErrors","SetGlobalLogLevelSuccess"],SetSQLLoggingPayload:["SetSQLLoggingSuccess"],SetServicesLogLevelsPayload:["InputErrors","SetServicesLogLevelsSuccess"],UpdateBridgePayload:["NotFoundError","UpdateBridgeSuccess"],UpdateFeedsManagerChainConfigPayload:["InputErrors","NotFoundError","UpdateFeedsManagerChainConfigSuccess"],UpdateFeedsManagerPayload:["InputErrors","NotFoundError","UpdateFeedsManagerSuccess"],UpdateJobProposalSpecDefinitionPayload:["NotFoundError","UpdateJobProposalSpecDefinitionSuccess"],UpdatePasswordPayload:["InputErrors","UpdatePasswordSuccess"],VRFKeyPayload:["NotFoundError","VRFKeySuccess"]}};let ai=ar;var aa=(r=void 0,location.origin),ao=new nh({uri:"".concat(aa,"/query"),credentials:"include"}),as=new ia({cache:new an({possibleTypes:ai.possibleTypes}),link:ao});if(a.Z.locale(o),u().defaultFormat="YYYY-MM-DD h:mm:ss A","undefined"!=typeof document){var au,ac,al=f().hydrate;ac=X,al(c.createElement(et,{client:as},c.createElement(d.zj,null,c.createElement(i.MuiThemeProvider,{theme:J.r},c.createElement(ac,null)))),document.getElementById("root"))}})()})(); \ No newline at end of file +`+(a!==i?`result of cast: ${a}`:""))}return r}_cast(e,t){let n=void 0===e?e:this.transforms.reduce((t,n)=>n.call(this,t,e,this),e);return void 0===n&&(n=this.getDefault()),n}_validate(e,t={},n){let{sync:r,path:i,from:a=[],originalValue:o=e,strict:s=this.spec.strict,abortEarly:u=this.spec.abortEarly}=t,c=e;s||(c=this._cast(c,pU({assert:!1},t)));let l={value:c,path:i,options:t,originalValue:o,schema:this,label:this.spec.label,sync:r,from:a},f=[];this._typeError&&f.push(this._typeError),this._whitelistError&&f.push(this._whitelistError),this._blacklistError&&f.push(this._blacklistError),pA({args:l,value:c,path:i,sync:r,tests:f,endEarly:u},e=>{if(e)return void n(e,c);pA({tests:this.tests,args:l,path:i,sync:r,value:c,endEarly:u},n)})}validate(e,t,n){let r=this.resolve(pU({},t,{value:e}));return"function"==typeof n?r._validate(e,t,n):new Promise((n,i)=>r._validate(e,t,(e,t)=>{e?i(e):n(t)}))}validateSync(e,t){let n;return this.resolve(pU({},t,{value:e}))._validate(e,pU({},t,{sync:!0}),(e,t)=>{if(e)throw e;n=t}),n}isValid(e,t){return this.validate(e,t).then(()=>!0,e=>{if(pM.isError(e))return!1;throw e})}isValidSync(e,t){try{return this.validateSync(e,t),!0}catch(n){if(pM.isError(n))return!1;throw n}}_getDefault(){let e=this.spec.default;return null==e?e:"function"==typeof e?e.call(this):pr(e)}getDefault(e){return this.resolve(e||{})._getDefault()}default(e){return 0===arguments.length?this._getDefault():this.clone({default:e})}strict(e=!0){var t=this.clone();return t.spec.strict=e,t}_isPresent(e){return null!=e}defined(e=pd.defined){return this.test({message:e,name:"defined",exclusive:!0,test:e=>void 0!==e})}required(e=pd.required){return this.clone({presence:"required"}).withMutation(t=>t.test({message:e,name:"required",exclusive:!0,test(e){return this.schema._isPresent(e)}}))}notRequired(){var e=this.clone({presence:"optional"});return e.tests=e.tests.filter(e=>"required"!==e.OPTIONS.name),e}nullable(e=!0){return this.clone({nullable:!1!==e})}transform(e){var t=this.clone();return t.transforms.push(e),t}test(...e){let t;if(void 0===(t=1===e.length?"function"==typeof e[0]?{test:e[0]}:e[0]:2===e.length?{name:e[0],test:e[1]}:{name:e[0],message:e[1],test:e[2]}).message&&(t.message=pd.default),"function"!=typeof t.test)throw TypeError("`test` is a required parameters");let n=this.clone(),r=pj(t),i=t.exclusive||t.name&&!0===n.exclusiveTests[t.name];if(t.exclusive&&!t.name)throw TypeError("Exclusive tests must provide a unique `name` identifying the test");return t.name&&(n.exclusiveTests[t.name]=!!t.exclusive),n.tests=n.tests.filter(e=>e.OPTIONS.name!==t.name||!i&&e.OPTIONS.test!==r.OPTIONS.test),n.tests.push(r),n}when(e,t){Array.isArray(e)||"string"==typeof e||(t=e,e=".");let n=this.clone(),r=pk(e).map(e=>new pN(e));return r.forEach(e=>{e.isSibling&&n.deps.push(e.key)}),n.conditions.push(new pS(r,t)),n}typeError(e){var t=this.clone();return t._typeError=pj({message:e,name:"typeError",test(e){return!!(void 0===e||this.schema.isType(e))||this.createError({params:{type:this.schema._type}})}}),t}oneOf(e,t=pd.oneOf){var n=this.clone();return e.forEach(e=>{n._whitelist.add(e),n._blacklist.delete(e)}),n._whitelistError=pj({message:t,name:"oneOf",test(e){if(void 0===e)return!0;let t=this.schema._whitelist;return!!t.has(e,this.resolve)||this.createError({params:{values:t.toArray().join(", ")}})}}),n}notOneOf(e,t=pd.notOneOf){var n=this.clone();return e.forEach(e=>{n._blacklist.add(e),n._whitelist.delete(e)}),n._blacklistError=pj({message:t,name:"notOneOf",test(e){let t=this.schema._blacklist;return!t.has(e,this.resolve)||this.createError({params:{values:t.toArray().join(", ")}})}}),n}strip(e=!0){let t=this.clone();return t.spec.strip=e,t}describe(){let e=this.clone(),{label:t,meta:n}=e.spec,r={meta:n,label:t,type:e.type,oneOf:e._whitelist.describe(),notOneOf:e._blacklist.describe(),tests:e.tests.map(e=>({name:e.OPTIONS.name,params:e.OPTIONS.params})).filter((e,t,n)=>n.findIndex(t=>t.name===e.name)===t)};return r}}for(let p$ of(pH.prototype.__isYupSchema__=!0,["validate","validateSync"]))pH.prototype[`${p$}At`]=function(e,t,n={}){let{parent:r,parentPath:i,schema:a}=pY(this,e,t,n.context);return a[p$](r&&r[i],pU({},n,{parent:r,path:e}))};for(let pz of["equals","is"])pH.prototype[pz]=pH.prototype.oneOf;for(let pG of["not","nope"])pH.prototype[pG]=pH.prototype.notOneOf;pH.prototype.optional=pH.prototype.notRequired;let pW=pH;function pK(){return new pW}pK.prototype=pW.prototype;let pV=e=>null==e;function pq(){return new pZ}class pZ extends pH{constructor(){super({type:"boolean"}),this.withMutation(()=>{this.transform(function(e){if(!this.isType(e)){if(/^(true|1)$/i.test(String(e)))return!0;if(/^(false|0)$/i.test(String(e)))return!1}return e})})}_typeCheck(e){return e instanceof Boolean&&(e=e.valueOf()),"boolean"==typeof e}isTrue(e=pm.isValue){return this.test({message:e,name:"is-value",exclusive:!0,params:{value:"true"},test:e=>pV(e)||!0===e})}isFalse(e=pm.isValue){return this.test({message:e,name:"is-value",exclusive:!0,params:{value:"false"},test:e=>pV(e)||!1===e})}}pq.prototype=pZ.prototype;let pX=/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i,pJ=/^((https?|ftp):)?\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i,pQ=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i,p1=e=>pV(e)||e===e.trim(),p0=({}).toString();function p2(){return new p3}class p3 extends pH{constructor(){super({type:"string"}),this.withMutation(()=>{this.transform(function(e){if(this.isType(e)||Array.isArray(e))return e;let t=null!=e&&e.toString?e.toString():e;return t===p0?e:t})})}_typeCheck(e){return e instanceof String&&(e=e.valueOf()),"string"==typeof e}_isPresent(e){return super._isPresent(e)&&!!e.length}length(e,t=ph.length){return this.test({message:t,name:"length",exclusive:!0,params:{length:e},test(t){return pV(t)||t.length===this.resolve(e)}})}min(e,t=ph.min){return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t.length>=this.resolve(e)}})}max(e,t=ph.max){return this.test({name:"max",exclusive:!0,message:t,params:{max:e},test(t){return pV(t)||t.length<=this.resolve(e)}})}matches(e,t){let n=!1,r,i;return t&&("object"==typeof t?{excludeEmptyString:n=!1,message:r,name:i}=t:r=t),this.test({name:i||"matches",message:r||ph.matches,params:{regex:e},test:t=>pV(t)||""===t&&n||-1!==t.search(e)})}email(e=ph.email){return this.matches(pX,{name:"email",message:e,excludeEmptyString:!0})}url(e=ph.url){return this.matches(pJ,{name:"url",message:e,excludeEmptyString:!0})}uuid(e=ph.uuid){return this.matches(pQ,{name:"uuid",message:e,excludeEmptyString:!1})}ensure(){return this.default("").transform(e=>null===e?"":e)}trim(e=ph.trim){return this.transform(e=>null!=e?e.trim():e).test({message:e,name:"trim",test:p1})}lowercase(e=ph.lowercase){return this.transform(e=>pV(e)?e:e.toLowerCase()).test({message:e,name:"string_case",exclusive:!0,test:e=>pV(e)||e===e.toLowerCase()})}uppercase(e=ph.uppercase){return this.transform(e=>pV(e)?e:e.toUpperCase()).test({message:e,name:"string_case",exclusive:!0,test:e=>pV(e)||e===e.toUpperCase()})}}p2.prototype=p3.prototype;let p4=e=>e!=+e;function p5(){return new p6}class p6 extends pH{constructor(){super({type:"number"}),this.withMutation(()=>{this.transform(function(e){let t=e;if("string"==typeof t){if(""===(t=t.replace(/\s/g,"")))return NaN;t=+t}return this.isType(t)?t:parseFloat(t)})})}_typeCheck(e){return e instanceof Number&&(e=e.valueOf()),"number"==typeof e&&!p4(e)}min(e,t=pp.min){return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t>=this.resolve(e)}})}max(e,t=pp.max){return this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(t){return pV(t)||t<=this.resolve(e)}})}lessThan(e,t=pp.lessThan){return this.test({message:t,name:"max",exclusive:!0,params:{less:e},test(t){return pV(t)||tthis.resolve(e)}})}positive(e=pp.positive){return this.moreThan(0,e)}negative(e=pp.negative){return this.lessThan(0,e)}integer(e=pp.integer){return this.test({name:"integer",message:e,test:e=>pV(e)||Number.isInteger(e)})}truncate(){return this.transform(e=>pV(e)?e:0|e)}round(e){var t,n=["ceil","floor","round","trunc"];if("trunc"===(e=(null==(t=e)?void 0:t.toLowerCase())||"round"))return this.truncate();if(-1===n.indexOf(e.toLowerCase()))throw TypeError("Only valid options for round() are: "+n.join(", "));return this.transform(t=>pV(t)?t:Math[e](t))}}p5.prototype=p6.prototype;var p9=/^(\d{4}|[+\-]\d{6})(?:-?(\d{2})(?:-?(\d{2}))?)?(?:[ T]?(\d{2}):?(\d{2})(?::?(\d{2})(?:[,\.](\d{1,}))?)?(?:(Z)|([+\-])(\d{2})(?::?(\d{2}))?)?)?$/;function p8(e){var t,n,r=[1,4,5,6,7,10,11],i=0;if(n=p9.exec(e)){for(var a,o=0;a=r[o];++o)n[a]=+n[a]||0;n[2]=(+n[2]||1)-1,n[3]=+n[3]||1,n[7]=n[7]?String(n[7]).substr(0,3):0,(void 0===n[8]||""===n[8])&&(void 0===n[9]||""===n[9])?t=+new Date(n[1],n[2],n[3],n[4],n[5],n[6],n[7]):("Z"!==n[8]&&void 0!==n[9]&&(i=60*n[10]+n[11],"+"===n[9]&&(i=0-i)),t=Date.UTC(n[1],n[2],n[3],n[4],n[5]+i,n[6],n[7]))}else t=Date.parse?Date.parse(e):NaN;return t}let p7=new Date(""),be=e=>"[object Date]"===Object.prototype.toString.call(e);function bt(){return new bn}class bn extends pH{constructor(){super({type:"date"}),this.withMutation(()=>{this.transform(function(e){return this.isType(e)?e:(e=p8(e),isNaN(e)?p7:new Date(e))})})}_typeCheck(e){return be(e)&&!isNaN(e.getTime())}prepareParam(e,t){let n;if(pN.isRef(e))n=e;else{let r=this.cast(e);if(!this._typeCheck(r))throw TypeError(`\`${t}\` must be a Date or a value that can be \`cast()\` to a Date`);n=r}return n}min(e,t=pb.min){let n=this.prepareParam(e,"min");return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(e){return pV(e)||e>=this.resolve(n)}})}max(e,t=pb.max){var n=this.prepareParam(e,"max");return this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(e){return pV(e)||e<=this.resolve(n)}})}}bn.INVALID_DATE=p7,bt.prototype=bn.prototype,bt.INVALID_DATE=p7;var br=n(11865),bi=n.n(br),ba=n(68929),bo=n.n(ba),bs=n(67523),bu=n.n(bs),bc=n(94633),bl=n.n(bc);function bf(e,t=[]){let n=[],r=[];function i(e,i){var a=(0,pI.split)(e)[0];~r.indexOf(a)||r.push(a),~t.indexOf(`${i}-${a}`)||n.push([i,a])}for(let a in e)if(pw()(e,a)){let o=e[a];~r.indexOf(a)||r.push(a),pN.isRef(o)&&o.isSibling?i(o.path,a):p_(o)&&"deps"in o&&o.deps.forEach(e=>i(e,a))}return bl().array(r,n).reverse()}function bd(e,t){let n=1/0;return e.some((e,r)=>{var i;if((null==(i=t.path)?void 0:i.indexOf(e))!==-1)return n=r,!0}),n}function bh(e){return(t,n)=>bd(e,t)-bd(e,n)}function bp(){return(bp=Object.assign||function(e){for(var t=1;t"[object Object]"===Object.prototype.toString.call(e);function bm(e,t){let n=Object.keys(e.fields);return Object.keys(t).filter(e=>-1===n.indexOf(e))}let bg=bh([]);class bv extends pH{constructor(e){super({type:"object"}),this.fields=Object.create(null),this._sortErrors=bg,this._nodes=[],this._excludedEdges=[],this.withMutation(()=>{this.transform(function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(t){e=null}return this.isType(e)?e:null}),e&&this.shape(e)})}_typeCheck(e){return bb(e)||"function"==typeof e}_cast(e,t={}){var n;let r=super._cast(e,t);if(void 0===r)return this.getDefault();if(!this._typeCheck(r))return r;let i=this.fields,a=null!=(n=t.stripUnknown)?n:this.spec.noUnknown,o=this._nodes.concat(Object.keys(r).filter(e=>-1===this._nodes.indexOf(e))),s={},u=bp({},t,{parent:s,__validating:t.__validating||!1}),c=!1;for(let l of o){let f=i[l],d=pw()(r,l);if(f){let h,p=r[l];u.path=(t.path?`${t.path}.`:"")+l;let b="spec"in(f=f.resolve({value:p,context:t.context,parent:s}))?f.spec:void 0,m=null==b?void 0:b.strict;if(null==b?void 0:b.strip){c=c||l in r;continue}void 0!==(h=t.__validating&&m?r[l]:f.cast(r[l],u))&&(s[l]=h)}else d&&!a&&(s[l]=r[l]);s[l]!==r[l]&&(c=!0)}return c?s:r}_validate(e,t={},n){let r=[],{sync:i,from:a=[],originalValue:o=e,abortEarly:s=this.spec.abortEarly,recursive:u=this.spec.recursive}=t;a=[{schema:this,value:o},...a],t.__validating=!0,t.originalValue=o,t.from=a,super._validate(e,t,(e,c)=>{if(e){if(!pM.isError(e)||s)return void n(e,c);r.push(e)}if(!u||!bb(c)){n(r[0]||null,c);return}o=o||c;let l=this._nodes.map(e=>(n,r)=>{let i=-1===e.indexOf(".")?(t.path?`${t.path}.`:"")+e:`${t.path||""}["${e}"]`,s=this.fields[e];if(s&&"validate"in s){s.validate(c[e],bp({},t,{path:i,from:a,strict:!0,parent:c,originalValue:o[e]}),r);return}r(null)});pA({sync:i,tests:l,value:c,errors:r,endEarly:s,sort:this._sortErrors,path:t.path},n)})}clone(e){let t=super.clone(e);return t.fields=bp({},this.fields),t._nodes=this._nodes,t._excludedEdges=this._excludedEdges,t._sortErrors=this._sortErrors,t}concat(e){let t=super.concat(e),n=t.fields;for(let[r,i]of Object.entries(this.fields)){let a=n[r];void 0===a?n[r]=i:a instanceof pH&&i instanceof pH&&(n[r]=i.concat(a))}return t.withMutation(()=>t.shape(n))}getDefaultFromShape(){let e={};return this._nodes.forEach(t=>{let n=this.fields[t];e[t]="default"in n?n.getDefault():void 0}),e}_getDefault(){return"default"in this.spec?super._getDefault():this._nodes.length?this.getDefaultFromShape():void 0}shape(e,t=[]){let n=this.clone(),r=Object.assign(n.fields,e);if(n.fields=r,n._sortErrors=bh(Object.keys(r)),t.length){Array.isArray(t[0])||(t=[t]);let i=t.map(([e,t])=>`${e}-${t}`);n._excludedEdges=n._excludedEdges.concat(i)}return n._nodes=bf(r,n._excludedEdges),n}pick(e){let t={};for(let n of e)this.fields[n]&&(t[n]=this.fields[n]);return this.clone().withMutation(e=>(e.fields={},e.shape(t)))}omit(e){let t=this.clone(),n=t.fields;for(let r of(t.fields={},e))delete n[r];return t.withMutation(()=>t.shape(n))}from(e,t,n){let r=(0,pI.getter)(e,!0);return this.transform(i=>{if(null==i)return i;let a=i;return pw()(i,e)&&(a=bp({},i),n||delete a[e],a[t]=r(i)),a})}noUnknown(e=!0,t=pg.noUnknown){"string"==typeof e&&(t=e,e=!0);let n=this.test({name:"noUnknown",exclusive:!0,message:t,test(t){if(null==t)return!0;let n=bm(this.schema,t);return!e||0===n.length||this.createError({params:{unknown:n.join(", ")}})}});return n.spec.noUnknown=e,n}unknown(e=!0,t=pg.noUnknown){return this.noUnknown(!e,t)}transformKeys(e){return this.transform(t=>t&&bu()(t,(t,n)=>e(n)))}camelCase(){return this.transformKeys(bo())}snakeCase(){return this.transformKeys(bi())}constantCase(){return this.transformKeys(e=>bi()(e).toUpperCase())}describe(){let e=super.describe();return e.fields=pC()(this.fields,e=>e.describe()),e}}function by(e){return new bv(e)}function bw(){return(bw=Object.assign||function(e){for(var t=1;t{this.transform(function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(t){e=null}return this.isType(e)?e:null})})}_typeCheck(e){return Array.isArray(e)}get _subType(){return this.innerType}_cast(e,t){let n=super._cast(e,t);if(!this._typeCheck(n)||!this.innerType)return n;let r=!1,i=n.map((e,n)=>{let i=this.innerType.cast(e,bw({},t,{path:`${t.path||""}[${n}]`}));return i!==e&&(r=!0),i});return r?i:n}_validate(e,t={},n){var r,i;let a=[],o=t.sync,s=t.path,u=this.innerType,c=null!=(r=t.abortEarly)?r:this.spec.abortEarly,l=null!=(i=t.recursive)?i:this.spec.recursive,f=null!=t.originalValue?t.originalValue:e;super._validate(e,t,(e,r)=>{if(e){if(!pM.isError(e)||c)return void n(e,r);a.push(e)}if(!l||!u||!this._typeCheck(r)){n(a[0]||null,r);return}f=f||r;let i=Array(r.length);for(let d=0;du.validate(h,b,t)}pA({sync:o,path:s,value:r,errors:a,endEarly:c,tests:i},n)})}clone(e){let t=super.clone(e);return t.innerType=this.innerType,t}concat(e){let t=super.concat(e);return t.innerType=this.innerType,e.innerType&&(t.innerType=t.innerType?t.innerType.concat(e.innerType):e.innerType),t}of(e){let t=this.clone();if(!p_(e))throw TypeError("`array.of()` sub-schema must be a valid yup schema not: "+pf(e));return t.innerType=e,t}length(e,t=pv.length){return this.test({message:t,name:"length",exclusive:!0,params:{length:e},test(t){return pV(t)||t.length===this.resolve(e)}})}min(e,t){return t=t||pv.min,this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t.length>=this.resolve(e)}})}max(e,t){return t=t||pv.max,this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(t){return pV(t)||t.length<=this.resolve(e)}})}ensure(){return this.default(()=>[]).transform((e,t)=>this._typeCheck(e)?e:null==t?[]:[].concat(t))}compact(e){let t=e?(t,n,r)=>!e(t,n,r):e=>!!e;return this.transform(e=>null!=e?e.filter(t):e)}describe(){let e=super.describe();return this.innerType&&(e.innerType=this.innerType.describe()),e}nullable(e=!0){return super.nullable(e)}defined(){return super.defined()}required(e){return super.required(e)}}b_.prototype=bE.prototype;var bS=by().shape({name:p2().required("Required"),url:p2().required("Required")}),bk=function(e){var t=e.initialValues,n=e.onSubmit,r=e.submitButtonText,i=e.nameDisabled,a=void 0!==i&&i;return l.createElement(hM,{initialValues:t,validationSchema:bS,onSubmit:n},function(e){var t=e.isSubmitting;return l.createElement(l.Fragment,null,l.createElement(hj,{"data-testid":"bridge-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(hR,{component:hJ,id:"name",name:"name",label:"Name",disabled:a,required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"name-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(hR,{component:hJ,id:"url",name:"url",label:"Bridge URL",placeholder:"https://",required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"url-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:7},l.createElement(hR,{component:hJ,id:"minimumContractPayment",name:"minimumContractPayment",label:"Minimum Contract Payment",placeholder:"0",fullWidth:!0,inputProps:{min:0},FormHelperTextProps:{"data-testid":"minimumContractPayment-helper-text"}})),l.createElement(d.Z,{item:!0,xs:7},l.createElement(hR,{component:hJ,id:"confirmations",name:"confirmations",label:"Confirmations",placeholder:"0",type:"number",fullWidth:!0,inputProps:{min:0},FormHelperTextProps:{"data-testid":"confirmations-helper-text"}})))),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ox.default,{variant:"contained",color:"primary",type:"submit",disabled:t,size:"large"},r)))))})},bx=function(e){var t=e.bridge,n=e.onSubmit,r={name:t.name,url:t.url,minimumContractPayment:t.minimumContractPayment,confirmations:t.confirmations};return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:40},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Edit Bridge",action:l.createElement(aL.Z,{component:tz,href:"/bridges/".concat(t.id)},"Cancel")}),l.createElement(aK.Z,null,l.createElement(bk,{nameDisabled:!0,initialValues:r,onSubmit:n,submitButtonText:"Save Bridge"}))))))};function bT(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]&&arguments[0],t=e?function(){return l.createElement(x.default,{variant:"body1"},"Loading...")}:function(){return null};return{isLoading:e,LoadingPlaceholder:t}},ml=n(76023);function mf(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=0||(i[n]=e[n]);return i}function mB(e,t){if(null==e)return{};var n,r,i=mY(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function mU(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n=4?[e[0],e[1],e[2],e[3],"".concat(e[0],".").concat(e[1]),"".concat(e[0],".").concat(e[2]),"".concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[0]),"".concat(e[1],".").concat(e[2]),"".concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[1]),"".concat(e[2],".").concat(e[3]),"".concat(e[3],".").concat(e[0]),"".concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[0]),"".concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[1],".").concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[2],".").concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[3],".").concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[2],".").concat(e[1],".").concat(e[0])]:void 0}var mX={};function mJ(e){if(0===e.length||1===e.length)return e;var t=e.join(".");return mX[t]||(mX[t]=mZ(e)),mX[t]}function mQ(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0;return mJ(e.filter(function(e){return"token"!==e})).reduce(function(e,t){return mV({},e,n[t])},t)}function m1(e){return e.join(" ")}function m0(e,t){var n=0;return function(r){return n+=1,r.map(function(r,i){return m2({node:r,stylesheet:e,useInlineStyles:t,key:"code-segment-".concat(n,"-").concat(i)})})}}function m2(e){var t=e.node,n=e.stylesheet,r=e.style,i=void 0===r?{}:r,a=e.useInlineStyles,o=e.key,s=t.properties,u=t.type,c=t.tagName,f=t.value;if("text"===u)return f;if(c){var d,h=m0(n,a);if(a){var p=Object.keys(n).reduce(function(e,t){return t.split(".").forEach(function(t){e.includes(t)||e.push(t)}),e},[]),b=s.className&&s.className.includes("token")?["token"]:[],m=s.className&&b.concat(s.className.filter(function(e){return!p.includes(e)}));d=mV({},s,{className:m1(m)||void 0,style:mQ(s.className,Object.assign({},s.style,i),n)})}else d=mV({},s,{className:m1(s.className)});var g=h(t.children);return l.createElement(c,mq({key:o},d),g)}}let m3=function(e,t){return -1!==e.listLanguages().indexOf(t)};var m4=/\n/g;function m5(e){return e.match(m4)}function m6(e){var t=e.lines,n=e.startingLineNumber,r=e.style;return t.map(function(e,t){var i=t+n;return l.createElement("span",{key:"line-".concat(t),className:"react-syntax-highlighter-line-number",style:"function"==typeof r?r(i):r},"".concat(i,"\n"))})}function m9(e){var t=e.codeString,n=e.codeStyle,r=e.containerStyle,i=void 0===r?{float:"left",paddingRight:"10px"}:r,a=e.numberStyle,o=void 0===a?{}:a,s=e.startingLineNumber;return l.createElement("code",{style:Object.assign({},n,i)},m6({lines:t.replace(/\n$/,"").split("\n"),style:o,startingLineNumber:s}))}function m8(e){return"".concat(e.toString().length,".25em")}function m7(e,t){return{type:"element",tagName:"span",properties:{key:"line-number--".concat(e),className:["comment","linenumber","react-syntax-highlighter-line-number"],style:t},children:[{type:"text",value:e}]}}function ge(e,t,n){var r,i={display:"inline-block",minWidth:m8(n),paddingRight:"1em",textAlign:"right",userSelect:"none"};return mV({},i,"function"==typeof e?e(t):e)}function gt(e){var t=e.children,n=e.lineNumber,r=e.lineNumberStyle,i=e.largestLineNumber,a=e.showInlineLineNumbers,o=e.lineProps,s=void 0===o?{}:o,u=e.className,c=void 0===u?[]:u,l=e.showLineNumbers,f=e.wrapLongLines,d="function"==typeof s?s(n):s;if(d.className=c,n&&a){var h=ge(r,n,i);t.unshift(m7(n,h))}return f&l&&(d.style=mV({},d.style,{display:"flex"})),{type:"element",tagName:"span",properties:d,children:t}}function gn(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],r=0;r2&&void 0!==arguments[2]?arguments[2]:[];return gt({children:e,lineNumber:t,lineNumberStyle:s,largestLineNumber:o,showInlineLineNumbers:i,lineProps:n,className:a,showLineNumbers:r,wrapLongLines:u})}function b(e,t){if(r&&t&&i){var n=ge(s,t,o);e.unshift(m7(t,n))}return e}function m(e,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];return t||r.length>0?p(e,n,r):b(e,n)}for(var g=function(){var e=l[h],t=e.children[0].value;if(m5(t)){var n=t.split("\n");n.forEach(function(t,i){var o=r&&f.length+a,s={type:"text",value:"".concat(t,"\n")};if(0===i){var u=l.slice(d+1,h).concat(gt({children:[s],className:e.properties.className})),c=m(u,o);f.push(c)}else if(i===n.length-1){if(l[h+1]&&l[h+1].children&&l[h+1].children[0]){var p={type:"text",value:"".concat(t)},b=gt({children:[p],className:e.properties.className});l.splice(h+1,0,b)}else{var g=[s],v=m(g,o,e.properties.className);f.push(v)}}else{var y=[s],w=m(y,o,e.properties.className);f.push(w)}}),d=h}h++};h code[class*="language-"]':{background:"#f5f2f0",padding:".1em",borderRadius:".3em",whiteSpace:"normal"},comment:{color:"slategray"},prolog:{color:"slategray"},doctype:{color:"slategray"},cdata:{color:"slategray"},punctuation:{color:"#999"},namespace:{Opacity:".7"},property:{color:"#905"},tag:{color:"#905"},boolean:{color:"#905"},number:{color:"#905"},constant:{color:"#905"},symbol:{color:"#905"},deleted:{color:"#905"},selector:{color:"#690"},"attr-name":{color:"#690"},string:{color:"#690"},char:{color:"#690"},builtin:{color:"#690"},inserted:{color:"#690"},operator:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},entity:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)",cursor:"help"},url:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".language-css .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".style .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},atrule:{color:"#07a"},"attr-value":{color:"#07a"},keyword:{color:"#07a"},function:{color:"#DD4A68"},"class-name":{color:"#DD4A68"},regex:{color:"#e90"},important:{color:"#e90",fontWeight:"bold"},variable:{color:"#e90"},bold:{fontWeight:"bold"},italic:{fontStyle:"italic"}};var gc=n(98695),gl=n.n(gc);let gf=["abap","abnf","actionscript","ada","agda","al","antlr4","apacheconf","apl","applescript","aql","arduino","arff","asciidoc","asm6502","aspnet","autohotkey","autoit","bash","basic","batch","bbcode","birb","bison","bnf","brainfuck","brightscript","bro","bsl","c","cil","clike","clojure","cmake","coffeescript","concurnas","cpp","crystal","csharp","csp","css-extras","css","cypher","d","dart","dax","dhall","diff","django","dns-zone-file","docker","ebnf","editorconfig","eiffel","ejs","elixir","elm","erb","erlang","etlua","excel-formula","factor","firestore-security-rules","flow","fortran","fsharp","ftl","gcode","gdscript","gedcom","gherkin","git","glsl","gml","go","graphql","groovy","haml","handlebars","haskell","haxe","hcl","hlsl","hpkp","hsts","http","ichigojam","icon","iecst","ignore","inform7","ini","io","j","java","javadoc","javadoclike","javascript","javastacktrace","jolie","jq","js-extras","js-templates","jsdoc","json","json5","jsonp","jsstacktrace","jsx","julia","keyman","kotlin","latex","latte","less","lilypond","liquid","lisp","livescript","llvm","lolcode","lua","makefile","markdown","markup-templating","markup","matlab","mel","mizar","mongodb","monkey","moonscript","n1ql","n4js","nand2tetris-hdl","naniscript","nasm","neon","nginx","nim","nix","nsis","objectivec","ocaml","opencl","oz","parigp","parser","pascal","pascaligo","pcaxis","peoplecode","perl","php-extras","php","phpdoc","plsql","powerquery","powershell","processing","prolog","properties","protobuf","pug","puppet","pure","purebasic","purescript","python","q","qml","qore","r","racket","reason","regex","renpy","rest","rip","roboconf","robotframework","ruby","rust","sas","sass","scala","scheme","scss","shell-session","smali","smalltalk","smarty","sml","solidity","solution-file","soy","sparql","splunk-spl","sqf","sql","stan","stylus","swift","t4-cs","t4-templating","t4-vb","tap","tcl","textile","toml","tsx","tt2","turtle","twig","typescript","typoscript","unrealscript","vala","vbnet","velocity","verilog","vhdl","vim","visual-basic","warpscript","wasm","wiki","xeora","xml-doc","xojo","xquery","yaml","yang","zig"];var gd=gs(gl(),gu);gd.supportedLanguages=gf;let gh=gd;var gp=n(64566);function gb(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function gm(){var e=gb(["\n query FetchConfigV2 {\n configv2 {\n user\n effective\n }\n }\n"]);return gm=function(){return e},e}var gg=n0(gm()),gv=function(e){var t=e.children;return l.createElement(ii.Z,null,l.createElement(ie.default,{component:"th",scope:"row",colSpan:3},t))},gy=function(){return l.createElement(gv,null,"...")},gw=function(e){var t=e.children;return l.createElement(gv,null,t)},g_=function(e){var t=e.loading,n=e.toml,r=e.error,i=void 0===r?"":r,a=e.title,o=e.expanded;if(i)return l.createElement(gw,null,i);if(t)return l.createElement(gy,null);a||(a="TOML");var s={display:"block"};return l.createElement(x.default,null,l.createElement(mR.Z,{defaultExpanded:o},l.createElement(mj.Z,{expandIcon:l.createElement(gp.Z,null)},a),l.createElement(mF.Z,{style:s},l.createElement(gh,{language:"toml",style:gu},n))))},gE=function(){var e=ry(gg,{fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return(null==t?void 0:t.configv2.effective)=="N/A"?l.createElement(l.Fragment,null,l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"TOML Configuration"}),l.createElement(g_,{title:"V2 config dump:",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.user,showHead:!0})))):l.createElement(l.Fragment,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"TOML Configuration"}),l.createElement(g_,{title:"User specified:",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.user,showHead:!0,expanded:!0}),l.createElement(g_,{title:"Effective (with defaults):",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.effective,showHead:!0})))))},gS=n(34823),gk=function(e){return(0,b.createStyles)({cell:{paddingTop:1.5*e.spacing.unit,paddingBottom:1.5*e.spacing.unit}})},gx=(0,b.withStyles)(gk)(function(e){var t=e.classes,n=(0,A.I0)();(0,l.useEffect)(function(){n((0,ty.DQ)())});var r=(0,A.v9)(gS.N,A.wU);return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Node"}),l.createElement(r8.Z,null,l.createElement(r7.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,{className:t.cell},l.createElement(x.default,null,"Version"),l.createElement(x.default,{variant:"subtitle1",color:"textSecondary"},r.version))),l.createElement(ii.Z,null,l.createElement(ie.default,{className:t.cell},l.createElement(x.default,null,"SHA"),l.createElement(x.default,{variant:"subtitle1",color:"textSecondary"},r.commitSHA))))))}),gT=function(){return l.createElement(iv,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,sm:12,md:8},l.createElement(d.Z,{container:!0},l.createElement(gE,null))),l.createElement(d.Z,{item:!0,sm:12,md:4},l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gx,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(mP,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(mS,null))))))},gM=function(){return l.createElement(gT,null)},gO=function(){return l.createElement(gM,null)},gA=n(44431),gL=1e18,gC=function(e){return new gA.BigNumber(e).dividedBy(gL).toFixed(8)},gI=function(e){var t=e.keys,n=e.chainID,r=e.hideHeaderTitle;return l.createElement(l.Fragment,null,l.createElement(sf.Z,{title:!r&&"Account Balances",subheader:"Chain ID "+n}),l.createElement(aK.Z,null,l.createElement(w.default,{dense:!1,disablePadding:!0},t&&t.map(function(e,r){return l.createElement(l.Fragment,null,l.createElement(_.default,{disableGutters:!0,key:["acc-balance",n.toString(),r.toString()].join("-")},l.createElement(E.Z,{primary:l.createElement(l.Fragment,null,l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ob,{title:"Address"}),l.createElement(om,{value:e.address})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(ob,{title:"Native Token Balance"}),l.createElement(om,{value:e.ethBalance||"--"})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(ob,{title:"LINK Balance"}),l.createElement(om,{value:e.linkBalance?gC(e.linkBalance):"--"}))))})),r+1s&&l.createElement(gU.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,{className:r.footer},l.createElement(aL.Z,{href:"/runs",component:tz},"View More"))))))});function vn(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vr(){var e=vn(["\n ","\n query FetchRecentJobRuns($offset: Int, $limit: Int) {\n jobRuns(offset: $offset, limit: $limit) {\n results {\n ...RecentJobRunsPayload_ResultsFields\n }\n metadata {\n total\n }\n }\n }\n"]);return vr=function(){return e},e}var vi=5,va=n0(vr(),g7),vo=function(){var e=ry(va,{variables:{offset:0,limit:vi},fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return l.createElement(vt,{data:t,errorMsg:null==r?void 0:r.message,loading:n,maxRunsSize:vi})},vs=function(e){return(0,b.createStyles)({style:{textAlign:"center",padding:2.5*e.spacing.unit,position:"fixed",left:"0",bottom:"0",width:"100%",borderRadius:0},bareAnchor:{color:e.palette.common.black,textDecoration:"none"}})},vu=(0,b.withStyles)(vs)(function(e){var t=e.classes,n=(0,A.v9)(gS.N,A.wU),r=(0,A.I0)();return(0,l.useEffect)(function(){r((0,ty.DQ)())}),l.createElement(ia.default,{className:t.style},l.createElement(x.default,null,"Chainlink Node ",n.version," at commit"," ",l.createElement("a",{target:"_blank",rel:"noopener noreferrer",href:"https://github.com/smartcontractkit/chainlink/commit/".concat(n.commitSHA),className:t.bareAnchor},n.commitSHA)))}),vc=function(e){return(0,b.createStyles)({cell:{borderColor:e.palette.divider,borderTop:"1px solid",borderBottom:"none",paddingTop:2*e.spacing.unit,paddingBottom:2*e.spacing.unit,paddingLeft:2*e.spacing.unit},block:{display:"block"},overflowEllipsis:{textOverflow:"ellipsis",overflow:"hidden"}})},vl=(0,b.withStyles)(vc)(function(e){var t=e.classes,n=e.job;return l.createElement(ii.Z,null,l.createElement(ie.default,{scope:"row",className:t.cell},l.createElement(d.Z,{container:!0,spacing:0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ip,{href:"/jobs/".concat(n.id),classes:{linkContent:t.block}},l.createElement(x.default,{className:t.overflowEllipsis,variant:"body1",component:"span",color:"primary"},n.name||n.id))),l.createElement(d.Z,{item:!0,xs:12},l.createElement(x.default,{variant:"body1",color:"textSecondary"},"Created ",l.createElement(aA,{tooltip:!0},n.createdAt))))))});function vf(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vd(){var e=vf(["\n fragment RecentJobsPayload_ResultsFields on Job {\n id\n name\n createdAt\n }\n"]);return vd=function(){return e},e}var vh=n0(vd()),vp=function(){return(0,b.createStyles)({cardHeader:{borderBottom:0},table:{tableLayout:"fixed"}})},vb=(0,b.withStyles)(vp)(function(e){var t,n,r=e.classes,i=e.data,a=e.errorMsg,o=e.loading;return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Recent Jobs",className:r.cardHeader}),l.createElement(r8.Z,{className:r.table},l.createElement(r7.Z,null,l.createElement(gz,{visible:o}),l.createElement(gG,{visible:(null===(t=null==i?void 0:i.jobs.results)||void 0===t?void 0:t.length)===0},"No recently created jobs"),l.createElement(gH,{msg:a}),null===(n=null==i?void 0:i.jobs.results)||void 0===n?void 0:n.map(function(e,t){return l.createElement(vl,{job:e,key:t})}))))});function vm(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vg(){var e=vm(["\n ","\n query FetchRecentJobs($offset: Int, $limit: Int) {\n jobs(offset: $offset, limit: $limit) {\n results {\n ...RecentJobsPayload_ResultsFields\n }\n }\n }\n"]);return vg=function(){return e},e}var vv=5,vy=n0(vg(),vh),vw=function(){var e=ry(vy,{variables:{offset:0,limit:vv},fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return l.createElement(vb,{data:t,errorMsg:null==r?void 0:r.message,loading:n})},v_=function(){return l.createElement(iv,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:8},l.createElement(vo,null)),l.createElement(d.Z,{item:!0,xs:4},l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gB,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(vw,null))))),l.createElement(vu,null))},vE=function(){return l.createElement(v_,null)},vS=function(){return l.createElement(vE,null)},vk=n(87239),vx=function(e){switch(e){case"DirectRequestSpec":return"Direct Request";case"FluxMonitorSpec":return"Flux Monitor";default:return e.replace(/Spec$/,"")}},vT=n(5022),vM=n(78718),vO=n.n(vM);function vA(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1?t-1:0),r=1;r1?t-1:0),r=1;re.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&n.map(function(e){return l.createElement(ii.Z,{key:e.id,style:{cursor:"pointer"},onClick:function(){return r.push("/runs/".concat(e.id))}},l.createElement(ie.default,{className:t.idCell,scope:"row"},l.createElement("div",{className:t.runDetails},l.createElement(x.default,{variant:"h5",color:"primary",component:"span"},e.id))),l.createElement(ie.default,{className:t.stampCell},l.createElement(x.default,{variant:"body1",color:"textSecondary",className:t.stamp},"Created ",l.createElement(aA,{tooltip:!0},e.createdAt))),l.createElement(ie.default,{className:t.statusCell,scope:"row"},l.createElement(x.default,{variant:"body1",className:O()(t.status,yp(t,e.status))},e.status.toLowerCase())))})))}),ym=n(16839),yg=n.n(ym);function yv(e){var t=e.replace(/\w+\s*=\s*<([^>]|[\r\n])*>/g,""),n=yg().read(t),r=n.edges();return n.nodes().map(function(e){var t={id:e,parentIds:r.filter(function(t){return t.w===e}).map(function(e){return e.v})};return Object.keys(n.node(e)).length>0&&(t.attributes=n.node(e)),t})}var yy=n(94164),yw=function(e){var t=e.data,n=[];return(null==t?void 0:t.attributes)&&Object.keys(t.attributes).forEach(function(e){var r;n.push(l.createElement("div",{key:e},l.createElement(x.default,{variant:"body1",color:"textSecondary",component:"div"},l.createElement("b",null,e,":")," ",null===(r=t.attributes)||void 0===r?void 0:r[e])))}),l.createElement("div",null,t&&l.createElement(x.default,{variant:"body1",color:"textPrimary"},l.createElement("b",null,t.id)),n)},y_=n(73343),yE=n(3379),yS=n.n(yE);function yk(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);nwindow.innerWidth?u-r.getBoundingClientRect().width-a:u+a,n=c+r.getBoundingClientRect().height+i>window.innerHeight?c-r.getBoundingClientRect().height-a:c+a,r.style.opacity=String(1),r.style.top="".concat(n,"px"),r.style.left="".concat(t,"px"),r.style.zIndex=String(1)}},h=function(e){var t=document.getElementById("tooltip-d3-chart-".concat(e));t&&(t.style.opacity=String(0),t.style.zIndex=String(-1))};return l.createElement("div",{style:{fontFamily:"sans-serif",fontWeight:"normal"}},l.createElement(yy.kJ,{id:"task-list-graph-d3",data:i,config:s,onMouseOverNode:d,onMouseOutNode:h},"D3 chart"),n.map(function(e){return l.createElement("div",{key:"d3-tooltip-key-".concat(e.id),id:"tooltip-d3-chart-".concat(e.id),style:{position:"absolute",opacity:"0",border:"1px solid rgba(0, 0, 0, 0.1)",padding:y_.r.spacing.unit,background:"white",borderRadius:5,zIndex:-1,inlineSize:"min-content"}},l.createElement(yw,{data:e}))}))};function yC(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);nyB&&l.createElement("div",{className:t.runDetails},l.createElement(aL.Z,{href:"/jobs/".concat(n.id,"/runs"),component:tz},"View more")))),l.createElement(d.Z,{item:!0,xs:12,sm:6},l.createElement(yY,{observationSource:n.observationSource})))});function y$(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]?arguments[0]:"";try{return vT.parse(e),!0}catch(t){return!1}})}),wK=function(e){var t=e.initialValues,n=e.onSubmit,r=e.onTOMLChange;return l.createElement(hM,{initialValues:t,validationSchema:wW,onSubmit:n},function(e){var t=e.isSubmitting,n=e.values;return r&&r(n.toml),l.createElement(hj,{"data-testid":"job-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12},l.createElement(hR,{component:hJ,id:"toml",name:"toml",label:"Job Spec (TOML)",required:!0,fullWidth:!0,multiline:!0,rows:10,rowsMax:25,variant:"outlined",autoComplete:"off",FormHelperTextProps:{"data-testid":"toml-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ox.default,{variant:"contained",color:"primary",type:"submit",disabled:t,size:"large"},"Create Job"))))})},wV=n(50109),wq="persistSpec";function wZ(e){var t=e.query,n=new URLSearchParams(t).get("definition");return n?(wV.t8(wq,n),{toml:n}):{toml:wV.U2(wq)||""}}var wX=function(e){var t=e.onSubmit,n=e.onTOMLChange,r=wZ({query:(0,h.TH)().search}),i=function(e){var t=e.replace(/[\u200B-\u200D\uFEFF]/g,"");wV.t8("".concat(wq),t),n&&n(t)};return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"New Job"}),l.createElement(aK.Z,null,l.createElement(wK,{initialValues:r,onSubmit:t,onTOMLChange:i})))};function wJ(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n1&&void 0!==arguments[1]?arguments[1]:{},n=t.start,r=void 0===n?6:n,i=t.end,a=void 0===i?4:i;return e.substring(0,r)+"..."+e.substring(e.length-a)}function _O(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(_K,e)},_q=function(){var e=_V({fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error,i=e.refetch;return l.createElement(_H,{loading:n,data:t,errorMsg:null==r?void 0:r.message,refetch:i})},_Z=function(e){var t=e.csaKey;return l.createElement(ii.Z,{hover:!0},l.createElement(ie.default,null,l.createElement(x.default,{variant:"body1"},t.publicKey," ",l.createElement(_T,{data:t.publicKey}))))};function _X(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function _J(){var e=_X(["\n fragment CSAKeysPayload_ResultsFields on CSAKey {\n id\n publicKey\n }\n"]);return _J=function(){return e},e}var _Q=n0(_J()),_1=function(e){var t,n,r,i=e.data,a=e.errorMsg,o=e.loading,s=e.onCreate;return l.createElement(r9.Z,null,l.createElement(sf.Z,{action:(null===(t=null==i?void 0:i.csaKeys.results)||void 0===t?void 0:t.length)===0&&l.createElement(ox.default,{variant:"outlined",color:"primary",onClick:s},"New CSA Key"),title:"CSA Key",subheader:"Manage your CSA Key"}),l.createElement(r8.Z,null,l.createElement(it.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,null,"Public Key"))),l.createElement(r7.Z,null,l.createElement(gz,{visible:o}),l.createElement(gG,{visible:(null===(n=null==i?void 0:i.csaKeys.results)||void 0===n?void 0:n.length)===0}),l.createElement(gH,{msg:a}),null===(r=null==i?void 0:i.csaKeys.results)||void 0===r?void 0:r.map(function(e,t){return l.createElement(_Z,{csaKey:e,key:t})}))))};function _0(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(EO,e)};function EL(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(EQ,e)},E4=function(){return os(E1)},E5=function(){return os(E0)},E6=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return ry(E2,e)};function E9(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(SV,e)};function SZ(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function kq(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}var kZ=function(e){var t=e.run,n=l.useMemo(function(){var e=t.inputs,n=t.outputs,r=t.taskRuns,i=kV(t,["inputs","outputs","taskRuns"]),a={};try{a=JSON.parse(e)}catch(o){a={}}return kK(kG({},i),{inputs:a,outputs:n,taskRuns:r})},[t]);return l.createElement(r9.Z,null,l.createElement(aK.Z,null,l.createElement(k$,{object:n})))};function kX(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function kJ(e){for(var t=1;t0&&l.createElement(ki,{errors:t.allErrors})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(h.rs,null,l.createElement(h.AW,{path:"".concat(n,"/json")},l.createElement(kZ,{run:t})),l.createElement(h.AW,{path:n},t.taskRuns.length>0&&l.createElement(kP,{taskRuns:t.taskRuns,observationSource:t.job.observationSource}))))))))};function k9(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function k8(){var e=k9(["\n ","\n query FetchJobRun($id: ID!) {\n jobRun(id: $id) {\n __typename\n ... on JobRun {\n ...JobRunPayload_Fields\n }\n ... on NotFoundError {\n message\n }\n }\n }\n"]);return k8=function(){return e},e}var k7=n0(k8(),k5),xe=function(){var e=ry(k7,{variables:{id:(0,h.UO)().id}}),t=e.data,n=e.loading,r=e.error;if(n)return l.createElement(ij,null);if(r)return l.createElement(iN,{error:r});var i=null==t?void 0:t.jobRun;switch(null==i?void 0:i.__typename){case"JobRun":return l.createElement(k6,{run:i});case"NotFoundError":return l.createElement(oo,null);default:return null}};function xt(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xn(){var e=xt(["\n fragment JobRunsPayload_ResultsFields on JobRun {\n id\n allErrors\n createdAt\n finishedAt\n status\n job {\n id\n }\n }\n"]);return xn=function(){return e},e}var xr=n0(xn()),xi=function(e){var t=e.loading,n=e.data,r=e.page,i=e.pageSize,a=(0,h.k6)(),o=l.useMemo(function(){return null==n?void 0:n.jobRuns.results.map(function(e){var t,n=e.allErrors,r=e.id,i=e.createdAt;return{id:r,createdAt:i,errors:n,finishedAt:e.finishedAt,status:e.status}})},[n]);return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:12},l.createElement(iw,null,"Job Runs")),t&&l.createElement(ij,null),n&&o&&l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(yb,{runs:o}),l.createElement(ir.Z,{component:"div",count:n.jobRuns.metadata.total,rowsPerPage:i,rowsPerPageOptions:[i],page:r-1,onChangePage:function(e,t){a.push("/runs?page=".concat(t+1,"&per=").concat(i))},onChangeRowsPerPage:function(){},backIconButtonProps:{"aria-label":"prev-page"},nextIconButtonProps:{"aria-label":"next-page"}})))))};function xa(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xo(){var e=xa(["\n ","\n query FetchJobRuns($offset: Int, $limit: Int) {\n jobRuns(offset: $offset, limit: $limit) {\n results {\n ...JobRunsPayload_ResultsFields\n }\n metadata {\n total\n }\n }\n }\n"]);return xo=function(){return e},e}var xs=n0(xo(),xr),xu=function(){var e=iF(),t=parseInt(e.get("page")||"1",10),n=parseInt(e.get("per")||"25",10),r=ry(xs,{variables:{offset:(t-1)*n,limit:n},fetchPolicy:"cache-and-network"}),i=r.data,a=r.loading,o=r.error;return o?l.createElement(iN,{error:o}):l.createElement(xi,{loading:a,data:i,page:t,pageSize:n})},xc=function(){var e=(0,h.$B)().path;return l.createElement(h.rs,null,l.createElement(h.AW,{exact:!0,path:e},l.createElement(xu,null)),l.createElement(h.AW,{path:"".concat(e,"/:id")},l.createElement(xe,null)))},xl=by().shape({name:p2().required("Required"),uri:p2().required("Required"),publicKey:p2().required("Required")}),xf=function(e){var t=e.initialValues,n=e.onSubmit;return l.createElement(hM,{initialValues:t,validationSchema:xl,onSubmit:n},function(e){var t=e.isSubmitting,n=e.submitForm;return l.createElement(hj,{"data-testid":"feeds-manager-form"},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"name",name:"name",label:"Name",required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"name-helper-text"}})),l.createElement(d.Z,{item:!0,xs:!1,md:6}),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"uri",name:"uri",label:"URI",required:!0,fullWidth:!0,helperText:"Provided by the Feeds Manager operator",FormHelperTextProps:{"data-testid":"uri-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"publicKey",name:"publicKey",label:"Public Key",required:!0,fullWidth:!0,helperText:"Provided by the Feeds Manager operator",FormHelperTextProps:{"data-testid":"publicKey-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(ox.default,{variant:"contained",color:"primary",disabled:t,onClick:n},"Submit"))))})},xd=function(e){var t=e.data,n=e.onSubmit,r={name:t.name,uri:t.uri,publicKey:t.publicKey};return l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Edit Feeds Manager"}),l.createElement(aK.Z,null,l.createElement(xf,{initialValues:r,onSubmit:n})))))};function xh(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xp(){var e=xh(["\n query FetchFeedsManagers {\n feedsManagers {\n results {\n __typename\n id\n name\n uri\n publicKey\n isConnectionActive\n createdAt\n }\n }\n }\n"]);return xp=function(){return e},e}var xb=n0(xp()),xm=function(){return ry(xb)};function xg(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(xZ,e)};function xJ(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0?n.feedsManagers.results[0]:void 0;return n&&a?l.createElement(TH,{manager:a}):l.createElement(h.l_,{to:{pathname:"/feeds_manager/new",state:{from:e}}})},Tz={name:"Chainlink Feeds Manager",uri:"",publicKey:""},TG=function(e){var t=e.onSubmit;return l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Register Feeds Manager"}),l.createElement(aK.Z,null,l.createElement(xf,{initialValues:Tz,onSubmit:t})))))};function TW(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);nt.version?e:t})},[o]),g=l.useMemo(function(){return Mp(o).sort(function(e,t){return t.version-e.version})},[o]),v=function(e,t,n){switch(e){case"PENDING":return l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"text",color:"secondary",onClick:function(){return b("reject",t)}},"Reject"),m.id===t&&"DELETED"!==n.status&&"REVOKED"!==n.status&&l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("approve",t)}},"Approve"),m.id===t&&"DELETED"===n.status&&n.pendingUpdate&&l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("cancel",t)}},"Cancel"),l.createElement(x.default,{color:"error"},"This proposal was deleted. Cancel the spec to delete any running jobs")));case"APPROVED":return l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"contained",onClick:function(){return b("cancel",t)}},"Cancel"),"DELETED"===n.status&&n.pendingUpdate&&l.createElement(x.default,{color:"error"},"This proposal was deleted. Cancel the spec to delete any running jobs"));case"CANCELLED":if(m.id===t&&"DELETED"!==n.status&&"REVOKED"!==n.status)return l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("approve",t)}},"Approve");return null;default:return null}};return l.createElement("div",null,g.map(function(e,n){return l.createElement(mR.Z,{defaultExpanded:0===n,key:n},l.createElement(mj.Z,{expandIcon:l.createElement(gp.Z,null)},l.createElement(x.default,{className:t.versionText},"Version ",e.version),l.createElement(Eu.Z,{label:e.status,color:"APPROVED"===e.status?"primary":"default",variant:"REJECTED"===e.status||"CANCELLED"===e.status?"outlined":"default"}),l.createElement("div",{className:t.proposedAtContainer},l.createElement(x.default,null,"Proposed ",l.createElement(aA,{tooltip:!0},e.createdAt)))),l.createElement(mF.Z,{className:t.expansionPanelDetails},l.createElement("div",{className:t.actions},l.createElement("div",{className:t.editContainer},0===n&&("PENDING"===e.status||"CANCELLED"===e.status)&&"DELETED"!==s.status&&"REVOKED"!==s.status&&l.createElement(ox.default,{variant:"contained",onClick:function(){return p(!0)}},"Edit")),l.createElement("div",{className:t.actionsContainer},v(e.status,e.id,s))),l.createElement(gh,{language:"toml",style:gu,"data-testid":"codeblock"},e.definition)))}),l.createElement(oI,{open:null!=c,title:c?My[c.action].title:"",body:c?My[c.action].body:"",onConfirm:function(){if(c){switch(c.action){case"approve":n(c.id);break;case"cancel":r(c.id);break;case"reject":i(c.id)}f(null)}},cancelButtonText:"Cancel",onCancel:function(){return f(null)}}),l.createElement(Mi,{open:h,onClose:function(){return p(!1)},initialValues:{definition:m.definition,id:m.id},onSubmit:a}))});function M_(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function ME(){var e=M_(["\n ","\n fragment JobProposalPayloadFields on JobProposal {\n id\n externalJobID\n remoteUUID\n jobID\n specs {\n ...JobProposal_SpecsFields\n }\n status\n pendingUpdate\n }\n"]);return ME=function(){return e},e}var MS=n0(ME(),Mg),Mk=function(e){var t=e.onApprove,n=e.onCancel,r=e.onReject,i=e.onUpdateSpec,a=e.proposal;return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:9},l.createElement(iw,null,"Job Proposal #",a.id))),l.createElement(T8,{proposal:a}),l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:9},l.createElement(TU,null,"Specs"))),l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:12},l.createElement(Mw,{proposal:a,specs:a.specs,onReject:r,onApprove:t,onCancel:n,onUpdateSpec:i}))))};function Mx(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);nU,tA:()=>$,KL:()=>H,Iw:()=>V,DQ:()=>W,cB:()=>T,LO:()=>M,t5:()=>k,qt:()=>x,Jc:()=>C,L7:()=>Y,EO:()=>B});var r,i,a=n(66289),o=n(41800),s=n.n(o),u=n(67932);(i=r||(r={})).IN_PROGRESS="in_progress",i.PENDING_INCOMING_CONFIRMATIONS="pending_incoming_confirmations",i.PENDING_CONNECTION="pending_connection",i.PENDING_BRIDGE="pending_bridge",i.PENDING_SLEEP="pending_sleep",i.ERRORED="errored",i.COMPLETED="completed";var c=n(87013),l=n(19084),f=n(34823);function d(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]j,v2:()=>F});var r=n(66289);function i(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var a="/sessions",o="/sessions",s=function e(t){var n=this;i(this,e),this.api=t,this.createSession=function(e){return n.create(e)},this.destroySession=function(){return n.destroy()},this.create=this.api.createResource(a),this.destroy=this.api.deleteResource(o)};function u(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var c="/v2/bulk_delete_runs",l=function e(t){var n=this;u(this,e),this.api=t,this.bulkDeleteJobRuns=function(e){return n.destroy(e)},this.destroy=this.api.deleteResource(c)};function f(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var d="/v2/chains/evm",h="".concat(d,"/:id"),p=function e(t){var n=this;f(this,e),this.api=t,this.getChains=function(){return n.index()},this.createChain=function(e){return n.create(e)},this.destroyChain=function(e){return n.destroy(void 0,{id:e})},this.updateChain=function(e,t){return n.update(t,{id:e})},this.index=this.api.fetchResource(d),this.create=this.api.createResource(d),this.destroy=this.api.deleteResource(h),this.update=this.api.updateResource(h)};function b(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var m="/v2/keys/evm/chain",g=function e(t){var n=this;b(this,e),this.api=t,this.chain=function(e){var t=new URLSearchParams;t.append("address",e.address),t.append("evmChainID",e.evmChainID),null!==e.nextNonce&&t.append("nextNonce",e.nextNonce),null!==e.abandon&&t.append("abandon",String(e.abandon)),null!==e.enabled&&t.append("enabled",String(e.enabled));var r=m+"?"+t.toString();return n.api.createResource(r)()}};function v(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var y="/v2/jobs",w="".concat(y,"/:specId/runs"),_=function e(t){var n=this;v(this,e),this.api=t,this.createJobRunV2=function(e,t){return n.post(t,{specId:e})},this.post=this.api.createResource(w,!0)};function E(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var S="/v2/log",k=function e(t){var n=this;E(this,e),this.api=t,this.getLogConfig=function(){return n.show()},this.updateLogConfig=function(e){return n.update(e)},this.show=this.api.fetchResource(S),this.update=this.api.updateResource(S)};function x(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var T="/v2/nodes",M=function e(t){var n=this;x(this,e),this.api=t,this.getNodes=function(){return n.index()},this.createNode=function(e){return n.create(e)},this.index=this.api.fetchResource(T),this.create=this.api.createResource(T)};function O(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var A="/v2/enroll_webauthn",L=function e(t){var n=this;O(this,e),this.api=t,this.beginKeyRegistration=function(e){return n.create(e)},this.finishKeyRegistration=function(e){return n.put(e)},this.create=this.api.fetchResource(A),this.put=this.api.createResource(A)};function C(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var I="/v2/build_info",D=function e(t){var n=this;C(this,e),this.api=t,this.show=function(){return n.api.GET(I)()}};function N(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var P=function e(t){N(this,e),this.api=t,this.buildInfo=new D(this.api),this.bulkDeleteRuns=new l(this.api),this.chains=new p(this.api),this.logConfig=new k(this.api),this.nodes=new M(this.api),this.jobs=new _(this.api),this.webauthn=new L(this.api),this.evmKeys=new g(this.api)},R=new r.V0({base:void 0}),j=new s(R),F=new P(R)},1398(e,t,n){"use strict";n.d(t,{Z:()=>d});var r=n(67294),i=n(32316),a=n(83638),o=n(94184),s=n.n(o);function u(){return(u=Object.assign||function(e){for(var t=1;tc});var r=n(67294),i=n(32316);function a(){return(a=Object.assign||function(e){for(var t=1;tx,jK:()=>v});var r=n(67294),i=n(55977),a=n(45697),o=n.n(a),s=n(82204),u=n(71426),c=n(94184),l=n.n(c),f=n(32316),d=function(e){var t=e.palette.success||{},n=e.palette.warning||{};return{base:{paddingLeft:5*e.spacing.unit,paddingRight:5*e.spacing.unit},success:{backgroundColor:t.main,color:t.contrastText},error:{backgroundColor:e.palette.error.dark,color:e.palette.error.contrastText},warning:{backgroundColor:n.contrastText,color:n.main}}},h=function(e){var t,n=e.success,r=e.error,i=e.warning,a=e.classes,o=e.className;return n?t=a.success:r?t=a.error:i&&(t=a.warning),l()(a.base,o,t)},p=function(e){return r.createElement(s.Z,{className:h(e),square:!0},r.createElement(u.default,{variant:"body2",color:"inherit",component:"div"},e.children))};p.defaultProps={success:!1,error:!1,warning:!1},p.propTypes={success:o().bool,error:o().bool,warning:o().bool};let b=(0,f.withStyles)(d)(p);var m=function(){return r.createElement(r.Fragment,null,"Unhandled error. Please help us by opening a"," ",r.createElement("a",{href:"https://github.com/smartcontractkit/chainlink/issues/new"},"bug report"))};let g=m;function v(e){return"string"==typeof e?e:e.component?e.component(e.props):r.createElement(g,null)}function y(e,t){var n;return n="string"==typeof e?e:e.component?e.component(e.props):r.createElement(g,null),r.createElement("p",{key:t},n)}var w=function(e){var t=e.notifications;return r.createElement(b,{error:!0},t.map(y))},_=function(e){var t=e.notifications;return r.createElement(b,{success:!0},t.map(y))},E=function(e){var t=e.errors,n=e.successes;return r.createElement("div",null,(null==t?void 0:t.length)>0&&r.createElement(w,{notifications:t}),n.length>0&&r.createElement(_,{notifications:n}))},S=function(e){return{errors:e.notifications.errors,successes:e.notifications.successes}},k=(0,i.$j)(S)(E);let x=k},9409(e,t,n){"use strict";n.d(t,{ZP:()=>j});var r=n(67294),i=n(55977),a=n(47886),o=n(32316),s=n(1398),u=n(82204),c=n(30060),l=n(71426),f=n(60520),d=n(97779),h=n(57209),p=n(26842),b=n(3950),m=n(5536),g=n(45697),v=n.n(g);let y=n.p+"9f6d832ef97e8493764e.svg";function w(){return(w=Object.assign||function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&_.map(function(e,t){return r.createElement(d.Z,{item:!0,xs:12,key:t},r.createElement(u.Z,{raised:!1,className:v.error},r.createElement(c.Z,null,r.createElement(l.default,{variant:"body1",className:v.errorText},(0,b.jK)(e)))))}),r.createElement(d.Z,{item:!0,xs:12},r.createElement(f.Z,{id:"email",label:"Email",margin:"normal",value:n,onChange:m("email"),error:_.length>0,variant:"outlined",fullWidth:!0})),r.createElement(d.Z,{item:!0,xs:12},r.createElement(f.Z,{id:"password",label:"Password",type:"password",autoComplete:"password",margin:"normal",value:h,onChange:m("password"),error:_.length>0,variant:"outlined",fullWidth:!0})),r.createElement(d.Z,{item:!0,xs:12},r.createElement(d.Z,{container:!0,spacing:0,justify:"center"},r.createElement(d.Z,{item:!0},r.createElement(s.Z,{type:"submit",variant:"primary"},"Access Account")))),y&&r.createElement(l.default,{variant:"body1",color:"textSecondary"},"Signing in...")))))))},P=function(e){return{fetching:e.authentication.fetching,authenticated:e.authentication.allowed,errors:e.notifications.errors}},R=(0,i.$j)(P,x({submitSignIn:p.L7}))(N);let j=(0,h.wU)(e)((0,o.withStyles)(D)(R))},16353(e,t,n){"use strict";n.d(t,{ZP:()=>H,rH:()=>U});var r,i=n(55977),a=n(15857),o=n(9541),s=n(19084);function u(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:h,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.Mk.RECEIVE_SIGNOUT_SUCCESS:case s.Mk.RECEIVE_SIGNIN_SUCCESS:var n={allowed:t.authenticated};return o.Ks(n),f(c({},e,n),{errors:[]});case s.Mk.RECEIVE_SIGNIN_FAIL:var r={allowed:!1};return o.Ks(r),f(c({},e,r),{errors:[]});case s.Mk.RECEIVE_SIGNIN_ERROR:case s.Mk.RECEIVE_SIGNOUT_ERROR:var i={allowed:!1};return o.Ks(i),f(c({},e,i),{errors:t.errors||[]});default:return e}};let b=p;function m(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function g(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:_,t=arguments.length>1?arguments[1]:void 0;return t.type?t.type.startsWith(r.REQUEST)?y(g({},e),{count:e.count+1}):t.type.startsWith(r.RECEIVE)?y(g({},e),{count:Math.max(e.count-1,0)}):t.type.startsWith(r.RESPONSE)?y(g({},e),{count:Math.max(e.count-1,0)}):t.type===s.di.REDIRECT?y(g({},e),{count:0}):e:e};let S=E;function k(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function x(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:O,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.di.MATCH_ROUTE:return M(x({},O),{currentUrl:t.pathname});case s.Ih.NOTIFY_SUCCESS:var n={component:t.component,props:t.props};return M(x({},e),{successes:[n],errors:[]});case s.Ih.NOTIFY_SUCCESS_MSG:return M(x({},e),{successes:[t.msg],errors:[]});case s.Ih.NOTIFY_ERROR:var r=t.error.errors,i=null==r?void 0:r.map(function(e){return L(t,e)});return M(x({},e),{successes:[],errors:i});case s.Ih.NOTIFY_ERROR_MSG:return M(x({},e),{successes:[],errors:[t.msg]});case s.Mk.RECEIVE_SIGNIN_FAIL:return M(x({},e),{successes:[],errors:["Your email or password is incorrect. Please try again"]});default:return e}};function L(e,t){return{component:e.component,props:{msg:t.detail}}}let C=A;function I(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function D(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:R,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.di.REDIRECT:return P(D({},e),{to:t.to});case s.di.MATCH_ROUTE:return P(D({},e),{to:void 0});default:return e}};let F=j;var Y=n(87013),B=(0,a.UY)({authentication:b,fetching:S,notifications:C,redirect:F,buildInfo:Y.Z});B(void 0,{type:"INITIAL_STATE"});var U=i.v9;let H=B},19084(e,t,n){"use strict";var r,i,a,o,s,u,c,l,f,d;n.d(t,{Ih:()=>i,Mk:()=>a,Y0:()=>s,di:()=>r,jp:()=>o}),n(67294),(u=r||(r={})).REDIRECT="REDIRECT",u.MATCH_ROUTE="MATCH_ROUTE",(c=i||(i={})).NOTIFY_SUCCESS="NOTIFY_SUCCESS",c.NOTIFY_SUCCESS_MSG="NOTIFY_SUCCESS_MSG",c.NOTIFY_ERROR="NOTIFY_ERROR",c.NOTIFY_ERROR_MSG="NOTIFY_ERROR_MSG",(l=a||(a={})).REQUEST_SIGNIN="REQUEST_SIGNIN",l.RECEIVE_SIGNIN_SUCCESS="RECEIVE_SIGNIN_SUCCESS",l.RECEIVE_SIGNIN_FAIL="RECEIVE_SIGNIN_FAIL",l.RECEIVE_SIGNIN_ERROR="RECEIVE_SIGNIN_ERROR",l.RECEIVE_SIGNOUT_SUCCESS="RECEIVE_SIGNOUT_SUCCESS",l.RECEIVE_SIGNOUT_ERROR="RECEIVE_SIGNOUT_ERROR",(f=o||(o={})).RECEIVE_CREATE_ERROR="RECEIVE_CREATE_ERROR",f.RECEIVE_CREATE_SUCCESS="RECEIVE_CREATE_SUCCESS",f.RECEIVE_DELETE_ERROR="RECEIVE_DELETE_ERROR",f.RECEIVE_DELETE_SUCCESS="RECEIVE_DELETE_SUCCESS",f.RECEIVE_UPDATE_ERROR="RECEIVE_UPDATE_ERROR",f.RECEIVE_UPDATE_SUCCESS="RECEIVE_UPDATE_SUCCESS",f.REQUEST_CREATE="REQUEST_CREATE",f.REQUEST_DELETE="REQUEST_DELETE",f.REQUEST_UPDATE="REQUEST_UPDATE",f.UPSERT_CONFIGURATION="UPSERT_CONFIGURATION",f.UPSERT_JOB_RUN="UPSERT_JOB_RUN",f.UPSERT_JOB_RUNS="UPSERT_JOB_RUNS",f.UPSERT_TRANSACTION="UPSERT_TRANSACTION",f.UPSERT_TRANSACTIONS="UPSERT_TRANSACTIONS",f.UPSERT_BUILD_INFO="UPSERT_BUILD_INFO",(d=s||(s={})).FETCH_BUILD_INFO_REQUESTED="FETCH_BUILD_INFO_REQUESTED",d.FETCH_BUILD_INFO_SUCCEEDED="FETCH_BUILD_INFO_SUCCEEDED",d.FETCH_BUILD_INFO_FAILED="FETCH_BUILD_INFO_FAILED"},87013(e,t,n){"use strict";n.d(t,{Y:()=>o,Z:()=>u});var r=n(19084);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:o,t=arguments.length>1?arguments[1]:void 0;return t.type===r.Y0.FETCH_BUILD_INFO_SUCCEEDED?a({},t.buildInfo):e};let u=s},34823(e,t,n){"use strict";n.d(t,{N:()=>r});var r=function(e){return e.buildInfo}},73343(e,t,n){"use strict";n.d(t,{r:()=>u});var r=n(19350),i=n(32316),a=n(59114),o=n(5324),s={props:{MuiGrid:{spacing:3*o.default.unit},MuiCardHeader:{titleTypographyProps:{color:"secondary"}}},palette:{action:{hoverOpacity:.3},primary:{light:"#E5F1FF",main:"#3c40c6",contrastText:"#fff"},secondary:{main:"#3d5170"},success:{light:"#e8faf1",main:r.ek.A700,dark:r.ek[700],contrastText:r.y0.white},warning:{light:"#FFFBF1",main:"#fff6b6",contrastText:"#fad27a"},error:{light:"#ffdada",main:"#f44336",dark:"#d32f2f",contrastText:"#fff"},background:{default:"#f5f6f8",appBar:"#3c40c6"},text:{primary:(0,a.darken)(r.BA.A700,.7),secondary:"#818ea3"},listPendingStatus:{background:"#fef7e5",color:"#fecb4c"},listCompletedStatus:{background:"#e9faf2",color:"#4ed495"}},shape:{borderRadius:o.default.unit},overrides:{MuiButton:{root:{borderRadius:o.default.unit/2,textTransform:"none"},sizeLarge:{padding:void 0,fontSize:void 0,paddingTop:o.default.unit,paddingBottom:o.default.unit,paddingLeft:5*o.default.unit,paddingRight:5*o.default.unit}},MuiTableCell:{body:{fontSize:"1rem"},head:{fontSize:"1rem",fontWeight:400}},MuiCardHeader:{root:{borderBottom:"1px solid rgba(0, 0, 0, 0.12)"},action:{marginTop:-2,marginRight:0,"& >*":{marginLeft:2*o.default.unit}},subheader:{marginTop:.5*o.default.unit}}},typography:{useNextVariants:!0,fontFamily:"-apple-system,BlinkMacSystemFont,Roboto,Helvetica,Arial,sans-serif",button:{textTransform:"none",fontSize:"1.2em"},body1:{fontSize:"1.0rem",fontWeight:400,lineHeight:"1.46429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},body2:{fontSize:"1.0rem",fontWeight:500,lineHeight:"1.71429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},body1Next:{color:"rgb(29, 29, 29)",fontWeight:400,fontSize:"1rem",lineHeight:1.5,letterSpacing:-.4},body2Next:{color:"rgb(29, 29, 29)",fontWeight:400,fontSize:"0.875rem",lineHeight:1.5,letterSpacing:-.4},display1:{color:"#818ea3",fontSize:"2.125rem",fontWeight:400,lineHeight:"1.20588em",letterSpacing:-.4},display2:{color:"#818ea3",fontSize:"2.8125rem",fontWeight:400,lineHeight:"1.13333em",marginLeft:"-.02em",letterSpacing:-.4},display3:{color:"#818ea3",fontSize:"3.5rem",fontWeight:400,lineHeight:"1.30357em",marginLeft:"-.02em",letterSpacing:-.4},display4:{fontSize:14,fontWeightLight:300,fontWeightMedium:500,fontWeightRegular:400,letterSpacing:-.4},h1:{color:"rgb(29, 29, 29)",fontSize:"6rem",fontWeight:300,lineHeight:1},h2:{color:"rgb(29, 29, 29)",fontSize:"3.75rem",fontWeight:300,lineHeight:1},h3:{color:"rgb(29, 29, 29)",fontSize:"3rem",fontWeight:400,lineHeight:1.04},h4:{color:"rgb(29, 29, 29)",fontSize:"2.125rem",fontWeight:400,lineHeight:1.17},h5:{color:"rgb(29, 29, 29)",fontSize:"1.5rem",fontWeight:400,lineHeight:1.33,letterSpacing:-.4},h6:{fontSize:"0.8rem",fontWeight:450,lineHeight:"1.71429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},subheading:{color:"rgb(29, 29, 29)",fontSize:"1rem",fontWeight:400,lineHeight:"1.5em",letterSpacing:-.4},subtitle1:{color:"rgb(29, 29, 29)",fontSize:"1rem",fontWeight:400,lineHeight:1.75,letterSpacing:-.4},subtitle2:{color:"rgb(29, 29, 29)",fontSize:"0.875rem",fontWeight:500,lineHeight:1.57,letterSpacing:-.4}},shadows:["none","0px 1px 3px 0px rgba(0, 0, 0, 0.1),0px 1px 1px 0px rgba(0, 0, 0, 0.04),0px 2px 1px -1px rgba(0, 0, 0, 0.02)","0px 1px 5px 0px rgba(0, 0, 0, 0.1),0px 2px 2px 0px rgba(0, 0, 0, 0.04),0px 3px 1px -2px rgba(0, 0, 0, 0.02)","0px 1px 8px 0px rgba(0, 0, 0, 0.1),0px 3px 4px 0px rgba(0, 0, 0, 0.04),0px 3px 3px -2px rgba(0, 0, 0, 0.02)","0px 2px 4px -1px rgba(0, 0, 0, 0.1),0px 4px 5px 0px rgba(0, 0, 0, 0.04),0px 1px 10px 0px rgba(0, 0, 0, 0.02)","0px 3px 5px -1px rgba(0, 0, 0, 0.1),0px 5px 8px 0px rgba(0, 0, 0, 0.04),0px 1px 14px 0px rgba(0, 0, 0, 0.02)","0px 3px 5px -1px rgba(0, 0, 0, 0.1),0px 6px 10px 0px rgba(0, 0, 0, 0.04),0px 1px 18px 0px rgba(0, 0, 0, 0.02)","0px 4px 5px -2px rgba(0, 0, 0, 0.1),0px 7px 10px 1px rgba(0, 0, 0, 0.04),0px 2px 16px 1px rgba(0, 0, 0, 0.02)","0px 5px 5px -3px rgba(0, 0, 0, 0.1),0px 8px 10px 1px rgba(0, 0, 0, 0.04),0px 3px 14px 2px rgba(0, 0, 0, 0.02)","0px 5px 6px -3px rgba(0, 0, 0, 0.1),0px 9px 12px 1px rgba(0, 0, 0, 0.04),0px 3px 16px 2px rgba(0, 0, 0, 0.02)","0px 6px 6px -3px rgba(0, 0, 0, 0.1),0px 10px 14px 1px rgba(0, 0, 0, 0.04),0px 4px 18px 3px rgba(0, 0, 0, 0.02)","0px 6px 7px -4px rgba(0, 0, 0, 0.1),0px 11px 15px 1px rgba(0, 0, 0, 0.04),0px 4px 20px 3px rgba(0, 0, 0, 0.02)","0px 7px 8px -4px rgba(0, 0, 0, 0.1),0px 12px 17px 2px rgba(0, 0, 0, 0.04),0px 5px 22px 4px rgba(0, 0, 0, 0.02)","0px 7px 8px -4px rgba(0, 0, 0, 0.1),0px 13px 19px 2px rgba(0, 0, 0, 0.04),0px 5px 24px 4px rgba(0, 0, 0, 0.02)","0px 7px 9px -4px rgba(0, 0, 0, 0.1),0px 14px 21px 2px rgba(0, 0, 0, 0.04),0px 5px 26px 4px rgba(0, 0, 0, 0.02)","0px 8px 9px -5px rgba(0, 0, 0, 0.1),0px 15px 22px 2px rgba(0, 0, 0, 0.04),0px 6px 28px 5px rgba(0, 0, 0, 0.02)","0px 8px 10px -5px rgba(0, 0, 0, 0.1),0px 16px 24px 2px rgba(0, 0, 0, 0.04),0px 6px 30px 5px rgba(0, 0, 0, 0.02)","0px 8px 11px -5px rgba(0, 0, 0, 0.1),0px 17px 26px 2px rgba(0, 0, 0, 0.04),0px 6px 32px 5px rgba(0, 0, 0, 0.02)","0px 9px 11px -5px rgba(0, 0, 0, 0.1),0px 18px 28px 2px rgba(0, 0, 0, 0.04),0px 7px 34px 6px rgba(0, 0, 0, 0.02)","0px 9px 12px -6px rgba(0, 0, 0, 0.1),0px 19px 29px 2px rgba(0, 0, 0, 0.04),0px 7px 36px 6px rgba(0, 0, 0, 0.02)","0px 10px 13px -6px rgba(0, 0, 0, 0.1),0px 20px 31px 3px rgba(0, 0, 0, 0.04),0px 8px 38px 7px rgba(0, 0, 0, 0.02)","0px 10px 13px -6px rgba(0, 0, 0, 0.1),0px 21px 33px 3px rgba(0, 0, 0, 0.04),0px 8px 40px 7px rgba(0, 0, 0, 0.02)","0px 10px 14px -6px rgba(0, 0, 0, 0.1),0px 22px 35px 3px rgba(0, 0, 0, 0.04),0px 8px 42px 7px rgba(0, 0, 0, 0.02)","0px 11px 14px -7px rgba(0, 0, 0, 0.1),0px 23px 36px 3px rgba(0, 0, 0, 0.04),0px 9px 44px 8px rgba(0, 0, 0, 0.02)","0px 11px 15px -7px rgba(0, 0, 0, 0.1),0px 24px 38px 3px rgba(0, 0, 0, 0.04),0px 9px 46px 8px rgba(0, 0, 0, 0.02)",]},u=(0,i.createMuiTheme)(s)},66289(e,t,n){"use strict";function r(e){if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function i(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function a(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(e){return!1}}function o(e,t,n){return(o=a()?Reflect.construct:function(e,t,n){var r=[null];r.push.apply(r,t);var i=new(Function.bind.apply(e,r));return n&&f(i,n.prototype),i}).apply(null,arguments)}function s(e){return(s=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function u(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&f(e,t)}function c(e){return -1!==Function.toString.call(e).indexOf("[native code]")}function l(e,t){return t&&("object"===p(t)||"function"==typeof t)?t:r(e)}function f(e,t){return(f=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}n.d(t,{V0:()=>B,_7:()=>v});var d,h,p=function(e){return e&&"undefined"!=typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};function b(e){var t="function"==typeof Map?new Map:void 0;return(b=function(e){if(null===e||!c(e))return e;if("function"!=typeof e)throw TypeError("Super expression must either be null or a function");if(void 0!==t){if(t.has(e))return t.get(e);t.set(e,n)}function n(){return o(e,arguments,s(this).constructor)}return n.prototype=Object.create(e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),f(n,e)})(e)}function m(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}function g(e){var t=m();return function(){var n,r=s(e);if(t){var i=s(this).constructor;n=Reflect.construct(r,arguments,i)}else n=r.apply(this,arguments);return l(this,n)}}var v=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"AuthenticationError(".concat(e.statusText,")"))).errors=[{status:e.status,detail:e},],r}return n}(b(Error)),y=function(e){u(n,e);var t=g(n);function n(e){var r,a=e.errors;return i(this,n),(r=t.call(this,"BadRequestError")).errors=a,r}return n}(b(Error)),w=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"UnprocessableEntityError")).errors=e,r}return n}(b(Error)),_=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"ServerError")).errors=e,r}return n}(b(Error)),E=function(e){u(n,e);var t=g(n);function n(e){var r,a=e.errors;return i(this,n),(r=t.call(this,"ConflictError")).errors=a,r}return n}(b(Error)),S=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"UnknownResponseError(".concat(e.statusText,")"))).errors=[{status:e.status,detail:e.statusText},],r}return n}(b(Error));function k(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:2e4;return Promise.race([fetch(e,t),new Promise(function(e,t){return setTimeout(function(){return t(Error("timeout"))},n)}),])}function x(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=200&&e.status<300))return[3,2];return[2,e.json()];case 2:if(400!==e.status)return[3,3];return[2,e.json().then(function(e){throw new y(e)})];case 3:if(401!==e.status)return[3,4];throw new v(e);case 4:if(422!==e.status)return[3,6];return[4,$(e)];case 5:throw n=i.sent(),new w(n);case 6:if(409!==e.status)return[3,7];return[2,e.json().then(function(e){throw new E(e)})];case 7:if(!(e.status>=500))return[3,9];return[4,$(e)];case 8:throw r=i.sent(),new _(r);case 9:throw new S(e);case 10:return[2]}})})).apply(this,arguments)}function $(e){return z.apply(this,arguments)}function z(){return(z=j(function(e){return Y(this,function(t){return[2,e.json().then(function(t){return t.errors?t.errors.map(function(t){return{status:e.status,detail:t.detail}}):G(e)}).catch(function(){return G(e)})]})})).apply(this,arguments)}function G(e){return[{status:e.status,detail:e.statusText},]}},50109(e,t,n){"use strict";n.d(t,{LK:()=>o,U2:()=>i,eT:()=>s,t8:()=>a});var r=n(12795);function i(e){return r.ZP.getItem("chainlink.".concat(e))}function a(e,t){r.ZP.setItem("chainlink.".concat(e),t)}function o(e){var t=i(e),n={};if(t)try{return JSON.parse(t)}catch(r){}return n}function s(e,t){a(e,JSON.stringify(t))}},9541(e,t,n){"use strict";n.d(t,{Ks:()=>u,Tp:()=>a,iR:()=>o,pm:()=>s});var r=n(50109),i="persistURL";function a(){return r.U2(i)||""}function o(e){r.t8(i,e)}function s(){return r.LK("authentication")}function u(e){r.eT("authentication",e)}},67121(e,t,n){"use strict";function r(e){var t,n=e.Symbol;return"function"==typeof n?n.observable?t=n.observable:(t=n("observable"),n.observable=t):t="@@observable",t}n.r(t),n.d(t,{default:()=>o}),e=n.hmd(e),i="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==n.g?n.g:e;var i,a=r(i);let o=a},2177(e,t,n){"use strict";n.d(t,{Z:()=>o});var r=!0,i="Invariant failed";function a(e,t){if(!e){if(r)throw Error(i);throw Error(i+": "+(t||""))}}let o=a},11742(e){e.exports=function(){var e=document.getSelection();if(!e.rangeCount)return function(){};for(var t=document.activeElement,n=[],r=0;ri,pi:()=>a});var r=function(e,t){return(r=Object.setPrototypeOf||({__proto__:[]})instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])})(e,t)};function i(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}var a=function(){return(a=Object.assign||function(e){for(var t,n=1,r=arguments.length;nr})},94927(e,t,n){function r(e,t){if(i("noDeprecation"))return e;var n=!1;function r(){if(!n){if(i("throwDeprecation"))throw Error(t);i("traceDeprecation")?console.trace(t):console.warn(t),n=!0}return e.apply(this,arguments)}return r}function i(e){try{if(!n.g.localStorage)return!1}catch(t){return!1}var r=n.g.localStorage[e];return null!=r&&"true"===String(r).toLowerCase()}e.exports=r},42473(e){"use strict";var t=function(){};e.exports=t},84763(e){e.exports=Worker},47529(e){e.exports=n;var t=Object.prototype.hasOwnProperty;function n(){for(var e={},n=0;nr,O:()=>a}),(i=r||(r={}))[i.loading=1]="loading",i[i.setVariables=2]="setVariables",i[i.fetchMore=3]="fetchMore",i[i.refetch=4]="refetch",i[i.poll=6]="poll",i[i.ready=7]="ready",i[i.error=8]="error"},30990(e,t,n){"use strict";n.d(t,{MS:()=>s,YG:()=>a,cA:()=>c,ls:()=>o});var r=n(23564);n(83952);var i=n(13154),a=Symbol();function o(e){return!!e.extensions&&Array.isArray(e.extensions[a])}function s(e){return e.hasOwnProperty("graphQLErrors")}var u=function(e){var t=(0,r.ev)((0,r.ev)((0,r.ev)([],e.graphQLErrors,!0),e.clientErrors,!0),e.protocolErrors,!0);return e.networkError&&t.push(e.networkError),t.map(function(e){return(0,i.s)(e)&&e.message||"Error message not found."}).join("\n")},c=function(e){function t(n){var r=n.graphQLErrors,i=n.protocolErrors,a=n.clientErrors,o=n.networkError,s=n.errorMessage,c=n.extraInfo,l=e.call(this,s)||this;return l.name="ApolloError",l.graphQLErrors=r||[],l.protocolErrors=i||[],l.clientErrors=a||[],l.networkError=o||null,l.message=s||u(l),l.extraInfo=c,l.__proto__=t.prototype,l}return(0,r.ZT)(t,e),t}(Error)},85317(e,t,n){"use strict";n.d(t,{K:()=>a});var r=n(67294),i=n(30320).aS?Symbol.for("__APOLLO_CONTEXT__"):"__APOLLO_CONTEXT__";function a(){var e=r.createContext[i];return e||(Object.defineProperty(r.createContext,i,{value:e=r.createContext({}),enumerable:!1,writable:!1,configurable:!0}),e.displayName="ApolloContext"),e}},21436(e,t,n){"use strict";n.d(t,{O:()=>i,k:()=>r});var r=Array.isArray;function i(e){return Array.isArray(e)&&e.length>0}},30320(e,t,n){"use strict";n.d(t,{DN:()=>s,JC:()=>l,aS:()=>o,mr:()=>i,sy:()=>a});var r=n(83952),i="function"==typeof WeakMap&&"ReactNative"!==(0,r.wY)(function(){return navigator.product}),a="function"==typeof WeakSet,o="function"==typeof Symbol&&"function"==typeof Symbol.for,s=o&&Symbol.asyncIterator,u="function"==typeof(0,r.wY)(function(){return window.document.createElement}),c=(0,r.wY)(function(){return navigator.userAgent.indexOf("jsdom")>=0})||!1,l=u&&!c},53712(e,t,n){"use strict";function r(){for(var e=[],t=0;tr})},10542(e,t,n){"use strict";n.d(t,{J:()=>o}),n(83952);var r=n(13154);function i(e){var t=new Set([e]);return t.forEach(function(e){(0,r.s)(e)&&a(e)===e&&Object.getOwnPropertyNames(e).forEach(function(n){(0,r.s)(e[n])&&t.add(e[n])})}),e}function a(e){if(__DEV__&&!Object.isFrozen(e))try{Object.freeze(e)}catch(t){if(t instanceof TypeError)return null;throw t}return e}function o(e){return __DEV__&&i(e),e}},14012(e,t,n){"use strict";n.d(t,{J:()=>a});var r=n(23564),i=n(53712);function a(e,t){return(0,i.o)(e,t,t.variables&&{variables:(0,r.pi)((0,r.pi)({},e&&e.variables),t.variables)})}},13154(e,t,n){"use strict";function r(e){return null!==e&&"object"==typeof e}n.d(t,{s:()=>r})},83952(e,t,n){"use strict";n.d(t,{ej:()=>u,kG:()=>c,wY:()=>h});var r,i=n(70655),a="Invariant Violation",o=Object.setPrototypeOf,s=void 0===o?function(e,t){return e.__proto__=t,e}:o,u=function(e){function t(n){void 0===n&&(n=a);var r=e.call(this,"number"==typeof n?a+": "+n+" (see https://github.com/apollographql/invariant-packages)":n)||this;return r.framesToPop=1,r.name=a,s(r,t.prototype),r}return(0,i.ZT)(t,e),t}(Error);function c(e,t){if(!e)throw new u(t)}var l=["debug","log","warn","error","silent"],f=l.indexOf("log");function d(e){return function(){if(l.indexOf(e)>=f)return(console[e]||console.log).apply(console,arguments)}}function h(e){try{return e()}catch(t){}}(r=c||(c={})).debug=d("debug"),r.log=d("log"),r.warn=d("warn"),r.error=d("error");let p=h(function(){return globalThis})||h(function(){return window})||h(function(){return self})||h(function(){return global})||h(function(){return h.constructor("return this")()});var b="__",m=[b,b].join("DEV");function g(){try{return Boolean(__DEV__)}catch(e){return Object.defineProperty(p,m,{value:"production"!==h(function(){return"production"}),enumerable:!1,configurable:!0,writable:!0}),p[m]}}let v=g();function y(e){try{return e()}catch(t){}}var w=y(function(){return globalThis})||y(function(){return window})||y(function(){return self})||y(function(){return global})||y(function(){return y.constructor("return this")()}),_=!1;function E(){!w||y(function(){return"production"})||y(function(){return process})||(Object.defineProperty(w,"process",{value:{env:{NODE_ENV:"production"}},configurable:!0,enumerable:!1,writable:!0}),_=!0)}function S(){_&&(delete w.process,_=!1)}E();var k=n(10143);function x(){return k.H,S()}function T(){__DEV__?c("boolean"==typeof v,v):c("boolean"==typeof v,39)}x(),T()},87462(e,t,n){"use strict";function r(){return(r=Object.assign||function(e){for(var t=1;tr})},25821(e,t,n){"use strict";n.d(t,{Z:()=>s});var r=n(45695);function i(e){return(i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}var a=10,o=2;function s(e){return u(e,[])}function u(e,t){switch(i(e)){case"string":return JSON.stringify(e);case"function":return e.name?"[function ".concat(e.name,"]"):"[function]";case"object":if(null===e)return"null";return c(e,t);default:return String(e)}}function c(e,t){if(-1!==t.indexOf(e))return"[Circular]";var n=[].concat(t,[e]),r=d(e);if(void 0!==r){var i=r.call(e);if(i!==e)return"string"==typeof i?i:u(i,n)}else if(Array.isArray(e))return f(e,n);return l(e,n)}function l(e,t){var n=Object.keys(e);return 0===n.length?"{}":t.length>o?"["+h(e)+"]":"{ "+n.map(function(n){var r=u(e[n],t);return n+": "+r}).join(", ")+" }"}function f(e,t){if(0===e.length)return"[]";if(t.length>o)return"[Array]";for(var n=Math.min(a,e.length),r=e.length-n,i=[],s=0;s1&&i.push("... ".concat(r," more items")),"["+i.join(", ")+"]"}function d(e){var t=e[String(r.Z)];return"function"==typeof t?t:"function"==typeof e.inspect?e.inspect:void 0}function h(e){var t=Object.prototype.toString.call(e).replace(/^\[object /,"").replace(/]$/,"");if("Object"===t&&"function"==typeof e.constructor){var n=e.constructor.name;if("string"==typeof n&&""!==n)return n}return t}},45695(e,t,n){"use strict";n.d(t,{Z:()=>i});var r="function"==typeof Symbol&&"function"==typeof Symbol.for?Symbol.for("nodejs.util.inspect.custom"):void 0;let i=r},25217(e,t,n){"use strict";function r(e,t){if(!Boolean(e))throw Error(null!=t?t:"Unexpected invariant triggered.")}n.d(t,{Ye:()=>o,WU:()=>s,UG:()=>u});var i=n(45695);function a(e){var t=e.prototype.toJSON;"function"==typeof t||r(0),e.prototype.inspect=t,i.Z&&(e.prototype[i.Z]=t)}var o=function(){function e(e,t,n){this.start=e.start,this.end=t.end,this.startToken=e,this.endToken=t,this.source=n}return e.prototype.toJSON=function(){return{start:this.start,end:this.end}},e}();a(o);var s=function(){function e(e,t,n,r,i,a,o){this.kind=e,this.start=t,this.end=n,this.line=r,this.column=i,this.value=o,this.prev=a,this.next=null}return e.prototype.toJSON=function(){return{kind:this.kind,value:this.value,line:this.line,column:this.column}},e}();function u(e){return null!=e&&"string"==typeof e.kind}a(s)},87392(e,t,n){"use strict";function r(e){var t=e.split(/\r\n|[\n\r]/g),n=a(e);if(0!==n)for(var r=1;ro&&i(t[s-1]);)--s;return t.slice(o,s).join("\n")}function i(e){for(var t=0;t1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],r=-1===e.indexOf("\n"),i=" "===e[0]||" "===e[0],a='"'===e[e.length-1],o="\\"===e[e.length-1],s=!r||a||o||n,u="";return s&&!(r&&i)&&(u+="\n"+t),u+=t?e.replace(/\n/g,"\n"+t):e,s&&(u+="\n"),'"""'+u.replace(/"""/g,'\\"""')+'"""'}n.d(t,{LZ:()=>o,W7:()=>r})},97359(e,t,n){"use strict";n.d(t,{h:()=>r});var r=Object.freeze({NAME:"Name",DOCUMENT:"Document",OPERATION_DEFINITION:"OperationDefinition",VARIABLE_DEFINITION:"VariableDefinition",SELECTION_SET:"SelectionSet",FIELD:"Field",ARGUMENT:"Argument",FRAGMENT_SPREAD:"FragmentSpread",INLINE_FRAGMENT:"InlineFragment",FRAGMENT_DEFINITION:"FragmentDefinition",VARIABLE:"Variable",INT:"IntValue",FLOAT:"FloatValue",STRING:"StringValue",BOOLEAN:"BooleanValue",NULL:"NullValue",ENUM:"EnumValue",LIST:"ListValue",OBJECT:"ObjectValue",OBJECT_FIELD:"ObjectField",DIRECTIVE:"Directive",NAMED_TYPE:"NamedType",LIST_TYPE:"ListType",NON_NULL_TYPE:"NonNullType",SCHEMA_DEFINITION:"SchemaDefinition",OPERATION_TYPE_DEFINITION:"OperationTypeDefinition",SCALAR_TYPE_DEFINITION:"ScalarTypeDefinition",OBJECT_TYPE_DEFINITION:"ObjectTypeDefinition",FIELD_DEFINITION:"FieldDefinition",INPUT_VALUE_DEFINITION:"InputValueDefinition",INTERFACE_TYPE_DEFINITION:"InterfaceTypeDefinition",UNION_TYPE_DEFINITION:"UnionTypeDefinition",ENUM_TYPE_DEFINITION:"EnumTypeDefinition",ENUM_VALUE_DEFINITION:"EnumValueDefinition",INPUT_OBJECT_TYPE_DEFINITION:"InputObjectTypeDefinition",DIRECTIVE_DEFINITION:"DirectiveDefinition",SCHEMA_EXTENSION:"SchemaExtension",SCALAR_TYPE_EXTENSION:"ScalarTypeExtension",OBJECT_TYPE_EXTENSION:"ObjectTypeExtension",INTERFACE_TYPE_EXTENSION:"InterfaceTypeExtension",UNION_TYPE_EXTENSION:"UnionTypeExtension",ENUM_TYPE_EXTENSION:"EnumTypeExtension",INPUT_OBJECT_TYPE_EXTENSION:"InputObjectTypeExtension"})},10143(e,t,n){"use strict";n.d(t,{H:()=>c,T:()=>l});var r=n(99763),i=n(25821);function a(e,t){if(!Boolean(e))throw Error(t)}let o=function(e,t){return e instanceof t};function s(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:"GraphQL request",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{line:1,column:1};"string"==typeof e||a(0,"Body must be a string. Received: ".concat((0,i.Z)(e),".")),this.body=e,this.name=t,this.locationOffset=n,this.locationOffset.line>0||a(0,"line in locationOffset is 1-indexed and must be positive."),this.locationOffset.column>0||a(0,"column in locationOffset is 1-indexed and must be positive.")}return u(e,[{key:r.YF,get:function(){return"Source"}}]),e}();function l(e){return o(e,c)}},99763(e,t,n){"use strict";n.d(t,{YF:()=>r});var r="function"==typeof Symbol&&null!=Symbol.toStringTag?Symbol.toStringTag:"@@toStringTag"},37452(e){"use strict";e.exports=JSON.parse('{"AElig":"\xc6","AMP":"&","Aacute":"\xc1","Acirc":"\xc2","Agrave":"\xc0","Aring":"\xc5","Atilde":"\xc3","Auml":"\xc4","COPY":"\xa9","Ccedil":"\xc7","ETH":"\xd0","Eacute":"\xc9","Ecirc":"\xca","Egrave":"\xc8","Euml":"\xcb","GT":">","Iacute":"\xcd","Icirc":"\xce","Igrave":"\xcc","Iuml":"\xcf","LT":"<","Ntilde":"\xd1","Oacute":"\xd3","Ocirc":"\xd4","Ograve":"\xd2","Oslash":"\xd8","Otilde":"\xd5","Ouml":"\xd6","QUOT":"\\"","REG":"\xae","THORN":"\xde","Uacute":"\xda","Ucirc":"\xdb","Ugrave":"\xd9","Uuml":"\xdc","Yacute":"\xdd","aacute":"\xe1","acirc":"\xe2","acute":"\xb4","aelig":"\xe6","agrave":"\xe0","amp":"&","aring":"\xe5","atilde":"\xe3","auml":"\xe4","brvbar":"\xa6","ccedil":"\xe7","cedil":"\xb8","cent":"\xa2","copy":"\xa9","curren":"\xa4","deg":"\xb0","divide":"\xf7","eacute":"\xe9","ecirc":"\xea","egrave":"\xe8","eth":"\xf0","euml":"\xeb","frac12":"\xbd","frac14":"\xbc","frac34":"\xbe","gt":">","iacute":"\xed","icirc":"\xee","iexcl":"\xa1","igrave":"\xec","iquest":"\xbf","iuml":"\xef","laquo":"\xab","lt":"<","macr":"\xaf","micro":"\xb5","middot":"\xb7","nbsp":"\xa0","not":"\xac","ntilde":"\xf1","oacute":"\xf3","ocirc":"\xf4","ograve":"\xf2","ordf":"\xaa","ordm":"\xba","oslash":"\xf8","otilde":"\xf5","ouml":"\xf6","para":"\xb6","plusmn":"\xb1","pound":"\xa3","quot":"\\"","raquo":"\xbb","reg":"\xae","sect":"\xa7","shy":"\xad","sup1":"\xb9","sup2":"\xb2","sup3":"\xb3","szlig":"\xdf","thorn":"\xfe","times":"\xd7","uacute":"\xfa","ucirc":"\xfb","ugrave":"\xf9","uml":"\xa8","uuml":"\xfc","yacute":"\xfd","yen":"\xa5","yuml":"\xff"}')},93580(e){"use strict";e.exports=JSON.parse('{"0":"�","128":"€","130":"‚","131":"ƒ","132":"„","133":"…","134":"†","135":"‡","136":"ˆ","137":"‰","138":"Š","139":"‹","140":"Œ","142":"Ž","145":"‘","146":"’","147":"“","148":"”","149":"•","150":"–","151":"—","152":"˜","153":"™","154":"š","155":"›","156":"œ","158":"ž","159":"Ÿ"}')},67946(e){"use strict";e.exports=JSON.parse('{"locale":"en","long":{"year":{"previous":"last year","current":"this year","next":"next year","past":{"one":"{0} year ago","other":"{0} years ago"},"future":{"one":"in {0} year","other":"in {0} years"}},"quarter":{"previous":"last quarter","current":"this quarter","next":"next quarter","past":{"one":"{0} quarter ago","other":"{0} quarters ago"},"future":{"one":"in {0} quarter","other":"in {0} quarters"}},"month":{"previous":"last month","current":"this month","next":"next month","past":{"one":"{0} month ago","other":"{0} months ago"},"future":{"one":"in {0} month","other":"in {0} months"}},"week":{"previous":"last week","current":"this week","next":"next week","past":{"one":"{0} week ago","other":"{0} weeks ago"},"future":{"one":"in {0} week","other":"in {0} weeks"}},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":{"one":"{0} hour ago","other":"{0} hours ago"},"future":{"one":"in {0} hour","other":"in {0} hours"}},"minute":{"current":"this minute","past":{"one":"{0} minute ago","other":"{0} minutes ago"},"future":{"one":"in {0} minute","other":"in {0} minutes"}},"second":{"current":"now","past":{"one":"{0} second ago","other":"{0} seconds ago"},"future":{"one":"in {0} second","other":"in {0} seconds"}}},"short":{"year":{"previous":"last yr.","current":"this yr.","next":"next yr.","past":"{0} yr. ago","future":"in {0} yr."},"quarter":{"previous":"last qtr.","current":"this qtr.","next":"next qtr.","past":{"one":"{0} qtr. ago","other":"{0} qtrs. ago"},"future":{"one":"in {0} qtr.","other":"in {0} qtrs."}},"month":{"previous":"last mo.","current":"this mo.","next":"next mo.","past":"{0} mo. ago","future":"in {0} mo."},"week":{"previous":"last wk.","current":"this wk.","next":"next wk.","past":"{0} wk. ago","future":"in {0} wk."},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":"{0} hr. ago","future":"in {0} hr."},"minute":{"current":"this minute","past":"{0} min. ago","future":"in {0} min."},"second":{"current":"now","past":"{0} sec. ago","future":"in {0} sec."}},"narrow":{"year":{"previous":"last yr.","current":"this yr.","next":"next yr.","past":"{0} yr. ago","future":"in {0} yr."},"quarter":{"previous":"last qtr.","current":"this qtr.","next":"next qtr.","past":{"one":"{0} qtr. ago","other":"{0} qtrs. ago"},"future":{"one":"in {0} qtr.","other":"in {0} qtrs."}},"month":{"previous":"last mo.","current":"this mo.","next":"next mo.","past":"{0} mo. ago","future":"in {0} mo."},"week":{"previous":"last wk.","current":"this wk.","next":"next wk.","past":"{0} wk. ago","future":"in {0} wk."},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":"{0} hr. ago","future":"in {0} hr."},"minute":{"current":"this minute","past":"{0} min. ago","future":"in {0} min."},"second":{"current":"now","past":"{0} sec. ago","future":"in {0} sec."}},"now":{"now":{"current":"now","future":"in a moment","past":"just now"}},"mini":{"year":"{0}yr","month":"{0}mo","week":"{0}wk","day":"{0}d","hour":"{0}h","minute":"{0}m","second":"{0}s","now":"now"},"short-time":{"year":"{0} yr.","month":"{0} mo.","week":"{0} wk.","day":{"one":"{0} day","other":"{0} days"},"hour":"{0} hr.","minute":"{0} min.","second":"{0} sec."},"long-time":{"year":{"one":"{0} year","other":"{0} years"},"month":{"one":"{0} month","other":"{0} months"},"week":{"one":"{0} week","other":"{0} weeks"},"day":{"one":"{0} day","other":"{0} days"},"hour":{"one":"{0} hour","other":"{0} hours"},"minute":{"one":"{0} minute","other":"{0} minutes"},"second":{"one":"{0} second","other":"{0} seconds"}}}')}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={id:e,loaded:!1,exports:{}};return __webpack_modules__[e].call(n.exports,n,n.exports,__webpack_require__),n.loaded=!0,n.exports}__webpack_require__.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return __webpack_require__.d(t,{a:t}),t},(()=>{var e,t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__;__webpack_require__.t=function(n,r){if(1&r&&(n=this(n)),8&r||"object"==typeof n&&n&&(4&r&&n.__esModule||16&r&&"function"==typeof n.then))return n;var i=Object.create(null);__webpack_require__.r(i);var a={};e=e||[null,t({}),t([]),t(t)];for(var o=2&r&&n;"object"==typeof o&&!~e.indexOf(o);o=t(o))Object.getOwnPropertyNames(o).forEach(e=>a[e]=()=>n[e]);return a.default=()=>n,__webpack_require__.d(i,a),i}})(),__webpack_require__.d=(e,t)=>{for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),__webpack_require__.hmd=e=>((e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set(){throw Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e),__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},__webpack_require__.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),__webpack_require__.p="/assets/",__webpack_require__.nc=void 0;var __webpack_exports__={};(()=>{"use strict";var e,t,n,r,i=__webpack_require__(32316),a=__webpack_require__(8126),o=__webpack_require__(5690),s=__webpack_require__(30381),u=__webpack_require__.n(s),c=__webpack_require__(67294),l=__webpack_require__(73935),f=__webpack_require__.n(l),d=__webpack_require__(57209),h=__webpack_require__(55977),p=__webpack_require__(15857),b=__webpack_require__(28500);function m(e){return function(t){var n=t.dispatch,r=t.getState;return function(t){return function(i){return"function"==typeof i?i(n,r,e):t(i)}}}}var g=m();g.withExtraArgument=m;let v=g;var y=__webpack_require__(76489);function w(e){return function(t){return function(n){return function(r){n(r);var i=e||document&&document.cookie||"",a=t.getState();if("MATCH_ROUTE"===r.type&&"/signin"!==a.notifications.currentUrl){var o=(0,y.Q)(i);if(o.explorer)try{var s=JSON.parse(o.explorer);if("error"===s.status){var u=_(s.url);n({type:"NOTIFY_ERROR_MSG",msg:u})}}catch(c){n({type:"NOTIFY_ERROR_MSG",msg:"Invalid explorer status"})}}}}}}function _(e){var t="Can't connect to explorer: ".concat(e);return e.match(/^wss?:.+/)?t:"".concat(t,". You must use a websocket.")}var E=__webpack_require__(16353);function S(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n=e.length?{done:!0}:{done:!1,value:e[r++]}}}throw TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function ei(e,t){if(e){if("string"==typeof e)return ea(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);if("Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return ea(e,t)}}function ea(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1,i=!1,a=arguments[1],o=a;return new n(function(n){return t.subscribe({next:function(t){var a=!i;if(i=!0,!a||r)try{o=e(o,t)}catch(s){return n.error(s)}else o=t},error:function(e){n.error(e)},complete:function(){if(!i&&!r)return n.error(TypeError("Cannot reduce an empty sequence"));n.next(o),n.complete()}})})},t.concat=function(){for(var e=this,t=arguments.length,n=Array(t),r=0;r=0&&i.splice(e,1),o()}});i.push(s)},error:function(e){r.error(e)},complete:function(){o()}});function o(){a.closed&&0===i.length&&r.complete()}return function(){i.forEach(function(e){return e.unsubscribe()}),a.unsubscribe()}})},t[ed]=function(){return this},e.from=function(t){var n="function"==typeof this?this:e;if(null==t)throw TypeError(t+" is not an object");var r=ep(t,ed);if(r){var i=r.call(t);if(Object(i)!==i)throw TypeError(i+" is not an object");return em(i)&&i.constructor===n?i:new n(function(e){return i.subscribe(e)})}if(ec("iterator")&&(r=ep(t,ef)))return new n(function(e){ev(function(){if(!e.closed){for(var n,i=er(r.call(t));!(n=i()).done;){var a=n.value;if(e.next(a),e.closed)return}e.complete()}})});if(Array.isArray(t))return new n(function(e){ev(function(){if(!e.closed){for(var n=0;n0))return n.connection.key;var r=n.connection.filter?n.connection.filter:[];r.sort();var i={};return r.forEach(function(e){i[e]=t[e]}),"".concat(n.connection.key,"(").concat(eV(i),")")}var a=e;if(t){var o=eV(t);a+="(".concat(o,")")}return n&&Object.keys(n).forEach(function(e){-1===eW.indexOf(e)&&(n[e]&&Object.keys(n[e]).length?a+="@".concat(e,"(").concat(eV(n[e]),")"):a+="@".concat(e))}),a},{setStringify:function(e){var t=eV;return eV=e,t}}),eV=function(e){return JSON.stringify(e,eq)};function eq(e,t){return(0,eO.s)(t)&&!Array.isArray(t)&&(t=Object.keys(t).sort().reduce(function(e,n){return e[n]=t[n],e},{})),t}function eZ(e,t){if(e.arguments&&e.arguments.length){var n={};return e.arguments.forEach(function(e){var r;return ez(n,e.name,e.value,t)}),n}return null}function eX(e){return e.alias?e.alias.value:e.name.value}function eJ(e,t,n){for(var r,i=0,a=t.selections;it.indexOf(i))throw __DEV__?new Q.ej("illegal argument: ".concat(i)):new Q.ej(27)}return e}function tt(e,t){return t?t(e):eT.of()}function tn(e){return"function"==typeof e?new ta(e):e}function tr(e){return e.request.length<=1}var ti=function(e){function t(t,n){var r=e.call(this,t)||this;return r.link=n,r}return(0,en.ZT)(t,e),t}(Error),ta=function(){function e(e){e&&(this.request=e)}return e.empty=function(){return new e(function(){return eT.of()})},e.from=function(t){return 0===t.length?e.empty():t.map(tn).reduce(function(e,t){return e.concat(t)})},e.split=function(t,n,r){var i=tn(n),a=tn(r||new e(tt));return new e(tr(i)&&tr(a)?function(e){return t(e)?i.request(e)||eT.of():a.request(e)||eT.of()}:function(e,n){return t(e)?i.request(e,n)||eT.of():a.request(e,n)||eT.of()})},e.execute=function(e,t){return e.request(eM(t.context,e7(te(t))))||eT.of()},e.concat=function(t,n){var r=tn(t);if(tr(r))return __DEV__&&Q.kG.warn(new ti("You are calling concat on a terminating link, which will have no effect",r)),r;var i=tn(n);return new e(tr(i)?function(e){return r.request(e,function(e){return i.request(e)||eT.of()})||eT.of()}:function(e,t){return r.request(e,function(e){return i.request(e,t)||eT.of()})||eT.of()})},e.prototype.split=function(t,n,r){return this.concat(e.split(t,n,r||new e(tt)))},e.prototype.concat=function(t){return e.concat(this,t)},e.prototype.request=function(e,t){throw __DEV__?new Q.ej("request is not implemented"):new Q.ej(22)},e.prototype.onError=function(e,t){if(t&&t.error)return t.error(e),!1;throw e},e.prototype.setOnError=function(e){return this.onError=e,this},e}(),to=__webpack_require__(25821),ts=__webpack_require__(25217),tu={Name:[],Document:["definitions"],OperationDefinition:["name","variableDefinitions","directives","selectionSet"],VariableDefinition:["variable","type","defaultValue","directives"],Variable:["name"],SelectionSet:["selections"],Field:["alias","name","arguments","directives","selectionSet"],Argument:["name","value"],FragmentSpread:["name","directives"],InlineFragment:["typeCondition","directives","selectionSet"],FragmentDefinition:["name","variableDefinitions","typeCondition","directives","selectionSet"],IntValue:[],FloatValue:[],StringValue:[],BooleanValue:[],NullValue:[],EnumValue:[],ListValue:["values"],ObjectValue:["fields"],ObjectField:["name","value"],Directive:["name","arguments"],NamedType:["name"],ListType:["type"],NonNullType:["type"],SchemaDefinition:["description","directives","operationTypes"],OperationTypeDefinition:["type"],ScalarTypeDefinition:["description","name","directives"],ObjectTypeDefinition:["description","name","interfaces","directives","fields"],FieldDefinition:["description","name","arguments","type","directives"],InputValueDefinition:["description","name","type","defaultValue","directives"],InterfaceTypeDefinition:["description","name","interfaces","directives","fields"],UnionTypeDefinition:["description","name","directives","types"],EnumTypeDefinition:["description","name","directives","values"],EnumValueDefinition:["description","name","directives"],InputObjectTypeDefinition:["description","name","directives","fields"],DirectiveDefinition:["description","name","arguments","locations"],SchemaExtension:["directives","operationTypes"],ScalarTypeExtension:["name","directives"],ObjectTypeExtension:["name","interfaces","directives","fields"],InterfaceTypeExtension:["name","interfaces","directives","fields"],UnionTypeExtension:["name","directives","types"],EnumTypeExtension:["name","directives","values"],InputObjectTypeExtension:["name","directives","fields"]},tc=Object.freeze({});function tl(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:tu,r=void 0,i=Array.isArray(e),a=[e],o=-1,s=[],u=void 0,c=void 0,l=void 0,f=[],d=[],h=e;do{var p,b=++o===a.length,m=b&&0!==s.length;if(b){if(c=0===d.length?void 0:f[f.length-1],u=l,l=d.pop(),m){if(i)u=u.slice();else{for(var g={},v=0,y=Object.keys(u);v1)for(var r=new tB,i=1;i=0;--a){var o=i[a],s=isNaN(+o)?{}:[];s[o]=t,t=s}n=r.merge(n,t)}),n}var tW=Object.prototype.hasOwnProperty;function tK(e,t){var n,r,i,a,o;return(0,en.mG)(this,void 0,void 0,function(){var s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T,M,O,A;return(0,en.Jh)(this,function(L){switch(L.label){case 0:if(void 0===TextDecoder)throw Error("TextDecoder must be defined in the environment: please import a polyfill.");s=new TextDecoder("utf-8"),u=null===(n=e.headers)||void 0===n?void 0:n.get("content-type"),c="boundary=",l=(null==u?void 0:u.includes(c))?null==u?void 0:u.substring((null==u?void 0:u.indexOf(c))+c.length).replace(/['"]/g,"").replace(/\;(.*)/gm,"").trim():"-",f="\r\n--".concat(l),d="",h=tI(e),p=!0,L.label=1;case 1:if(!p)return[3,3];return[4,h.next()];case 2:for(m=(b=L.sent()).value,g=b.done,v="string"==typeof m?m:s.decode(m),y=d.length-f.length+1,p=!g,d+=v,w=d.indexOf(f,y);w>-1;){if(_=void 0,_=(O=[d.slice(0,w),d.slice(w+f.length),])[0],d=O[1],E=_.indexOf("\r\n\r\n"),(k=(S=tV(_.slice(0,E)))["content-type"])&&-1===k.toLowerCase().indexOf("application/json"))throw Error("Unsupported patch content type: application/json is required.");if(x=_.slice(E))try{T=tq(e,x),Object.keys(T).length>1||"data"in T||"incremental"in T||"errors"in T||"payload"in T?tz(T)?(M={},"payload"in T&&(M=(0,en.pi)({},T.payload)),"errors"in T&&(M=(0,en.pi)((0,en.pi)({},M),{extensions:(0,en.pi)((0,en.pi)({},"extensions"in M?M.extensions:null),((A={})[tN.YG]=T.errors,A))})),null===(r=t.next)||void 0===r||r.call(t,M)):null===(i=t.next)||void 0===i||i.call(t,T):1===Object.keys(T).length&&"hasNext"in T&&!T.hasNext&&(null===(a=t.complete)||void 0===a||a.call(t))}catch(C){tZ(C,t)}w=d.indexOf(f)}return[3,1];case 3:return null===(o=t.complete)||void 0===o||o.call(t),[2]}})})}function tV(e){var t={};return e.split("\n").forEach(function(e){var n=e.indexOf(":");if(n>-1){var r=e.slice(0,n).trim().toLowerCase(),i=e.slice(n+1).trim();t[r]=i}}),t}function tq(e,t){e.status>=300&&tD(e,function(){try{return JSON.parse(t)}catch(e){return t}}(),"Response not successful: Received status code ".concat(e.status));try{return JSON.parse(t)}catch(n){var r=n;throw r.name="ServerParseError",r.response=e,r.statusCode=e.status,r.bodyText=t,r}}function tZ(e,t){var n,r;"AbortError"!==e.name&&(e.result&&e.result.errors&&e.result.data&&(null===(n=t.next)||void 0===n||n.call(t,e.result)),null===(r=t.error)||void 0===r||r.call(t,e))}function tX(e,t,n){tJ(t)(e).then(function(e){var t,r;null===(t=n.next)||void 0===t||t.call(n,e),null===(r=n.complete)||void 0===r||r.call(n)}).catch(function(e){return tZ(e,n)})}function tJ(e){return function(t){return t.text().then(function(e){return tq(t,e)}).then(function(n){return t.status>=300&&tD(t,n,"Response not successful: Received status code ".concat(t.status)),Array.isArray(n)||tW.call(n,"data")||tW.call(n,"errors")||tD(t,n,"Server response was missing for query '".concat(Array.isArray(e)?e.map(function(e){return e.operationName}):e.operationName,"'.")),n})}}var tQ=function(e){if(!e&&"undefined"==typeof fetch)throw __DEV__?new Q.ej("\n\"fetch\" has not been found globally and no fetcher has been configured. To fix this, install a fetch package (like https://www.npmjs.com/package/cross-fetch), instantiate the fetcher, and pass it into your HttpLink constructor. For example:\n\nimport fetch from 'cross-fetch';\nimport { ApolloClient, HttpLink } from '@apollo/client';\nconst client = new ApolloClient({\n link: new HttpLink({ uri: '/graphql', fetch })\n});\n "):new Q.ej(23)},t1=__webpack_require__(87392);function t0(e){return tl(e,{leave:t3})}var t2=80,t3={Name:function(e){return e.value},Variable:function(e){return"$"+e.name},Document:function(e){return t5(e.definitions,"\n\n")+"\n"},OperationDefinition:function(e){var t=e.operation,n=e.name,r=t9("(",t5(e.variableDefinitions,", "),")"),i=t5(e.directives," "),a=e.selectionSet;return n||i||r||"query"!==t?t5([t,t5([n,r]),i,a]," "):a},VariableDefinition:function(e){var t=e.variable,n=e.type,r=e.defaultValue,i=e.directives;return t+": "+n+t9(" = ",r)+t9(" ",t5(i," "))},SelectionSet:function(e){return t6(e.selections)},Field:function(e){var t=e.alias,n=e.name,r=e.arguments,i=e.directives,a=e.selectionSet,o=t9("",t,": ")+n,s=o+t9("(",t5(r,", "),")");return s.length>t2&&(s=o+t9("(\n",t8(t5(r,"\n")),"\n)")),t5([s,t5(i," "),a]," ")},Argument:function(e){var t;return e.name+": "+e.value},FragmentSpread:function(e){var t;return"..."+e.name+t9(" ",t5(e.directives," "))},InlineFragment:function(e){var t=e.typeCondition,n=e.directives,r=e.selectionSet;return t5(["...",t9("on ",t),t5(n," "),r]," ")},FragmentDefinition:function(e){var t=e.name,n=e.typeCondition,r=e.variableDefinitions,i=e.directives,a=e.selectionSet;return"fragment ".concat(t).concat(t9("(",t5(r,", "),")")," ")+"on ".concat(n," ").concat(t9("",t5(i," ")," "))+a},IntValue:function(e){return e.value},FloatValue:function(e){return e.value},StringValue:function(e,t){var n=e.value;return e.block?(0,t1.LZ)(n,"description"===t?"":" "):JSON.stringify(n)},BooleanValue:function(e){return e.value?"true":"false"},NullValue:function(){return"null"},EnumValue:function(e){return e.value},ListValue:function(e){return"["+t5(e.values,", ")+"]"},ObjectValue:function(e){return"{"+t5(e.fields,", ")+"}"},ObjectField:function(e){var t;return e.name+": "+e.value},Directive:function(e){var t;return"@"+e.name+t9("(",t5(e.arguments,", "),")")},NamedType:function(e){return e.name},ListType:function(e){return"["+e.type+"]"},NonNullType:function(e){return e.type+"!"},SchemaDefinition:t4(function(e){var t=e.directives,n=e.operationTypes;return t5(["schema",t5(t," "),t6(n)]," ")}),OperationTypeDefinition:function(e){var t;return e.operation+": "+e.type},ScalarTypeDefinition:t4(function(e){var t;return t5(["scalar",e.name,t5(e.directives," ")]," ")}),ObjectTypeDefinition:t4(function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["type",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")}),FieldDefinition:t4(function(e){var t=e.name,n=e.arguments,r=e.type,i=e.directives;return t+(ne(n)?t9("(\n",t8(t5(n,"\n")),"\n)"):t9("(",t5(n,", "),")"))+": "+r+t9(" ",t5(i," "))}),InputValueDefinition:t4(function(e){var t=e.name,n=e.type,r=e.defaultValue,i=e.directives;return t5([t+": "+n,t9("= ",r),t5(i," ")]," ")}),InterfaceTypeDefinition:t4(function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["interface",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")}),UnionTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.types;return t5(["union",t,t5(n," "),r&&0!==r.length?"= "+t5(r," | "):""]," ")}),EnumTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.values;return t5(["enum",t,t5(n," "),t6(r)]," ")}),EnumValueDefinition:t4(function(e){var t;return t5([e.name,t5(e.directives," ")]," ")}),InputObjectTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.fields;return t5(["input",t,t5(n," "),t6(r)]," ")}),DirectiveDefinition:t4(function(e){var t=e.name,n=e.arguments,r=e.repeatable,i=e.locations;return"directive @"+t+(ne(n)?t9("(\n",t8(t5(n,"\n")),"\n)"):t9("(",t5(n,", "),")"))+(r?" repeatable":"")+" on "+t5(i," | ")}),SchemaExtension:function(e){var t=e.directives,n=e.operationTypes;return t5(["extend schema",t5(t," "),t6(n)]," ")},ScalarTypeExtension:function(e){var t;return t5(["extend scalar",e.name,t5(e.directives," ")]," ")},ObjectTypeExtension:function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["extend type",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")},InterfaceTypeExtension:function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["extend interface",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")},UnionTypeExtension:function(e){var t=e.name,n=e.directives,r=e.types;return t5(["extend union",t,t5(n," "),r&&0!==r.length?"= "+t5(r," | "):""]," ")},EnumTypeExtension:function(e){var t=e.name,n=e.directives,r=e.values;return t5(["extend enum",t,t5(n," "),t6(r)]," ")},InputObjectTypeExtension:function(e){var t=e.name,n=e.directives,r=e.fields;return t5(["extend input",t,t5(n," "),t6(r)]," ")}};function t4(e){return function(t){return t5([t.description,e(t)],"\n")}}function t5(e){var t,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return null!==(t=null==e?void 0:e.filter(function(e){return e}).join(n))&&void 0!==t?t:""}function t6(e){return t9("{\n",t8(t5(e,"\n")),"\n}")}function t9(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";return null!=t&&""!==t?e+t+n:""}function t8(e){return t9(" ",e.replace(/\n/g,"\n "))}function t7(e){return -1!==e.indexOf("\n")}function ne(e){return null!=e&&e.some(t7)}var nt,nn,nr,ni={http:{includeQuery:!0,includeExtensions:!1,preserveHeaderCase:!1},headers:{accept:"*/*","content-type":"application/json"},options:{method:"POST"}},na=function(e,t){return t(e)};function no(e,t){for(var n=[],r=2;rObject.create(null),{forEach:nv,slice:ny}=Array.prototype,{hasOwnProperty:nw}=Object.prototype;class n_{constructor(e=!0,t=ng){this.weakness=e,this.makeData=t}lookup(...e){return this.lookupArray(e)}lookupArray(e){let t=this;return nv.call(e,e=>t=t.getChildTrie(e)),nw.call(t,"data")?t.data:t.data=this.makeData(ny.call(e))}peek(...e){return this.peekArray(e)}peekArray(e){let t=this;for(let n=0,r=e.length;t&&n=0;--o)t.definitions[o].kind===nL.h.OPERATION_DEFINITION&&++a;var s=nN(e),u=e.some(function(e){return e.remove}),c=function(e){return u&&e&&e.some(s)},l=new Map,f=!1,d={enter:function(e){if(c(e.directives))return f=!0,null}},h=tl(t,{Field:d,InlineFragment:d,VariableDefinition:{enter:function(){return!1}},Variable:{enter:function(e,t,n,r,a){var o=i(a);o&&o.variables.add(e.name.value)}},FragmentSpread:{enter:function(e,t,n,r,a){if(c(e.directives))return f=!0,null;var o=i(a);o&&o.fragmentSpreads.add(e.name.value)}},FragmentDefinition:{enter:function(e,t,n,r){l.set(JSON.stringify(r),e)},leave:function(e,t,n,i){return e===l.get(JSON.stringify(i))?e:a>0&&e.selectionSet.selections.every(function(e){return e.kind===nL.h.FIELD&&"__typename"===e.name.value})?(r(e.name.value).removed=!0,f=!0,null):void 0}},Directive:{leave:function(e){if(s(e))return f=!0,null}}});if(!f)return t;var p=function(e){return e.transitiveVars||(e.transitiveVars=new Set(e.variables),e.removed||e.fragmentSpreads.forEach(function(t){p(r(t)).transitiveVars.forEach(function(t){e.transitiveVars.add(t)})})),e},b=new Set;h.definitions.forEach(function(e){e.kind===nL.h.OPERATION_DEFINITION?p(n(e.name&&e.name.value)).fragmentSpreads.forEach(function(e){b.add(e)}):e.kind!==nL.h.FRAGMENT_DEFINITION||0!==a||r(e.name.value).removed||b.add(e.name.value)}),b.forEach(function(e){p(r(e)).fragmentSpreads.forEach(function(e){b.add(e)})});var m=function(e){return!!(!b.has(e)||r(e).removed)},g={enter:function(e){if(m(e.name.value))return null}};return nD(tl(h,{FragmentSpread:g,FragmentDefinition:g,OperationDefinition:{leave:function(e){if(e.variableDefinitions){var t=p(n(e.name&&e.name.value)).transitiveVars;if(t.size0},t.prototype.tearDownQuery=function(){this.isTornDown||(this.concast&&this.observer&&(this.concast.removeObserver(this.observer),delete this.concast,delete this.observer),this.stopPolling(),this.subscriptions.forEach(function(e){return e.unsubscribe()}),this.subscriptions.clear(),this.queryManager.stopQuery(this.queryId),this.observers.clear(),this.isTornDown=!0)},t}(eT);function n4(e){var t=e.options,n=t.fetchPolicy,r=t.nextFetchPolicy;return"cache-and-network"===n||"network-only"===n?e.reobserve({fetchPolicy:"cache-first",nextFetchPolicy:function(){return(this.nextFetchPolicy=r,"function"==typeof r)?r.apply(this,arguments):n}}):e.reobserve()}function n5(e){__DEV__&&Q.kG.error("Unhandled error",e.message,e.stack)}function n6(e){__DEV__&&e&&__DEV__&&Q.kG.debug("Missing cache result fields: ".concat(JSON.stringify(e)),e)}function n9(e){return"network-only"===e||"no-cache"===e||"standby"===e}nK(n3);function n8(e){return e.kind===nL.h.FIELD||e.kind===nL.h.FRAGMENT_SPREAD||e.kind===nL.h.INLINE_FRAGMENT}function n7(e){return e.kind===Kind.SCALAR_TYPE_DEFINITION||e.kind===Kind.OBJECT_TYPE_DEFINITION||e.kind===Kind.INTERFACE_TYPE_DEFINITION||e.kind===Kind.UNION_TYPE_DEFINITION||e.kind===Kind.ENUM_TYPE_DEFINITION||e.kind===Kind.INPUT_OBJECT_TYPE_DEFINITION}function re(e){return e.kind===Kind.SCALAR_TYPE_EXTENSION||e.kind===Kind.OBJECT_TYPE_EXTENSION||e.kind===Kind.INTERFACE_TYPE_EXTENSION||e.kind===Kind.UNION_TYPE_EXTENSION||e.kind===Kind.ENUM_TYPE_EXTENSION||e.kind===Kind.INPUT_OBJECT_TYPE_EXTENSION}var rt=function(){return Object.create(null)},rn=Array.prototype,rr=rn.forEach,ri=rn.slice,ra=function(){function e(e,t){void 0===e&&(e=!0),void 0===t&&(t=rt),this.weakness=e,this.makeData=t}return e.prototype.lookup=function(){for(var e=[],t=0;tclass{constructor(){this.id=["slot",rc++,Date.now(),Math.random().toString(36).slice(2),].join(":")}hasValue(){for(let e=rs;e;e=e.parent)if(this.id in e.slots){let t=e.slots[this.id];if(t===ru)break;return e!==rs&&(rs.slots[this.id]=t),!0}return rs&&(rs.slots[this.id]=ru),!1}getValue(){if(this.hasValue())return rs.slots[this.id]}withValue(e,t,n,r){let i={__proto__:null,[this.id]:e},a=rs;rs={parent:a,slots:i};try{return t.apply(r,n)}finally{rs=a}}static bind(e){let t=rs;return function(){let n=rs;try{return rs=t,e.apply(this,arguments)}finally{rs=n}}}static noContext(e,t,n){if(!rs)return e.apply(n,t);{let r=rs;try{return rs=null,e.apply(n,t)}finally{rs=r}}}};function rf(e){try{return e()}catch(t){}}let rd="@wry/context:Slot",rh=rf(()=>globalThis)||rf(()=>global)||Object.create(null),rp=rh,rb=rp[rd]||Array[rd]||function(e){try{Object.defineProperty(rp,rd,{value:e,enumerable:!1,writable:!1,configurable:!0})}finally{return e}}(rl()),{bind:rm,noContext:rg}=rb;function rv(){}var ry=function(){function e(e,t){void 0===e&&(e=1/0),void 0===t&&(t=rv),this.max=e,this.dispose=t,this.map=new Map,this.newest=null,this.oldest=null}return e.prototype.has=function(e){return this.map.has(e)},e.prototype.get=function(e){var t=this.getNode(e);return t&&t.value},e.prototype.getNode=function(e){var t=this.map.get(e);if(t&&t!==this.newest){var n=t.older,r=t.newer;r&&(r.older=n),n&&(n.newer=r),t.older=this.newest,t.older.newer=t,t.newer=null,this.newest=t,t===this.oldest&&(this.oldest=r)}return t},e.prototype.set=function(e,t){var n=this.getNode(e);return n?n.value=t:(n={key:e,value:t,newer:null,older:this.newest},this.newest&&(this.newest.newer=n),this.newest=n,this.oldest=this.oldest||n,this.map.set(e,n),n.value)},e.prototype.clean=function(){for(;this.oldest&&this.map.size>this.max;)this.delete(this.oldest.key)},e.prototype.delete=function(e){var t=this.map.get(e);return!!t&&(t===this.newest&&(this.newest=t.older),t===this.oldest&&(this.oldest=t.newer),t.newer&&(t.newer.older=t.older),t.older&&(t.older.newer=t.newer),this.map.delete(e),this.dispose(t.value,e),!0)},e}(),rw=new rb,r_=Object.prototype.hasOwnProperty,rE=void 0===(n=Array.from)?function(e){var t=[];return e.forEach(function(e){return t.push(e)}),t}:n;function rS(e){var t=e.unsubscribe;"function"==typeof t&&(e.unsubscribe=void 0,t())}var rk=[],rx=100;function rT(e,t){if(!e)throw Error(t||"assertion failure")}function rM(e,t){var n=e.length;return n>0&&n===t.length&&e[n-1]===t[n-1]}function rO(e){switch(e.length){case 0:throw Error("unknown value");case 1:return e[0];case 2:throw e[1]}}function rA(e){return e.slice(0)}var rL=function(){function e(t){this.fn=t,this.parents=new Set,this.childValues=new Map,this.dirtyChildren=null,this.dirty=!0,this.recomputing=!1,this.value=[],this.deps=null,++e.count}return e.prototype.peek=function(){if(1===this.value.length&&!rN(this))return rC(this),this.value[0]},e.prototype.recompute=function(e){return rT(!this.recomputing,"already recomputing"),rC(this),rN(this)?rI(this,e):rO(this.value)},e.prototype.setDirty=function(){this.dirty||(this.dirty=!0,this.value.length=0,rR(this),rS(this))},e.prototype.dispose=function(){var e=this;this.setDirty(),rH(this),rF(this,function(t,n){t.setDirty(),r$(t,e)})},e.prototype.forget=function(){this.dispose()},e.prototype.dependOn=function(e){e.add(this),this.deps||(this.deps=rk.pop()||new Set),this.deps.add(e)},e.prototype.forgetDeps=function(){var e=this;this.deps&&(rE(this.deps).forEach(function(t){return t.delete(e)}),this.deps.clear(),rk.push(this.deps),this.deps=null)},e.count=0,e}();function rC(e){var t=rw.getValue();if(t)return e.parents.add(t),t.childValues.has(e)||t.childValues.set(e,[]),rN(e)?rY(t,e):rB(t,e),t}function rI(e,t){return rH(e),rw.withValue(e,rD,[e,t]),rz(e,t)&&rP(e),rO(e.value)}function rD(e,t){e.recomputing=!0,e.value.length=0;try{e.value[0]=e.fn.apply(null,t)}catch(n){e.value[1]=n}e.recomputing=!1}function rN(e){return e.dirty||!!(e.dirtyChildren&&e.dirtyChildren.size)}function rP(e){e.dirty=!1,!rN(e)&&rj(e)}function rR(e){rF(e,rY)}function rj(e){rF(e,rB)}function rF(e,t){var n=e.parents.size;if(n)for(var r=rE(e.parents),i=0;i0&&e.childValues.forEach(function(t,n){r$(e,n)}),e.forgetDeps(),rT(null===e.dirtyChildren)}function r$(e,t){t.parents.delete(e),e.childValues.delete(t),rU(e,t)}function rz(e,t){if("function"==typeof e.subscribe)try{rS(e),e.unsubscribe=e.subscribe.apply(null,t)}catch(n){return e.setDirty(),!1}return!0}var rG={setDirty:!0,dispose:!0,forget:!0};function rW(e){var t=new Map,n=e&&e.subscribe;function r(e){var r=rw.getValue();if(r){var i=t.get(e);i||t.set(e,i=new Set),r.dependOn(i),"function"==typeof n&&(rS(i),i.unsubscribe=n(e))}}return r.dirty=function(e,n){var r=t.get(e);if(r){var i=n&&r_.call(rG,n)?n:"setDirty";rE(r).forEach(function(e){return e[i]()}),t.delete(e),rS(r)}},r}function rK(){var e=new ra("function"==typeof WeakMap);return function(){return e.lookupArray(arguments)}}var rV=rK(),rq=new Set;function rZ(e,t){void 0===t&&(t=Object.create(null));var n=new ry(t.max||65536,function(e){return e.dispose()}),r=t.keyArgs,i=t.makeCacheKey||rK(),a=function(){var a=i.apply(null,r?r.apply(null,arguments):arguments);if(void 0===a)return e.apply(null,arguments);var o=n.get(a);o||(n.set(a,o=new rL(e)),o.subscribe=t.subscribe,o.forget=function(){return n.delete(a)});var s=o.recompute(Array.prototype.slice.call(arguments));return n.set(a,o),rq.add(n),rw.hasValue()||(rq.forEach(function(e){return e.clean()}),rq.clear()),s};function o(e){var t=n.get(e);t&&t.setDirty()}function s(e){var t=n.get(e);if(t)return t.peek()}function u(e){return n.delete(e)}return Object.defineProperty(a,"size",{get:function(){return n.map.size},configurable:!1,enumerable:!1}),a.dirtyKey=o,a.dirty=function(){o(i.apply(null,arguments))},a.peekKey=s,a.peek=function(){return s(i.apply(null,arguments))},a.forgetKey=u,a.forget=function(){return u(i.apply(null,arguments))},a.makeCacheKey=i,a.getKey=r?function(){return i.apply(null,r.apply(null,arguments))}:i,Object.freeze(a)}var rX=new rb,rJ=new WeakMap;function rQ(e){var t=rJ.get(e);return t||rJ.set(e,t={vars:new Set,dep:rW()}),t}function r1(e){rQ(e).vars.forEach(function(t){return t.forgetCache(e)})}function r0(e){rQ(e).vars.forEach(function(t){return t.attachCache(e)})}function r2(e){var t=new Set,n=new Set,r=function(a){if(arguments.length>0){if(e!==a){e=a,t.forEach(function(e){rQ(e).dep.dirty(r),r3(e)});var o=Array.from(n);n.clear(),o.forEach(function(t){return t(e)})}}else{var s=rX.getValue();s&&(i(s),rQ(s).dep(r))}return e};r.onNextChange=function(e){return n.add(e),function(){n.delete(e)}};var i=r.attachCache=function(e){return t.add(e),rQ(e).vars.add(r),r};return r.forgetCache=function(e){return t.delete(e)},r}function r3(e){e.broadcastWatches&&e.broadcastWatches()}var r4=function(){function e(e){var t=e.cache,n=e.client,r=e.resolvers,i=e.fragmentMatcher;this.selectionsToResolveCache=new WeakMap,this.cache=t,n&&(this.client=n),r&&this.addResolvers(r),i&&this.setFragmentMatcher(i)}return e.prototype.addResolvers=function(e){var t=this;this.resolvers=this.resolvers||{},Array.isArray(e)?e.forEach(function(e){t.resolvers=tj(t.resolvers,e)}):this.resolvers=tj(this.resolvers,e)},e.prototype.setResolvers=function(e){this.resolvers={},this.addResolvers(e)},e.prototype.getResolvers=function(){return this.resolvers||{}},e.prototype.runResolvers=function(e){var t=e.document,n=e.remoteResult,r=e.context,i=e.variables,a=e.onlyRunForcedResolvers,o=void 0!==a&&a;return(0,en.mG)(this,void 0,void 0,function(){return(0,en.Jh)(this,function(e){return t?[2,this.resolveDocument(t,n.data,r,i,this.fragmentMatcher,o).then(function(e){return(0,en.pi)((0,en.pi)({},n),{data:e.result})})]:[2,n]})})},e.prototype.setFragmentMatcher=function(e){this.fragmentMatcher=e},e.prototype.getFragmentMatcher=function(){return this.fragmentMatcher},e.prototype.clientQuery=function(e){return tb(["client"],e)&&this.resolvers?e:null},e.prototype.serverQuery=function(e){return n$(e)},e.prototype.prepareContext=function(e){var t=this.cache;return(0,en.pi)((0,en.pi)({},e),{cache:t,getCacheKey:function(e){return t.identify(e)}})},e.prototype.addExportedVariables=function(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),(0,en.mG)(this,void 0,void 0,function(){return(0,en.Jh)(this,function(r){return e?[2,this.resolveDocument(e,this.buildRootValueFromCache(e,t)||{},this.prepareContext(n),t).then(function(e){return(0,en.pi)((0,en.pi)({},t),e.exportedVariables)})]:[2,(0,en.pi)({},t)]})})},e.prototype.shouldForceResolvers=function(e){var t=!1;return tl(e,{Directive:{enter:function(e){if("client"===e.name.value&&e.arguments&&(t=e.arguments.some(function(e){return"always"===e.name.value&&"BooleanValue"===e.value.kind&&!0===e.value.value})))return tc}}}),t},e.prototype.buildRootValueFromCache=function(e,t){return this.cache.diff({query:nH(e),variables:t,returnPartialData:!0,optimistic:!1}).result},e.prototype.resolveDocument=function(e,t,n,r,i,a){return void 0===n&&(n={}),void 0===r&&(r={}),void 0===i&&(i=function(){return!0}),void 0===a&&(a=!1),(0,en.mG)(this,void 0,void 0,function(){var o,s,u,c,l,f,d,h,p,b,m;return(0,en.Jh)(this,function(g){return o=e9(e),s=e4(e),u=eL(s),c=this.collectSelectionsToResolve(o,u),f=(l=o.operation)?l.charAt(0).toUpperCase()+l.slice(1):"Query",d=this,h=d.cache,p=d.client,b={fragmentMap:u,context:(0,en.pi)((0,en.pi)({},n),{cache:h,client:p}),variables:r,fragmentMatcher:i,defaultOperationType:f,exportedVariables:{},selectionsToResolve:c,onlyRunForcedResolvers:a},m=!1,[2,this.resolveSelectionSet(o.selectionSet,m,t,b).then(function(e){return{result:e,exportedVariables:b.exportedVariables}})]})})},e.prototype.resolveSelectionSet=function(e,t,n,r){return(0,en.mG)(this,void 0,void 0,function(){var i,a,o,s,u,c=this;return(0,en.Jh)(this,function(l){return i=r.fragmentMap,a=r.context,o=r.variables,s=[n],u=function(e){return(0,en.mG)(c,void 0,void 0,function(){var u,c;return(0,en.Jh)(this,function(l){return(t||r.selectionsToResolve.has(e))&&td(e,o)?eQ(e)?[2,this.resolveField(e,t,n,r).then(function(t){var n;void 0!==t&&s.push(((n={})[eX(e)]=t,n))})]:(e1(e)?u=e:(u=i[e.name.value],__DEV__?(0,Q.kG)(u,"No fragment named ".concat(e.name.value)):(0,Q.kG)(u,11)),u&&u.typeCondition&&(c=u.typeCondition.name.value,r.fragmentMatcher(n,c,a)))?[2,this.resolveSelectionSet(u.selectionSet,t,n,r).then(function(e){s.push(e)})]:[2]:[2]})})},[2,Promise.all(e.selections.map(u)).then(function(){return tF(s)})]})})},e.prototype.resolveField=function(e,t,n,r){return(0,en.mG)(this,void 0,void 0,function(){var i,a,o,s,u,c,l,f,d,h=this;return(0,en.Jh)(this,function(p){return n?(i=r.variables,a=e.name.value,o=eX(e),s=a!==o,c=Promise.resolve(u=n[o]||n[a]),(!r.onlyRunForcedResolvers||this.shouldForceResolvers(e))&&(l=n.__typename||r.defaultOperationType,(f=this.resolvers&&this.resolvers[l])&&(d=f[s?a:o])&&(c=Promise.resolve(rX.withValue(this.cache,d,[n,eZ(e,i),r.context,{field:e,fragmentMap:r.fragmentMap},])))),[2,c.then(function(n){if(void 0===n&&(n=u),e.directives&&e.directives.forEach(function(e){"export"===e.name.value&&e.arguments&&e.arguments.forEach(function(e){"as"===e.name.value&&"StringValue"===e.value.kind&&(r.exportedVariables[e.value.value]=n)})}),!e.selectionSet||null==n)return n;var i,a,o=null!==(a=null===(i=e.directives)||void 0===i?void 0:i.some(function(e){return"client"===e.name.value}))&&void 0!==a&&a;return Array.isArray(n)?h.resolveSubSelectedArray(e,t||o,n,r):e.selectionSet?h.resolveSelectionSet(e.selectionSet,t||o,n,r):void 0})]):[2,null]})})},e.prototype.resolveSubSelectedArray=function(e,t,n,r){var i=this;return Promise.all(n.map(function(n){return null===n?null:Array.isArray(n)?i.resolveSubSelectedArray(e,t,n,r):e.selectionSet?i.resolveSelectionSet(e.selectionSet,t,n,r):void 0}))},e.prototype.collectSelectionsToResolve=function(e,t){var n=function(e){return!Array.isArray(e)},r=this.selectionsToResolveCache;function i(e){if(!r.has(e)){var a=new Set;r.set(e,a),tl(e,{Directive:function(e,t,r,i,o){"client"===e.name.value&&o.forEach(function(e){n(e)&&n8(e)&&a.add(e)})},FragmentSpread:function(e,r,o,s,u){var c=t[e.name.value];__DEV__?(0,Q.kG)(c,"No fragment named ".concat(e.name.value)):(0,Q.kG)(c,12);var l=i(c);l.size>0&&(u.forEach(function(e){n(e)&&n8(e)&&a.add(e)}),a.add(e),l.forEach(function(e){a.add(e)}))}})}return r.get(e)}return i(e)},e}(),r5=new(t_.mr?WeakMap:Map);function r6(e,t){var n=e[t];"function"==typeof n&&(e[t]=function(){return r5.set(e,(r5.get(e)+1)%1e15),n.apply(this,arguments)})}function r9(e){e.notifyTimeout&&(clearTimeout(e.notifyTimeout),e.notifyTimeout=void 0)}var r8=function(){function e(e,t){void 0===t&&(t=e.generateQueryId()),this.queryId=t,this.listeners=new Set,this.document=null,this.lastRequestId=1,this.subscriptions=new Set,this.stopped=!1,this.dirty=!1,this.observableQuery=null;var n=this.cache=e.cache;r5.has(n)||(r5.set(n,0),r6(n,"evict"),r6(n,"modify"),r6(n,"reset"))}return e.prototype.init=function(e){var t=e.networkStatus||nZ.I.loading;return this.variables&&this.networkStatus!==nZ.I.loading&&!(0,nm.D)(this.variables,e.variables)&&(t=nZ.I.setVariables),(0,nm.D)(e.variables,this.variables)||(this.lastDiff=void 0),Object.assign(this,{document:e.document,variables:e.variables,networkError:null,graphQLErrors:this.graphQLErrors||[],networkStatus:t}),e.observableQuery&&this.setObservableQuery(e.observableQuery),e.lastRequestId&&(this.lastRequestId=e.lastRequestId),this},e.prototype.reset=function(){r9(this),this.dirty=!1},e.prototype.getDiff=function(e){void 0===e&&(e=this.variables);var t=this.getDiffOptions(e);if(this.lastDiff&&(0,nm.D)(t,this.lastDiff.options))return this.lastDiff.diff;this.updateWatch(this.variables=e);var n=this.observableQuery;if(n&&"no-cache"===n.options.fetchPolicy)return{complete:!1};var r=this.cache.diff(t);return this.updateLastDiff(r,t),r},e.prototype.updateLastDiff=function(e,t){this.lastDiff=e?{diff:e,options:t||this.getDiffOptions()}:void 0},e.prototype.getDiffOptions=function(e){var t;return void 0===e&&(e=this.variables),{query:this.document,variables:e,returnPartialData:!0,optimistic:!0,canonizeResults:null===(t=this.observableQuery)||void 0===t?void 0:t.options.canonizeResults}},e.prototype.setDiff=function(e){var t=this,n=this.lastDiff&&this.lastDiff.diff;this.updateLastDiff(e),this.dirty||(0,nm.D)(n&&n.result,e&&e.result)||(this.dirty=!0,this.notifyTimeout||(this.notifyTimeout=setTimeout(function(){return t.notify()},0)))},e.prototype.setObservableQuery=function(e){var t=this;e!==this.observableQuery&&(this.oqListener&&this.listeners.delete(this.oqListener),this.observableQuery=e,e?(e.queryInfo=this,this.listeners.add(this.oqListener=function(){t.getDiff().fromOptimisticTransaction?e.observe():n4(e)})):delete this.oqListener)},e.prototype.notify=function(){var e=this;r9(this),this.shouldNotify()&&this.listeners.forEach(function(t){return t(e)}),this.dirty=!1},e.prototype.shouldNotify=function(){if(!this.dirty||!this.listeners.size)return!1;if((0,nZ.O)(this.networkStatus)&&this.observableQuery){var e=this.observableQuery.options.fetchPolicy;if("cache-only"!==e&&"cache-and-network"!==e)return!1}return!0},e.prototype.stop=function(){if(!this.stopped){this.stopped=!0,this.reset(),this.cancel(),this.cancel=e.prototype.cancel,this.subscriptions.forEach(function(e){return e.unsubscribe()});var t=this.observableQuery;t&&t.stopPolling()}},e.prototype.cancel=function(){},e.prototype.updateWatch=function(e){var t=this;void 0===e&&(e=this.variables);var n=this.observableQuery;if(!n||"no-cache"!==n.options.fetchPolicy){var r=(0,en.pi)((0,en.pi)({},this.getDiffOptions(e)),{watcher:this,callback:function(e){return t.setDiff(e)}});this.lastWatch&&(0,nm.D)(r,this.lastWatch)||(this.cancel(),this.cancel=this.cache.watch(this.lastWatch=r))}},e.prototype.resetLastWrite=function(){this.lastWrite=void 0},e.prototype.shouldWrite=function(e,t){var n=this.lastWrite;return!(n&&n.dmCount===r5.get(this.cache)&&(0,nm.D)(t,n.variables)&&(0,nm.D)(e.data,n.result.data))},e.prototype.markResult=function(e,t,n,r){var i=this,a=new tB,o=(0,tP.O)(e.errors)?e.errors.slice(0):[];if(this.reset(),"incremental"in e&&(0,tP.O)(e.incremental)){var s=tG(this.getDiff().result,e);e.data=s}else if("hasNext"in e&&e.hasNext){var u=this.getDiff();e.data=a.merge(u.result,e.data)}this.graphQLErrors=o,"no-cache"===n.fetchPolicy?this.updateLastDiff({result:e.data,complete:!0},this.getDiffOptions(n.variables)):0!==r&&(r7(e,n.errorPolicy)?this.cache.performTransaction(function(a){if(i.shouldWrite(e,n.variables))a.writeQuery({query:t,data:e.data,variables:n.variables,overwrite:1===r}),i.lastWrite={result:e,variables:n.variables,dmCount:r5.get(i.cache)};else if(i.lastDiff&&i.lastDiff.diff.complete){e.data=i.lastDiff.diff.result;return}var o=i.getDiffOptions(n.variables),s=a.diff(o);i.stopped||i.updateWatch(n.variables),i.updateLastDiff(s,o),s.complete&&(e.data=s.result)}):this.lastWrite=void 0)},e.prototype.markReady=function(){return this.networkError=null,this.networkStatus=nZ.I.ready},e.prototype.markError=function(e){return this.networkStatus=nZ.I.error,this.lastWrite=void 0,this.reset(),e.graphQLErrors&&(this.graphQLErrors=e.graphQLErrors),e.networkError&&(this.networkError=e.networkError),e},e}();function r7(e,t){void 0===t&&(t="none");var n="ignore"===t||"all"===t,r=!nO(e);return!r&&n&&e.data&&(r=!0),r}var ie=Object.prototype.hasOwnProperty,it=function(){function e(e){var t=e.cache,n=e.link,r=e.defaultOptions,i=e.queryDeduplication,a=void 0!==i&&i,o=e.onBroadcast,s=e.ssrMode,u=void 0!==s&&s,c=e.clientAwareness,l=void 0===c?{}:c,f=e.localState,d=e.assumeImmutableResults;this.clientAwareness={},this.queries=new Map,this.fetchCancelFns=new Map,this.transformCache=new(t_.mr?WeakMap:Map),this.queryIdCounter=1,this.requestIdCounter=1,this.mutationIdCounter=1,this.inFlightLinkObservables=new Map,this.cache=t,this.link=n,this.defaultOptions=r||Object.create(null),this.queryDeduplication=a,this.clientAwareness=l,this.localState=f||new r4({cache:t}),this.ssrMode=u,this.assumeImmutableResults=!!d,(this.onBroadcast=o)&&(this.mutationStore=Object.create(null))}return e.prototype.stop=function(){var e=this;this.queries.forEach(function(t,n){e.stopQueryNoBroadcast(n)}),this.cancelPendingFetches(__DEV__?new Q.ej("QueryManager stopped while query was in flight"):new Q.ej(14))},e.prototype.cancelPendingFetches=function(e){this.fetchCancelFns.forEach(function(t){return t(e)}),this.fetchCancelFns.clear()},e.prototype.mutate=function(e){var t,n,r=e.mutation,i=e.variables,a=e.optimisticResponse,o=e.updateQueries,s=e.refetchQueries,u=void 0===s?[]:s,c=e.awaitRefetchQueries,l=void 0!==c&&c,f=e.update,d=e.onQueryUpdated,h=e.fetchPolicy,p=void 0===h?(null===(t=this.defaultOptions.mutate)||void 0===t?void 0:t.fetchPolicy)||"network-only":h,b=e.errorPolicy,m=void 0===b?(null===(n=this.defaultOptions.mutate)||void 0===n?void 0:n.errorPolicy)||"none":b,g=e.keepRootFields,v=e.context;return(0,en.mG)(this,void 0,void 0,function(){var e,t,n,s,c,h;return(0,en.Jh)(this,function(b){switch(b.label){case 0:if(__DEV__?(0,Q.kG)(r,"mutation option is required. You must specify your GraphQL document in the mutation option."):(0,Q.kG)(r,15),__DEV__?(0,Q.kG)("network-only"===p||"no-cache"===p,"Mutations support only 'network-only' or 'no-cache' fetchPolicy strings. The default `network-only` behavior automatically writes mutation results to the cache. Passing `no-cache` skips the cache write."):(0,Q.kG)("network-only"===p||"no-cache"===p,16),e=this.generateMutationId(),n=(t=this.transform(r)).document,s=t.hasClientExports,r=this.cache.transformForLink(n),i=this.getVariables(r,i),!s)return[3,2];return[4,this.localState.addExportedVariables(r,i,v)];case 1:i=b.sent(),b.label=2;case 2:return c=this.mutationStore&&(this.mutationStore[e]={mutation:r,variables:i,loading:!0,error:null}),a&&this.markMutationOptimistic(a,{mutationId:e,document:r,variables:i,fetchPolicy:p,errorPolicy:m,context:v,updateQueries:o,update:f,keepRootFields:g}),this.broadcastQueries(),h=this,[2,new Promise(function(t,n){return nM(h.getObservableFromLink(r,(0,en.pi)((0,en.pi)({},v),{optimisticResponse:a}),i,!1),function(t){if(nO(t)&&"none"===m)throw new tN.cA({graphQLErrors:nA(t)});c&&(c.loading=!1,c.error=null);var n=(0,en.pi)({},t);return"function"==typeof u&&(u=u(n)),"ignore"===m&&nO(n)&&delete n.errors,h.markMutationResult({mutationId:e,result:n,document:r,variables:i,fetchPolicy:p,errorPolicy:m,context:v,update:f,updateQueries:o,awaitRefetchQueries:l,refetchQueries:u,removeOptimistic:a?e:void 0,onQueryUpdated:d,keepRootFields:g})}).subscribe({next:function(e){h.broadcastQueries(),"hasNext"in e&&!1!==e.hasNext||t(e)},error:function(t){c&&(c.loading=!1,c.error=t),a&&h.cache.removeOptimistic(e),h.broadcastQueries(),n(t instanceof tN.cA?t:new tN.cA({networkError:t}))}})})]}})})},e.prototype.markMutationResult=function(e,t){var n=this;void 0===t&&(t=this.cache);var r=e.result,i=[],a="no-cache"===e.fetchPolicy;if(!a&&r7(r,e.errorPolicy)){if(tU(r)||i.push({result:r.data,dataId:"ROOT_MUTATION",query:e.document,variables:e.variables}),tU(r)&&(0,tP.O)(r.incremental)){var o=t.diff({id:"ROOT_MUTATION",query:this.transform(e.document).asQuery,variables:e.variables,optimistic:!1,returnPartialData:!0}),s=void 0;o.result&&(s=tG(o.result,r)),void 0!==s&&(r.data=s,i.push({result:s,dataId:"ROOT_MUTATION",query:e.document,variables:e.variables}))}var u=e.updateQueries;u&&this.queries.forEach(function(e,a){var o=e.observableQuery,s=o&&o.queryName;if(s&&ie.call(u,s)){var c,l=u[s],f=n.queries.get(a),d=f.document,h=f.variables,p=t.diff({query:d,variables:h,returnPartialData:!0,optimistic:!1}),b=p.result;if(p.complete&&b){var m=l(b,{mutationResult:r,queryName:d&&e3(d)||void 0,queryVariables:h});m&&i.push({result:m,dataId:"ROOT_QUERY",query:d,variables:h})}}})}if(i.length>0||e.refetchQueries||e.update||e.onQueryUpdated||e.removeOptimistic){var c=[];if(this.refetchQueries({updateCache:function(t){a||i.forEach(function(e){return t.write(e)});var o=e.update,s=!t$(r)||tU(r)&&!r.hasNext;if(o){if(!a){var u=t.diff({id:"ROOT_MUTATION",query:n.transform(e.document).asQuery,variables:e.variables,optimistic:!1,returnPartialData:!0});u.complete&&("incremental"in(r=(0,en.pi)((0,en.pi)({},r),{data:u.result}))&&delete r.incremental,"hasNext"in r&&delete r.hasNext)}s&&o(t,r,{context:e.context,variables:e.variables})}a||e.keepRootFields||!s||t.modify({id:"ROOT_MUTATION",fields:function(e,t){var n=t.fieldName,r=t.DELETE;return"__typename"===n?e:r}})},include:e.refetchQueries,optimistic:!1,removeOptimistic:e.removeOptimistic,onQueryUpdated:e.onQueryUpdated||null}).forEach(function(e){return c.push(e)}),e.awaitRefetchQueries||e.onQueryUpdated)return Promise.all(c).then(function(){return r})}return Promise.resolve(r)},e.prototype.markMutationOptimistic=function(e,t){var n=this,r="function"==typeof e?e(t.variables):e;return this.cache.recordOptimisticTransaction(function(e){try{n.markMutationResult((0,en.pi)((0,en.pi)({},t),{result:{data:r}}),e)}catch(i){__DEV__&&Q.kG.error(i)}},t.mutationId)},e.prototype.fetchQuery=function(e,t,n){return this.fetchQueryObservable(e,t,n).promise},e.prototype.getQueryStore=function(){var e=Object.create(null);return this.queries.forEach(function(t,n){e[n]={variables:t.variables,networkStatus:t.networkStatus,networkError:t.networkError,graphQLErrors:t.graphQLErrors}}),e},e.prototype.resetErrors=function(e){var t=this.queries.get(e);t&&(t.networkError=void 0,t.graphQLErrors=[])},e.prototype.transform=function(e){var t=this.transformCache;if(!t.has(e)){var n=this.cache.transformDocument(e),r=nY(n),i=this.localState.clientQuery(n),a=r&&this.localState.serverQuery(r),o={document:n,hasClientExports:tm(n),hasForcedResolvers:this.localState.shouldForceResolvers(n),clientQuery:i,serverQuery:a,defaultVars:e8(e2(n)),asQuery:(0,en.pi)((0,en.pi)({},n),{definitions:n.definitions.map(function(e){return"OperationDefinition"===e.kind&&"query"!==e.operation?(0,en.pi)((0,en.pi)({},e),{operation:"query"}):e})})},s=function(e){e&&!t.has(e)&&t.set(e,o)};s(e),s(n),s(i),s(a)}return t.get(e)},e.prototype.getVariables=function(e,t){return(0,en.pi)((0,en.pi)({},this.transform(e).defaultVars),t)},e.prototype.watchQuery=function(e){void 0===(e=(0,en.pi)((0,en.pi)({},e),{variables:this.getVariables(e.query,e.variables)})).notifyOnNetworkStatusChange&&(e.notifyOnNetworkStatusChange=!1);var t=new r8(this),n=new n3({queryManager:this,queryInfo:t,options:e});return this.queries.set(n.queryId,t),t.init({document:n.query,observableQuery:n,variables:n.variables}),n},e.prototype.query=function(e,t){var n=this;return void 0===t&&(t=this.generateQueryId()),__DEV__?(0,Q.kG)(e.query,"query option is required. You must specify your GraphQL document in the query option."):(0,Q.kG)(e.query,17),__DEV__?(0,Q.kG)("Document"===e.query.kind,'You must wrap the query string in a "gql" tag.'):(0,Q.kG)("Document"===e.query.kind,18),__DEV__?(0,Q.kG)(!e.returnPartialData,"returnPartialData option only supported on watchQuery."):(0,Q.kG)(!e.returnPartialData,19),__DEV__?(0,Q.kG)(!e.pollInterval,"pollInterval option only supported on watchQuery."):(0,Q.kG)(!e.pollInterval,20),this.fetchQuery(t,e).finally(function(){return n.stopQuery(t)})},e.prototype.generateQueryId=function(){return String(this.queryIdCounter++)},e.prototype.generateRequestId=function(){return this.requestIdCounter++},e.prototype.generateMutationId=function(){return String(this.mutationIdCounter++)},e.prototype.stopQueryInStore=function(e){this.stopQueryInStoreNoBroadcast(e),this.broadcastQueries()},e.prototype.stopQueryInStoreNoBroadcast=function(e){var t=this.queries.get(e);t&&t.stop()},e.prototype.clearStore=function(e){return void 0===e&&(e={discardWatches:!0}),this.cancelPendingFetches(__DEV__?new Q.ej("Store reset while query was in flight (not completed in link chain)"):new Q.ej(21)),this.queries.forEach(function(e){e.observableQuery?e.networkStatus=nZ.I.loading:e.stop()}),this.mutationStore&&(this.mutationStore=Object.create(null)),this.cache.reset(e)},e.prototype.getObservableQueries=function(e){var t=this;void 0===e&&(e="active");var n=new Map,r=new Map,i=new Set;return Array.isArray(e)&&e.forEach(function(e){"string"==typeof e?r.set(e,!1):eN(e)?r.set(t.transform(e).document,!1):(0,eO.s)(e)&&e.query&&i.add(e)}),this.queries.forEach(function(t,i){var a=t.observableQuery,o=t.document;if(a){if("all"===e){n.set(i,a);return}var s=a.queryName;if("standby"===a.options.fetchPolicy||"active"===e&&!a.hasObservers())return;("active"===e||s&&r.has(s)||o&&r.has(o))&&(n.set(i,a),s&&r.set(s,!0),o&&r.set(o,!0))}}),i.size&&i.forEach(function(e){var r=nG("legacyOneTimeQuery"),i=t.getQuery(r).init({document:e.query,variables:e.variables}),a=new n3({queryManager:t,queryInfo:i,options:(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"network-only"})});(0,Q.kG)(a.queryId===r),i.setObservableQuery(a),n.set(r,a)}),__DEV__&&r.size&&r.forEach(function(e,t){!e&&__DEV__&&Q.kG.warn("Unknown query ".concat("string"==typeof t?"named ":"").concat(JSON.stringify(t,null,2)," requested in refetchQueries options.include array"))}),n},e.prototype.reFetchObservableQueries=function(e){var t=this;void 0===e&&(e=!1);var n=[];return this.getObservableQueries(e?"all":"active").forEach(function(r,i){var a=r.options.fetchPolicy;r.resetLastResults(),(e||"standby"!==a&&"cache-only"!==a)&&n.push(r.refetch()),t.getQuery(i).setDiff(null)}),this.broadcastQueries(),Promise.all(n)},e.prototype.setObservableQuery=function(e){this.getQuery(e.queryId).setObservableQuery(e)},e.prototype.startGraphQLSubscription=function(e){var t=this,n=e.query,r=e.fetchPolicy,i=e.errorPolicy,a=e.variables,o=e.context,s=void 0===o?{}:o;n=this.transform(n).document,a=this.getVariables(n,a);var u=function(e){return t.getObservableFromLink(n,s,e).map(function(a){"no-cache"!==r&&(r7(a,i)&&t.cache.write({query:n,result:a.data,dataId:"ROOT_SUBSCRIPTION",variables:e}),t.broadcastQueries());var o=nO(a),s=(0,tN.ls)(a);if(o||s){var u={};throw o&&(u.graphQLErrors=a.errors),s&&(u.protocolErrors=a.extensions[tN.YG]),new tN.cA(u)}return a})};if(this.transform(n).hasClientExports){var c=this.localState.addExportedVariables(n,a,s).then(u);return new eT(function(e){var t=null;return c.then(function(n){return t=n.subscribe(e)},e.error),function(){return t&&t.unsubscribe()}})}return u(a)},e.prototype.stopQuery=function(e){this.stopQueryNoBroadcast(e),this.broadcastQueries()},e.prototype.stopQueryNoBroadcast=function(e){this.stopQueryInStoreNoBroadcast(e),this.removeQuery(e)},e.prototype.removeQuery=function(e){this.fetchCancelFns.delete(e),this.queries.has(e)&&(this.getQuery(e).stop(),this.queries.delete(e))},e.prototype.broadcastQueries=function(){this.onBroadcast&&this.onBroadcast(),this.queries.forEach(function(e){return e.notify()})},e.prototype.getLocalState=function(){return this.localState},e.prototype.getObservableFromLink=function(e,t,n,r){var i,a,o=this;void 0===r&&(r=null!==(i=null==t?void 0:t.queryDeduplication)&&void 0!==i?i:this.queryDeduplication);var s=this.transform(e).serverQuery;if(s){var u=this,c=u.inFlightLinkObservables,l=u.link,f={query:s,variables:n,operationName:e3(s)||void 0,context:this.prepareContext((0,en.pi)((0,en.pi)({},t),{forceFetch:!r}))};if(t=f.context,r){var d=c.get(s)||new Map;c.set(s,d);var h=nx(n);if(!(a=d.get(h))){var p=new nq([np(l,f)]);d.set(h,a=p),p.beforeNext(function(){d.delete(h)&&d.size<1&&c.delete(s)})}}else a=new nq([np(l,f)])}else a=new nq([eT.of({data:{}})]),t=this.prepareContext(t);var b=this.transform(e).clientQuery;return b&&(a=nM(a,function(e){return o.localState.runResolvers({document:b,remoteResult:e,context:t,variables:n})})),a},e.prototype.getResultsFromLink=function(e,t,n){var r=e.lastRequestId=this.generateRequestId(),i=this.cache.transformForLink(this.transform(e.document).document);return nM(this.getObservableFromLink(i,n.context,n.variables),function(a){var o=nA(a),s=o.length>0;if(r>=e.lastRequestId){if(s&&"none"===n.errorPolicy)throw e.markError(new tN.cA({graphQLErrors:o}));e.markResult(a,i,n,t),e.markReady()}var u={data:a.data,loading:!1,networkStatus:nZ.I.ready};return s&&"ignore"!==n.errorPolicy&&(u.errors=o,u.networkStatus=nZ.I.error),u},function(t){var n=(0,tN.MS)(t)?t:new tN.cA({networkError:t});throw r>=e.lastRequestId&&e.markError(n),n})},e.prototype.fetchQueryObservable=function(e,t,n){return this.fetchConcastWithInfo(e,t,n).concast},e.prototype.fetchConcastWithInfo=function(e,t,n){var r,i,a=this;void 0===n&&(n=nZ.I.loading);var o=this.transform(t.query).document,s=this.getVariables(o,t.variables),u=this.getQuery(e),c=this.defaultOptions.watchQuery,l=t.fetchPolicy,f=void 0===l?c&&c.fetchPolicy||"cache-first":l,d=t.errorPolicy,h=void 0===d?c&&c.errorPolicy||"none":d,p=t.returnPartialData,b=void 0!==p&&p,m=t.notifyOnNetworkStatusChange,g=void 0!==m&&m,v=t.context,y=void 0===v?{}:v,w=Object.assign({},t,{query:o,variables:s,fetchPolicy:f,errorPolicy:h,returnPartialData:b,notifyOnNetworkStatusChange:g,context:y}),_=function(e){w.variables=e;var r=a.fetchQueryByPolicy(u,w,n);return"standby"!==w.fetchPolicy&&r.sources.length>0&&u.observableQuery&&u.observableQuery.applyNextFetchPolicy("after-fetch",t),r},E=function(){return a.fetchCancelFns.delete(e)};if(this.fetchCancelFns.set(e,function(e){E(),setTimeout(function(){return r.cancel(e)})}),this.transform(w.query).hasClientExports)r=new nq(this.localState.addExportedVariables(w.query,w.variables,w.context).then(_).then(function(e){return e.sources})),i=!0;else{var S=_(w.variables);i=S.fromLink,r=new nq(S.sources)}return r.promise.then(E,E),{concast:r,fromLink:i}},e.prototype.refetchQueries=function(e){var t=this,n=e.updateCache,r=e.include,i=e.optimistic,a=void 0!==i&&i,o=e.removeOptimistic,s=void 0===o?a?nG("refetchQueries"):void 0:o,u=e.onQueryUpdated,c=new Map;r&&this.getObservableQueries(r).forEach(function(e,n){c.set(n,{oq:e,lastDiff:t.getQuery(n).getDiff()})});var l=new Map;return n&&this.cache.batch({update:n,optimistic:a&&s||!1,removeOptimistic:s,onWatchUpdated:function(e,t,n){var r=e.watcher instanceof r8&&e.watcher.observableQuery;if(r){if(u){c.delete(r.queryId);var i=u(r,t,n);return!0===i&&(i=r.refetch()),!1!==i&&l.set(r,i),i}null!==u&&c.set(r.queryId,{oq:r,lastDiff:n,diff:t})}}}),c.size&&c.forEach(function(e,n){var r,i=e.oq,a=e.lastDiff,o=e.diff;if(u){if(!o){var s=i.queryInfo;s.reset(),o=s.getDiff()}r=u(i,o,a)}u&&!0!==r||(r=i.refetch()),!1!==r&&l.set(i,r),n.indexOf("legacyOneTimeQuery")>=0&&t.stopQueryNoBroadcast(n)}),s&&this.cache.removeOptimistic(s),l},e.prototype.fetchQueryByPolicy=function(e,t,n){var r=this,i=t.query,a=t.variables,o=t.fetchPolicy,s=t.refetchWritePolicy,u=t.errorPolicy,c=t.returnPartialData,l=t.context,f=t.notifyOnNetworkStatusChange,d=e.networkStatus;e.init({document:this.transform(i).document,variables:a,networkStatus:n});var h=function(){return e.getDiff(a)},p=function(t,n){void 0===n&&(n=e.networkStatus||nZ.I.loading);var o=t.result;!__DEV__||c||(0,nm.D)(o,{})||n6(t.missing);var s=function(e){return eT.of((0,en.pi)({data:e,loading:(0,nZ.O)(n),networkStatus:n},t.complete?null:{partial:!0}))};return o&&r.transform(i).hasForcedResolvers?r.localState.runResolvers({document:i,remoteResult:{data:o},context:l,variables:a,onlyRunForcedResolvers:!0}).then(function(e){return s(e.data||void 0)}):"none"===u&&n===nZ.I.refetch&&Array.isArray(t.missing)?s(void 0):s(o)},b="no-cache"===o?0:n===nZ.I.refetch&&"merge"!==s?1:2,m=function(){return r.getResultsFromLink(e,b,{variables:a,context:l,fetchPolicy:o,errorPolicy:u})},g=f&&"number"==typeof d&&d!==n&&(0,nZ.O)(n);switch(o){default:case"cache-first":var v=h();if(v.complete)return{fromLink:!1,sources:[p(v,e.markReady())]};if(c||g)return{fromLink:!0,sources:[p(v),m()]};return{fromLink:!0,sources:[m()]};case"cache-and-network":var v=h();if(v.complete||c||g)return{fromLink:!0,sources:[p(v),m()]};return{fromLink:!0,sources:[m()]};case"cache-only":return{fromLink:!1,sources:[p(h(),e.markReady())]};case"network-only":if(g)return{fromLink:!0,sources:[p(h()),m()]};return{fromLink:!0,sources:[m()]};case"no-cache":if(g)return{fromLink:!0,sources:[p(e.getDiff()),m(),]};return{fromLink:!0,sources:[m()]};case"standby":return{fromLink:!1,sources:[]}}},e.prototype.getQuery=function(e){return e&&!this.queries.has(e)&&this.queries.set(e,new r8(this,e)),this.queries.get(e)},e.prototype.prepareContext=function(e){void 0===e&&(e={});var t=this.localState.prepareContext(e);return(0,en.pi)((0,en.pi)({},t),{clientAwareness:this.clientAwareness})},e}(),ir=__webpack_require__(14012),ii=!1,ia=function(){function e(e){var t=this;this.resetStoreCallbacks=[],this.clearStoreCallbacks=[];var n=e.uri,r=e.credentials,i=e.headers,a=e.cache,o=e.ssrMode,s=void 0!==o&&o,u=e.ssrForceFetchDelay,c=void 0===u?0:u,l=e.connectToDevTools,f=void 0===l?"object"==typeof window&&!window.__APOLLO_CLIENT__&&__DEV__:l,d=e.queryDeduplication,h=void 0===d||d,p=e.defaultOptions,b=e.assumeImmutableResults,m=void 0!==b&&b,g=e.resolvers,v=e.typeDefs,y=e.fragmentMatcher,w=e.name,_=e.version,E=e.link;if(E||(E=n?new nh({uri:n,credentials:r,headers:i}):ta.empty()),!a)throw __DEV__?new Q.ej("To initialize Apollo Client, you must specify a 'cache' property in the options object. \nFor more information, please visit: https://go.apollo.dev/c/docs"):new Q.ej(9);if(this.link=E,this.cache=a,this.disableNetworkFetches=s||c>0,this.queryDeduplication=h,this.defaultOptions=p||Object.create(null),this.typeDefs=v,c&&setTimeout(function(){return t.disableNetworkFetches=!1},c),this.watchQuery=this.watchQuery.bind(this),this.query=this.query.bind(this),this.mutate=this.mutate.bind(this),this.resetStore=this.resetStore.bind(this),this.reFetchObservableQueries=this.reFetchObservableQueries.bind(this),f&&"object"==typeof window&&(window.__APOLLO_CLIENT__=this),!ii&&f&&__DEV__&&(ii=!0,"undefined"!=typeof window&&window.document&&window.top===window.self&&!window.__APOLLO_DEVTOOLS_GLOBAL_HOOK__)){var S=window.navigator,k=S&&S.userAgent,x=void 0;"string"==typeof k&&(k.indexOf("Chrome/")>-1?x="https://chrome.google.com/webstore/detail/apollo-client-developer-t/jdkknkkbebbapilgoeccciglkfbmbnfm":k.indexOf("Firefox/")>-1&&(x="https://addons.mozilla.org/en-US/firefox/addon/apollo-developer-tools/")),x&&__DEV__&&Q.kG.log("Download the Apollo DevTools for a better development experience: "+x)}this.version=nb,this.localState=new r4({cache:a,client:this,resolvers:g,fragmentMatcher:y}),this.queryManager=new it({cache:this.cache,link:this.link,defaultOptions:this.defaultOptions,queryDeduplication:h,ssrMode:s,clientAwareness:{name:w,version:_},localState:this.localState,assumeImmutableResults:m,onBroadcast:f?function(){t.devToolsHookCb&&t.devToolsHookCb({action:{},state:{queries:t.queryManager.getQueryStore(),mutations:t.queryManager.mutationStore||{}},dataWithOptimisticResults:t.cache.extract(!0)})}:void 0})}return e.prototype.stop=function(){this.queryManager.stop()},e.prototype.watchQuery=function(e){return this.defaultOptions.watchQuery&&(e=(0,ir.J)(this.defaultOptions.watchQuery,e)),this.disableNetworkFetches&&("network-only"===e.fetchPolicy||"cache-and-network"===e.fetchPolicy)&&(e=(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"cache-first"})),this.queryManager.watchQuery(e)},e.prototype.query=function(e){return this.defaultOptions.query&&(e=(0,ir.J)(this.defaultOptions.query,e)),__DEV__?(0,Q.kG)("cache-and-network"!==e.fetchPolicy,"The cache-and-network fetchPolicy does not work with client.query, because client.query can only return a single result. Please use client.watchQuery to receive multiple results from the cache and the network, or consider using a different fetchPolicy, such as cache-first or network-only."):(0,Q.kG)("cache-and-network"!==e.fetchPolicy,10),this.disableNetworkFetches&&"network-only"===e.fetchPolicy&&(e=(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"cache-first"})),this.queryManager.query(e)},e.prototype.mutate=function(e){return this.defaultOptions.mutate&&(e=(0,ir.J)(this.defaultOptions.mutate,e)),this.queryManager.mutate(e)},e.prototype.subscribe=function(e){return this.queryManager.startGraphQLSubscription(e)},e.prototype.readQuery=function(e,t){return void 0===t&&(t=!1),this.cache.readQuery(e,t)},e.prototype.readFragment=function(e,t){return void 0===t&&(t=!1),this.cache.readFragment(e,t)},e.prototype.writeQuery=function(e){var t=this.cache.writeQuery(e);return!1!==e.broadcast&&this.queryManager.broadcastQueries(),t},e.prototype.writeFragment=function(e){var t=this.cache.writeFragment(e);return!1!==e.broadcast&&this.queryManager.broadcastQueries(),t},e.prototype.__actionHookForDevTools=function(e){this.devToolsHookCb=e},e.prototype.__requestRaw=function(e){return np(this.link,e)},e.prototype.resetStore=function(){var e=this;return Promise.resolve().then(function(){return e.queryManager.clearStore({discardWatches:!1})}).then(function(){return Promise.all(e.resetStoreCallbacks.map(function(e){return e()}))}).then(function(){return e.reFetchObservableQueries()})},e.prototype.clearStore=function(){var e=this;return Promise.resolve().then(function(){return e.queryManager.clearStore({discardWatches:!0})}).then(function(){return Promise.all(e.clearStoreCallbacks.map(function(e){return e()}))})},e.prototype.onResetStore=function(e){var t=this;return this.resetStoreCallbacks.push(e),function(){t.resetStoreCallbacks=t.resetStoreCallbacks.filter(function(t){return t!==e})}},e.prototype.onClearStore=function(e){var t=this;return this.clearStoreCallbacks.push(e),function(){t.clearStoreCallbacks=t.clearStoreCallbacks.filter(function(t){return t!==e})}},e.prototype.reFetchObservableQueries=function(e){return this.queryManager.reFetchObservableQueries(e)},e.prototype.refetchQueries=function(e){var t=this.queryManager.refetchQueries(e),n=[],r=[];t.forEach(function(e,t){n.push(t),r.push(e)});var i=Promise.all(r);return i.queries=n,i.results=r,i.catch(function(e){__DEV__&&Q.kG.debug("In client.refetchQueries, Promise.all promise rejected with error ".concat(e))}),i},e.prototype.getObservableQueries=function(e){return void 0===e&&(e="active"),this.queryManager.getObservableQueries(e)},e.prototype.extract=function(e){return this.cache.extract(e)},e.prototype.restore=function(e){return this.cache.restore(e)},e.prototype.addResolvers=function(e){this.localState.addResolvers(e)},e.prototype.setResolvers=function(e){this.localState.setResolvers(e)},e.prototype.getResolvers=function(){return this.localState.getResolvers()},e.prototype.setLocalStateFragmentMatcher=function(e){this.localState.setFragmentMatcher(e)},e.prototype.setLink=function(e){this.link=this.queryManager.link=e},e}(),io=function(){function e(){this.getFragmentDoc=rZ(eA)}return e.prototype.batch=function(e){var t,n=this,r="string"==typeof e.optimistic?e.optimistic:!1===e.optimistic?null:void 0;return this.performTransaction(function(){return t=e.update(n)},r),t},e.prototype.recordOptimisticTransaction=function(e,t){this.performTransaction(e,t)},e.prototype.transformDocument=function(e){return e},e.prototype.transformForLink=function(e){return e},e.prototype.identify=function(e){},e.prototype.gc=function(){return[]},e.prototype.modify=function(e){return!1},e.prototype.readQuery=function(e,t){return void 0===t&&(t=!!e.optimistic),this.read((0,en.pi)((0,en.pi)({},e),{rootId:e.id||"ROOT_QUERY",optimistic:t}))},e.prototype.readFragment=function(e,t){return void 0===t&&(t=!!e.optimistic),this.read((0,en.pi)((0,en.pi)({},e),{query:this.getFragmentDoc(e.fragment,e.fragmentName),rootId:e.id,optimistic:t}))},e.prototype.writeQuery=function(e){var t=e.id,n=e.data,r=(0,en._T)(e,["id","data"]);return this.write(Object.assign(r,{dataId:t||"ROOT_QUERY",result:n}))},e.prototype.writeFragment=function(e){var t=e.id,n=e.data,r=e.fragment,i=e.fragmentName,a=(0,en._T)(e,["id","data","fragment","fragmentName"]);return this.write(Object.assign(a,{query:this.getFragmentDoc(r,i),dataId:t,result:n}))},e.prototype.updateQuery=function(e,t){return this.batch({update:function(n){var r=n.readQuery(e),i=t(r);return null==i?r:(n.writeQuery((0,en.pi)((0,en.pi)({},e),{data:i})),i)}})},e.prototype.updateFragment=function(e,t){return this.batch({update:function(n){var r=n.readFragment(e),i=t(r);return null==i?r:(n.writeFragment((0,en.pi)((0,en.pi)({},e),{data:i})),i)}})},e}(),is=function(e){function t(n,r,i,a){var o,s=e.call(this,n)||this;if(s.message=n,s.path=r,s.query=i,s.variables=a,Array.isArray(s.path)){s.missing=s.message;for(var u=s.path.length-1;u>=0;--u)s.missing=((o={})[s.path[u]]=s.missing,o)}else s.missing=s.path;return s.__proto__=t.prototype,s}return(0,en.ZT)(t,e),t}(Error),iu=__webpack_require__(10542),ic=Object.prototype.hasOwnProperty;function il(e){return null==e}function id(e,t){var n=e.__typename,r=e.id,i=e._id;if("string"==typeof n&&(t&&(t.keyObject=il(r)?il(i)?void 0:{_id:i}:{id:r}),il(r)&&!il(i)&&(r=i),!il(r)))return"".concat(n,":").concat("number"==typeof r||"string"==typeof r?r:JSON.stringify(r))}var ih={dataIdFromObject:id,addTypename:!0,resultCaching:!0,canonizeResults:!1};function ip(e){return(0,n1.o)(ih,e)}function ib(e){var t=e.canonizeResults;return void 0===t?ih.canonizeResults:t}function im(e,t){return eD(t)?e.get(t.__ref,"__typename"):t&&t.__typename}var ig=/^[_a-z][_0-9a-z]*/i;function iv(e){var t=e.match(ig);return t?t[0]:e}function iy(e,t,n){return!!(0,eO.s)(t)&&((0,tP.k)(t)?t.every(function(t){return iy(e,t,n)}):e.selections.every(function(e){if(eQ(e)&&td(e,n)){var r=eX(e);return ic.call(t,r)&&(!e.selectionSet||iy(e.selectionSet,t[r],n))}return!0}))}function iw(e){return(0,eO.s)(e)&&!eD(e)&&!(0,tP.k)(e)}function i_(){return new tB}function iE(e,t){var n=eL(e4(e));return{fragmentMap:n,lookupFragment:function(e){var r=n[e];return!r&&t&&(r=t.lookup(e)),r||null}}}var iS=Object.create(null),ik=function(){return iS},ix=Object.create(null),iT=function(){function e(e,t){var n=this;this.policies=e,this.group=t,this.data=Object.create(null),this.rootIds=Object.create(null),this.refs=Object.create(null),this.getFieldValue=function(e,t){return(0,iu.J)(eD(e)?n.get(e.__ref,t):e&&e[t])},this.canRead=function(e){return eD(e)?n.has(e.__ref):"object"==typeof e},this.toReference=function(e,t){if("string"==typeof e)return eI(e);if(eD(e))return e;var r=n.policies.identify(e)[0];if(r){var i=eI(r);return t&&n.merge(r,e),i}}}return e.prototype.toObject=function(){return(0,en.pi)({},this.data)},e.prototype.has=function(e){return void 0!==this.lookup(e,!0)},e.prototype.get=function(e,t){if(this.group.depend(e,t),ic.call(this.data,e)){var n=this.data[e];if(n&&ic.call(n,t))return n[t]}return"__typename"===t&&ic.call(this.policies.rootTypenamesById,e)?this.policies.rootTypenamesById[e]:this instanceof iL?this.parent.get(e,t):void 0},e.prototype.lookup=function(e,t){return(t&&this.group.depend(e,"__exists"),ic.call(this.data,e))?this.data[e]:this instanceof iL?this.parent.lookup(e,t):this.policies.rootTypenamesById[e]?Object.create(null):void 0},e.prototype.merge=function(e,t){var n,r=this;eD(e)&&(e=e.__ref),eD(t)&&(t=t.__ref);var i="string"==typeof e?this.lookup(n=e):e,a="string"==typeof t?this.lookup(n=t):t;if(a){__DEV__?(0,Q.kG)("string"==typeof n,"store.merge expects a string ID"):(0,Q.kG)("string"==typeof n,1);var o=new tB(iI).merge(i,a);if(this.data[n]=o,o!==i&&(delete this.refs[n],this.group.caching)){var s=Object.create(null);i||(s.__exists=1),Object.keys(a).forEach(function(e){if(!i||i[e]!==o[e]){s[e]=1;var t=iv(e);t===e||r.policies.hasKeyArgs(o.__typename,t)||(s[t]=1),void 0!==o[e]||r instanceof iL||delete o[e]}}),s.__typename&&!(i&&i.__typename)&&this.policies.rootTypenamesById[n]===o.__typename&&delete s.__typename,Object.keys(s).forEach(function(e){return r.group.dirty(n,e)})}}},e.prototype.modify=function(e,t){var n=this,r=this.lookup(e);if(r){var i=Object.create(null),a=!1,o=!0,s={DELETE:iS,INVALIDATE:ix,isReference:eD,toReference:this.toReference,canRead:this.canRead,readField:function(t,r){return n.policies.readField("string"==typeof t?{fieldName:t,from:r||eI(e)}:t,{store:n})}};if(Object.keys(r).forEach(function(u){var c=iv(u),l=r[u];if(void 0!==l){var f="function"==typeof t?t:t[u]||t[c];if(f){var d=f===ik?iS:f((0,iu.J)(l),(0,en.pi)((0,en.pi)({},s),{fieldName:c,storeFieldName:u,storage:n.getStorage(e,u)}));d===ix?n.group.dirty(e,u):(d===iS&&(d=void 0),d!==l&&(i[u]=d,a=!0,l=d))}void 0!==l&&(o=!1)}}),a)return this.merge(e,i),o&&(this instanceof iL?this.data[e]=void 0:delete this.data[e],this.group.dirty(e,"__exists")),!0}return!1},e.prototype.delete=function(e,t,n){var r,i=this.lookup(e);if(i){var a=this.getFieldValue(i,"__typename"),o=t&&n?this.policies.getStoreFieldName({typename:a,fieldName:t,args:n}):t;return this.modify(e,o?((r={})[o]=ik,r):ik)}return!1},e.prototype.evict=function(e,t){var n=!1;return e.id&&(ic.call(this.data,e.id)&&(n=this.delete(e.id,e.fieldName,e.args)),this instanceof iL&&this!==t&&(n=this.parent.evict(e,t)||n),(e.fieldName||n)&&this.group.dirty(e.id,e.fieldName||"__exists")),n},e.prototype.clear=function(){this.replace(null)},e.prototype.extract=function(){var e=this,t=this.toObject(),n=[];return this.getRootIdSet().forEach(function(t){ic.call(e.policies.rootTypenamesById,t)||n.push(t)}),n.length&&(t.__META={extraRootIds:n.sort()}),t},e.prototype.replace=function(e){var t=this;if(Object.keys(this.data).forEach(function(n){e&&ic.call(e,n)||t.delete(n)}),e){var n=e.__META,r=(0,en._T)(e,["__META"]);Object.keys(r).forEach(function(e){t.merge(e,r[e])}),n&&n.extraRootIds.forEach(this.retain,this)}},e.prototype.retain=function(e){return this.rootIds[e]=(this.rootIds[e]||0)+1},e.prototype.release=function(e){if(this.rootIds[e]>0){var t=--this.rootIds[e];return t||delete this.rootIds[e],t}return 0},e.prototype.getRootIdSet=function(e){return void 0===e&&(e=new Set),Object.keys(this.rootIds).forEach(e.add,e),this instanceof iL?this.parent.getRootIdSet(e):Object.keys(this.policies.rootTypenamesById).forEach(e.add,e),e},e.prototype.gc=function(){var e=this,t=this.getRootIdSet(),n=this.toObject();t.forEach(function(r){ic.call(n,r)&&(Object.keys(e.findChildRefIds(r)).forEach(t.add,t),delete n[r])});var r=Object.keys(n);if(r.length){for(var i=this;i instanceof iL;)i=i.parent;r.forEach(function(e){return i.delete(e)})}return r},e.prototype.findChildRefIds=function(e){if(!ic.call(this.refs,e)){var t=this.refs[e]=Object.create(null),n=this.data[e];if(!n)return t;var r=new Set([n]);r.forEach(function(e){eD(e)&&(t[e.__ref]=!0),(0,eO.s)(e)&&Object.keys(e).forEach(function(t){var n=e[t];(0,eO.s)(n)&&r.add(n)})})}return this.refs[e]},e.prototype.makeCacheKey=function(){return this.group.keyMaker.lookupArray(arguments)},e}(),iM=function(){function e(e,t){void 0===t&&(t=null),this.caching=e,this.parent=t,this.d=null,this.resetCaching()}return e.prototype.resetCaching=function(){this.d=this.caching?rW():null,this.keyMaker=new n_(t_.mr)},e.prototype.depend=function(e,t){if(this.d){this.d(iO(e,t));var n=iv(t);n!==t&&this.d(iO(e,n)),this.parent&&this.parent.depend(e,t)}},e.prototype.dirty=function(e,t){this.d&&this.d.dirty(iO(e,t),"__exists"===t?"forget":"setDirty")},e}();function iO(e,t){return t+"#"+e}function iA(e,t){iD(e)&&e.group.depend(t,"__exists")}!function(e){var t=function(e){function t(t){var n=t.policies,r=t.resultCaching,i=void 0===r||r,a=t.seed,o=e.call(this,n,new iM(i))||this;return o.stump=new iC(o),o.storageTrie=new n_(t_.mr),a&&o.replace(a),o}return(0,en.ZT)(t,e),t.prototype.addLayer=function(e,t){return this.stump.addLayer(e,t)},t.prototype.removeLayer=function(){return this},t.prototype.getStorage=function(){return this.storageTrie.lookupArray(arguments)},t}(e);e.Root=t}(iT||(iT={}));var iL=function(e){function t(t,n,r,i){var a=e.call(this,n.policies,i)||this;return a.id=t,a.parent=n,a.replay=r,a.group=i,r(a),a}return(0,en.ZT)(t,e),t.prototype.addLayer=function(e,n){return new t(e,this,n,this.group)},t.prototype.removeLayer=function(e){var t=this,n=this.parent.removeLayer(e);return e===this.id?(this.group.caching&&Object.keys(this.data).forEach(function(e){var r=t.data[e],i=n.lookup(e);i?r?r!==i&&Object.keys(r).forEach(function(n){(0,nm.D)(r[n],i[n])||t.group.dirty(e,n)}):(t.group.dirty(e,"__exists"),Object.keys(i).forEach(function(n){t.group.dirty(e,n)})):t.delete(e)}),n):n===this.parent?this:n.addLayer(this.id,this.replay)},t.prototype.toObject=function(){return(0,en.pi)((0,en.pi)({},this.parent.toObject()),this.data)},t.prototype.findChildRefIds=function(t){var n=this.parent.findChildRefIds(t);return ic.call(this.data,t)?(0,en.pi)((0,en.pi)({},n),e.prototype.findChildRefIds.call(this,t)):n},t.prototype.getStorage=function(){for(var e=this.parent;e.parent;)e=e.parent;return e.getStorage.apply(e,arguments)},t}(iT),iC=function(e){function t(t){return e.call(this,"EntityStore.Stump",t,function(){},new iM(t.group.caching,t.group))||this}return(0,en.ZT)(t,e),t.prototype.removeLayer=function(){return this},t.prototype.merge=function(){return this.parent.merge.apply(this.parent,arguments)},t}(iL);function iI(e,t,n){var r=e[n],i=t[n];return(0,nm.D)(r,i)?r:i}function iD(e){return!!(e instanceof iT&&e.group.caching)}function iN(e){return[e.selectionSet,e.objectOrReference,e.context,e.context.canonizeResults,]}var iP=function(){function e(e){var t=this;this.knownResults=new(t_.mr?WeakMap:Map),this.config=(0,n1.o)(e,{addTypename:!1!==e.addTypename,canonizeResults:ib(e)}),this.canon=e.canon||new nk,this.executeSelectionSet=rZ(function(e){var n,r=e.context.canonizeResults,i=iN(e);i[3]=!r;var a=(n=t.executeSelectionSet).peek.apply(n,i);return a?r?(0,en.pi)((0,en.pi)({},a),{result:t.canon.admit(a.result)}):a:(iA(e.context.store,e.enclosingRef.__ref),t.execSelectionSetImpl(e))},{max:this.config.resultCacheMaxSize,keyArgs:iN,makeCacheKey:function(e,t,n,r){if(iD(n.store))return n.store.makeCacheKey(e,eD(t)?t.__ref:t,n.varString,r)}}),this.executeSubSelectedArray=rZ(function(e){return iA(e.context.store,e.enclosingRef.__ref),t.execSubSelectedArrayImpl(e)},{max:this.config.resultCacheMaxSize,makeCacheKey:function(e){var t=e.field,n=e.array,r=e.context;if(iD(r.store))return r.store.makeCacheKey(t,n,r.varString)}})}return e.prototype.resetCanon=function(){this.canon=new nk},e.prototype.diffQueryAgainstStore=function(e){var t,n=e.store,r=e.query,i=e.rootId,a=void 0===i?"ROOT_QUERY":i,o=e.variables,s=e.returnPartialData,u=void 0===s||s,c=e.canonizeResults,l=void 0===c?this.config.canonizeResults:c,f=this.config.cache.policies;o=(0,en.pi)((0,en.pi)({},e8(e5(r))),o);var d=eI(a),h=this.executeSelectionSet({selectionSet:e9(r).selectionSet,objectOrReference:d,enclosingRef:d,context:(0,en.pi)({store:n,query:r,policies:f,variables:o,varString:nx(o),canonizeResults:l},iE(r,this.config.fragments))});if(h.missing&&(t=[new is(iR(h.missing),h.missing,r,o)],!u))throw t[0];return{result:h.result,complete:!t,missing:t}},e.prototype.isFresh=function(e,t,n,r){if(iD(r.store)&&this.knownResults.get(e)===n){var i=this.executeSelectionSet.peek(n,t,r,this.canon.isKnown(e));if(i&&e===i.result)return!0}return!1},e.prototype.execSelectionSetImpl=function(e){var t,n=this,r=e.selectionSet,i=e.objectOrReference,a=e.enclosingRef,o=e.context;if(eD(i)&&!o.policies.rootTypenamesById[i.__ref]&&!o.store.has(i.__ref))return{result:this.canon.empty,missing:"Dangling reference to missing ".concat(i.__ref," object")};var s=o.variables,u=o.policies,c=o.store.getFieldValue(i,"__typename"),l=[],f=new tB;function d(e,n){var r;return e.missing&&(t=f.merge(t,((r={})[n]=e.missing,r))),e.result}this.config.addTypename&&"string"==typeof c&&!u.rootIdsByTypename[c]&&l.push({__typename:c});var h=new Set(r.selections);h.forEach(function(e){var r,p;if(td(e,s)){if(eQ(e)){var b=u.readField({fieldName:e.name.value,field:e,variables:o.variables,from:i},o),m=eX(e);void 0===b?nj.added(e)||(t=f.merge(t,((r={})[m]="Can't find field '".concat(e.name.value,"' on ").concat(eD(i)?i.__ref+" object":"object "+JSON.stringify(i,null,2)),r))):(0,tP.k)(b)?b=d(n.executeSubSelectedArray({field:e,array:b,enclosingRef:a,context:o}),m):e.selectionSet?null!=b&&(b=d(n.executeSelectionSet({selectionSet:e.selectionSet,objectOrReference:b,enclosingRef:eD(b)?b:a,context:o}),m)):o.canonizeResults&&(b=n.canon.pass(b)),void 0!==b&&l.push(((p={})[m]=b,p))}else{var g=eC(e,o.lookupFragment);if(!g&&e.kind===nL.h.FRAGMENT_SPREAD)throw __DEV__?new Q.ej("No fragment named ".concat(e.name.value)):new Q.ej(5);g&&u.fragmentMatches(g,c)&&g.selectionSet.selections.forEach(h.add,h)}}});var p={result:tF(l),missing:t},b=o.canonizeResults?this.canon.admit(p):(0,iu.J)(p);return b.result&&this.knownResults.set(b.result,r),b},e.prototype.execSubSelectedArrayImpl=function(e){var t,n=this,r=e.field,i=e.array,a=e.enclosingRef,o=e.context,s=new tB;function u(e,n){var r;return e.missing&&(t=s.merge(t,((r={})[n]=e.missing,r))),e.result}return r.selectionSet&&(i=i.filter(o.store.canRead)),i=i.map(function(e,t){return null===e?null:(0,tP.k)(e)?u(n.executeSubSelectedArray({field:r,array:e,enclosingRef:a,context:o}),t):r.selectionSet?u(n.executeSelectionSet({selectionSet:r.selectionSet,objectOrReference:e,enclosingRef:eD(e)?e:a,context:o}),t):(__DEV__&&ij(o.store,r,e),e)}),{result:o.canonizeResults?this.canon.admit(i):i,missing:t}},e}();function iR(e){try{JSON.stringify(e,function(e,t){if("string"==typeof t)throw t;return t})}catch(t){return t}}function ij(e,t,n){if(!t.selectionSet){var r=new Set([n]);r.forEach(function(n){(0,eO.s)(n)&&(__DEV__?(0,Q.kG)(!eD(n),"Missing selection set for object of type ".concat(im(e,n)," returned for query field ").concat(t.name.value)):(0,Q.kG)(!eD(n),6),Object.values(n).forEach(r.add,r))})}}function iF(e){var t=nG("stringifyForDisplay");return JSON.stringify(e,function(e,n){return void 0===n?t:n}).split(JSON.stringify(t)).join("")}var iY=Object.create(null);function iB(e){var t=JSON.stringify(e);return iY[t]||(iY[t]=Object.create(null))}function iU(e){var t=iB(e);return t.keyFieldsFn||(t.keyFieldsFn=function(t,n){var r=function(e,t){return n.readField(t,e)},i=n.keyObject=i$(e,function(e){var i=iW(n.storeObject,e,r);return void 0===i&&t!==n.storeObject&&ic.call(t,e[0])&&(i=iW(t,e,iG)),__DEV__?(0,Q.kG)(void 0!==i,"Missing field '".concat(e.join("."),"' while extracting keyFields from ").concat(JSON.stringify(t))):(0,Q.kG)(void 0!==i,2),i});return"".concat(n.typename,":").concat(JSON.stringify(i))})}function iH(e){var t=iB(e);return t.keyArgsFn||(t.keyArgsFn=function(t,n){var r=n.field,i=n.variables,a=n.fieldName,o=JSON.stringify(i$(e,function(e){var n=e[0],a=n.charAt(0);if("@"===a){if(r&&(0,tP.O)(r.directives)){var o=n.slice(1),s=r.directives.find(function(e){return e.name.value===o}),u=s&&eZ(s,i);return u&&iW(u,e.slice(1))}return}if("$"===a){var c=n.slice(1);if(i&&ic.call(i,c)){var l=e.slice(0);return l[0]=c,iW(i,l)}return}if(t)return iW(t,e)}));return(t||"{}"!==o)&&(a+=":"+o),a})}function i$(e,t){var n=new tB;return iz(e).reduce(function(e,r){var i,a=t(r);if(void 0!==a){for(var o=r.length-1;o>=0;--o)a=((i={})[r[o]]=a,i);e=n.merge(e,a)}return e},Object.create(null))}function iz(e){var t=iB(e);if(!t.paths){var n=t.paths=[],r=[];e.forEach(function(t,i){(0,tP.k)(t)?(iz(t).forEach(function(e){return n.push(r.concat(e))}),r.length=0):(r.push(t),(0,tP.k)(e[i+1])||(n.push(r.slice(0)),r.length=0))})}return t.paths}function iG(e,t){return e[t]}function iW(e,t,n){return n=n||iG,iK(t.reduce(function e(t,r){return(0,tP.k)(t)?t.map(function(t){return e(t,r)}):t&&n(t,r)},e))}function iK(e){return(0,eO.s)(e)?(0,tP.k)(e)?e.map(iK):i$(Object.keys(e).sort(),function(t){return iW(e,t)}):e}function iV(e){return void 0!==e.args?e.args:e.field?eZ(e.field,e.variables):null}eK.setStringify(nx);var iq=function(){},iZ=function(e,t){return t.fieldName},iX=function(e,t,n){return(0,n.mergeObjects)(e,t)},iJ=function(e,t){return t},iQ=function(){function e(e){this.config=e,this.typePolicies=Object.create(null),this.toBeAdded=Object.create(null),this.supertypeMap=new Map,this.fuzzySubtypes=new Map,this.rootIdsByTypename=Object.create(null),this.rootTypenamesById=Object.create(null),this.usingPossibleTypes=!1,this.config=(0,en.pi)({dataIdFromObject:id},e),this.cache=this.config.cache,this.setRootTypename("Query"),this.setRootTypename("Mutation"),this.setRootTypename("Subscription"),e.possibleTypes&&this.addPossibleTypes(e.possibleTypes),e.typePolicies&&this.addTypePolicies(e.typePolicies)}return e.prototype.identify=function(e,t){var n,r,i=this,a=t&&(t.typename||(null===(n=t.storeObject)||void 0===n?void 0:n.__typename))||e.__typename;if(a===this.rootTypenamesById.ROOT_QUERY)return["ROOT_QUERY"];for(var o=t&&t.storeObject||e,s=(0,en.pi)((0,en.pi)({},t),{typename:a,storeObject:o,readField:t&&t.readField||function(){var e=i0(arguments,o);return i.readField(e,{store:i.cache.data,variables:e.variables})}}),u=a&&this.getTypePolicy(a),c=u&&u.keyFn||this.config.dataIdFromObject;c;){var l=c((0,en.pi)((0,en.pi)({},e),o),s);if((0,tP.k)(l))c=iU(l);else{r=l;break}}return r=r?String(r):void 0,s.keyObject?[r,s.keyObject]:[r]},e.prototype.addTypePolicies=function(e){var t=this;Object.keys(e).forEach(function(n){var r=e[n],i=r.queryType,a=r.mutationType,o=r.subscriptionType,s=(0,en._T)(r,["queryType","mutationType","subscriptionType"]);i&&t.setRootTypename("Query",n),a&&t.setRootTypename("Mutation",n),o&&t.setRootTypename("Subscription",n),ic.call(t.toBeAdded,n)?t.toBeAdded[n].push(s):t.toBeAdded[n]=[s]})},e.prototype.updateTypePolicy=function(e,t){var n=this,r=this.getTypePolicy(e),i=t.keyFields,a=t.fields;function o(e,t){e.merge="function"==typeof t?t:!0===t?iX:!1===t?iJ:e.merge}o(r,t.merge),r.keyFn=!1===i?iq:(0,tP.k)(i)?iU(i):"function"==typeof i?i:r.keyFn,a&&Object.keys(a).forEach(function(t){var r=n.getFieldPolicy(e,t,!0),i=a[t];if("function"==typeof i)r.read=i;else{var s=i.keyArgs,u=i.read,c=i.merge;r.keyFn=!1===s?iZ:(0,tP.k)(s)?iH(s):"function"==typeof s?s:r.keyFn,"function"==typeof u&&(r.read=u),o(r,c)}r.read&&r.merge&&(r.keyFn=r.keyFn||iZ)})},e.prototype.setRootTypename=function(e,t){void 0===t&&(t=e);var n="ROOT_"+e.toUpperCase(),r=this.rootTypenamesById[n];t!==r&&(__DEV__?(0,Q.kG)(!r||r===e,"Cannot change root ".concat(e," __typename more than once")):(0,Q.kG)(!r||r===e,3),r&&delete this.rootIdsByTypename[r],this.rootIdsByTypename[t]=n,this.rootTypenamesById[n]=t)},e.prototype.addPossibleTypes=function(e){var t=this;this.usingPossibleTypes=!0,Object.keys(e).forEach(function(n){t.getSupertypeSet(n,!0),e[n].forEach(function(e){t.getSupertypeSet(e,!0).add(n);var r=e.match(ig);r&&r[0]===e||t.fuzzySubtypes.set(e,RegExp(e))})})},e.prototype.getTypePolicy=function(e){var t=this;if(!ic.call(this.typePolicies,e)){var n=this.typePolicies[e]=Object.create(null);n.fields=Object.create(null);var r=this.supertypeMap.get(e);r&&r.size&&r.forEach(function(e){var r=t.getTypePolicy(e),i=r.fields;Object.assign(n,(0,en._T)(r,["fields"])),Object.assign(n.fields,i)})}var i=this.toBeAdded[e];return i&&i.length&&i.splice(0).forEach(function(n){t.updateTypePolicy(e,n)}),this.typePolicies[e]},e.prototype.getFieldPolicy=function(e,t,n){if(e){var r=this.getTypePolicy(e).fields;return r[t]||n&&(r[t]=Object.create(null))}},e.prototype.getSupertypeSet=function(e,t){var n=this.supertypeMap.get(e);return!n&&t&&this.supertypeMap.set(e,n=new Set),n},e.prototype.fragmentMatches=function(e,t,n,r){var i=this;if(!e.typeCondition)return!0;if(!t)return!1;var a=e.typeCondition.name.value;if(t===a)return!0;if(this.usingPossibleTypes&&this.supertypeMap.has(a))for(var o=this.getSupertypeSet(t,!0),s=[o],u=function(e){var t=i.getSupertypeSet(e,!1);t&&t.size&&0>s.indexOf(t)&&s.push(t)},c=!!(n&&this.fuzzySubtypes.size),l=!1,f=0;f1?a:t}:(r=(0,en.pi)({},i),ic.call(r,"from")||(r.from=t)),__DEV__&&void 0===r.from&&__DEV__&&Q.kG.warn("Undefined 'from' passed to readField with arguments ".concat(iF(Array.from(e)))),void 0===r.variables&&(r.variables=n),r}function i2(e){return function(t,n){if((0,tP.k)(t)||(0,tP.k)(n))throw __DEV__?new Q.ej("Cannot automatically merge arrays"):new Q.ej(4);if((0,eO.s)(t)&&(0,eO.s)(n)){var r=e.getFieldValue(t,"__typename"),i=e.getFieldValue(n,"__typename");if(r&&i&&r!==i)return n;if(eD(t)&&iw(n))return e.merge(t.__ref,n),t;if(iw(t)&&eD(n))return e.merge(t,n.__ref),n;if(iw(t)&&iw(n))return(0,en.pi)((0,en.pi)({},t),n)}return n}}function i3(e,t,n){var r="".concat(t).concat(n),i=e.flavors.get(r);return i||e.flavors.set(r,i=e.clientOnly===t&&e.deferred===n?e:(0,en.pi)((0,en.pi)({},e),{clientOnly:t,deferred:n})),i}var i4=function(){function e(e,t,n){this.cache=e,this.reader=t,this.fragments=n}return e.prototype.writeToStore=function(e,t){var n=this,r=t.query,i=t.result,a=t.dataId,o=t.variables,s=t.overwrite,u=e2(r),c=i_();o=(0,en.pi)((0,en.pi)({},e8(u)),o);var l=(0,en.pi)((0,en.pi)({store:e,written:Object.create(null),merge:function(e,t){return c.merge(e,t)},variables:o,varString:nx(o)},iE(r,this.fragments)),{overwrite:!!s,incomingById:new Map,clientOnly:!1,deferred:!1,flavors:new Map}),f=this.processSelectionSet({result:i||Object.create(null),dataId:a,selectionSet:u.selectionSet,mergeTree:{map:new Map},context:l});if(!eD(f))throw __DEV__?new Q.ej("Could not identify object ".concat(JSON.stringify(i))):new Q.ej(7);return l.incomingById.forEach(function(t,r){var i=t.storeObject,a=t.mergeTree,o=t.fieldNodeSet,s=eI(r);if(a&&a.map.size){var u=n.applyMerges(a,s,i,l);if(eD(u))return;i=u}if(__DEV__&&!l.overwrite){var c=Object.create(null);o.forEach(function(e){e.selectionSet&&(c[e.name.value]=!0)});var f=function(e){return!0===c[iv(e)]},d=function(e){var t=a&&a.map.get(e);return Boolean(t&&t.info&&t.info.merge)};Object.keys(i).forEach(function(e){f(e)&&!d(e)&&at(s,i,e,l.store)})}e.merge(r,i)}),e.retain(f.__ref),f},e.prototype.processSelectionSet=function(e){var t=this,n=e.dataId,r=e.result,i=e.selectionSet,a=e.context,o=e.mergeTree,s=this.cache.policies,u=Object.create(null),c=n&&s.rootTypenamesById[n]||eJ(r,i,a.fragmentMap)||n&&a.store.get(n,"__typename");"string"==typeof c&&(u.__typename=c);var l=function(){var e=i0(arguments,u,a.variables);if(eD(e.from)){var t=a.incomingById.get(e.from.__ref);if(t){var n=s.readField((0,en.pi)((0,en.pi)({},e),{from:t.storeObject}),a);if(void 0!==n)return n}}return s.readField(e,a)},f=new Set;this.flattenFields(i,r,a,c).forEach(function(e,n){var i,a=r[eX(n)];if(f.add(n),void 0!==a){var d=s.getStoreFieldName({typename:c,fieldName:n.name.value,field:n,variables:e.variables}),h=i6(o,d),p=t.processFieldValue(a,n,n.selectionSet?i3(e,!1,!1):e,h),b=void 0;n.selectionSet&&(eD(p)||iw(p))&&(b=l("__typename",p));var m=s.getMergeFunction(c,n.name.value,b);m?h.info={field:n,typename:c,merge:m}:i7(o,d),u=e.merge(u,((i={})[d]=p,i))}else __DEV__&&!e.clientOnly&&!e.deferred&&!nj.added(n)&&!s.getReadFunction(c,n.name.value)&&__DEV__&&Q.kG.error("Missing field '".concat(eX(n),"' while writing result ").concat(JSON.stringify(r,null,2)).substring(0,1e3))});try{var d=s.identify(r,{typename:c,selectionSet:i,fragmentMap:a.fragmentMap,storeObject:u,readField:l}),h=d[0],p=d[1];n=n||h,p&&(u=a.merge(u,p))}catch(b){if(!n)throw b}if("string"==typeof n){var m=eI(n),g=a.written[n]||(a.written[n]=[]);if(g.indexOf(i)>=0||(g.push(i),this.reader&&this.reader.isFresh(r,m,i,a)))return m;var v=a.incomingById.get(n);return v?(v.storeObject=a.merge(v.storeObject,u),v.mergeTree=i9(v.mergeTree,o),f.forEach(function(e){return v.fieldNodeSet.add(e)})):a.incomingById.set(n,{storeObject:u,mergeTree:i8(o)?void 0:o,fieldNodeSet:f}),m}return u},e.prototype.processFieldValue=function(e,t,n,r){var i=this;return t.selectionSet&&null!==e?(0,tP.k)(e)?e.map(function(e,a){var o=i.processFieldValue(e,t,n,i6(r,a));return i7(r,a),o}):this.processSelectionSet({result:e,selectionSet:t.selectionSet,context:n,mergeTree:r}):__DEV__?nJ(e):e},e.prototype.flattenFields=function(e,t,n,r){void 0===r&&(r=eJ(t,e,n.fragmentMap));var i=new Map,a=this.cache.policies,o=new n_(!1);return function e(s,u){var c=o.lookup(s,u.clientOnly,u.deferred);c.visited||(c.visited=!0,s.selections.forEach(function(o){if(td(o,n.variables)){var s=u.clientOnly,c=u.deferred;if(!(s&&c)&&(0,tP.O)(o.directives)&&o.directives.forEach(function(e){var t=e.name.value;if("client"===t&&(s=!0),"defer"===t){var r=eZ(e,n.variables);r&&!1===r.if||(c=!0)}}),eQ(o)){var l=i.get(o);l&&(s=s&&l.clientOnly,c=c&&l.deferred),i.set(o,i3(n,s,c))}else{var f=eC(o,n.lookupFragment);if(!f&&o.kind===nL.h.FRAGMENT_SPREAD)throw __DEV__?new Q.ej("No fragment named ".concat(o.name.value)):new Q.ej(8);f&&a.fragmentMatches(f,r,t,n.variables)&&e(f.selectionSet,i3(n,s,c))}}}))}(e,n),i},e.prototype.applyMerges=function(e,t,n,r,i){var a=this;if(e.map.size&&!eD(n)){var o,s,u=!(0,tP.k)(n)&&(eD(t)||iw(t))?t:void 0,c=n;u&&!i&&(i=[eD(u)?u.__ref:u]);var l=function(e,t){return(0,tP.k)(e)?"number"==typeof t?e[t]:void 0:r.store.getFieldValue(e,String(t))};e.map.forEach(function(e,t){var n=l(u,t),o=l(c,t);if(void 0!==o){i&&i.push(t);var f=a.applyMerges(e,n,o,r,i);f!==o&&(s=s||new Map).set(t,f),i&&(0,Q.kG)(i.pop()===t)}}),s&&(n=(0,tP.k)(c)?c.slice(0):(0,en.pi)({},c),s.forEach(function(e,t){n[t]=e}))}return e.info?this.cache.policies.runMergeFunction(t,n,e.info,r,i&&(o=r.store).getStorage.apply(o,i)):n},e}(),i5=[];function i6(e,t){var n=e.map;return n.has(t)||n.set(t,i5.pop()||{map:new Map}),n.get(t)}function i9(e,t){if(e===t||!t||i8(t))return e;if(!e||i8(e))return t;var n=e.info&&t.info?(0,en.pi)((0,en.pi)({},e.info),t.info):e.info||t.info,r=e.map.size&&t.map.size,i=r?new Map:e.map.size?e.map:t.map,a={info:n,map:i};if(r){var o=new Set(t.map.keys());e.map.forEach(function(e,n){a.map.set(n,i9(e,t.map.get(n))),o.delete(n)}),o.forEach(function(n){a.map.set(n,i9(t.map.get(n),e.map.get(n)))})}return a}function i8(e){return!e||!(e.info||e.map.size)}function i7(e,t){var n=e.map,r=n.get(t);r&&i8(r)&&(i5.push(r),n.delete(t))}var ae=new Set;function at(e,t,n,r){var i=function(e){var t=r.getFieldValue(e,n);return"object"==typeof t&&t},a=i(e);if(a){var o=i(t);if(!(!o||eD(a)||(0,nm.D)(a,o)||Object.keys(a).every(function(e){return void 0!==r.getFieldValue(o,e)}))){var s=r.getFieldValue(e,"__typename")||r.getFieldValue(t,"__typename"),u=iv(n),c="".concat(s,".").concat(u);if(!ae.has(c)){ae.add(c);var l=[];(0,tP.k)(a)||(0,tP.k)(o)||[a,o].forEach(function(e){var t=r.getFieldValue(e,"__typename");"string"!=typeof t||l.includes(t)||l.push(t)}),__DEV__&&Q.kG.warn("Cache data may be lost when replacing the ".concat(u," field of a ").concat(s," object.\n\nThis could cause additional (usually avoidable) network requests to fetch data that were otherwise cached.\n\nTo address this problem (which is not a bug in Apollo Client), ").concat(l.length?"either ensure all objects of type "+l.join(" and ")+" have an ID or a custom merge function, or ":"","define a custom merge function for the ").concat(c," field, so InMemoryCache can safely merge these objects:\n\n existing: ").concat(JSON.stringify(a).slice(0,1e3),"\n incoming: ").concat(JSON.stringify(o).slice(0,1e3),"\n\nFor more information about these options, please refer to the documentation:\n\n * Ensuring entity objects have IDs: https://go.apollo.dev/c/generating-unique-identifiers\n * Defining custom merge functions: https://go.apollo.dev/c/merging-non-normalized-objects\n"))}}}}var an=function(e){function t(t){void 0===t&&(t={});var n=e.call(this)||this;return n.watches=new Set,n.typenameDocumentCache=new Map,n.makeVar=r2,n.txCount=0,n.config=ip(t),n.addTypename=!!n.config.addTypename,n.policies=new iQ({cache:n,dataIdFromObject:n.config.dataIdFromObject,possibleTypes:n.config.possibleTypes,typePolicies:n.config.typePolicies}),n.init(),n}return(0,en.ZT)(t,e),t.prototype.init=function(){var e=this.data=new iT.Root({policies:this.policies,resultCaching:this.config.resultCaching});this.optimisticData=e.stump,this.resetResultCache()},t.prototype.resetResultCache=function(e){var t=this,n=this.storeReader,r=this.config.fragments;this.storeWriter=new i4(this,this.storeReader=new iP({cache:this,addTypename:this.addTypename,resultCacheMaxSize:this.config.resultCacheMaxSize,canonizeResults:ib(this.config),canon:e?void 0:n&&n.canon,fragments:r}),r),this.maybeBroadcastWatch=rZ(function(e,n){return t.broadcastWatch(e,n)},{max:this.config.resultCacheMaxSize,makeCacheKey:function(e){var n=e.optimistic?t.optimisticData:t.data;if(iD(n)){var r=e.optimistic,i=e.id,a=e.variables;return n.makeCacheKey(e.query,e.callback,nx({optimistic:r,id:i,variables:a}))}}}),new Set([this.data.group,this.optimisticData.group,]).forEach(function(e){return e.resetCaching()})},t.prototype.restore=function(e){return this.init(),e&&this.data.replace(e),this},t.prototype.extract=function(e){return void 0===e&&(e=!1),(e?this.optimisticData:this.data).extract()},t.prototype.read=function(e){var t=e.returnPartialData,n=void 0!==t&&t;try{return this.storeReader.diffQueryAgainstStore((0,en.pi)((0,en.pi)({},e),{store:e.optimistic?this.optimisticData:this.data,config:this.config,returnPartialData:n})).result||null}catch(r){if(r instanceof is)return null;throw r}},t.prototype.write=function(e){try{return++this.txCount,this.storeWriter.writeToStore(this.data,e)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.modify=function(e){if(ic.call(e,"id")&&!e.id)return!1;var t=e.optimistic?this.optimisticData:this.data;try{return++this.txCount,t.modify(e.id||"ROOT_QUERY",e.fields)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.diff=function(e){return this.storeReader.diffQueryAgainstStore((0,en.pi)((0,en.pi)({},e),{store:e.optimistic?this.optimisticData:this.data,rootId:e.id||"ROOT_QUERY",config:this.config}))},t.prototype.watch=function(e){var t=this;return this.watches.size||r0(this),this.watches.add(e),e.immediate&&this.maybeBroadcastWatch(e),function(){t.watches.delete(e)&&!t.watches.size&&r1(t),t.maybeBroadcastWatch.forget(e)}},t.prototype.gc=function(e){nx.reset();var t=this.optimisticData.gc();return e&&!this.txCount&&(e.resetResultCache?this.resetResultCache(e.resetResultIdentities):e.resetResultIdentities&&this.storeReader.resetCanon()),t},t.prototype.retain=function(e,t){return(t?this.optimisticData:this.data).retain(e)},t.prototype.release=function(e,t){return(t?this.optimisticData:this.data).release(e)},t.prototype.identify=function(e){if(eD(e))return e.__ref;try{return this.policies.identify(e)[0]}catch(t){__DEV__&&Q.kG.warn(t)}},t.prototype.evict=function(e){if(!e.id){if(ic.call(e,"id"))return!1;e=(0,en.pi)((0,en.pi)({},e),{id:"ROOT_QUERY"})}try{return++this.txCount,this.optimisticData.evict(e,this.data)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.reset=function(e){var t=this;return this.init(),nx.reset(),e&&e.discardWatches?(this.watches.forEach(function(e){return t.maybeBroadcastWatch.forget(e)}),this.watches.clear(),r1(this)):this.broadcastWatches(),Promise.resolve()},t.prototype.removeOptimistic=function(e){var t=this.optimisticData.removeLayer(e);t!==this.optimisticData&&(this.optimisticData=t,this.broadcastWatches())},t.prototype.batch=function(e){var t,n=this,r=e.update,i=e.optimistic,a=void 0===i||i,o=e.removeOptimistic,s=e.onWatchUpdated,u=function(e){var i=n,a=i.data,o=i.optimisticData;++n.txCount,e&&(n.data=n.optimisticData=e);try{return t=r(n)}finally{--n.txCount,n.data=a,n.optimisticData=o}},c=new Set;return s&&!this.txCount&&this.broadcastWatches((0,en.pi)((0,en.pi)({},e),{onWatchUpdated:function(e){return c.add(e),!1}})),"string"==typeof a?this.optimisticData=this.optimisticData.addLayer(a,u):!1===a?u(this.data):u(),"string"==typeof o&&(this.optimisticData=this.optimisticData.removeLayer(o)),s&&c.size?(this.broadcastWatches((0,en.pi)((0,en.pi)({},e),{onWatchUpdated:function(e,t){var n=s.call(this,e,t);return!1!==n&&c.delete(e),n}})),c.size&&c.forEach(function(e){return n.maybeBroadcastWatch.dirty(e)})):this.broadcastWatches(e),t},t.prototype.performTransaction=function(e,t){return this.batch({update:e,optimistic:t||null!==t})},t.prototype.transformDocument=function(e){if(this.addTypename){var t=this.typenameDocumentCache.get(e);return t||(t=nj(e),this.typenameDocumentCache.set(e,t),this.typenameDocumentCache.set(t,t)),t}return e},t.prototype.transformForLink=function(e){var t=this.config.fragments;return t?t.transform(e):e},t.prototype.broadcastWatches=function(e){var t=this;this.txCount||this.watches.forEach(function(n){return t.maybeBroadcastWatch(n,e)})},t.prototype.broadcastWatch=function(e,t){var n=e.lastDiff,r=this.diff(e);(!t||(e.optimistic&&"string"==typeof t.optimistic&&(r.fromOptimisticTransaction=!0),!t.onWatchUpdated||!1!==t.onWatchUpdated.call(this,e,r,n)))&&(n&&(0,nm.D)(n.result,r.result)||e.callback(e.lastDiff=r,n))},t}(io),ar={possibleTypes:{ApproveJobProposalSpecPayload:["ApproveJobProposalSpecSuccess","JobAlreadyExistsError","NotFoundError"],BridgePayload:["Bridge","NotFoundError"],CancelJobProposalSpecPayload:["CancelJobProposalSpecSuccess","NotFoundError"],ChainPayload:["Chain","NotFoundError"],CreateAPITokenPayload:["CreateAPITokenSuccess","InputErrors"],CreateBridgePayload:["CreateBridgeSuccess"],CreateCSAKeyPayload:["CSAKeyExistsError","CreateCSAKeySuccess"],CreateFeedsManagerChainConfigPayload:["CreateFeedsManagerChainConfigSuccess","InputErrors","NotFoundError"],CreateFeedsManagerPayload:["CreateFeedsManagerSuccess","InputErrors","NotFoundError","SingleFeedsManagerError"],CreateJobPayload:["CreateJobSuccess","InputErrors"],CreateOCR2KeyBundlePayload:["CreateOCR2KeyBundleSuccess"],CreateOCRKeyBundlePayload:["CreateOCRKeyBundleSuccess"],CreateP2PKeyPayload:["CreateP2PKeySuccess"],DeleteAPITokenPayload:["DeleteAPITokenSuccess","InputErrors"],DeleteBridgePayload:["DeleteBridgeConflictError","DeleteBridgeInvalidNameError","DeleteBridgeSuccess","NotFoundError"],DeleteCSAKeyPayload:["DeleteCSAKeySuccess","NotFoundError"],DeleteFeedsManagerChainConfigPayload:["DeleteFeedsManagerChainConfigSuccess","NotFoundError"],DeleteJobPayload:["DeleteJobSuccess","NotFoundError"],DeleteOCR2KeyBundlePayload:["DeleteOCR2KeyBundleSuccess","NotFoundError"],DeleteOCRKeyBundlePayload:["DeleteOCRKeyBundleSuccess","NotFoundError"],DeleteP2PKeyPayload:["DeleteP2PKeySuccess","NotFoundError"],DeleteVRFKeyPayload:["DeleteVRFKeySuccess","NotFoundError"],DismissJobErrorPayload:["DismissJobErrorSuccess","NotFoundError"],Error:["CSAKeyExistsError","DeleteBridgeConflictError","DeleteBridgeInvalidNameError","InputError","JobAlreadyExistsError","NotFoundError","RunJobCannotRunError","SingleFeedsManagerError"],EthTransactionPayload:["EthTransaction","NotFoundError"],FeaturesPayload:["Features"],FeedsManagerPayload:["FeedsManager","NotFoundError"],GetSQLLoggingPayload:["SQLLogging"],GlobalLogLevelPayload:["GlobalLogLevel"],JobPayload:["Job","NotFoundError"],JobProposalPayload:["JobProposal","NotFoundError"],JobRunPayload:["JobRun","NotFoundError"],JobSpec:["BlockHeaderFeederSpec","BlockhashStoreSpec","BootstrapSpec","CronSpec","DirectRequestSpec","FluxMonitorSpec","GatewaySpec","KeeperSpec","OCR2Spec","OCRSpec","VRFSpec","WebhookSpec"],NodePayload:["Node","NotFoundError"],PaginatedPayload:["BridgesPayload","ChainsPayload","EthTransactionAttemptsPayload","EthTransactionsPayload","JobRunsPayload","JobsPayload","NodesPayload"],RejectJobProposalSpecPayload:["NotFoundError","RejectJobProposalSpecSuccess"],RunJobPayload:["NotFoundError","RunJobCannotRunError","RunJobSuccess"],SetGlobalLogLevelPayload:["InputErrors","SetGlobalLogLevelSuccess"],SetSQLLoggingPayload:["SetSQLLoggingSuccess"],SetServicesLogLevelsPayload:["InputErrors","SetServicesLogLevelsSuccess"],UpdateBridgePayload:["NotFoundError","UpdateBridgeSuccess"],UpdateFeedsManagerChainConfigPayload:["InputErrors","NotFoundError","UpdateFeedsManagerChainConfigSuccess"],UpdateFeedsManagerPayload:["InputErrors","NotFoundError","UpdateFeedsManagerSuccess"],UpdateJobProposalSpecDefinitionPayload:["NotFoundError","UpdateJobProposalSpecDefinitionSuccess"],UpdatePasswordPayload:["InputErrors","UpdatePasswordSuccess"],VRFKeyPayload:["NotFoundError","VRFKeySuccess"]}};let ai=ar;var aa=(r=void 0,location.origin),ao=new nh({uri:"".concat(aa,"/query"),credentials:"include"}),as=new ia({cache:new an({possibleTypes:ai.possibleTypes}),link:ao});if(a.Z.locale(o),u().defaultFormat="YYYY-MM-DD h:mm:ss A","undefined"!=typeof document){var au,ac,al=f().hydrate;ac=X,al(c.createElement(et,{client:as},c.createElement(d.zj,null,c.createElement(i.MuiThemeProvider,{theme:J.r},c.createElement(ac,null)))),document.getElementById("root"))}})()})(); \ No newline at end of file diff --git a/core/web/assets/main.f42e73c0c7811e9907db.js.gz b/core/web/assets/main.4a9b933093bb165fcc8f.js.gz similarity index 95% rename from core/web/assets/main.f42e73c0c7811e9907db.js.gz rename to core/web/assets/main.4a9b933093bb165fcc8f.js.gz index 408214985c1..6e962127a7e 100644 Binary files a/core/web/assets/main.f42e73c0c7811e9907db.js.gz and b/core/web/assets/main.4a9b933093bb165fcc8f.js.gz differ diff --git a/core/web/eth_keys_controller_test.go b/core/web/eth_keys_controller_test.go index 94d92849887..bab987fbcc2 100644 --- a/core/web/eth_keys_controller_test.go +++ b/core/web/eth_keys_controller_test.go @@ -416,7 +416,7 @@ func TestETHKeysController_ChainSuccess_ResetWithAbandon(t *testing.T) { assert.NoError(t, err) db := app.GetSqlxDB() - txStore := txmgr.NewTxStore(db, logger.TestLogger(t), cfg.Database()) + txStore := txmgr.NewTxStore(db, logger.TestLogger(t)) txes, err := txStore.FindTxesByFromAddressAndState(testutils.Context(t), addr, "fatal_error") require.NoError(t, err) diff --git a/core/web/evm_chains_controller_test.go b/core/web/evm_chains_controller_test.go index ea3d5476cec..5d31374cfb7 100644 --- a/core/web/evm_chains_controller_test.go +++ b/core/web/evm_chains_controller_test.go @@ -12,12 +12,12 @@ import ( "github.com/stretchr/testify/require" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -48,7 +48,7 @@ func Test_EVMChainsController_Show(t *testing.T) { }, RPCBlockQueryDelay: ptr[uint16](23), MinIncomingConfirmations: ptr[uint32](12), - LinkContractAddress: ptr(ethkey.EIP55AddressFromAddress(testutils.NewAddress())), + LinkContractAddress: ptr(types.EIP55AddressFromAddress(testutils.NewAddress())), }), }, wantStatusCode: http.StatusOK, diff --git a/core/web/evm_transactions_controller.go b/core/web/evm_transactions_controller.go index 2b2fd2d554f..af9bcc78b07 100644 --- a/core/web/evm_transactions_controller.go +++ b/core/web/evm_transactions_controller.go @@ -19,7 +19,7 @@ type TransactionsController struct { // Index returns paginated transactions func (tc *TransactionsController) Index(c *gin.Context, size, page, offset int) { - txs, count, err := tc.App.TxmStorageService().TransactionsWithAttempts(offset, size) + txs, count, err := tc.App.TxmStorageService().TransactionsWithAttempts(c, offset, size) ptxs := make([]presenters.EthTxResource, len(txs)) for i, tx := range txs { tx.TxAttempts[0].Tx = tx @@ -35,7 +35,7 @@ func (tc *TransactionsController) Index(c *gin.Context, size, page, offset int) func (tc *TransactionsController) Show(c *gin.Context) { hash := common.HexToHash(c.Param("TxHash")) - ethTxAttempt, err := tc.App.TxmStorageService().FindTxAttempt(hash) + ethTxAttempt, err := tc.App.TxmStorageService().FindTxAttempt(c, hash) if errors.Is(err, sql.ErrNoRows) { jsonAPIError(c, http.StatusNotFound, errors.New("Transaction not found")) return diff --git a/core/web/evm_transactions_controller_test.go b/core/web/evm_transactions_controller_test.go index 9135be432de..e6d186fbab3 100644 --- a/core/web/evm_transactions_controller_test.go +++ b/core/web/evm_transactions_controller_test.go @@ -23,9 +23,10 @@ func TestTransactionsController_Index_Success(t *testing.T) { app := cltest.NewApplicationWithKey(t) require.NoError(t, app.Start(testutils.Context(t))) + ctx := testutils.Context(t) db := app.GetSqlxDB() - txStore := cltest.NewTestTxStore(t, app.GetSqlxDB(), app.GetConfig().Database()) + txStore := cltest.NewTestTxStore(t, app.GetSqlxDB()) ethKeyStore := cltest.NewKeyStore(t, db, app.Config.Database()).Eth() client := app.NewHTTPClient(nil) _, from := cltest.MustInsertRandomKey(t, ethKeyStore) @@ -40,9 +41,9 @@ func TestTransactionsController_Index_Success(t *testing.T) { attempt.State = txmgrtypes.TxAttemptBroadcast attempt.TxFee = gas.EvmFee{Legacy: assets.NewWeiI(3)} attempt.BroadcastBeforeBlockNum = &blockNum - require.NoError(t, txStore.InsertTxAttempt(&attempt)) + require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt)) - _, count, err := txStore.TransactionsWithAttempts(0, 100) + _, count, err := txStore.TransactionsWithAttempts(ctx, 0, 100) require.NoError(t, err) require.Equal(t, count, 3) @@ -81,7 +82,7 @@ func TestTransactionsController_Show_Success(t *testing.T) { app := cltest.NewApplicationWithKey(t) require.NoError(t, app.Start(testutils.Context(t))) - txStore := cltest.NewTestTxStore(t, app.GetSqlxDB(), app.GetConfig().Database()) + txStore := cltest.NewTestTxStore(t, app.GetSqlxDB()) client := app.NewHTTPClient(nil) _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) @@ -114,7 +115,7 @@ func TestTransactionsController_Show_NotFound(t *testing.T) { app := cltest.NewApplicationWithKey(t) require.NoError(t, app.Start(testutils.Context(t))) - txStore := cltest.NewTestTxStore(t, app.GetSqlxDB(), app.GetConfig().Database()) + txStore := cltest.NewTestTxStore(t, app.GetSqlxDB()) client := app.NewHTTPClient(nil) _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) tx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 1, from) diff --git a/core/web/evm_transfer_controller.go b/core/web/evm_transfer_controller.go index 26f199ed961..88d3dead4c8 100644 --- a/core/web/evm_transfer_controller.go +++ b/core/web/evm_transfer_controller.go @@ -113,7 +113,7 @@ func ValidateEthBalanceForTransfer(c *gin.Context, chain legacyevm.Chain, fromAd return errors.Errorf("balance is too low for this transaction to be executed: %v", balance) } - gasLimit := uint64(chain.Config().EVM().GasEstimator().LimitTransfer()) + gasLimit := chain.Config().EVM().GasEstimator().LimitTransfer() estimator := chain.GasEstimator() amountWithFees, err := estimator.GetMaxCost(c, amount, nil, gasLimit, chain.Config().EVM().GasEstimator().PriceMaxKey(fromAddr)) @@ -128,7 +128,7 @@ func ValidateEthBalanceForTransfer(c *gin.Context, chain legacyevm.Chain, fromAd return nil } -func FindTxAttempt(ctx context.Context, timeout time.Duration, etx txmgr.Tx, FindTxWithAttempts func(int64) (txmgr.Tx, error)) (attempt txmgr.TxAttempt, err error) { +func FindTxAttempt(ctx context.Context, timeout time.Duration, etx txmgr.Tx, FindTxWithAttempts func(context.Context, int64) (txmgr.Tx, error)) (attempt txmgr.TxAttempt, err error) { recheckTime := time.Second tick := time.After(0) ctx, cancel := context.WithTimeout(ctx, timeout) @@ -138,7 +138,7 @@ func FindTxAttempt(ctx context.Context, timeout time.Duration, etx txmgr.Tx, Fin case <-ctx.Done(): return attempt, fmt.Errorf("%w - tx may still have been broadcast", ctx.Err()) case <-tick: - etx, err = FindTxWithAttempts(etx.ID) + etx, err = FindTxWithAttempts(ctx, etx.ID) if err != nil { return attempt, fmt.Errorf("failed to find transaction: %w", err) } diff --git a/core/web/evm_transfer_controller_test.go b/core/web/evm_transfer_controller_test.go index 86d6b4618aa..bfac6752f51 100644 --- a/core/web/evm_transfer_controller_test.go +++ b/core/web/evm_transfer_controller_test.go @@ -21,7 +21,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/store/models" @@ -348,7 +347,7 @@ func TestTransfersController_FindTxAttempt(t *testing.T) { ctx := testutils.Context(t) timeout := 5 * time.Second var done bool - find := func(_ int64) (txmgr.Tx, error) { + find := func(_ context.Context, _ int64) (txmgr.Tx, error) { if !done { done = true return tx, nil @@ -364,7 +363,7 @@ func TestTransfersController_FindTxAttempt(t *testing.T) { // failed to find tx t.Run("failed to find tx", func(t *testing.T) { ctx := testutils.Context(t) - find := func(_ int64) (txmgr.Tx, error) { + find := func(_ context.Context, _ int64) (txmgr.Tx, error) { return txmgr.Tx{}, fmt.Errorf("ERRORED") } _, err := web.FindTxAttempt(ctx, time.Second, tx, find) @@ -374,7 +373,7 @@ func TestTransfersController_FindTxAttempt(t *testing.T) { // timeout t.Run("timeout", func(t *testing.T) { ctx := testutils.Context(t) - find := func(_ int64) (txmgr.Tx, error) { + find := func(_ context.Context, _ int64) (txmgr.Tx, error) { return tx, nil } _, err := web.FindTxAttempt(ctx, time.Second, tx, find) @@ -384,7 +383,7 @@ func TestTransfersController_FindTxAttempt(t *testing.T) { // context canceled t.Run("context canceled", func(t *testing.T) { ctx := testutils.Context(t) - find := func(_ int64) (txmgr.Tx, error) { + find := func(_ context.Context, _ int64) (txmgr.Tx, error) { return tx, nil } @@ -400,8 +399,7 @@ func TestTransfersController_FindTxAttempt(t *testing.T) { } func validateTxCount(t *testing.T, db *sqlx.DB, count int) { - cfg := pgtest.NewQConfig(false) - txStore := txmgr.NewTxStore(db, logger.TestLogger(t), cfg) + txStore := txmgr.NewTxStore(db, logger.TestLogger(t)) txes, err := txStore.GetAllTxes(testutils.Context(t)) require.NoError(t, err) diff --git a/core/web/evm_tx_attempts_controller.go b/core/web/evm_tx_attempts_controller.go index a17aedd5898..a18bf5492d6 100644 --- a/core/web/evm_tx_attempts_controller.go +++ b/core/web/evm_tx_attempts_controller.go @@ -14,7 +14,7 @@ type TxAttemptsController struct { // Index returns paginated transaction attempts func (tac *TxAttemptsController) Index(c *gin.Context, size, page, offset int) { - attempts, count, err := tac.App.TxmStorageService().TxAttempts(offset, size) + attempts, count, err := tac.App.TxmStorageService().TxAttempts(c, offset, size) ptxs := make([]presenters.EthTxResource, len(attempts)) for i, attempt := range attempts { ptxs[i] = presenters.NewEthTxResourceFromAttempt(attempt) diff --git a/core/web/evm_tx_attempts_controller_test.go b/core/web/evm_tx_attempts_controller_test.go index 6c073b3ac41..a92c8293a3f 100644 --- a/core/web/evm_tx_attempts_controller_test.go +++ b/core/web/evm_tx_attempts_controller_test.go @@ -20,7 +20,7 @@ func TestTxAttemptsController_Index_Success(t *testing.T) { app := cltest.NewApplicationWithKey(t) require.NoError(t, app.Start(testutils.Context(t))) - txStore := cltest.NewTestTxStore(t, app.GetSqlxDB(), app.GetConfig().Database()) + txStore := cltest.NewTestTxStore(t, app.GetSqlxDB()) client := app.NewHTTPClient(nil) _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) diff --git a/core/web/jobs_controller.go b/core/web/jobs_controller.go index 6296c6a016f..5226d7dd7d6 100644 --- a/core/web/jobs_controller.go +++ b/core/web/jobs_controller.go @@ -105,7 +105,7 @@ func (jc *JobsController) Create(c *gin.Context) { return } - jb, status, err := jc.validateJobSpec(request.TOML) + jb, status, err := jc.validateJobSpec(c.Request.Context(), request.TOML) if err != nil { jsonAPIError(c, status, err) return @@ -174,7 +174,7 @@ func (jc *JobsController) Update(c *gin.Context) { return } - jb, status, err := jc.validateJobSpec(request.TOML) + jb, status, err := jc.validateJobSpec(c.Request.Context(), request.TOML) if err != nil { jsonAPIError(c, status, err) return @@ -214,12 +214,11 @@ func (jc *JobsController) Update(c *gin.Context) { jsonAPIResponse(c, presenters.NewJobResource(jb), jb.Type.String()) } -func (jc *JobsController) validateJobSpec(tomlString string) (jb job.Job, statusCode int, err error) { +func (jc *JobsController) validateJobSpec(ctx context.Context, tomlString string) (jb job.Job, statusCode int, err error) { jobType, err := job.ValidateSpec(tomlString) if err != nil { return jb, http.StatusUnprocessableEntity, errors.Wrap(err, "failed to parse TOML") } - config := jc.App.GetConfig() switch jobType { case job.OffchainReporting: @@ -228,7 +227,7 @@ func (jc *JobsController) validateJobSpec(tomlString string) (jb job.Job, status return jb, http.StatusNotImplemented, errors.New("The Offchain Reporting feature is disabled by configuration") } case job.OffchainReporting2: - jb, err = validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), tomlString) + jb, err = validate.ValidatedOracleSpecToml(ctx, config.OCR2(), config.Insecure(), tomlString, jc.App.GetLoopRegistrarConfig()) if !config.OCR2().Enabled() { return jb, http.StatusNotImplemented, errors.New("The Offchain Reporting 2 feature is disabled by configuration") } diff --git a/core/web/jobs_controller_test.go b/core/web/jobs_controller_test.go index 0dc04ff34e8..1e83d60cb7e 100644 --- a/core/web/jobs_controller_test.go +++ b/core/web/jobs_controller_test.go @@ -28,13 +28,13 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/directrequest" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -79,7 +79,7 @@ func TestJobsController_Create_ValidationFailure_OffchainReportingSpec(t *testin t.Run(tc.name, func(t *testing.T) { ta, client := setupJobsControllerTests(t) - var address ethkey.EIP55Address + var address types.EIP55Address if tc.taExists { key, _ := cltest.MustInsertRandomKey(t, ta.KeyStore.Eth()) address = key.EIP55Address @@ -191,7 +191,7 @@ func TestJobController_Create_HappyPath(t *testing.T) { assert.Equal(t, jb.OCROracleSpec.ContractConfigConfirmations, resource.OffChainReportingSpec.ContractConfigConfirmations) assert.NotNil(t, resource.PipelineSpec.DotDAGSource) // Sanity check to make sure it inserted correctly - require.Equal(t, ethkey.EIP55Address("0x613a38AC1659769640aaE063C651F48E0250454C"), jb.OCROracleSpec.ContractAddress) + require.Equal(t, types.EIP55Address("0x613a38AC1659769640aaE063C651F48E0250454C"), jb.OCROracleSpec.ContractAddress) }, }, { @@ -221,13 +221,13 @@ func TestJobController_Create_HappyPath(t *testing.T) { require.NoError(t, err) require.NotNil(t, jb.KeeperSpec) - require.Equal(t, ethkey.EIP55Address("0x9E40733cC9df84636505f4e6Db28DCa0dC5D1bba"), jb.KeeperSpec.ContractAddress) - require.Equal(t, ethkey.EIP55Address("0xa8037A20989AFcBC51798de9762b351D63ff462e"), jb.KeeperSpec.FromAddress) + require.Equal(t, types.EIP55Address("0x9E40733cC9df84636505f4e6Db28DCa0dC5D1bba"), jb.KeeperSpec.ContractAddress) + require.Equal(t, types.EIP55Address("0xa8037A20989AFcBC51798de9762b351D63ff462e"), jb.KeeperSpec.FromAddress) assert.Equal(t, nameAndExternalJobID, jb.Name.ValueOrZero()) // Sanity check to make sure it inserted correctly - require.Equal(t, ethkey.EIP55Address("0x9E40733cC9df84636505f4e6Db28DCa0dC5D1bba"), jb.KeeperSpec.ContractAddress) - require.Equal(t, ethkey.EIP55Address("0xa8037A20989AFcBC51798de9762b351D63ff462e"), jb.KeeperSpec.FromAddress) + require.Equal(t, types.EIP55Address("0x9E40733cC9df84636505f4e6Db28DCa0dC5D1bba"), jb.KeeperSpec.ContractAddress) + require.Equal(t, types.EIP55Address("0xa8037A20989AFcBC51798de9762b351D63ff462e"), jb.KeeperSpec.FromAddress) }, }, { @@ -286,7 +286,7 @@ func TestJobController_Create_HappyPath(t *testing.T) { assert.Equal(t, nameAndExternalJobID, jb.Name.ValueOrZero()) assert.NotNil(t, resource.PipelineSpec.DotDAGSource) // Sanity check to make sure it inserted correctly - require.Equal(t, ethkey.EIP55Address("0x613a38AC1659769640aaE063C651F48E0250454C"), jb.DirectRequestSpec.ContractAddress) + require.Equal(t, types.EIP55Address("0x613a38AC1659769640aaE063C651F48E0250454C"), jb.DirectRequestSpec.ContractAddress) require.Equal(t, jb.ExternalJobID.String(), nameAndExternalJobID) }, }, @@ -336,7 +336,7 @@ func TestJobController_Create_HappyPath(t *testing.T) { assert.Equal(t, nameAndExternalJobID, jb.Name.ValueOrZero()) assert.NotNil(t, jb.PipelineSpec.DotDagSource) - assert.Equal(t, ethkey.EIP55Address("0x3cCad4715152693fE3BC4460591e3D3Fbd071b42"), jb.FluxMonitorSpec.ContractAddress) + assert.Equal(t, types.EIP55Address("0x3cCad4715152693fE3BC4460591e3D3Fbd071b42"), jb.FluxMonitorSpec.ContractAddress) assert.Equal(t, time.Second, jb.FluxMonitorSpec.IdleTimerPeriod) assert.Equal(t, false, jb.FluxMonitorSpec.IdleTimerDisabled) assert.Equal(t, tomlutils.Float32(0.5), jb.FluxMonitorSpec.Threshold) diff --git a/core/web/loader/eth_transaction_attempt.go b/core/web/loader/eth_transaction_attempt.go index c215574f490..8bc0af771c3 100644 --- a/core/web/loader/eth_transaction_attempt.go +++ b/core/web/loader/eth_transaction_attempt.go @@ -28,7 +28,7 @@ func (b *ethTransactionAttemptBatcher) loadByEthTransactionIDs(ctx context.Conte keyOrder[key.String()] = ix } - attempts, err := b.app.TxmStorageService().FindTxAttemptConfirmedByTxIDs(ethTxsIDs) + attempts, err := b.app.TxmStorageService().FindTxAttemptConfirmedByTxIDs(ctx, ethTxsIDs) if err != nil { return []*dataloader.Result{{Data: nil, Error: err}} } diff --git a/core/web/loader/loader_test.go b/core/web/loader/loader_test.go index b17c96ee206..d12a10a9e52 100644 --- a/core/web/loader/loader_test.go +++ b/core/web/loader/loader_test.go @@ -305,7 +305,7 @@ func TestLoader_EthTransactionsAttempts(t *testing.T) { TxID: ethTxIDs[1], } - txStore.On("FindTxAttemptConfirmedByTxIDs", []int64{ethTxIDs[2], ethTxIDs[1], ethTxIDs[0]}).Return([]txmgr.TxAttempt{ + txStore.On("FindTxAttemptConfirmedByTxIDs", ctx, []int64{ethTxIDs[2], ethTxIDs[1], ethTxIDs[0]}).Return([]txmgr.TxAttempt{ attempt1, attempt2, }, nil) app.On("TxmStorageService").Return(txStore) @@ -394,7 +394,7 @@ func TestLoader_loadByEthTransactionID(t *testing.T) { Receipts: []txmgr.ChainReceipt{txmgr.DbReceiptToEvmReceipt(&receipt)}, } - txStore.On("FindTxAttemptConfirmedByTxIDs", []int64{ethTxID}).Return([]txmgr.TxAttempt{ + txStore.On("FindTxAttemptConfirmedByTxIDs", ctx, []int64{ethTxID}).Return([]txmgr.TxAttempt{ attempt1, }, nil) diff --git a/core/web/pipeline_runs_controller.go b/core/web/pipeline_runs_controller.go index 3892da749ea..2c6caa648fc 100644 --- a/core/web/pipeline_runs_controller.go +++ b/core/web/pipeline_runs_controller.go @@ -10,6 +10,7 @@ import ( "github.com/google/uuid" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -116,7 +117,7 @@ func (prc *PipelineRunsController) Create(c *gin.Context) { return } if canRun { - jobRunID, err3 := prc.App.RunWebhookJobV2(c.Request.Context(), jobUUID, string(bodyBytes), pipeline.JSONSerializable{}) + jobRunID, err3 := prc.App.RunWebhookJobV2(c.Request.Context(), jobUUID, string(bodyBytes), jsonserializable.JSONSerializable{}) if errors.Is(err3, webhook.ErrJobNotExists) { jsonAPIError(c, http.StatusNotFound, err3) return diff --git a/core/web/presenters/eth_key_test.go b/core/web/presenters/eth_key_test.go index 46402141a4c..9ba7c432e6a 100644 --- a/core/web/presenters/eth_key_test.go +++ b/core/web/presenters/eth_key_test.go @@ -7,6 +7,7 @@ import ( commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" @@ -22,7 +23,7 @@ func TestETHKeyResource(t *testing.T) { addressStr = "0x2aCFF2ec69aa9945Ed84f4F281eCCF6911A3B0eD" address = common.HexToAddress(addressStr) ) - eip55address, err := ethkey.NewEIP55Address(addressStr) + eip55address, err := types.NewEIP55Address(addressStr) require.NoError(t, err) key := ethkey.KeyV2{ Address: address, diff --git a/core/web/presenters/job.go b/core/web/presenters/job.go index 7c8643015dd..3e3d0335afb 100644 --- a/core/web/presenters/job.go +++ b/core/web/presenters/job.go @@ -10,17 +10,17 @@ import ( commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) -// JobSpecType defines the the the spec type of the job +// JobSpecType defines the spec type of the job type JobSpecType string func (t JobSpecType) String() string { @@ -43,7 +43,7 @@ const ( // DirectRequestSpec defines the spec details of a DirectRequest Job type DirectRequestSpec struct { - ContractAddress ethkey.EIP55Address `json:"contractAddress"` + ContractAddress types.EIP55Address `json:"contractAddress"` MinIncomingConfirmations clnull.Uint32 `json:"minIncomingConfirmations"` MinContractPayment *commonassets.Link `json:"minContractPaymentLinkJuels"` Requesters models.AddressCollection `json:"requesters"` @@ -72,20 +72,20 @@ func NewDirectRequestSpec(spec *job.DirectRequestSpec) *DirectRequestSpec { // FluxMonitorSpec defines the spec details of a FluxMonitor Job type FluxMonitorSpec struct { - ContractAddress ethkey.EIP55Address `json:"contractAddress"` - Threshold float32 `json:"threshold"` - AbsoluteThreshold float32 `json:"absoluteThreshold"` - PollTimerPeriod string `json:"pollTimerPeriod"` - PollTimerDisabled bool `json:"pollTimerDisabled"` - IdleTimerPeriod string `json:"idleTimerPeriod"` - IdleTimerDisabled bool `json:"idleTimerDisabled"` - DrumbeatEnabled bool `json:"drumbeatEnabled"` - DrumbeatSchedule *string `json:"drumbeatSchedule"` - DrumbeatRandomDelay *string `json:"drumbeatRandomDelay"` - MinPayment *commonassets.Link `json:"minPayment"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - EVMChainID *big.Big `json:"evmChainID"` + ContractAddress types.EIP55Address `json:"contractAddress"` + Threshold float32 `json:"threshold"` + AbsoluteThreshold float32 `json:"absoluteThreshold"` + PollTimerPeriod string `json:"pollTimerPeriod"` + PollTimerDisabled bool `json:"pollTimerDisabled"` + IdleTimerPeriod string `json:"idleTimerPeriod"` + IdleTimerDisabled bool `json:"idleTimerDisabled"` + DrumbeatEnabled bool `json:"drumbeatEnabled"` + DrumbeatSchedule *string `json:"drumbeatSchedule"` + DrumbeatRandomDelay *string `json:"drumbeatRandomDelay"` + MinPayment *commonassets.Link `json:"minPayment"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + EVMChainID *big.Big `json:"evmChainID"` } // NewFluxMonitorSpec initializes a new DirectFluxMonitorSpec from a @@ -120,23 +120,23 @@ func NewFluxMonitorSpec(spec *job.FluxMonitorSpec) *FluxMonitorSpec { // OffChainReportingSpec defines the spec details of a OffChainReporting Job type OffChainReportingSpec struct { - ContractAddress ethkey.EIP55Address `json:"contractAddress"` - P2PV2Bootstrappers pq.StringArray `json:"p2pv2Bootstrappers"` - IsBootstrapPeer bool `json:"isBootstrapPeer"` - EncryptedOCRKeyBundleID *models.Sha256Hash `json:"keyBundleID"` - TransmitterAddress *ethkey.EIP55Address `json:"transmitterAddress"` - ObservationTimeout models.Interval `json:"observationTimeout"` - BlockchainTimeout models.Interval `json:"blockchainTimeout"` - ContractConfigTrackerSubscribeInterval models.Interval `json:"contractConfigTrackerSubscribeInterval"` - ContractConfigTrackerPollInterval models.Interval `json:"contractConfigTrackerPollInterval"` - ContractConfigConfirmations uint16 `json:"contractConfigConfirmations"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - EVMChainID *big.Big `json:"evmChainID"` - DatabaseTimeout *models.Interval `json:"databaseTimeout"` - ObservationGracePeriod *models.Interval `json:"observationGracePeriod"` - ContractTransmitterTransmitTimeout *models.Interval `json:"contractTransmitterTransmitTimeout"` - CollectTelemetry bool `json:"collectTelemetry,omitempty"` + ContractAddress types.EIP55Address `json:"contractAddress"` + P2PV2Bootstrappers pq.StringArray `json:"p2pv2Bootstrappers"` + IsBootstrapPeer bool `json:"isBootstrapPeer"` + EncryptedOCRKeyBundleID *models.Sha256Hash `json:"keyBundleID"` + TransmitterAddress *types.EIP55Address `json:"transmitterAddress"` + ObservationTimeout models.Interval `json:"observationTimeout"` + BlockchainTimeout models.Interval `json:"blockchainTimeout"` + ContractConfigTrackerSubscribeInterval models.Interval `json:"contractConfigTrackerSubscribeInterval"` + ContractConfigTrackerPollInterval models.Interval `json:"contractConfigTrackerPollInterval"` + ContractConfigConfirmations uint16 `json:"contractConfigConfirmations"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + EVMChainID *big.Big `json:"evmChainID"` + DatabaseTimeout *models.Interval `json:"databaseTimeout"` + ObservationGracePeriod *models.Interval `json:"observationGracePeriod"` + ContractTransmitterTransmitTimeout *models.Interval `json:"contractTransmitterTransmitTimeout"` + CollectTelemetry bool `json:"collectTelemetry,omitempty"` } // NewOffChainReportingSpec initializes a new OffChainReportingSpec from a @@ -217,11 +217,11 @@ func NewPipelineSpec(spec *pipeline.Spec) PipelineSpec { // KeeperSpec defines the spec details of a Keeper Job type KeeperSpec struct { - ContractAddress ethkey.EIP55Address `json:"contractAddress"` - FromAddress ethkey.EIP55Address `json:"fromAddress"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - EVMChainID *big.Big `json:"evmChainID"` + ContractAddress types.EIP55Address `json:"contractAddress"` + FromAddress types.EIP55Address `json:"fromAddress"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + EVMChainID *big.Big `json:"evmChainID"` } // NewKeeperSpec generates a new KeeperSpec from a job.KeeperSpec @@ -266,13 +266,13 @@ func NewCronSpec(spec *job.CronSpec) *CronSpec { } type VRFSpec struct { - BatchCoordinatorAddress *ethkey.EIP55Address `json:"batchCoordinatorAddress"` + BatchCoordinatorAddress *types.EIP55Address `json:"batchCoordinatorAddress"` BatchFulfillmentEnabled bool `json:"batchFulfillmentEnabled"` CustomRevertsPipelineEnabled *bool `json:"customRevertsPipelineEnabled,omitempty"` BatchFulfillmentGasMultiplier float64 `json:"batchFulfillmentGasMultiplier"` - CoordinatorAddress ethkey.EIP55Address `json:"coordinatorAddress"` + CoordinatorAddress types.EIP55Address `json:"coordinatorAddress"` PublicKey secp256k1.PublicKey `json:"publicKey"` - FromAddresses []ethkey.EIP55Address `json:"fromAddresses"` + FromAddresses []types.EIP55Address `json:"fromAddresses"` PollPeriod commonconfig.Duration `json:"pollPeriod"` MinIncomingConfirmations uint32 `json:"confirmations"` CreatedAt time.Time `json:"createdAt"` @@ -284,7 +284,7 @@ type VRFSpec struct { BackoffMaxDelay commonconfig.Duration `json:"backoffMaxDelay"` GasLanePrice *assets.Wei `json:"gasLanePrice"` RequestedConfsDelay int64 `json:"requestedConfsDelay"` - VRFOwnerAddress *ethkey.EIP55Address `json:"vrfOwnerAddress,omitempty"` + VRFOwnerAddress *types.EIP55Address `json:"vrfOwnerAddress,omitempty"` } func NewVRFSpec(spec *job.VRFSpec) *VRFSpec { @@ -313,21 +313,21 @@ func NewVRFSpec(spec *job.VRFSpec) *VRFSpec { // BlockhashStoreSpec defines the job parameters for a blockhash store feeder job. type BlockhashStoreSpec struct { - CoordinatorV1Address *ethkey.EIP55Address `json:"coordinatorV1Address"` - CoordinatorV2Address *ethkey.EIP55Address `json:"coordinatorV2Address"` - CoordinatorV2PlusAddress *ethkey.EIP55Address `json:"coordinatorV2PlusAddress"` - WaitBlocks int32 `json:"waitBlocks"` - LookbackBlocks int32 `json:"lookbackBlocks"` - HeartbeatPeriod time.Duration `json:"heartbeatPeriod"` - BlockhashStoreAddress ethkey.EIP55Address `json:"blockhashStoreAddress"` - TrustedBlockhashStoreAddress *ethkey.EIP55Address `json:"trustedBlockhashStoreAddress"` - TrustedBlockhashStoreBatchSize int32 `json:"trustedBlockhashStoreBatchSize"` - PollPeriod time.Duration `json:"pollPeriod"` - RunTimeout time.Duration `json:"runTimeout"` - EVMChainID *big.Big `json:"evmChainID"` - FromAddresses []ethkey.EIP55Address `json:"fromAddresses"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` + CoordinatorV1Address *types.EIP55Address `json:"coordinatorV1Address"` + CoordinatorV2Address *types.EIP55Address `json:"coordinatorV2Address"` + CoordinatorV2PlusAddress *types.EIP55Address `json:"coordinatorV2PlusAddress"` + WaitBlocks int32 `json:"waitBlocks"` + LookbackBlocks int32 `json:"lookbackBlocks"` + HeartbeatPeriod time.Duration `json:"heartbeatPeriod"` + BlockhashStoreAddress types.EIP55Address `json:"blockhashStoreAddress"` + TrustedBlockhashStoreAddress *types.EIP55Address `json:"trustedBlockhashStoreAddress"` + TrustedBlockhashStoreBatchSize int32 `json:"trustedBlockhashStoreBatchSize"` + PollPeriod time.Duration `json:"pollPeriod"` + RunTimeout time.Duration `json:"runTimeout"` + EVMChainID *big.Big `json:"evmChainID"` + FromAddresses []types.EIP55Address `json:"fromAddresses"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` } // NewBlockhashStoreSpec creates a new BlockhashStoreSpec for the given parameters. @@ -351,19 +351,19 @@ func NewBlockhashStoreSpec(spec *job.BlockhashStoreSpec) *BlockhashStoreSpec { // BlockHeaderFeederSpec defines the job parameters for a blcok header feeder job. type BlockHeaderFeederSpec struct { - CoordinatorV1Address *ethkey.EIP55Address `json:"coordinatorV1Address"` - CoordinatorV2Address *ethkey.EIP55Address `json:"coordinatorV2Address"` - CoordinatorV2PlusAddress *ethkey.EIP55Address `json:"coordinatorV2PlusAddress"` - WaitBlocks int32 `json:"waitBlocks"` - LookbackBlocks int32 `json:"lookbackBlocks"` - BlockhashStoreAddress ethkey.EIP55Address `json:"blockhashStoreAddress"` - BatchBlockhashStoreAddress ethkey.EIP55Address `json:"batchBlockhashStoreAddress"` - PollPeriod time.Duration `json:"pollPeriod"` - RunTimeout time.Duration `json:"runTimeout"` - EVMChainID *big.Big `json:"evmChainID"` - FromAddresses []ethkey.EIP55Address `json:"fromAddresses"` - GetBlockhashesBatchSize uint16 `json:"getBlockhashesBatchSize"` - StoreBlockhashesBatchSize uint16 `json:"storeBlockhashesBatchSize"` + CoordinatorV1Address *types.EIP55Address `json:"coordinatorV1Address"` + CoordinatorV2Address *types.EIP55Address `json:"coordinatorV2Address"` + CoordinatorV2PlusAddress *types.EIP55Address `json:"coordinatorV2PlusAddress"` + WaitBlocks int32 `json:"waitBlocks"` + LookbackBlocks int32 `json:"lookbackBlocks"` + BlockhashStoreAddress types.EIP55Address `json:"blockhashStoreAddress"` + BatchBlockhashStoreAddress types.EIP55Address `json:"batchBlockhashStoreAddress"` + PollPeriod time.Duration `json:"pollPeriod"` + RunTimeout time.Duration `json:"runTimeout"` + EVMChainID *big.Big `json:"evmChainID"` + FromAddresses []types.EIP55Address `json:"fromAddresses"` + GetBlockhashesBatchSize uint16 `json:"getBlockhashesBatchSize"` + StoreBlockhashesBatchSize uint16 `json:"storeBlockhashesBatchSize"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` diff --git a/core/web/presenters/job_test.go b/core/web/presenters/job_test.go index b782452948b..963e5790110 100644 --- a/core/web/presenters/job_test.go +++ b/core/web/presenters/job_test.go @@ -15,10 +15,10 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/assets" evmassets "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" "github.com/smartcontractkit/chainlink/v2/core/store/models" @@ -28,34 +28,34 @@ import ( func TestJob(t *testing.T) { // Used in multiple tests timestamp := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC) - contractAddress, err := ethkey.NewEIP55Address("0x9E40733cC9df84636505f4e6Db28DCa0dC5D1bba") + contractAddress, err := types.NewEIP55Address("0x9E40733cC9df84636505f4e6Db28DCa0dC5D1bba") require.NoError(t, err) cronSchedule := "0 0 0 1 1 *" evmChainID := big.NewI(42) - fromAddress, err := ethkey.NewEIP55Address("0xa8037A20989AFcBC51798de9762b351D63ff462e") + fromAddress, err := types.NewEIP55Address("0xa8037A20989AFcBC51798de9762b351D63ff462e") require.NoError(t, err) // Used in OCR tests var ocrKeyBundleID = "f5bf259689b26f1374efb3c9a9868796953a0f814bb2d39b968d0e61b58620a5" ocrKeyID := models.MustSha256HashFromHex(ocrKeyBundleID) - transmitterAddress, err := ethkey.NewEIP55Address("0x27548a32b9aD5D64c5945EaE9Da5337bc3169D15") + transmitterAddress, err := types.NewEIP55Address("0x27548a32b9aD5D64c5945EaE9Da5337bc3169D15") require.NoError(t, err) // Used in blockhashstore test - v1CoordAddress, err := ethkey.NewEIP55Address("0x16988483b46e695f6c8D58e6e1461DC703e008e1") + v1CoordAddress, err := types.NewEIP55Address("0x16988483b46e695f6c8D58e6e1461DC703e008e1") require.NoError(t, err) - v2CoordAddress, err := ethkey.NewEIP55Address("0x2C409DD6D4eBDdA190B5174Cc19616DD13884262") + v2CoordAddress, err := types.NewEIP55Address("0x2C409DD6D4eBDdA190B5174Cc19616DD13884262") require.NoError(t, err) - v2PlusCoordAddress, err := ethkey.NewEIP55Address("0x92B5e28Ac583812874e4271380c7d070C5FB6E6b") + v2PlusCoordAddress, err := types.NewEIP55Address("0x92B5e28Ac583812874e4271380c7d070C5FB6E6b") require.NoError(t, err) // Used in blockheaderfeeder test - batchBHSAddress, err := ethkey.NewEIP55Address("0xF6bB415b033D19EFf24A872a4785c6e1C4426103") + batchBHSAddress, err := types.NewEIP55Address("0xF6bB415b033D19EFf24A872a4785c6e1C4426103") require.NoError(t, err) - trustedBlockhashStoreAddress, err := ethkey.NewEIP55Address("0x0ad9FE7a58216242a8475ca92F222b0640E26B63") + trustedBlockhashStoreAddress, err := types.NewEIP55Address("0x0ad9FE7a58216242a8475ca92F222b0640E26B63") require.NoError(t, err) trustedBlockhashStoreBatchSize := int32(20) @@ -489,7 +489,7 @@ func TestJob(t *testing.T) { CreatedAt: timestamp, UpdatedAt: timestamp, EVMChainID: evmChainID, - FromAddresses: []ethkey.EIP55Address{fromAddress}, + FromAddresses: []types.EIP55Address{fromAddress}, PublicKey: vrfPubKey, RequestedConfsDelay: 10, ChunkSize: 25, @@ -572,7 +572,7 @@ func TestJob(t *testing.T) { PollPeriod: 25 * time.Second, RunTimeout: 10 * time.Second, EVMChainID: big.NewI(4), - FromAddresses: []ethkey.EIP55Address{fromAddress}, + FromAddresses: []types.EIP55Address{fromAddress}, TrustedBlockhashStoreAddress: &trustedBlockhashStoreAddress, TrustedBlockhashStoreBatchSize: trustedBlockhashStoreBatchSize, }, @@ -652,7 +652,7 @@ func TestJob(t *testing.T) { PollPeriod: 25 * time.Second, RunTimeout: 10 * time.Second, EVMChainID: big.NewI(4), - FromAddresses: []ethkey.EIP55Address{fromAddress}, + FromAddresses: []types.EIP55Address{fromAddress}, GetBlockhashesBatchSize: 5, StoreBlockhashesBatchSize: 10, }, diff --git a/core/web/presenters/pipeline_run.go b/core/web/presenters/pipeline_run.go index 2fded460c2b..f4401b1bd5a 100644 --- a/core/web/presenters/pipeline_run.go +++ b/core/web/presenters/pipeline_run.go @@ -5,6 +5,7 @@ import ( "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" ) @@ -15,14 +16,14 @@ type PipelineRunResource struct { Outputs []*string `json:"outputs"` // XXX: Here for backwards compatibility, can be removed later // Deprecated: Errors - Errors []*string `json:"errors"` - AllErrors []*string `json:"allErrors"` - FatalErrors []*string `json:"fatalErrors"` - Inputs pipeline.JSONSerializable `json:"inputs"` - TaskRuns []PipelineTaskRunResource `json:"taskRuns"` - CreatedAt time.Time `json:"createdAt"` - FinishedAt null.Time `json:"finishedAt"` - PipelineSpec PipelineSpec `json:"pipelineSpec"` + Errors []*string `json:"errors"` + AllErrors []*string `json:"allErrors"` + FatalErrors []*string `json:"fatalErrors"` + Inputs jsonserializable.JSONSerializable `json:"inputs"` + TaskRuns []PipelineTaskRunResource `json:"taskRuns"` + CreatedAt time.Time `json:"createdAt"` + FinishedAt null.Time `json:"finishedAt"` + PipelineSpec PipelineSpec `json:"pipelineSpec"` } // GetName implements the api2go EntityNamer interface diff --git a/core/web/resolver/eth_key.go b/core/web/resolver/eth_key.go index a9c060ef0c1..d986374ec21 100644 --- a/core/web/resolver/eth_key.go +++ b/core/web/resolver/eth_key.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/graph-gophers/graphql-go" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/web/loader" @@ -13,7 +14,7 @@ import ( type ETHKey struct { state ethkey.State - addr ethkey.EIP55Address + addr types.EIP55Address chain legacyevm.Chain } diff --git a/core/web/resolver/eth_key_test.go b/core/web/resolver/eth_key_test.go index 7d1e3ff5025..40a60263f06 100644 --- a/core/web/resolver/eth_key_test.go +++ b/core/web/resolver/eth_key_test.go @@ -16,6 +16,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" mocks2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -60,11 +61,11 @@ func TestResolver_ETHKeys(t *testing.T) { keys := []ethkey.KeyV2{ { Address: address, - EIP55Address: ethkey.EIP55AddressFromAddress(address), + EIP55Address: evmtypes.EIP55AddressFromAddress(address), }, { Address: secondAddress, - EIP55Address: ethkey.EIP55AddressFromAddress(secondAddress), + EIP55Address: evmtypes.EIP55AddressFromAddress(secondAddress), }, } gError := errors.New("error") @@ -82,7 +83,7 @@ func TestResolver_ETHKeys(t *testing.T) { before: func(f *gqlTestFramework) { states := []ethkey.State{ { - Address: ethkey.MustEIP55Address(address.Hex()), + Address: evmtypes.MustEIP55Address(address.Hex()), EVMChainID: *big.NewI(12), Disabled: false, CreatedAt: f.Timestamp(), @@ -149,7 +150,7 @@ func TestResolver_ETHKeys(t *testing.T) { before: func(f *gqlTestFramework) { states := []ethkey.State{ { - Address: ethkey.MustEIP55Address(address.Hex()), + Address: evmtypes.MustEIP55Address(address.Hex()), EVMChainID: *big.NewI(12), Disabled: false, CreatedAt: f.Timestamp(), @@ -243,7 +244,7 @@ func TestResolver_ETHKeys(t *testing.T) { before: func(f *gqlTestFramework) { states := []ethkey.State{ { - Address: ethkey.MustEIP55Address(address.Hex()), + Address: evmtypes.MustEIP55Address(address.Hex()), EVMChainID: *big.NewI(12), Disabled: false, CreatedAt: f.Timestamp(), @@ -275,7 +276,7 @@ func TestResolver_ETHKeys(t *testing.T) { before: func(f *gqlTestFramework) { states := []ethkey.State{ { - Address: ethkey.MustEIP55Address(address.Hex()), + Address: evmtypes.MustEIP55Address(address.Hex()), EVMChainID: *big.NewI(12), Disabled: false, CreatedAt: f.Timestamp(), @@ -306,7 +307,7 @@ func TestResolver_ETHKeys(t *testing.T) { before: func(f *gqlTestFramework) { states := []ethkey.State{ { - Address: ethkey.MustEIP55Address(address.Hex()), + Address: evmtypes.MustEIP55Address(address.Hex()), EVMChainID: *big.NewI(12), Disabled: false, CreatedAt: f.Timestamp(), @@ -368,7 +369,7 @@ func TestResolver_ETHKeys(t *testing.T) { before: func(f *gqlTestFramework) { states := []ethkey.State{ { - Address: ethkey.EIP55AddressFromAddress(address), + Address: evmtypes.EIP55AddressFromAddress(address), EVMChainID: *big.NewI(12), Disabled: false, CreatedAt: f.Timestamp(), diff --git a/core/web/resolver/eth_transaction_test.go b/core/web/resolver/eth_transaction_test.go index 5c50d60539e..5568a6664cb 100644 --- a/core/web/resolver/eth_transaction_test.go +++ b/core/web/resolver/eth_transaction_test.go @@ -9,6 +9,8 @@ import ( "github.com/ethereum/go-ethereum/common" gqlerrors "github.com/graph-gophers/graphql-go/errors" + "github.com/stretchr/testify/mock" + "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/types" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" @@ -67,7 +69,7 @@ func TestResolver_EthTransaction(t *testing.T) { name: "success", authenticated: true, before: func(f *gqlTestFramework) { - f.Mocks.txmStore.On("FindTxByHash", hash).Return(&txmgr.Tx{ + f.Mocks.txmStore.On("FindTxByHash", mock.Anything, hash).Return(&txmgr.Tx{ ID: 1, ToAddress: common.HexToAddress("0x5431F5F973781809D18643b87B44921b11355d81"), FromAddress: common.HexToAddress("0x5431F5F973781809D18643b87B44921b11355d81"), @@ -78,7 +80,7 @@ func TestResolver_EthTransaction(t *testing.T) { ChainID: big.NewInt(22), Sequence: nil, }, nil) - f.Mocks.txmStore.On("FindTxAttemptConfirmedByTxIDs", []int64{1}).Return([]txmgr.TxAttempt{ + f.Mocks.txmStore.On("FindTxAttemptConfirmedByTxIDs", mock.Anything, []int64{1}).Return([]txmgr.TxAttempt{ { TxID: 1, Hash: hash, @@ -132,7 +134,7 @@ func TestResolver_EthTransaction(t *testing.T) { num := int64(2) nonce := evmtypes.Nonce(num) - f.Mocks.txmStore.On("FindTxByHash", hash).Return(&txmgr.Tx{ + f.Mocks.txmStore.On("FindTxByHash", mock.Anything, hash).Return(&txmgr.Tx{ ID: 1, ToAddress: common.HexToAddress("0x5431F5F973781809D18643b87B44921b11355d81"), FromAddress: common.HexToAddress("0x5431F5F973781809D18643b87B44921b11355d81"), @@ -143,7 +145,7 @@ func TestResolver_EthTransaction(t *testing.T) { ChainID: big.NewInt(22), Sequence: &nonce, }, nil) - f.Mocks.txmStore.On("FindTxAttemptConfirmedByTxIDs", []int64{1}).Return([]txmgr.TxAttempt{ + f.Mocks.txmStore.On("FindTxAttemptConfirmedByTxIDs", mock.Anything, []int64{1}).Return([]txmgr.TxAttempt{ { TxID: 1, Hash: hash, @@ -194,7 +196,7 @@ func TestResolver_EthTransaction(t *testing.T) { name: "not found error", authenticated: true, before: func(f *gqlTestFramework) { - f.Mocks.txmStore.On("FindTxByHash", hash).Return(nil, sql.ErrNoRows) + f.Mocks.txmStore.On("FindTxByHash", mock.Anything, hash).Return(nil, sql.ErrNoRows) f.App.On("TxmStorageService").Return(f.Mocks.txmStore) }, query: query, @@ -211,7 +213,7 @@ func TestResolver_EthTransaction(t *testing.T) { name: "generic error", authenticated: true, before: func(f *gqlTestFramework) { - f.Mocks.txmStore.On("FindTxByHash", hash).Return(nil, gError) + f.Mocks.txmStore.On("FindTxByHash", mock.Anything, hash).Return(nil, gError) f.App.On("TxmStorageService").Return(f.Mocks.txmStore) }, query: query, @@ -267,7 +269,7 @@ func TestResolver_EthTransactions(t *testing.T) { before: func(f *gqlTestFramework) { num := int64(2) - f.Mocks.txmStore.On("Transactions", PageDefaultOffset, PageDefaultLimit).Return([]txmgr.Tx{ + f.Mocks.txmStore.On("Transactions", mock.Anything, PageDefaultOffset, PageDefaultLimit).Return([]txmgr.Tx{ { ID: 1, ToAddress: common.HexToAddress("0x5431F5F973781809D18643b87B44921b11355d81"), @@ -279,7 +281,7 @@ func TestResolver_EthTransactions(t *testing.T) { ChainID: big.NewInt(22), }, }, 1, nil) - f.Mocks.txmStore.On("FindTxAttemptConfirmedByTxIDs", []int64{1}).Return([]txmgr.TxAttempt{ + f.Mocks.txmStore.On("FindTxAttemptConfirmedByTxIDs", mock.Anything, []int64{1}).Return([]txmgr.TxAttempt{ { TxID: 1, Hash: hash, @@ -318,7 +320,7 @@ func TestResolver_EthTransactions(t *testing.T) { name: "generic error", authenticated: true, before: func(f *gqlTestFramework) { - f.Mocks.txmStore.On("Transactions", PageDefaultOffset, PageDefaultLimit).Return(nil, 0, gError) + f.Mocks.txmStore.On("Transactions", mock.Anything, PageDefaultOffset, PageDefaultLimit).Return(nil, 0, gError) f.App.On("TxmStorageService").Return(f.Mocks.txmStore) }, query: query, @@ -365,7 +367,7 @@ func TestResolver_EthTransactionsAttempts(t *testing.T) { before: func(f *gqlTestFramework) { num := int64(2) - f.Mocks.txmStore.On("TxAttempts", PageDefaultOffset, PageDefaultLimit).Return([]txmgr.TxAttempt{ + f.Mocks.txmStore.On("TxAttempts", mock.Anything, PageDefaultOffset, PageDefaultLimit).Return([]txmgr.TxAttempt{ { Hash: hash, TxFee: gas.EvmFee{Legacy: assets.NewWeiI(12)}, @@ -396,7 +398,7 @@ func TestResolver_EthTransactionsAttempts(t *testing.T) { name: "success with nil values", authenticated: true, before: func(f *gqlTestFramework) { - f.Mocks.txmStore.On("TxAttempts", PageDefaultOffset, PageDefaultLimit).Return([]txmgr.TxAttempt{ + f.Mocks.txmStore.On("TxAttempts", mock.Anything, PageDefaultOffset, PageDefaultLimit).Return([]txmgr.TxAttempt{ { Hash: hash, TxFee: gas.EvmFee{Legacy: assets.NewWeiI(12)}, @@ -426,7 +428,7 @@ func TestResolver_EthTransactionsAttempts(t *testing.T) { name: "generic error", authenticated: true, before: func(f *gqlTestFramework) { - f.Mocks.txmStore.On("TxAttempts", PageDefaultOffset, PageDefaultLimit).Return(nil, 0, gError) + f.Mocks.txmStore.On("TxAttempts", mock.Anything, PageDefaultOffset, PageDefaultLimit).Return(nil, 0, gError) f.App.On("TxmStorageService").Return(f.Mocks.txmStore) }, query: query, diff --git a/core/web/resolver/job_proposal_spec.go b/core/web/resolver/job_proposal_spec.go index 878b592e6e2..1bbef514936 100644 --- a/core/web/resolver/job_proposal_spec.go +++ b/core/web/resolver/job_proposal_spec.go @@ -80,7 +80,7 @@ func (r *JobProposalSpecResolver) Status() SpecStatus { return ToSpecStatus(r.spec.Status) } -// StatusUpdatedAt resolves to the the last timestamp that the spec status was +// StatusUpdatedAt resolves to the last timestamp that the spec status was // updated. func (r *JobProposalSpecResolver) StatusUpdatedAt() graphql.Time { return graphql.Time{Time: r.spec.StatusUpdatedAt} diff --git a/core/web/resolver/job_run_test.go b/core/web/resolver/job_run_test.go index fd44f403484..18036311155 100644 --- a/core/web/resolver/job_run_test.go +++ b/core/web/resolver/job_run_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" @@ -116,11 +117,11 @@ func TestResolver_JobRun(t *testing.T) { gError := errors.New("error") _, idError := stringutils.ToInt64("asdasads") - inputs := pipeline.JSONSerializable{} + inputs := jsonserializable.JSONSerializable{} err := inputs.UnmarshalJSON([]byte(`{"foo": "bar"}`)) require.NoError(t, err) - outputs := pipeline.JSONSerializable{} + outputs := jsonserializable.JSONSerializable{} err = outputs.UnmarshalJSON([]byte(`[{"baz": "bar"}]`)) require.NoError(t, err) @@ -267,11 +268,11 @@ func TestResolver_RunJob(t *testing.T) { "id": idStr, } - inputs := pipeline.JSONSerializable{} + inputs := jsonserializable.JSONSerializable{} err := inputs.UnmarshalJSON([]byte(`{"foo": "bar"}`)) require.NoError(t, err) - outputs := pipeline.JSONSerializable{} + outputs := jsonserializable.JSONSerializable{} err = outputs.UnmarshalJSON([]byte(`[{"baz": "bar"}]`)) require.NoError(t, err) diff --git a/core/web/resolver/mutation.go b/core/web/resolver/mutation.go index 685fbe61ccb..7ab5b7a08e8 100644 --- a/core/web/resolver/mutation.go +++ b/core/web/resolver/mutation.go @@ -1024,7 +1024,7 @@ func (r *Resolver) CreateJob(ctx context.Context, args struct { return nil, errors.New("The Offchain Reporting feature is disabled by configuration") } case job.OffchainReporting2: - jb, err = validate.ValidatedOracleSpecToml(r.App.GetConfig().OCR2(), r.App.GetConfig().Insecure(), args.Input.TOML) + jb, err = validate.ValidatedOracleSpecToml(ctx, r.App.GetConfig().OCR2(), r.App.GetConfig().Insecure(), args.Input.TOML, r.App.GetLoopRegistrarConfig()) if !config.OCR2().Enabled() { return nil, errors.New("The Offchain Reporting 2 feature is disabled by configuration") } diff --git a/core/web/resolver/plugins.go b/core/web/resolver/plugins.go index f6fda3cf72d..187bd7977b7 100644 --- a/core/web/resolver/plugins.go +++ b/core/web/resolver/plugins.go @@ -8,22 +8,22 @@ type PluginsResolver struct { plugins feeds.Plugins } -// Commit returns the the status of the commit plugin. +// Commit returns the status of the commit plugin. func (r PluginsResolver) Commit() bool { return r.plugins.Commit } -// Execute returns the the status of the execute plugin. +// Execute returns the status of the execute plugin. func (r PluginsResolver) Execute() bool { return r.plugins.Execute } -// Median returns the the status of the median plugin. +// Median returns the status of the median plugin. func (r PluginsResolver) Median() bool { return r.plugins.Median } -// Mercury returns the the status of the mercury plugin. +// Mercury returns the status of the mercury plugin. func (r PluginsResolver) Mercury() bool { return r.plugins.Mercury } diff --git a/core/web/resolver/query.go b/core/web/resolver/query.go index f9039fd17fc..da68accb367 100644 --- a/core/web/resolver/query.go +++ b/core/web/resolver/query.go @@ -480,7 +480,7 @@ func (r *Resolver) EthTransaction(ctx context.Context, args struct { } hash := common.HexToHash(string(args.Hash)) - etx, err := r.App.TxmStorageService().FindTxByHash(hash) + etx, err := r.App.TxmStorageService().FindTxByHash(ctx, hash) if err != nil { if errors.Is(err, sql.ErrNoRows) { return NewEthTransactionPayload(nil, err), nil @@ -503,7 +503,7 @@ func (r *Resolver) EthTransactions(ctx context.Context, args struct { offset := pageOffset(args.Offset) limit := pageLimit(args.Limit) - txs, count, err := r.App.TxmStorageService().Transactions(offset, limit) + txs, count, err := r.App.TxmStorageService().Transactions(ctx, offset, limit) if err != nil { return nil, err } @@ -522,7 +522,7 @@ func (r *Resolver) EthTransactionsAttempts(ctx context.Context, args struct { offset := pageOffset(args.Offset) limit := pageLimit(args.Limit) - attempts, count, err := r.App.TxmStorageService().TxAttempts(offset, limit) + attempts, count, err := r.App.TxmStorageService().TxAttempts(ctx, offset, limit) if err != nil { return nil, err } diff --git a/core/web/resolver/spec_test.go b/core/web/resolver/spec_test.go index 828e8538071..2fa8281e3c7 100644 --- a/core/web/resolver/spec_test.go +++ b/core/web/resolver/spec_test.go @@ -13,10 +13,10 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" "github.com/smartcontractkit/chainlink/v2/core/store/models" @@ -81,7 +81,7 @@ func TestResolver_DirectRequestSpec(t *testing.T) { id = int32(1) requesterAddress = common.HexToAddress("0x3cCad4715152693fE3BC4460591e3D3Fbd071b42") ) - contractAddress, err := ethkey.NewEIP55Address("0x613a38AC1659769640aaE063C651F48E0250454C") + contractAddress, err := evmtypes.NewEIP55Address("0x613a38AC1659769640aaE063C651F48E0250454C") require.NoError(t, err) testCases := []GQLTestCase{ @@ -146,7 +146,7 @@ func TestResolver_FluxMonitorSpec(t *testing.T) { var ( id = int32(1) ) - contractAddress, err := ethkey.NewEIP55Address("0x613a38AC1659769640aaE063C651F48E0250454C") + contractAddress, err := evmtypes.NewEIP55Address("0x613a38AC1659769640aaE063C651F48E0250454C") require.NoError(t, err) testCases := []GQLTestCase{ @@ -296,7 +296,7 @@ func TestResolver_KeeperSpec(t *testing.T) { id = int32(1) fromAddress = common.HexToAddress("0x3cCad4715152693fE3BC4460591e3D3Fbd071b42") ) - contractAddress, err := ethkey.NewEIP55Address("0x613a38AC1659769640aaE063C651F48E0250454C") + contractAddress, err := evmtypes.NewEIP55Address("0x613a38AC1659769640aaE063C651F48E0250454C") require.NoError(t, err) testCases := []GQLTestCase{ @@ -311,7 +311,7 @@ func TestResolver_KeeperSpec(t *testing.T) { ContractAddress: contractAddress, CreatedAt: f.Timestamp(), EVMChainID: ubig.NewI(42), - FromAddress: ethkey.EIP55AddressFromAddress(fromAddress), + FromAddress: evmtypes.EIP55AddressFromAddress(fromAddress), }, }, nil) }, @@ -355,10 +355,10 @@ func TestResolver_OCRSpec(t *testing.T) { var ( id = int32(1) ) - contractAddress, err := ethkey.NewEIP55Address("0x613a38AC1659769640aaE063C651F48E0250454C") + contractAddress, err := evmtypes.NewEIP55Address("0x613a38AC1659769640aaE063C651F48E0250454C") require.NoError(t, err) - transmitterAddress, err := ethkey.NewEIP55Address("0x3cCad4715152693fE3BC4460591e3D3Fbd071b42") + transmitterAddress, err := evmtypes.NewEIP55Address("0x3cCad4715152693fE3BC4460591e3D3Fbd071b42") require.NoError(t, err) keyBundleID := models.MustSha256HashFromHex("f5bf259689b26f1374efb3c9a9868796953a0f814bb2d39b968d0e61b58620a5") @@ -452,10 +452,10 @@ func TestResolver_OCR2Spec(t *testing.T) { var ( id = int32(1) ) - contractAddress, err := ethkey.NewEIP55Address("0x613a38AC1659769640aaE063C651F48E0250454C") + contractAddress, err := evmtypes.NewEIP55Address("0x613a38AC1659769640aaE063C651F48E0250454C") require.NoError(t, err) - transmitterAddress, err := ethkey.NewEIP55Address("0x3cCad4715152693fE3BC4460591e3D3Fbd071b42") + transmitterAddress, err := evmtypes.NewEIP55Address("0x3cCad4715152693fE3BC4460591e3D3Fbd071b42") require.NoError(t, err) keyBundleID := models.MustSha256HashFromHex("f5bf259689b26f1374efb3c9a9868796953a0f814bb2d39b968d0e61b58620a5") @@ -555,16 +555,16 @@ func TestResolver_VRFSpec(t *testing.T) { var ( id = int32(1) ) - coordinatorAddress, err := ethkey.NewEIP55Address("0x613a38AC1659769640aaE063C651F48E0250454C") + coordinatorAddress, err := evmtypes.NewEIP55Address("0x613a38AC1659769640aaE063C651F48E0250454C") require.NoError(t, err) - batchCoordinatorAddress, err := ethkey.NewEIP55Address("0x0ad9FE7a58216242a8475ca92F222b0640E26B63") + batchCoordinatorAddress, err := evmtypes.NewEIP55Address("0x0ad9FE7a58216242a8475ca92F222b0640E26B63") require.NoError(t, err) - fromAddress1, err := ethkey.NewEIP55Address("0x3cCad4715152693fE3BC4460591e3D3Fbd071b42") + fromAddress1, err := evmtypes.NewEIP55Address("0x3cCad4715152693fE3BC4460591e3D3Fbd071b42") require.NoError(t, err) - fromAddress2, err := ethkey.NewEIP55Address("0x2301958F1BFbC9A068C2aC9c6166Bf483b95864C") + fromAddress2, err := evmtypes.NewEIP55Address("0x2301958F1BFbC9A068C2aC9c6166Bf483b95864C") require.NoError(t, err) pubKey, err := secp256k1.NewPublicKeyFromHex("0x9dc09a0f898f3b5e8047204e7ce7e44b587920932f08431e29c9bf6923b8450a01") @@ -586,7 +586,7 @@ func TestResolver_VRFSpec(t *testing.T) { CoordinatorAddress: coordinatorAddress, CreatedAt: f.Timestamp(), EVMChainID: ubig.NewI(42), - FromAddresses: []ethkey.EIP55Address{fromAddress1, fromAddress2}, + FromAddresses: []evmtypes.EIP55Address{fromAddress1, fromAddress2}, PollPeriod: 1 * time.Minute, PublicKey: pubKey, RequestedConfsDelay: 10, @@ -713,25 +713,25 @@ func TestResolver_BlockhashStoreSpec(t *testing.T) { var ( id = int32(1) ) - coordinatorV1Address, err := ethkey.NewEIP55Address("0x613a38AC1659769640aaE063C651F48E0250454C") + coordinatorV1Address, err := evmtypes.NewEIP55Address("0x613a38AC1659769640aaE063C651F48E0250454C") require.NoError(t, err) - coordinatorV2Address, err := ethkey.NewEIP55Address("0x2fcA960AF066cAc46085588a66dA2D614c7Cd337") + coordinatorV2Address, err := evmtypes.NewEIP55Address("0x2fcA960AF066cAc46085588a66dA2D614c7Cd337") require.NoError(t, err) - coordinatorV2PlusAddress, err := ethkey.NewEIP55Address("0x92B5e28Ac583812874e4271380c7d070C5FB6E6b") + coordinatorV2PlusAddress, err := evmtypes.NewEIP55Address("0x92B5e28Ac583812874e4271380c7d070C5FB6E6b") require.NoError(t, err) - fromAddress1, err := ethkey.NewEIP55Address("0x3cCad4715152693fE3BC4460591e3D3Fbd071b42") + fromAddress1, err := evmtypes.NewEIP55Address("0x3cCad4715152693fE3BC4460591e3D3Fbd071b42") require.NoError(t, err) - fromAddress2, err := ethkey.NewEIP55Address("0xD479d7c994D298cA05bF270136ED9627b7E684D3") + fromAddress2, err := evmtypes.NewEIP55Address("0xD479d7c994D298cA05bF270136ED9627b7E684D3") require.NoError(t, err) - blockhashStoreAddress, err := ethkey.NewEIP55Address("0xb26A6829D454336818477B946f03Fb21c9706f3A") + blockhashStoreAddress, err := evmtypes.NewEIP55Address("0xb26A6829D454336818477B946f03Fb21c9706f3A") require.NoError(t, err) - trustedBlockhashStoreAddress, err := ethkey.NewEIP55Address("0x0ad9FE7a58216242a8475ca92F222b0640E26B63") + trustedBlockhashStoreAddress, err := evmtypes.NewEIP55Address("0x0ad9FE7a58216242a8475ca92F222b0640E26B63") require.NoError(t, err) trustedBlockhashStoreBatchSize := int32(20) @@ -749,7 +749,7 @@ func TestResolver_BlockhashStoreSpec(t *testing.T) { CoordinatorV2PlusAddress: &coordinatorV2PlusAddress, CreatedAt: f.Timestamp(), EVMChainID: ubig.NewI(42), - FromAddresses: []ethkey.EIP55Address{fromAddress1, fromAddress2}, + FromAddresses: []evmtypes.EIP55Address{fromAddress1, fromAddress2}, PollPeriod: 1 * time.Minute, RunTimeout: 37 * time.Second, WaitBlocks: 100, @@ -821,22 +821,22 @@ func TestResolver_BlockHeaderFeederSpec(t *testing.T) { var ( id = int32(1) ) - coordinatorV1Address, err := ethkey.NewEIP55Address("0x613a38AC1659769640aaE063C651F48E0250454C") + coordinatorV1Address, err := evmtypes.NewEIP55Address("0x613a38AC1659769640aaE063C651F48E0250454C") require.NoError(t, err) - coordinatorV2Address, err := ethkey.NewEIP55Address("0x2fcA960AF066cAc46085588a66dA2D614c7Cd337") + coordinatorV2Address, err := evmtypes.NewEIP55Address("0x2fcA960AF066cAc46085588a66dA2D614c7Cd337") require.NoError(t, err) - coordinatorV2PlusAddress, err := ethkey.NewEIP55Address("0x92B5e28Ac583812874e4271380c7d070C5FB6E6b") + coordinatorV2PlusAddress, err := evmtypes.NewEIP55Address("0x92B5e28Ac583812874e4271380c7d070C5FB6E6b") require.NoError(t, err) - fromAddress, err := ethkey.NewEIP55Address("0x3cCad4715152693fE3BC4460591e3D3Fbd071b42") + fromAddress, err := evmtypes.NewEIP55Address("0x3cCad4715152693fE3BC4460591e3D3Fbd071b42") require.NoError(t, err) - blockhashStoreAddress, err := ethkey.NewEIP55Address("0xb26A6829D454336818477B946f03Fb21c9706f3A") + blockhashStoreAddress, err := evmtypes.NewEIP55Address("0xb26A6829D454336818477B946f03Fb21c9706f3A") require.NoError(t, err) - batchBHSAddress, err := ethkey.NewEIP55Address("0xd23BAE30019853Caf1D08b4C03291b10AD7743Df") + batchBHSAddress, err := evmtypes.NewEIP55Address("0xd23BAE30019853Caf1D08b4C03291b10AD7743Df") require.NoError(t, err) testCases := []GQLTestCase{ @@ -853,7 +853,7 @@ func TestResolver_BlockHeaderFeederSpec(t *testing.T) { CoordinatorV2PlusAddress: &coordinatorV2PlusAddress, CreatedAt: f.Timestamp(), EVMChainID: ubig.NewI(42), - FromAddresses: []ethkey.EIP55Address{fromAddress}, + FromAddresses: []evmtypes.EIP55Address{fromAddress}, PollPeriod: 1 * time.Minute, RunTimeout: 37 * time.Second, WaitBlocks: 100, diff --git a/core/web/resolver/testdata/config-empty-effective.toml b/core/web/resolver/testdata/config-empty-effective.toml index 8fdb2858cdb..759a380d15c 100644 --- a/core/web/resolver/testdata/config-empty-effective.toml +++ b/core/web/resolver/testdata/config-empty-effective.toml @@ -13,7 +13,7 @@ DefaultLockTimeout = '15s' DefaultQueryTimeout = '10s' LogQueries = false MaxIdleConns = 10 -MaxOpenConns = 20 +MaxOpenConns = 100 MigrateOnStartup = true [Database.Backup] @@ -116,6 +116,7 @@ MaxSuccessfulRuns = 10000 ReaperInterval = '1h0m0s' ReaperThreshold = '24h0m0s' ResultWriteQueueDepth = 100 +VerboseLogging = true [JobPipeline.HTTPRequest] DefaultTimeout = '15s' diff --git a/core/web/resolver/testdata/config-full.toml b/core/web/resolver/testdata/config-full.toml index a497428c06a..4eb2fce6c47 100644 --- a/core/web/resolver/testdata/config-full.toml +++ b/core/web/resolver/testdata/config-full.toml @@ -122,6 +122,7 @@ MaxSuccessfulRuns = 123456 ReaperInterval = '4h0m0s' ReaperThreshold = '168h0m0s' ResultWriteQueueDepth = 10 +VerboseLogging = false [JobPipeline.HTTPRequest] DefaultTimeout = '1m0s' @@ -340,6 +341,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 13 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [EVM.OCR] ContractConfirmations = 11 @@ -428,6 +430,7 @@ URL = 'http://solana.bar' [[Starknet]] ChainID = 'foobar' +FeederURL = 'http://feeder.url' Enabled = true OCR2CachePollPeriod = '6h0m0s' OCR2CacheTTL = '3m0s' @@ -438,3 +441,4 @@ ConfirmationPoll = '42s' [[Starknet.Nodes]] Name = 'primary' URL = 'http://stark.node' +APIKey = 'key' diff --git a/core/web/resolver/testdata/config-multi-chain-effective.toml b/core/web/resolver/testdata/config-multi-chain-effective.toml index 45d52432ee5..a6cba2aaac3 100644 --- a/core/web/resolver/testdata/config-multi-chain-effective.toml +++ b/core/web/resolver/testdata/config-multi-chain-effective.toml @@ -13,7 +13,7 @@ DefaultLockTimeout = '15s' DefaultQueryTimeout = '10s' LogQueries = false MaxIdleConns = 10 -MaxOpenConns = 20 +MaxOpenConns = 100 MigrateOnStartup = true [Database.Backup] @@ -116,6 +116,7 @@ MaxSuccessfulRuns = 10000 ReaperInterval = '1h0m0s' ReaperThreshold = '24h0m0s' ResultWriteQueueDepth = 100 +VerboseLogging = true [JobPipeline.HTTPRequest] DefaultTimeout = '30s' @@ -312,6 +313,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [EVM.OCR] ContractConfirmations = 4 @@ -323,7 +325,7 @@ ObservationGracePeriod = '1s' [EVM.OCR2] [EVM.OCR2.Automation] -GasLimit = 5400000 +GasLimit = 10500000 [[EVM.Nodes]] Name = 'primary' @@ -402,6 +404,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [EVM.OCR] ContractConfirmations = 4 @@ -486,6 +489,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [EVM.OCR] ContractConfirmations = 4 @@ -585,6 +589,7 @@ URL = 'http://testnet.solana.com' [[Starknet]] ChainID = 'foobar' +FeederURL = 'http://feeder.url' OCR2CachePollPeriod = '5s' OCR2CacheTTL = '1m0s' RequestTimeout = '10s' @@ -594,3 +599,4 @@ ConfirmationPoll = '1h0m0s' [[Starknet.Nodes]] Name = 'primary' URL = 'http://stark.node' +APIKey = 'key' diff --git a/core/web/resolver/testdata/config-multi-chain.toml b/core/web/resolver/testdata/config-multi-chain.toml index 543fb3156bd..3598e92cdc2 100644 --- a/core/web/resolver/testdata/config-multi-chain.toml +++ b/core/web/resolver/testdata/config-multi-chain.toml @@ -40,6 +40,10 @@ ChainID = '1' FinalityDepth = 26 FinalityTagEnabled = false +[EVM.OCR2] +[EVM.OCR2.Automation] +GasLimit = 10500000 + [[EVM.Nodes]] Name = 'primary' WSURL = 'wss://web.socket/mainnet' @@ -107,8 +111,10 @@ URL = 'http://testnet.solana.com' [[Starknet]] ChainID = 'foobar' +FeederURL = 'http://feeder.url' ConfirmationPoll = '1h0m0s' [[Starknet.Nodes]] Name = 'primary' URL = 'http://stark.node' +APIKey = 'key' diff --git a/dashboard/README.md b/dashboard-lib/README.md similarity index 72% rename from dashboard/README.md rename to dashboard-lib/README.md index 97c25acf00f..44fd655c72a 100644 --- a/dashboard/README.md +++ b/dashboard-lib/README.md @@ -8,10 +8,8 @@ dashboard |- lib |- component_1 |- component.go - |- component.spec.ts |- component_2 |- component.go - |- component.spec.ts |- go.mod |- go.sum ``` @@ -20,9 +18,7 @@ Each component should contain rows, logic and unique variables in `component.go` Components should be imported from this module, see [example](../charts/chainlink-cluster/dashboard/cmd/deploy.go) -`component.spec.ts` is a Playwright test step that can be used when testing project [dashboards](../charts/chainlink-cluster/dashboard/tests/specs/core-don.spec.ts) - ## How to convert from JSON using Grabana codegen utility 1. Download Grabana binary [here](https://github.com/K-Phoen/grabana/releases) 2. ./bin/grabana convert-go -i dashboard.json > lib/my_new_component/rows.go -3. Create a [component](lib/k8s-pods/component.go) \ No newline at end of file +3. Create a [component](k8s-pods/component.go) \ No newline at end of file diff --git a/dashboard-lib/ccip-load-test-view/component.go b/dashboard-lib/ccip-load-test-view/component.go new file mode 100644 index 00000000000..9f58438410e --- /dev/null +++ b/dashboard-lib/ccip-load-test-view/component.go @@ -0,0 +1,497 @@ +package ccip_load_test_view + +import ( + "encoding/json" + "fmt" + "github.com/K-Phoen/grabana/dashboard" + "github.com/K-Phoen/grabana/logs" + "github.com/K-Phoen/grabana/row" + "github.com/K-Phoen/grabana/stat" + "github.com/K-Phoen/grabana/target/loki" + "github.com/K-Phoen/grabana/target/prometheus" + "github.com/K-Phoen/grabana/timeseries" + "github.com/K-Phoen/grabana/timeseries/axis" + "github.com/K-Phoen/grabana/variable/query" + cLoki "github.com/grafana/grafana-foundation-sdk/go/loki" + cXYChart "github.com/grafana/grafana-foundation-sdk/go/xychart" +) + +type Props struct { + LokiDataSource string +} + +func vars(p Props) []dashboard.Option { + return []dashboard.Option{ + dashboard.VariableAsQuery( + "Test Run Name", + query.DataSource(p.LokiDataSource), + query.Multiple(), + query.IncludeAll(), + query.Request("label_values(namespace)"), + ), + dashboard.VariableAsQuery( + "cluster", + query.DataSource(p.LokiDataSource), + query.Multiple(), + query.IncludeAll(), + query.Request("label_values(cluster)"), + ), + dashboard.VariableAsQuery( + "test_group", + query.DataSource(p.LokiDataSource), + query.Multiple(), + query.IncludeAll(), + query.Request("label_values(test_group)"), + ), + dashboard.VariableAsQuery( + "test_id", + query.DataSource(p.LokiDataSource), + query.Multiple(), + query.IncludeAll(), + query.Request("label_values(test_id)"), + ), + dashboard.VariableAsQuery( + "source_chain", + query.DataSource(p.LokiDataSource), + query.Multiple(), + query.IncludeAll(), + query.Request("label_values(source_chain)"), + ), + dashboard.VariableAsQuery( + "dest_chain", + query.DataSource(p.LokiDataSource), + query.Multiple(), + query.IncludeAll(), + query.Request("label_values(dest_chain)"), + ), + dashboard.VariableAsQuery( + "geth_node", + query.DataSource(p.LokiDataSource), + query.Multiple(), + query.IncludeAll(), + query.Request("label_values(geth_node)"), + ), + dashboard.VariableAsQuery( + "remote_runner", + query.DataSource(p.LokiDataSource), + query.Multiple(), + query.IncludeAll(), + query.Request("namespace"), + ), + } +} + +func XYChartSeqNum() map[string]interface{} { + // TODO: https://github.com/grafana/grafana-foundation-sdk/tree/v10.4.x%2Bcog-v0.0.x/go has a lot of useful components + // TODO: need to change upload API and use combined upload in lib/dashboard.go + xAxisName := "seq_num" + builder := cXYChart.NewPanelBuilder(). + Title("XYChart"). + Dims(cXYChart.XYDimensionConfig{ + X: &xAxisName, + }). + WithTarget( + cLoki.NewDataqueryBuilder(). + Expr(`{namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_Commit_ReportAccepted_duration!= "" | data_Commit_ReportAccepted_success="✅"`). + LegendFormat("Commit Report Accepted"), + ) + sampleDashboard, err := builder.Build() + if err != nil { + panic(err) + } + dashboardJson, err := json.MarshalIndent(sampleDashboard, "", " ") + if err != nil { + panic(err) + } + var data map[string]interface{} + if err := json.Unmarshal(dashboardJson, &data); err != nil { + panic(err) + } + fmt.Println(string(dashboardJson)) + return data +} + +func statsRow(p Props) []dashboard.Option { + return []dashboard.Option{ + dashboard.Row( + "CCIP Duration Stats", + row.Collapse(), + row.WithTimeSeries( + "Sequence numbers", + timeseries.Transparent(), + timeseries.Description("Sequence Numbers triggered by Test"), + timeseries.Span(6), + timeseries.Height("200px"), + timeseries.DataSource(p.LokiDataSource), + timeseries.WithLokiTarget( + `min_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", source_chain="${source_chain}", dest_chain="${dest_chain}"} | json | data_CCIPSendRequested_success="✅" | unwrap data_CCIPSendRequested_seq_num [$__range]) by (test_id)`, + loki.Legend("Starts"), + ), + timeseries.WithLokiTarget( + `max_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}", source_chain="${source_chain}", dest_chain="${dest_chain}"} | json | data_CCIPSendRequested_success="✅" | unwrap data_CCIPSendRequested_seq_num [$__range]) by (test_id)`, + loki.Legend("Ends"), + ), + ), + row.WithTimeSeries( + "Source Router Fees ( /1e18)", + timeseries.Transparent(), + timeseries.Description("Router.GetFee"), + timeseries.Span(6), + timeseries.Height("200px"), + timeseries.DataSource(p.LokiDataSource), + timeseries.WithLokiTarget( + `avg_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_CCIP_Send_Transaction_success="✅"| unwrap data_CCIP_Send_Transaction_ccip_send_data_fee [$__range]) by (test_id) /1e18`, + loki.Legend("Avg"), + ), + timeseries.WithLokiTarget( + `min_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_CCIP_Send_Transaction_success="✅"| unwrap data_CCIP_Send_Transaction_ccip_send_data_fee [$__range]) by (test_id) /1e18`, + loki.Legend("Min"), + ), + timeseries.WithLokiTarget( + `max_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_CCIP_Send_Transaction_success="✅"| unwrap data_CCIP_Send_Transaction_ccip_send_data_fee [$__range]) by (test_id) /1e18 `, + loki.Legend("Max"), + ), + ), + row.WithTimeSeries( + "Commit Duration Summary", + timeseries.Transparent(), + timeseries.Description(""), + timeseries.Span(6), + timeseries.Height("200px"), + timeseries.DataSource(p.LokiDataSource), + timeseries.Axis( + axis.Unit("seconds"), + ), + timeseries.WithLokiTarget( + `avg_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_Commit_ReportAccepted_success="✅"| unwrap data_Commit_ReportAccepted_duration [$__range]) by (data_Commit_ReportAccepted_seqNum)`, + loki.Legend("Avg"), + ), + timeseries.WithLokiTarget( + `min_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_Commit_ReportAccepted_success="✅"| unwrap data_Commit_ReportAccepted_duration [$__range]) by (data_Commit_ReportAccepted_seqNum)`, + loki.Legend("Min"), + ), + timeseries.WithLokiTarget( + `max_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_Commit_ReportAccepted_success="✅"| unwrap data_Commit_ReportAccepted_duration [$__range]) by (data_Commit_ReportAccepted_seqNum)`, + loki.Legend("Max"), + ), + ), + row.WithTimeSeries( + "Report Blessing Summary", + timeseries.Transparent(), + timeseries.Description(""), + timeseries.Span(6), + timeseries.Height("200px"), + timeseries.DataSource(p.LokiDataSource), + timeseries.Axis( + axis.Unit("seconds"), + ), + timeseries.WithLokiTarget( + `avg_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_ReportBlessedByARM_success="✅"| unwrap data_ReportBlessedByARM_duration [$__range]) by (data_ReportBlessedByARM_seqNum)`, + loki.Legend("Avg"), + ), + timeseries.WithLokiTarget( + `min_over_time({ namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_ReportBlessedByARM_success="✅"| unwrap data_ReportBlessedByARM_duration [$__range]) by (data_ReportBlessedByARM_seqNum)`, + loki.Legend("Min"), + ), + timeseries.WithLokiTarget( + `max_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_ReportBlessedByARM_success="✅"| unwrap data_ReportBlessedByARM_duration [$__range]) by (data_ReportBlessedByARM_seqNum)`, + loki.Legend("Max"), + ), + ), + row.WithTimeSeries( + "Execution Duration Summary", + timeseries.Transparent(), + timeseries.Description(""), + timeseries.Span(6), + timeseries.Height("200px"), + timeseries.DataSource(p.LokiDataSource), + timeseries.Axis( + axis.Unit("seconds"), + ), + timeseries.WithLokiTarget( + `avg_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_ExecutionStateChanged_success="✅"| unwrap data_ExecutionStateChanged_duration [$__range]) by (data_ExecutionStateChanged_seqNum)`, + loki.Legend("Avg"), + ), + timeseries.WithLokiTarget( + `min_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_ExecutionStateChanged_success="✅"| unwrap data_ExecutionStateChanged_duration [$__range]) by (data_ExecutionStateChanged_seqNum)`, + loki.Legend("Min"), + ), + timeseries.WithLokiTarget( + `max_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_ExecutionStateChanged_success="✅"| unwrap data_ExecutionStateChanged_duration [$__range]) by (data_ExecutionStateChanged_seqNum)`, + loki.Legend("Max"), + ), + ), + row.WithTimeSeries( + "E2E (Commit, ARM, Execution)", + timeseries.Transparent(), + timeseries.Description(""), + timeseries.Span(6), + timeseries.Height("200px"), + timeseries.DataSource(p.LokiDataSource), + timeseries.Axis( + axis.Unit("seconds"), + ), + timeseries.WithLokiTarget( + `avg_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_CommitAndExecute_success="✅"| unwrap data_CommitAndExecute_duration [$__range]) by (data_CommitAndExecute_seqNum)`, + loki.Legend("Avg"), + ), + timeseries.WithLokiTarget( + `min_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_CommitAndExecute_success="✅"| unwrap data_CommitAndExecute_duration [$__range]) by (data_CommitAndExecute_seqNum)`, + loki.Legend("Min"), + ), + timeseries.WithLokiTarget( + `max_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_CommitAndExecute_success="✅"| unwrap data_CommitAndExecute_duration [$__range]) by (data_CommitAndExecute_seqNum)`, + loki.Legend("Max"), + ), + ), + ), + } +} + +func failedMessagesRow(p Props) []dashboard.Option { + return []dashboard.Option{ + dashboard.Row( + "Failed Messages", + row.Collapse(), + row.WithTimeSeries( + "Failed Commit", + timeseries.Transparent(), + timeseries.Description(""), + timeseries.Span(6), + timeseries.Height("200px"), + timeseries.DataSource(p.LokiDataSource), + timeseries.WithLokiTarget( + `count_over_time({ namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_Commit_ReportAccepted_success="❌" [$__range])`, + loki.Legend("{{error}}"), + ), + ), + row.WithTimeSeries( + "Failed Bless", + timeseries.Transparent(), + timeseries.Description(""), + timeseries.Span(6), + timeseries.Height("200px"), + timeseries.DataSource(p.LokiDataSource), + timeseries.WithLokiTarget( + `count_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_ReportBlessedByARM_success="❌" [$__range])`, + loki.Legend("{{error}}"), + ), + ), + row.WithTimeSeries( + "Failed Execution", + timeseries.Transparent(), + timeseries.Description(""), + timeseries.Span(6), + timeseries.Height("200px"), + timeseries.DataSource(p.LokiDataSource), + timeseries.WithLokiTarget( + `count_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_ExecutionStateChanged_success="❌" [$__range])`, + loki.Legend("{{error}}"), + ), + ), + row.WithTimeSeries( + "Failed Commit and Execution", + timeseries.Transparent(), + timeseries.Description(""), + timeseries.Span(6), + timeseries.Height("200px"), + timeseries.DataSource(p.LokiDataSource), + timeseries.WithLokiTarget( + `count_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_CommitAndExecute_success="❌" [$__range])`, + loki.Legend("{{error}}"), + ), + ), + ), + } +} + +func reqRespRow(p Props) []dashboard.Option { + return []dashboard.Option{ + dashboard.Row( + "Requests/Responses", + row.WithStat( + "Stats", + stat.DataSource(p.LokiDataSource), + stat.Transparent(), + stat.Text(stat.TextValueAndName), + stat.Height("100px"), + stat.TitleFontSize(20), + stat.ValueFontSize(20), + stat.Span(12), + stat.WithPrometheusTarget( + `max_over_time({namespace="${namespace}", go_test_name="${go_test_name:pipe}", test_data_type="stats", test_group="$test_group", test_id=~"${test_id:pipe}", source_chain="${source_chain}", dest_chain="${dest_chain}"} +| json +| unwrap current_time_unit [$__range]) by (test_id)`, + prometheus.Legend("Time Unit"), + ), + stat.WithPrometheusTarget( + `max_over_time({namespace="${namespace}", go_test_name="${go_test_name:pipe}", test_data_type="stats", test_group="$test_group", test_id=~"${test_id:pipe}", source_chain="${source_chain}", dest_chain="${dest_chain}"} +| json +| unwrap load_duration [$__range]) by (test_id)/ 1e9 `, + prometheus.Legend("Total Duration"), + ), + stat.WithPrometheusTarget( + `max_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_CCIP_Send_Transaction_success="✅"| unwrap data_CCIP_Send_Transaction_ccip_send_data_message_bytes_length [$__range]) by (test_id)`, + prometheus.Legend("Max Byte Len Sent"), + ), + stat.WithPrometheusTarget( + `max_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_CCIP_Send_Transaction_success="✅"| unwrap data_CCIP_Send_Transaction_ccip_send_data_no_of_tokens_sent [$__range]) by (test_id)`, + prometheus.Legend("Max No Of Tokens Sent"), + ), + ), + row.WithTimeSeries( + "Request Rate", + timeseries.Transparent(), + timeseries.Description("Requests triggered over test duration"), + timeseries.Span(6), + timeseries.Height("200px"), + timeseries.DataSource(p.LokiDataSource), + timeseries.WithLokiTarget( + `last_over_time({namespace="${namespace}", go_test_name="${go_test_name:pipe}", test_data_type="stats", test_group="$test_group", test_id="${test_id:pipe}", source_chain="${source_chain}", dest_chain="${dest_chain}"}| json | unwrap current_rps [$__interval]) by (test_id,gen_name)`, + loki.Legend("Request Triggered/TimeUnit"), + ), + ), + row.WithTimeSeries( + "Trigger Summary", + timeseries.Transparent(), + timeseries.Points(), + timeseries.Description("Latest Stage Stats"), + timeseries.Span(6), + timeseries.Height("200px"), + timeseries.DataSource(p.LokiDataSource), + timeseries.WithLokiTarget( + `max_over_time({namespace="${namespace}", go_test_name="${go_test_name:pipe}", test_data_type="stats", test_group="$test_group", test_id=~"${test_id:pipe}", source_chain="${source_chain}", dest_chain="${dest_chain}"} +| json +| unwrap success [$__range]) by (test_id)`, + loki.Legend("Successful Requests"), + ), + timeseries.WithLokiTarget( + `max_over_time({namespace="${namespace}", go_test_name="${go_test_name:pipe}", test_data_type="stats", test_group="$test_group", test_id=~"${test_id:pipe}", source_chain="${source_chain}", dest_chain="${dest_chain}"} +| json +| unwrap failed [$__range]) by (test_id)`, + loki.Legend("Failed Requests"), + ), + ), + row.WithLogs( + "All CCIP Phases Stats", + logs.DataSource(p.LokiDataSource), + logs.Span(12), + logs.Height("300px"), + logs.Transparent(), + logs.WithLokiTarget( + `{namespace="${namespace}", go_test_name="${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json `, + ), + ), + ), + } +} + +func gasStatsRow(p Props) []dashboard.Option { + return []dashboard.Option{ + dashboard.Row( + "CCIP Gas Stats", + row.Collapse(), + row.WithTimeSeries( + "Gas Used in CCIP-Send⛽️", + timeseries.Transparent(), + timeseries.Description(""), + timeseries.Span(6), + timeseries.Height("200px"), + timeseries.DataSource(p.LokiDataSource), + timeseries.Axis( + axis.Unit("wei"), + ), + timeseries.WithLokiTarget( + `avg_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_CCIP_Send_Transaction_success="✅"| unwrap data_CCIP_Send_Transaction_ccip_send_data_gas_used [$__range]) by (test_id)`, + loki.Legend("Avg"), + ), + timeseries.WithLokiTarget( + `min_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_CCIP_Send_Transaction_success="✅"| unwrap data_CCIP_Send_Transaction_ccip_send_data_gas_used [$__range]) by (test_id)`, + loki.Legend("Min"), + ), + timeseries.WithLokiTarget( + `max_over_time({ namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_CCIP_Send_Transaction_success="✅"| unwrap data_CCIP_Send_Transaction_ccip_send_data_gas_used [$__range]) by (test_id) `, + loki.Legend("Max"), + ), + ), + row.WithTimeSeries( + "Gas Used in Commit⛽️", + timeseries.Transparent(), + timeseries.Description(""), + timeseries.Span(6), + timeseries.Height("200px"), + timeseries.DataSource(p.LokiDataSource), + timeseries.Axis( + axis.Unit("wei"), + ), + timeseries.WithLokiTarget( + `avg_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_Commit_ReportAccepted_success="✅"| unwrap data_Commit_ReportAccepted_ccip_send_data_gas_used [$__range]) by (test_id)`, + loki.Legend("Avg"), + ), + timeseries.WithLokiTarget( + `min_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_Commit_ReportAccepted_success="✅"| unwrap data_Commit_ReportAccepted_ccip_send_data_gas_used [$__range]) by (test_id)`, + loki.Legend("Min"), + ), + timeseries.WithLokiTarget( + `max_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_Commit_ReportAccepted_success="✅"| unwrap data_Commit_ReportAccepted_ccip_send_data_gas_used [$__range]) by (test_id) `, + loki.Legend("Max"), + ), + ), + row.WithTimeSeries( + "Gas Used in ARM Blessing⛽️", + timeseries.Transparent(), + timeseries.Description(""), + timeseries.Span(6), + timeseries.Height("200px"), + timeseries.DataSource(p.LokiDataSource), + timeseries.Axis( + axis.Unit("wei"), + ), + timeseries.WithLokiTarget( + `avg_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_ReportBlessedByARM_success="✅"| unwrap data_ReportBlessedByARM_ccip_send_data_gas_used [$__range]) by (test_id)`, + loki.Legend("Avg"), + ), + timeseries.WithLokiTarget( + `min_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_ReportBlessedByARM_success="✅"| unwrap data_ReportBlessedByARM_ccip_send_data_gas_used [$__range]) by (test_id)`, + loki.Legend("Min"), + ), + timeseries.WithLokiTarget( + `max_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_ReportBlessedByARM_success="✅"| unwrap data_ReportBlessedByARM_ccip_send_data_gas_used [$__range]) by (test_id) `, + loki.Legend("Max"), + ), + ), + row.WithTimeSeries( + "Gas Used in Execution⛽️", + timeseries.Transparent(), + timeseries.Description(""), + timeseries.Span(6), + timeseries.Height("200px"), + timeseries.DataSource(p.LokiDataSource), + timeseries.Axis( + axis.Unit("wei"), + ), + timeseries.WithLokiTarget( + `avg_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_ExecutionStateChanged_success="✅"| unwrap data_ExecutionStateChanged_ccip_send_data_gas_used [$__range]) by (test_id)`, + loki.Legend("Avg"), + ), + timeseries.WithLokiTarget( + `min_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_ExecutionStateChanged_success="✅"| unwrap data_ExecutionStateChanged_ccip_send_data_gas_used [$__range]) by (test_id)`, + loki.Legend("Min"), + ), + timeseries.WithLokiTarget( + `max_over_time({namespace="${namespace}", go_test_name=~"${go_test_name:pipe}", test_data_type="responses", test_group="${test_group}", test_id=~"${test_id:pipe}",source_chain="${source_chain}",dest_chain="${dest_chain}"} | json | data_ExecutionStateChanged_success="✅"| unwrap data_ExecutionStateChanged_ccip_send_data_gas_used [$__range]) by (test_id) `, + loki.Legend("Max"), + ), + ), + ), + } +} + +func New(p Props) []dashboard.Option { + opts := vars(p) + opts = append(opts, statsRow(p)...) + opts = append(opts, gasStatsRow(p)...) + opts = append(opts, failedMessagesRow(p)...) + opts = append(opts, reqRespRow(p)...) + return opts +} diff --git a/dashboard/lib/config.go b/dashboard-lib/config.go similarity index 52% rename from dashboard/lib/config.go rename to dashboard-lib/config.go index eae6e956fc7..a2bbd3174a6 100644 --- a/dashboard/lib/config.go +++ b/dashboard-lib/config.go @@ -1,13 +1,20 @@ -package dashboardlib +package dashboard_lib -import "os" +import ( + "encoding/base64" + "github.com/pkg/errors" + "os" + "strings" +) type EnvConfig struct { - Platform string - GrafanaURL string - GrafanaToken string - GrafanaFolder string - DataSources DataSources + Platform string + GrafanaURL string + GrafanaToken string + GrafanaBasicAuthUser string + GrafanaBasicAuthPassword string + GrafanaFolder string + DataSources DataSources } type DataSources struct { @@ -37,10 +44,6 @@ func ReadEnvDeployOpts() EnvConfig { if grafanaURL == "" { L.Fatal().Msg("GRAFANA_URL must be provided") } - grafanaToken := os.Getenv("GRAFANA_TOKEN") - if grafanaToken == "" { - L.Fatal().Msg("GRAFANA_TOKEN must be provided") - } grafanaFolder := os.Getenv("GRAFANA_FOLDER") if grafanaFolder == "" { L.Fatal().Msg("GRAFANA_FOLDER must be provided") @@ -57,14 +60,45 @@ func ReadEnvDeployOpts() EnvConfig { if prometheusDataSourceName == "" { L.Fatal().Msg("PROMETHEUS_DATA_SOURCE_NAME must be provided") } + ba := os.Getenv("GRAFANA_BASIC_AUTH") + grafanaToken := os.Getenv("GRAFANA_TOKEN") + if grafanaToken == "" && ba == "" { + L.Fatal().Msg("GRAFANA_TOKEN or GRAFANA_BASIC_AUTH must be provided") + } + var user, password string + var err error + if ba != "" { + user, password, err = DecodeBasicAuth(ba) + if err != nil { + L.Fatal().Err(err).Msg("failed to decode basic auth") + } + } return EnvConfig{ - GrafanaURL: grafanaURL, - GrafanaToken: grafanaToken, - GrafanaFolder: grafanaFolder, - Platform: platform, + GrafanaURL: grafanaURL, + GrafanaToken: grafanaToken, + GrafanaBasicAuthUser: user, + GrafanaBasicAuthPassword: password, + GrafanaFolder: grafanaFolder, + Platform: platform, DataSources: DataSources{ Loki: loki, Prometheus: prom, }, } } + +func DecodeBasicAuth(authString string) (string, string, error) { + var data string + decodedBytes, err := base64.StdEncoding.DecodeString(authString) + if err != nil { + L.Warn().Err(err).Msg("failed to decode basic auth, plain text? reading auth data") + data = authString + } else { + data = string(decodedBytes[1 : len(decodedBytes)-1]) + } + parts := strings.Split(data, ":") + if len(parts) != 2 { + return "", "", errors.New("invalid basic authentication format") + } + return parts[0], parts[1], nil +} diff --git a/dashboard/lib/core-don/component.go b/dashboard-lib/core-don/component.go similarity index 92% rename from dashboard/lib/core-don/component.go rename to dashboard-lib/core-don/component.go index 421ee2ff19d..24173fb6cc9 100644 --- a/dashboard/lib/core-don/component.go +++ b/dashboard-lib/core-don/component.go @@ -159,108 +159,185 @@ func logPollerRow(p Props) []dashboard.Option { return []dashboard.Option{ dashboard.Row("LogPoller", row.Collapse(), + row.WithStat( + "Goroutines", + stat.DataSource(p.PrometheusDataSource), + stat.Text(stat.TextValueAndName), + stat.Orientation(stat.OrientationAuto), + stat.Height("200px"), + stat.TitleFontSize(30), + stat.ValueFontSize(30), + stat.Span(6), + stat.Text("Goroutines"), + stat.WithPrometheusTarget( + `count(count by (evmChainID) (log_poller_query_duration_sum{job=~"$instance"}))`, + prometheus.Legend("Goroutines"), + ), + ), row.WithTimeSeries( - "LogPoller RPS", - timeseries.Span(4), + "RPS", + timeseries.Span(6), timeseries.Height("200px"), timeseries.DataSource(p.PrometheusDataSource), + timeseries.Axis( + axis.Unit("requests"), + ), timeseries.WithPrometheusTarget( - `avg(sum(rate(log_poller_query_duration_count{`+p.PlatformOpts.LabelQuery+`evmChainID=~"$evmChainID"}[$__rate_interval])) by (query, `+p.PlatformOpts.LabelFilter+`)) by (query)`, - prometheus.Legend("{{query}}"), + `avg by (query) (sum by (query, job) (rate(log_poller_query_duration_count{job=~"$instance", evmChainID=~"$evmChainID"}[$__rate_interval])))`, + prometheus.Legend("{{query}} - {{job}}"), ), timeseries.WithPrometheusTarget( - `avg(sum(rate(log_poller_query_duration_count{`+p.PlatformOpts.LabelFilter+`=~"$instance", evmChainID=~"$evmChainID"}[$__rate_interval]))) by (`+p.PlatformOpts.LabelFilter+`)`, + `avg (sum by(job) (rate(log_poller_query_duration_count{job=~"$instance", evmChainID=~"$evmChainID"}[$__rate_interval])))`, prometheus.Legend("Total"), ), ), row.WithTimeSeries( - "LogPoller Logs Number Returned", - timeseries.Span(4), + "RPS by type", + timeseries.Span(6), timeseries.Height("200px"), timeseries.DataSource(p.PrometheusDataSource), + timeseries.Axis( + axis.Unit("requests"), + ), timeseries.WithPrometheusTarget( - `log_poller_query_dataset_size{`+p.PlatformOpts.LabelQuery+`evmChainID=~"$evmChainID"}`, - prometheus.Legend("{{query}} : {{type}}"), + `avg by (type) (sum by (type, job) (rate(log_poller_query_duration_count{job=~"$instance", evmChainID=~"$evmChainID"}[$__rate_interval])))`, ), ), row.WithTimeSeries( - "LogPoller Average Logs Number Returned", - timeseries.Span(4), + "Avg number of logs returned", + timeseries.Span(6), timeseries.Height("200px"), timeseries.DataSource(p.PrometheusDataSource), + timeseries.Axis( + axis.Unit("logs"), + ), timeseries.WithPrometheusTarget( - `avg(log_poller_query_dataset_size{`+p.PlatformOpts.LabelQuery+`evmChainID=~"$evmChainID"}) by (query)`, - prometheus.Legend("{{query}}"), + `avg by (query) (log_poller_query_dataset_size{job=~"$instance", evmChainID=~"$evmChainID"})`, + prometheus.Legend("{{query}} - {{job}}"), ), ), row.WithTimeSeries( - "LogPoller Max Logs Number Returned", - timeseries.Span(4), + "Max number of logs returned", + timeseries.Span(6), timeseries.Height("200px"), timeseries.DataSource(p.PrometheusDataSource), + timeseries.Axis( + axis.Unit("logs"), + ), timeseries.WithPrometheusTarget( - `max(log_poller_query_dataset_size{`+p.PlatformOpts.LabelQuery+`evmChainID=~"$evmChainID"}) by (query)`, - prometheus.Legend("{{query}}"), + `max by (query) (log_poller_query_dataset_size{job=~"$instance", evmChainID=~"$evmChainID"})`, + prometheus.Legend("{{query}} - {{job}}"), ), ), row.WithTimeSeries( - "LogPoller Logs Number Returned by Chain", - timeseries.Span(4), + "Logs returned by chain", + timeseries.Span(6), timeseries.Height("200px"), timeseries.DataSource(p.PrometheusDataSource), + timeseries.Axis( + axis.Unit("logs"), + ), timeseries.WithPrometheusTarget( - `max(log_poller_query_dataset_size{`+p.PlatformOpts.LabelQuery+`}) by (evmChainID)`, + `max by (evmChainID) (log_poller_query_dataset_size{job=~"$instance", evmChainID=~"$evmChainID"})`, prometheus.Legend("{{evmChainID}}"), ), ), row.WithTimeSeries( - "LogPoller Queries Duration Avg", - timeseries.Span(4), + "Queries duration by type (0.5 perc)", + timeseries.Span(6), timeseries.Height("200px"), timeseries.DataSource(p.PrometheusDataSource), + timeseries.Axis( + axis.Unit("ms"), + ), timeseries.WithPrometheusTarget( - `(sum(rate(log_poller_query_duration_sum{`+p.PlatformOpts.LabelQuery+`evmChainID=~"$evmChainID"}[$__rate_interval])) by (query) / sum(rate(log_poller_query_duration_count{`+p.PlatformOpts.LabelQuery+`}[$__rate_interval])) by (query)) / 1e6`, + `histogram_quantile(0.5, sum(rate(log_poller_query_duration_bucket{job=~"$instance", evmChainID=~"$evmChainID"}[$__rate_interval])) by (le, query)) / 1e6`, prometheus.Legend("{{query}}"), ), ), row.WithTimeSeries( - "LogPoller Queries Duration p99", - timeseries.Span(4), + "queries duration by type (0.9 perc)", + timeseries.Span(6), timeseries.Height("200px"), timeseries.DataSource(p.PrometheusDataSource), + timeseries.Axis( + axis.Unit("ms"), + ), timeseries.WithPrometheusTarget( - `histogram_quantile(0.99, sum(rate(log_poller_query_duration_bucket{`+p.PlatformOpts.LabelQuery+`evmChainID=~"$evmChainID"}[$__rate_interval])) by (le, query)) / 1e6`, + `histogram_quantile(0.9, sum(rate(log_poller_query_duration_bucket{job=~"$instance", evmChainID=~"$evmChainID"}[$__rate_interval])) by (le, query)) / 1e6`, prometheus.Legend("{{query}}"), ), ), row.WithTimeSeries( - "LogPoller Queries Duration p95", - timeseries.Span(4), + "Queries duration by type (0.99 perc)", + timeseries.Span(6), timeseries.Height("200px"), timeseries.DataSource(p.PrometheusDataSource), + timeseries.Axis( + axis.Unit("ms"), + ), timeseries.WithPrometheusTarget( - `histogram_quantile(0.95, sum(rate(log_poller_query_duration_bucket{`+p.PlatformOpts.LabelQuery+`evmChainID=~"$evmChainID"}[$__rate_interval])) by (le, query)) / 1e6`, + `histogram_quantile(0.99, sum(rate(log_poller_query_duration_bucket{job=~"$instance", evmChainID=~"$evmChainID"}[$__rate_interval])) by (le, query)) / 1e6`, prometheus.Legend("{{query}}"), ), ), row.WithTimeSeries( - "LogPoller Queries Duration p90", - timeseries.Span(4), + "Queries duration by chain (0.99 perc)", + timeseries.Span(6), timeseries.Height("200px"), timeseries.DataSource(p.PrometheusDataSource), + timeseries.Axis( + axis.Unit("ms"), + ), timeseries.WithPrometheusTarget( - `histogram_quantile(0.95, sum(rate(log_poller_query_duration_bucket{`+p.PlatformOpts.LabelQuery+`evmChainID=~"$evmChainID"}[$__rate_interval])) by (le, query)) / 1e6`, + `histogram_quantile(0.99, sum(rate(log_poller_query_duration_bucket{job=~"$instance", evmChainID=~"$evmChainID"}[$__rate_interval])) by (le, evmChainID)) / 1e6`, prometheus.Legend("{{query}}"), ), ), row.WithTimeSeries( - "LogPoller Queries Duration Median", - timeseries.Span(4), + "Number of logs inserted", + timeseries.Span(6), timeseries.Height("200px"), timeseries.DataSource(p.PrometheusDataSource), + timeseries.Axis( + axis.Unit("logs"), + ), timeseries.WithPrometheusTarget( - `histogram_quantile(0.5, sum(rate(log_poller_query_duration_bucket{`+p.PlatformOpts.LabelQuery+`evmChainID=~"$evmChainID"}[$__rate_interval])) by (le, query)) / 1e6`, - prometheus.Legend("{{query}}"), + `avg by (evmChainID) (log_poller_logs_inserted{job=~"$instance", evmChainID=~"$evmChainID"})`, + prometheus.Legend("{{evmChainID}}"), + ), + ), + row.WithTimeSeries( + "Logs insertion rate", + timeseries.Span(6), + timeseries.Height("200px"), + timeseries.DataSource(p.PrometheusDataSource), + timeseries.WithPrometheusTarget( + `avg by (evmChainID) (rate(log_poller_logs_inserted{job=~"$instance", evmChainID=~"$evmChainID"}[$__rate_interval]))`, + prometheus.Legend("{{evmChainID}}"), + ), + ), + row.WithTimeSeries( + "Number of blocks inserted", + timeseries.Span(6), + timeseries.Height("200px"), + timeseries.DataSource(p.PrometheusDataSource), + timeseries.Axis( + axis.Unit("blocks"), + ), + timeseries.WithPrometheusTarget( + `avg by (evmChainID) (log_poller_blocks_inserted{job=~"$instance", evmChainID=~"$evmChainID"})`, + prometheus.Legend("{{evmChainID}}"), + ), + ), + row.WithTimeSeries( + "Blocks insertion rate", + timeseries.Span(6), + timeseries.Height("200px"), + timeseries.DataSource(p.PrometheusDataSource), + timeseries.WithPrometheusTarget( + `avg by (evmChainID) (rate(log_poller_blocks_inserted{job=~"$instance", evmChainID=~"$evmChainID"}[$__rate_interval]))`, + prometheus.Legend("{{evmChainID}}"), ), ), ), diff --git a/dashboard/lib/core-don/platform.go b/dashboard-lib/core-don/platform.go similarity index 82% rename from dashboard/lib/core-don/platform.go rename to dashboard-lib/core-don/platform.go index 3abe16219c7..fbfed548146 100644 --- a/dashboard/lib/core-don/platform.go +++ b/dashboard-lib/core-don/platform.go @@ -22,10 +22,6 @@ func PlatformPanelOpts(platform string) PlatformOpts { switch platform { case "kubernetes": po.LabelFilters = map[string]string{ - // TODO: sometimes I can see my PodMonitor selector, sometimes I don't - // TODO: is it prometheus-operator issue or do we really need "job" selector for k8s? - // TODO: works without it - //"job": `=~"${instance}"`, "namespace": `=~"${namespace}"`, "pod": `=~"${pod}"`, } diff --git a/dashboard-lib/core-ocrv2-ccip/component.go b/dashboard-lib/core-ocrv2-ccip/component.go new file mode 100644 index 00000000000..837f693fcc7 --- /dev/null +++ b/dashboard-lib/core-ocrv2-ccip/component.go @@ -0,0 +1,83 @@ +package core_ocrv2_ccip + +import ( + "fmt" + "github.com/K-Phoen/grabana/dashboard" + "github.com/K-Phoen/grabana/row" + "github.com/K-Phoen/grabana/target/prometheus" + "github.com/K-Phoen/grabana/timeseries" +) + +type Props struct { + PrometheusDataSource string + PluginName string +} + +func quantileRowOpts(ds string, pluginName string, perc string) row.Option { + return row.WithTimeSeries( + fmt.Sprintf("(%s) OCR2 duration (%s)", pluginName, perc), + timeseries.Span(6), + timeseries.Height("200px"), + timeseries.DataSource(ds), + timeseries.WithPrometheusTarget( + fmt.Sprintf(`histogram_quantile(%s, sum(rate(ocr2_reporting_plugin_observation_time_bucket{plugin="%s", job=~"$instance", chainID=~"$evmChainID"}[$__rate_interval])) by (le)) / 1e9`, perc, pluginName), + prometheus.Legend("Observation"), + ), + timeseries.WithPrometheusTarget( + fmt.Sprintf(`histogram_quantile(%s, sum(rate(ocr2_reporting_plugin_report_time_bucket{plugin="%s", job=~"$instance", chainID=~"$evmChainID"}[$__rate_interval])) by (le)) / 1e9`, perc, pluginName), + prometheus.Legend("Report"), + ), + timeseries.WithPrometheusTarget( + fmt.Sprintf(`histogram_quantile(%s, sum(rate(ocr2_reporting_plugin_should_accept_finalized_report_time_bucket{plugin="%s", job=~"$instance", chainID=~"$evmChainID"}[$__rate_interval])) by (le)) / 1e9`, perc, pluginName), + prometheus.Legend("ShouldAcceptFinalizedReport"), + ), + timeseries.WithPrometheusTarget( + fmt.Sprintf(`histogram_quantile(%s, sum(rate(ocr2_reporting_plugin_should_transmit_accepted_report_time_bucket{plugin="%s", job=~"$instance", chainID=~"$evmChainID"}[$__rate_interval])) by (le)) / 1e9`, perc, pluginName), + prometheus.Legend("ShouldTransmitAcceptedReport"), + ), + ) +} + +func ocrv2PluginObservationStageQuantiles(p Props) []dashboard.Option { + opts := make([]row.Option, 0) + opts = append(opts, + row.Collapse(), + row.WithTimeSeries( + fmt.Sprintf("(%s) OCR2 RPS by phase", p.PluginName), + timeseries.Span(6), + timeseries.Height("200px"), + timeseries.DataSource(p.PrometheusDataSource), + timeseries.WithPrometheusTarget( + fmt.Sprintf(`sum(rate(ocr2_reporting_plugin_observation_time_count{plugin="%s", job=~"$instance", chainID=~"$evmChainID"}[$__range]))`, p.PluginName), + prometheus.Legend("Observation"), + ), + timeseries.WithPrometheusTarget( + fmt.Sprintf(`sum(rate(ocr2_reporting_plugin_report_time_count{plugin="%s", job=~"$instance", chainID=~"$evmChainID"}[$__range]))`, p.PluginName), + prometheus.Legend("Report"), + ), + timeseries.WithPrometheusTarget( + fmt.Sprintf(`sum(rate(ocr2_reporting_plugin_should_accept_finalized_report_time_count{plugin="%s", job=~"$instance", chainID=~"$evmChainID"}[$__range]))`, p.PluginName), + prometheus.Legend("ShouldAcceptFinalizedReport"), + ), + timeseries.WithPrometheusTarget( + fmt.Sprintf(`sum(rate(ocr2_reporting_plugin_should_transmit_accepted_report_time_count{plugin="%s", job=~"$instance", chainID=~"$evmChainID"}[$__range]))`, p.PluginName), + prometheus.Legend("ShouldTransmitAcceptedReport"), + ), + ), + quantileRowOpts(p.PrometheusDataSource, p.PluginName, "0.5"), + quantileRowOpts(p.PrometheusDataSource, p.PluginName, "0.9"), + quantileRowOpts(p.PrometheusDataSource, p.PluginName, "0.99"), + ) + return []dashboard.Option{ + dashboard.Row( + fmt.Sprintf("OCRv2 Metrics - Plugin: %s", p.PluginName), + opts..., + ), + } +} + +func New(p Props) []dashboard.Option { + opts := make([]dashboard.Option, 0) + opts = append(opts, ocrv2PluginObservationStageQuantiles(p)...) + return opts +} diff --git a/dashboard-lib/dashboard.go b/dashboard-lib/dashboard.go new file mode 100644 index 00000000000..33371a6163a --- /dev/null +++ b/dashboard-lib/dashboard.go @@ -0,0 +1,105 @@ +package dashboard_lib + +import ( + "context" + "encoding/json" + "github.com/K-Phoen/grabana" + "github.com/K-Phoen/grabana/dashboard" + "github.com/pkg/errors" + "net/http" + "os" +) + +type Dashboard struct { + Name string + DeployOpts EnvConfig + /* SDK panels that are missing in Grabana */ + SDKPanels []map[string]interface{} + /* generated dashboard opts and builder */ + builder dashboard.Builder + Opts []dashboard.Option +} + +func NewDashboard( + name string, + deployOpts EnvConfig, + opts []dashboard.Option, +) *Dashboard { + return &Dashboard{ + Name: name, + DeployOpts: deployOpts, + Opts: opts, + } +} + +func (m *Dashboard) Deploy() error { + ctx := context.Background() + b, err := m.build() + if err != nil { + return err + } + var client *grabana.Client + if m.DeployOpts.GrafanaBasicAuthUser != "" && m.DeployOpts.GrafanaBasicAuthPassword != "" { + L.Info().Msg("Authorizing using BasicAuth") + client = grabana.NewClient( + &http.Client{}, + m.DeployOpts.GrafanaURL, + grabana.WithBasicAuth(m.DeployOpts.GrafanaBasicAuthUser, m.DeployOpts.GrafanaBasicAuthPassword), + ) + } else { + L.Info().Msg("Authorizing using Bearer token") + client = grabana.NewClient( + &http.Client{}, + m.DeployOpts.GrafanaURL, + grabana.WithAPIToken(m.DeployOpts.GrafanaToken), + ) + } + fo, folderErr := client.FindOrCreateFolder(ctx, m.DeployOpts.GrafanaFolder) + if folderErr != nil { + return errors.Wrap(err, "could not find or create Grafana folder") + } + if _, err := client.UpsertDashboard(ctx, fo, b); err != nil { + return errors.Wrap(err, "failed to upsert the dashboard") + } + return nil +} + +func (m *Dashboard) Add(opts []dashboard.Option) { + m.Opts = append(m.Opts, opts...) +} + +func (m *Dashboard) AddSDKPanel(panel map[string]interface{}) { + m.SDKPanels = append(m.SDKPanels, panel) +} + +func (m *Dashboard) build() (dashboard.Builder, error) { + b, err := dashboard.New( + m.Name, + m.Opts..., + ) + if err != nil { + return dashboard.Builder{}, errors.Wrap(err, "failed to build the dashboard") + } + return b, nil +} + +// TODO: re-write after forking Grabana, inject foundation SDK components from official schema +func (m *Dashboard) injectSDKPanels(b dashboard.Builder) (dashboard.Builder, error) { + data, err := b.MarshalIndentJSON() + if err != nil { + return dashboard.Builder{}, err + } + var asMap map[string]interface{} + if err := json.Unmarshal(data, &asMap); err != nil { + return dashboard.Builder{}, err + } + asMap["rows"].([]interface{})[0].(map[string]interface{})["panels"] = append(asMap["rows"].([]interface{})[0].(map[string]interface{})["panels"].([]interface{}), m.SDKPanels[0]) + d, err := json.Marshal(asMap) + if err != nil { + return dashboard.Builder{}, err + } + if err := os.WriteFile("generated_ccip_dashboard.json", d, os.ModePerm); err != nil { + return dashboard.Builder{}, err + } + return b, nil +} diff --git a/dashboard/go.mod b/dashboard-lib/go.mod similarity index 70% rename from dashboard/go.mod rename to dashboard-lib/go.mod index 2731dc6fc67..eef60129771 100644 --- a/dashboard/go.mod +++ b/dashboard-lib/go.mod @@ -4,10 +4,13 @@ go 1.21.7 require ( github.com/K-Phoen/grabana v0.22.1 + github.com/grafana/grafana-foundation-sdk/go v0.0.0-00010101000000-000000000000 github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.32.0 ) +replace github.com/grafana/grafana-foundation-sdk/go => github.com/grafana/grafana-foundation-sdk/go v0.0.0-20240314112857-a7c9c6d0044c + require ( github.com/K-Phoen/sdk v0.12.4 // indirect github.com/gosimple/slug v1.13.1 // indirect diff --git a/dashboard/go.sum b/dashboard-lib/go.sum similarity index 91% rename from dashboard/go.sum rename to dashboard-lib/go.sum index 964a7ae7dd4..0af3f10f4fe 100644 --- a/dashboard/go.sum +++ b/dashboard-lib/go.sum @@ -10,6 +10,8 @@ github.com/gosimple/slug v1.13.1 h1:bQ+kpX9Qa6tHRaK+fZR0A0M2Kd7Pa5eHPPsb1JpHD+Q= github.com/gosimple/slug v1.13.1/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ= github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o= github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc= +github.com/grafana/grafana-foundation-sdk/go v0.0.0-20240314112857-a7c9c6d0044c h1:0vdGmlvHPzjNHx9Tx8soQEKe1ci0WVtA82s00sZDYUs= +github.com/grafana/grafana-foundation-sdk/go v0.0.0-20240314112857-a7c9c6d0044c/go.mod h1:WtWosval1KCZP9BGa42b8aVoJmVXSg0EvQXi9LDSVZQ= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= diff --git a/dashboard/lib/k8s-pods/component.go b/dashboard-lib/k8s-pods/component.go similarity index 100% rename from dashboard/lib/k8s-pods/component.go rename to dashboard-lib/k8s-pods/component.go diff --git a/dashboard/lib/log.go b/dashboard-lib/log.go similarity index 94% rename from dashboard/lib/log.go rename to dashboard-lib/log.go index fe30efc7f59..edb4607a0ba 100644 --- a/dashboard/lib/log.go +++ b/dashboard-lib/log.go @@ -1,4 +1,4 @@ -package dashboardlib +package dashboard_lib import ( "os" diff --git a/dashboard/index.ts b/dashboard/index.ts deleted file mode 100644 index 60cccebf00e..00000000000 --- a/dashboard/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export {testCoreDonComponentStep} from "./lib/core-don/component.spec" -export {testK8sPodsComponentStep} from "./lib/k8s-pods/component.spec" -export {selectors} from "@grafana/e2e-selectors" diff --git a/dashboard/lib/core-don/component.spec.ts b/dashboard/lib/core-don/component.spec.ts deleted file mode 100644 index 3b53070bd1a..00000000000 --- a/dashboard/lib/core-don/component.spec.ts +++ /dev/null @@ -1,10 +0,0 @@ -import {expect} from '@playwright/test'; -import chalk from 'chalk'; - - -export const testCoreDonComponentStep = async ({page}) => { - console.log(chalk.green('Core DON Component Step')); - // TODO: authorize and write tests - await page.goto('/'); - await expect(page).toHaveTitle(/Grafana/); -} \ No newline at end of file diff --git a/dashboard/lib/dashboard.go b/dashboard/lib/dashboard.go deleted file mode 100644 index ce7d37a3b80..00000000000 --- a/dashboard/lib/dashboard.go +++ /dev/null @@ -1,61 +0,0 @@ -package dashboardlib - -import ( - "context" - "github.com/K-Phoen/grabana" - "github.com/K-Phoen/grabana/dashboard" - "github.com/pkg/errors" - "net/http" -) - -type Dashboard struct { - Name string - DeployOpts EnvConfig - /* generated dashboard opts and builder */ - builder dashboard.Builder - Opts []dashboard.Option -} - -func NewDashboard( - name string, - deployOpts EnvConfig, - opts []dashboard.Option, -) *Dashboard { - return &Dashboard{ - Name: name, - DeployOpts: deployOpts, - Opts: opts, - } -} - -func (m *Dashboard) Deploy() error { - ctx := context.Background() - b, err := m.build() - if err != nil { - return err - } - client := grabana.NewClient(&http.Client{}, m.DeployOpts.GrafanaURL, grabana.WithAPIToken(m.DeployOpts.GrafanaToken)) - fo, folderErr := client.FindOrCreateFolder(ctx, m.DeployOpts.GrafanaFolder) - if folderErr != nil { - return errors.Wrap(err, "could not find or create Grafana folder") - } - if _, err := client.UpsertDashboard(ctx, fo, b); err != nil { - return errors.Wrap(err, "failed to upsert the dashboard") - } - return nil -} - -func (m *Dashboard) Add(opts []dashboard.Option) { - m.Opts = append(m.Opts, opts...) -} - -func (m *Dashboard) build() (dashboard.Builder, error) { - b, err := dashboard.New( - m.Name, - m.Opts..., - ) - if err != nil { - return dashboard.Builder{}, errors.Wrap(err, "failed to build the dashboard") - } - return b, nil -} diff --git a/dashboard/lib/k8s-pods/component.spec.ts b/dashboard/lib/k8s-pods/component.spec.ts deleted file mode 100644 index fa7e7bbe3b8..00000000000 --- a/dashboard/lib/k8s-pods/component.spec.ts +++ /dev/null @@ -1,9 +0,0 @@ -import {expect} from '@playwright/test'; -import chalk from "chalk"; - -export const testK8sPodsComponentStep = async ({page}) => { - console.log(chalk.green('K8s Pods Component Step')); - // TODO: authorize and write tests - await page.goto('/'); - await expect(page).toHaveTitle(/Grafana/); -} diff --git a/dashboard/package.json b/dashboard/package.json deleted file mode 100644 index cebce188b2b..00000000000 --- a/dashboard/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "dashboard-tests", - "version": "1.0.0", - "description": "", - "main": "index.ts", - "scripts": {}, - "keywords": [], - "author": "", - "license": "ISC", - "dependencies": { - "@grafana/e2e-selectors": "^10.4.0", - "chalk": "^4.1.2" - } -} diff --git a/dashboard/pnpm-lock.yaml b/dashboard/pnpm-lock.yaml deleted file mode 100644 index 876ea9d13b3..00000000000 --- a/dashboard/pnpm-lock.yaml +++ /dev/null @@ -1,75 +0,0 @@ -lockfileVersion: '6.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -dependencies: - '@grafana/e2e-selectors': - specifier: ^10.4.0 - version: 10.4.0 - chalk: - specifier: ^4.1.2 - version: 4.1.2 - -packages: - - /@grafana/e2e-selectors@10.4.0: - resolution: {integrity: sha512-8IWK8Yi0POh/3NMIUHjB9AbxCA+uKFMbYmQ7cJWT+qyjYl+82DQQPob/MTfzVGzWWIPYo4Ur7QSAP1dPgMVs8g==} - dependencies: - '@grafana/tsconfig': 1.2.0-rc1 - tslib: 2.6.2 - typescript: 5.3.3 - dev: false - - /@grafana/tsconfig@1.2.0-rc1: - resolution: {integrity: sha512-+SgQeBQ1pT6D/E3/dEdADqTrlgdIGuexUZ8EU+8KxQFKUeFeU7/3z/ayI2q/wpJ/Kr6WxBBNlrST6aOKia19Ag==} - dev: false - - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - dependencies: - color-convert: 2.0.1 - dev: false - - /chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - dev: false - - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - dependencies: - color-name: 1.1.4 - dev: false - - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: false - - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: false - - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - dependencies: - has-flag: 4.0.0 - dev: false - - /tslib@2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - dev: false - - /typescript@5.3.3: - resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} - engines: {node: '>=14.17'} - hasBin: true - dev: false diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 732ed762be3..2e4ccfa1196 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -80,7 +80,7 @@ DefaultLockTimeout = '15s' # Default DefaultQueryTimeout = '10s' # Default LogQueries = false # Default MaxIdleConns = 10 # Default -MaxOpenConns = 20 # Default +MaxOpenConns = 100 # Default MigrateOnStartup = true # Default ``` @@ -119,7 +119,7 @@ Postgres has connection limits, so you must use caution when increasing this val ### MaxOpenConns ```toml -MaxOpenConns = 20 # Default +MaxOpenConns = 100 # Default ``` MaxOpenConns configures the maximum number of database connections that a Chainlink node will have open at any one time. Think of this as the maximum burst upper bound limit of database connections per Chainlink node instance. Increasing this number can help to improve performance under database-heavy workloads. @@ -776,6 +776,7 @@ MaxSuccessfulRuns = 10000 # Default ReaperInterval = '1h' # Default ReaperThreshold = '24h' # Default ResultWriteQueueDepth = 100 # Default +VerboseLogging = true # Default ``` @@ -823,6 +824,16 @@ ResultWriteQueueDepth = 100 # Default ``` ResultWriteQueueDepth controls how many writes will be buffered before subsequent writes are dropped, for jobs that write results asynchronously for performance reasons, such as OCR. +### VerboseLogging +```toml +VerboseLogging = true # Default +``` +VerboseLogging enables detailed logging of pipeline execution steps. +This can be useful for debugging failed runs without relying on the UI +or database. + +You may disable if this results in excessive log volume. + ## JobPipeline.HTTPRequest ```toml [JobPipeline.HTTPRequest] @@ -1759,6 +1770,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -1770,7 +1782,7 @@ ObservationGracePeriod = '1s' [OCR2] [OCR2.Automation] -GasLimit = 5400000 +GasLimit = 10500000 ```

@@ -1843,6 +1855,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -1927,6 +1940,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -2011,6 +2025,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -2096,6 +2111,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -2180,6 +2196,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -2264,6 +2281,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -2349,6 +2367,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -2433,6 +2452,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -2516,6 +2536,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -2599,6 +2620,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -2683,6 +2705,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -2768,6 +2791,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -2852,6 +2876,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -2936,6 +2961,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -3020,6 +3046,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -3104,6 +3131,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -3188,6 +3216,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -3272,6 +3301,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -3356,6 +3386,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -3441,6 +3472,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -3525,6 +3557,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -3608,6 +3641,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -3692,6 +3726,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -3775,6 +3810,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -3859,6 +3895,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -3943,6 +3980,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -4026,6 +4064,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -4109,6 +4148,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -4193,6 +4233,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -4276,6 +4317,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -4360,6 +4402,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -4443,6 +4486,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -4527,6 +4571,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -4611,6 +4656,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -4696,6 +4742,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -4780,6 +4827,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -4864,6 +4912,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -4948,6 +4997,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -5032,6 +5082,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -5115,6 +5166,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -5198,6 +5250,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -5282,6 +5335,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -5366,6 +5420,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -5450,6 +5505,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -5535,6 +5591,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -5620,6 +5677,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -5704,6 +5762,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -5788,6 +5847,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -5872,6 +5932,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -5956,6 +6017,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -5967,7 +6029,7 @@ ObservationGracePeriod = '1s' [OCR2] [OCR2.Automation] -GasLimit = 5400000 +GasLimit = 10500000 ```

@@ -6040,6 +6102,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 10 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 1 @@ -6124,6 +6187,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -6208,6 +6272,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [OCR] ContractConfirmations = 4 @@ -6852,6 +6917,7 @@ SelectionMode = 'HighestHead' # Default SyncThreshold = 5 # Default LeaseDuration = '0s' # Default NodeIsSyncingEnabled = false # Default +FinalizedBlockPollInterval = '5s' # Default ``` The node pool manages multiple RPC endpoints. @@ -6913,6 +6979,18 @@ All of the requests to node in state `Syncing` are rejected. Set true to enable this check +### FinalizedBlockPollInterval +```toml +FinalizedBlockPollInterval = '5s' # Default +``` +FinalizedBlockPollInterval controls how often to poll RPC for new finalized blocks. +The finalized block is only used to report to the `pool_rpc_node_highest_finalized_block` metric. We plan to use it +in RPCs health assessment in the future. +If `FinalityTagEnabled = false`, poll is not performed and `pool_rpc_node_highest_finalized_block` is +reported based on latest block and finality depth. + +Set to 0 to disable. + ## EVM.OCR ```toml [EVM.OCR] @@ -7306,6 +7384,7 @@ URL is the HTTP(S) endpoint for this node. ```toml [[Starknet]] ChainID = 'foobar' # Example +FeederURL = 'http://feeder.url' # Example Enabled = true # Default OCR2CachePollPeriod = '5s' # Default OCR2CacheTTL = '1m' # Default @@ -7321,6 +7400,12 @@ ChainID = 'foobar' # Example ``` ChainID is the Starknet chain ID. +### FeederURL +```toml +FeederURL = 'http://feeder.url' # Example +``` +FeederURL is required to get tx metadata (that the RPC can't) + ### Enabled ```toml Enabled = true # Default @@ -7362,6 +7447,7 @@ ConfirmationPoll is how often to confirmer checks for tx inclusion on chain. [[Starknet.Nodes]] Name = 'primary' # Example URL = 'http://stark.node' # Example +APIKey = 'key' # Example ``` @@ -7377,3 +7463,9 @@ URL = 'http://stark.node' # Example ``` URL is the base HTTP(S) endpoint for this node. +### APIKey +```toml +APIKey = 'key' # Example +``` +APIKey Header is optional and only required for Nethermind RPCs + diff --git a/go.md b/go.md index 497f87d77b5..dd17f5207bd 100644 --- a/go.md +++ b/go.md @@ -20,8 +20,6 @@ flowchart LR classDef outline stroke-dasharray:6,fill:none; class chains,products outline - chainlink/v2 --> caigo - click caigo href "https://github.com/smartcontractkit/caigo" chainlink/v2 --> chain-selectors click chain-selectors href "https://github.com/smartcontractkit/chain-selectors" chainlink/v2 --> chainlink-automation @@ -60,7 +58,6 @@ flowchart LR chainlink-feeds --> libocr chainlink-solana --> chainlink-common chainlink-solana --> libocr - chainlink-starknet/relayer --> caigo chainlink-starknet/relayer --> chainlink-common chainlink-starknet/relayer --> libocr chainlink-vrf --> libocr diff --git a/go.mod b/go.mod index 77d2b20c09e..0a438d144c6 100644 --- a/go.mod +++ b/go.mod @@ -6,12 +6,15 @@ require ( github.com/Depado/ginprom v1.8.0 github.com/Masterminds/semver/v3 v3.2.1 github.com/Masterminds/sprig/v3 v3.2.3 + github.com/NethermindEth/juno v0.3.1 + github.com/NethermindEth/starknet.go v0.6.1-0.20231218140327-915109ab5bc1 github.com/XSAM/otelsql v0.27.0 github.com/avast/retry-go/v4 v4.5.1 github.com/btcsuite/btcd/btcec/v2 v2.3.2 github.com/cometbft/cometbft v0.37.2 github.com/cosmos/cosmos-sdk v0.47.4 github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e + github.com/dominikbraun/graph v0.23.0 github.com/esote/minmaxheap v1.0.0 github.com/ethereum/go-ethereum v1.13.8 github.com/fatih/color v1.16.0 @@ -33,14 +36,14 @@ require ( github.com/grafana/pyroscope-go v1.1.1 github.com/graph-gophers/dataloader v5.0.0+incompatible github.com/graph-gophers/graphql-go v1.3.0 - github.com/hashicorp/consul/sdk v0.14.1 + github.com/hashicorp/consul/sdk v0.16.0 github.com/hashicorp/go-envparse v0.1.0 github.com/hashicorp/go-plugin v1.6.0 github.com/hashicorp/go-retryablehttp v0.7.5 github.com/hdevalence/ed25519consensus v0.1.0 - github.com/jackc/pgconn v1.14.1 + github.com/jackc/pgconn v1.14.3 github.com/jackc/pgtype v1.14.0 - github.com/jackc/pgx/v4 v4.18.1 + github.com/jackc/pgx/v4 v4.18.2 github.com/jmoiron/sqlx v1.3.5 github.com/jonboulle/clockwork v0.4.0 github.com/jpillora/backoff v1.0.0 @@ -67,17 +70,16 @@ require ( github.com/scylladb/go-reflectx v1.0.1 github.com/shirou/gopsutil/v3 v3.23.11 github.com/shopspring/decimal v1.3.1 - github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 github.com/smartcontractkit/chain-selectors v1.0.10 - github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240311111125-22812a072c35 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240314172156-049609b8e1f9 + github.com/smartcontractkit/chainlink-automation v1.0.2 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240404141006-77085a02ce25 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e - github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240213121419-1272736c2ac0 + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 - github.com/smartcontractkit/libocr v0.0.0-20240229181116-bfb2432a7a66 + github.com/smartcontractkit/libocr v0.0.0-20240326191951-2bbe9382d052 github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/wsrpc v0.7.2 @@ -92,24 +94,23 @@ require ( github.com/urfave/cli v1.22.14 go.dedis.ch/fixbuf v1.0.3 go.dedis.ch/kyber/v3 v3.1.0 - go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1 - go.opentelemetry.io/otel v1.21.0 + go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.49.0 + go.opentelemetry.io/otel v1.24.0 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.26.0 - golang.org/x/crypto v0.19.0 + golang.org/x/crypto v0.21.0 golang.org/x/exp v0.0.0-20240213143201-ec583247a57a golang.org/x/mod v0.15.0 golang.org/x/sync v0.6.0 - golang.org/x/term v0.17.0 + golang.org/x/term v0.18.0 golang.org/x/text v0.14.0 golang.org/x/time v0.5.0 golang.org/x/tools v0.18.0 gonum.org/v1/gonum v0.14.0 google.golang.org/grpc v1.59.0 - google.golang.org/protobuf v1.32.0 + google.golang.org/protobuf v1.33.0 gopkg.in/guregu/null.v4 v4.0.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 - gopkg.in/yaml.v3 v3.0.1 ) require ( @@ -132,11 +133,13 @@ require ( github.com/VictoriaMetrics/fastcache v1.12.1 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect + github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/benbjohnson/clock v1.3.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/bits-and-blooms/bitset v1.10.0 // indirect github.com/blendle/zapdriver v1.3.1 // indirect + github.com/buger/jsonparser v1.1.1 // indirect github.com/bytedance/sonic v1.10.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect @@ -189,7 +192,7 @@ require ( github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-playground/locales v0.14.1 // indirect @@ -204,11 +207,10 @@ require ( github.com/golang-jwt/jwt/v5 v5.2.0 // indirect github.com/golang/glog v1.1.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/btree v1.1.2 // indirect - github.com/google/go-cmp v0.6.0 // indirect - github.com/google/go-querystring v1.1.0 // indirect + github.com/google/go-cmp v0.6.0 github.com/google/go-tpm v0.9.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/gorilla/context v1.1.1 // indirect @@ -235,10 +237,11 @@ require ( github.com/huin/goupnp v1.3.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/invopop/jsonschema v0.12.0 github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.2 // indirect + github.com/jackc/pgproto3/v2 v2.3.3 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jmhodges/levigo v1.0.0 // indirect @@ -251,6 +254,7 @@ require ( github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect @@ -276,6 +280,7 @@ require ( github.com/rivo/uniseg v0.4.4 // indirect github.com/rs/zerolog v1.30.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 github.com/sasha-s/go-deadlock v0.3.1 // indirect github.com/sethvargo/go-retry v0.2.4 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect @@ -293,6 +298,7 @@ require ( github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect github.com/tendermint/go-amino v0.16.0 // indirect github.com/teris-io/shortid v0.0.0-20201117134242-e59966efd125 // indirect + github.com/test-go/testify v1.1.4 // indirect github.com/tidwall/btree v1.6.0 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect @@ -302,6 +308,7 @@ require ( github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/umbracle/fastrlp v0.0.0-20220527094140-59d5dd30e722 // indirect github.com/valyala/fastjson v1.4.1 // indirect + github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/zondax/hid v0.9.1 // indirect @@ -312,15 +319,15 @@ require ( go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 // indirect - go.opentelemetry.io/otel/metric v1.21.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/otel/sdk v1.21.0 // indirect - go.opentelemetry.io/otel/trace v1.21.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/ratelimit v0.3.0 // indirect golang.org/x/arch v0.7.0 // indirect golang.org/x/net v0.21.0 // indirect golang.org/x/oauth2 v0.17.0 // indirect - golang.org/x/sys v0.17.0 // indirect + golang.org/x/sys v0.18.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect google.golang.org/api v0.149.0 // indirect google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 // indirect @@ -329,10 +336,11 @@ require ( gopkg.in/guregu/null.v2 v2.1.2 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect nhooyr.io/websocket v1.8.7 // indirect pgregory.net/rapid v0.5.5 // indirect rsc.io/tmplfunc v0.0.3 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect + sigs.k8s.io/yaml v1.4.0 ) replace ( diff --git a/go.sum b/go.sum index b64249e2094..3bba85e2c95 100644 --- a/go.sum +++ b/go.sum @@ -113,6 +113,10 @@ github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/NethermindEth/juno v0.3.1 h1:AW72LiAm9gqUeCVJWvepnZcTnpU4Vkl0KzPMxS+42FA= +github.com/NethermindEth/juno v0.3.1/go.mod h1:SGbTpgGaCsxhFsKOid7Ylnz//WZ8swtILk+NbHGsk/Q= +github.com/NethermindEth/starknet.go v0.6.1-0.20231218140327-915109ab5bc1 h1:9SBvy3eZut1X+wEyAFqfb7ADGj8IQw7ZnlkMwz0YOTY= +github.com/NethermindEth/starknet.go v0.6.1-0.20231218140327-915109ab5bc1/go.mod h1:V6qrbi1+fTDCftETIT1grBXIf+TvWP/4Aois1a9EF1E= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -159,6 +163,8 @@ github.com/aws/aws-sdk-go v1.45.25/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8P github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -185,6 +191,7 @@ github.com/btcsuite/btcd/chaincfg/chainhash v1.0.3 h1:SDlJ7bAm4ewvrmZtR0DaiYbQGd github.com/btcsuite/btcd/chaincfg/chainhash v1.0.3/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= @@ -346,6 +353,8 @@ github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKoh github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucVPgCo= +github.com/dominikbraun/graph v0.23.0/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= @@ -468,8 +477,8 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= @@ -561,8 +570,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= @@ -588,8 +597,6 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= -github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= @@ -679,8 +686,8 @@ github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uM github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.14.1 h1:ZiwE2bKb+zro68sWzZ1SgHF3kRMBZ94TwOCFRF4ylPs= -github.com/hashicorp/consul/sdk v0.14.1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg= +github.com/hashicorp/consul/sdk v0.16.0 h1:SE9m0W6DEfgIVCJX7xU+iv/hUl4m/nxqMTnCdMxDpJ8= +github.com/hashicorp/consul/sdk v0.16.0/go.mod h1:7pxqqhqoaPqnBnzXD1StKed62LqJeClzVsUEy85Zr0A= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= @@ -760,6 +767,8 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI= +github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= @@ -775,9 +784,8 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= -github.com/jackc/pgconn v1.14.1 h1:smbxIaZA08n6YuxEX1sDyjV/qkbtUtkH20qLkR9MUR4= -github.com/jackc/pgconn v1.14.1/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= +github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w= +github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= @@ -793,8 +801,8 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.2 h1:7eY55bdBeCz1F2fTzSz69QC+pG46jYq9/jtSPiJ5nn0= -github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= +github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= @@ -808,15 +816,14 @@ github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08 github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0= -github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE= +github.com/jackc/pgx/v4 v4.18.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU= +github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= github.com/jackc/pgx/v5 v5.5.0 h1:NxstgwndsTRy7eq9/kqYc/BZh5w2hHJV86wjvO+1xPw= github.com/jackc/pgx/v5 v5.5.0/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= -github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= @@ -838,6 +845,7 @@ github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwA github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -910,6 +918,8 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= github.com/manyminds/api2go v0.0.0-20171030193247-e7b693844a6f h1:tVvGiZQFjOXP+9YyGqSA6jE55x1XVxmoPYudncxrZ8U= @@ -1138,6 +1148,8 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= @@ -1166,14 +1178,12 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= -github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCqR1LNS7aI3jT0V+xGrg= github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= -github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240311111125-22812a072c35 h1:GNhRKD3izyzAoGMXDvVUAwEuzz4Atdj3U3RH7eak5Is= -github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240311111125-22812a072c35/go.mod h1:2I0dWdYdK6jHPnSYYy7Y7Xp7L0YTnJ3KZtkhLQflsTU= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240314172156-049609b8e1f9 h1:rlvE17wHiSnrl2d42TWQ2VVx8ho8c9vgznysXj68sRU= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240314172156-049609b8e1f9/go.mod h1:/bJGelrpXvCcDCuaIgt91UN4B9YxZdK1O7VX5lzbysI= +github.com/smartcontractkit/chainlink-automation v1.0.2 h1:xsfyuswL15q2YBGQT3qn2SBz6fnSKiSW7XZ8IZQLpnI= +github.com/smartcontractkit/chainlink-automation v1.0.2/go.mod h1:RjboV0Qd7YP+To+OrzHGXaxUxoSONveCoAK2TQ1INLU= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240404141006-77085a02ce25 h1:fY2wMtlr/VQxPyVVQdi1jFvQHi0VbDnGGVXzLKOZTOY= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240404141006-77085a02ce25/go.mod h1:kstYjAGqBswdZpl7YkSPeXBDVwaY1VaR6tUMPWl8ykA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 h1:I326nw5GwHQHsLKHwtu5Sb9EBLylC8CfUd7BFAS0jtg= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8/go.mod h1:a65NtrK4xZb01mf0dDNghPkN2wXgcqFQ55ADthVBgMc= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= @@ -1182,16 +1192,16 @@ github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 h github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8/go.mod h1:vy1L7NybTy2F/Yv7BOh+oZBa1MACD6gzd1+DkcSkfp8= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e h1:k8HS3GsAFZnxXIW3141VsQP2+EL1XrTtOi/HDt7sdBE= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e/go.mod h1:JiykN+8W5TA4UD2ClrzQCVvcH3NcyLEVv7RwY0busrw= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240213121419-1272736c2ac0 h1:7m9PVtccb8/pvKTXMaGuyceFno1icRyC2SFH7KG7+70= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240213121419-1272736c2ac0/go.mod h1:SZ899lZYQ0maUulWbZg+SWqabHQ1wTbyk3jT8wJfyo8= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595 h1:y6ks0HsSOhPUueOmTcoxDQ50RCS1XINlRDTemZyHjFw= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595/go.mod h1:vV6WfnVIbK5Q1JsIru4YcTG0T1uRpLJm6t2BgCnCSsg= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= github.com/smartcontractkit/go-plugin v0.0.0-20240208201424-b3b91517de16 h1:TFe+FvzxClblt6qRfqEhUfa4kFQx5UobuoFGO2W4mMo= github.com/smartcontractkit/go-plugin v0.0.0-20240208201424-b3b91517de16/go.mod h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -github.com/smartcontractkit/libocr v0.0.0-20240229181116-bfb2432a7a66 h1:xsU00JB9GJxEiN6tDbqgN+fT98ySdxkUwTw6CfBXscw= -github.com/smartcontractkit/libocr v0.0.0-20240229181116-bfb2432a7a66/go.mod h1:SJEZCHgMCAzzBvo9vMV2DQ9onfEcIJCYSViyP4JI6c4= +github.com/smartcontractkit/libocr v0.0.0-20240326191951-2bbe9382d052 h1:1WFjrrVrWoQ9UpVMh7Mx4jDpzhmo1h8hFUKd9awIhIU= +github.com/smartcontractkit/libocr v0.0.0-20240326191951-2bbe9382d052/go.mod h1:SJEZCHgMCAzzBvo9vMV2DQ9onfEcIJCYSViyP4JI6c4= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ= @@ -1318,6 +1328,8 @@ github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+ github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vertica/vertica-sql-go v1.3.3 h1:fL+FKEAEy5ONmsvya2WH5T8bhkvY27y/Ik3ReR2T+Qw= github.com/vertica/vertica-sql-go v1.3.3/go.mod h1:jnn2GFuv+O2Jcjktb7zyc4Utlbu9YVqpHH/lx63+1M4= +github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= +github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -1374,26 +1386,26 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1 h1:mMv2jG58h6ZI5t5S9QCVGdzCmAsTakMa3oxVgpSD44g= -go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1/go.mod h1:oqRuNKG0upTaDPbLVCG8AD0G2ETrfDtmh7jViy7ox6M= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.49.0 h1:1f31+6grJmV3X4lxcEvUy13i5/kfDw1nJZwhd8mA4tg= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.49.0/go.mod h1:1P/02zM3OwkX9uki+Wmxw3a5GVb6KUXRsa7m7bOC9Fg= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= -go.opentelemetry.io/contrib/propagators/b3 v1.21.1 h1:WPYiUgmw3+b7b3sQ1bFBFAf0q+Di9dvNc3AtYfnT4RQ= -go.opentelemetry.io/contrib/propagators/b3 v1.21.1/go.mod h1:EmzokPoSqsYMBVK4nRnhsfm5mbn8J1eDuz/U1UaQaWg= -go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= -go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/contrib/propagators/b3 v1.24.0 h1:n4xwCdTx3pZqZs2CjS/CUZAs03y3dZcGhC/FepKtEUY= +go.opentelemetry.io/contrib/propagators/b3 v1.24.0/go.mod h1:k5wRxKRU2uXx2F8uNJ4TaonuEO/V7/5xoz7kdsDACT8= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0= -go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= -go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= go.opentelemetry.io/otel/sdk/metric v1.21.0 h1:smhI5oD714d6jHE6Tie36fPx4WDFIg+Y6RfAY4ICcR0= go.opentelemetry.io/otel/sdk/metric v1.21.0/go.mod h1:FJ8RAsoPGv/wYMgBdUJXOm+6pzFY3YdljnXtv1SBE8Q= -go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= -go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -1452,10 +1464,9 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1668,8 +1679,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1678,8 +1689,8 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= -golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1902,8 +1913,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1989,5 +2000,5 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/integration-tests/actions/automationv2/actions.go b/integration-tests/actions/automationv2/actions.go index 33caf6fbc0f..4ce56d9b870 100644 --- a/integration-tests/actions/automationv2/actions.go +++ b/integration-tests/actions/automationv2/actions.go @@ -79,8 +79,10 @@ type AutomationTest struct { NodeDetails []NodeDetails DefaultP2Pv2Bootstrapper string - MercuryCredentialName string + mercuryCredentialName string TransmitterKeyIndex int + + useLogBufferV1 bool } type UpkeepConfig struct { @@ -108,6 +110,8 @@ func NewAutomationTestK8s( IsOnk8s: true, TransmitterKeyIndex: 0, UpkeepPrivilegeManager: common.HexToAddress(chainClient.GetDefaultWallet().Address()), + mercuryCredentialName: "", + useLogBufferV1: false, } } @@ -123,6 +127,8 @@ func NewAutomationTestDocker( IsOnk8s: false, TransmitterKeyIndex: 0, UpkeepPrivilegeManager: common.HexToAddress(chainClient.GetDefaultWallet().Address()), + mercuryCredentialName: "", + useLogBufferV1: false, } } @@ -131,7 +137,11 @@ func (a *AutomationTest) SetIsOnk8s(flag bool) { } func (a *AutomationTest) SetMercuryCredentialName(name string) { - a.MercuryCredentialName = name + a.mercuryCredentialName = name +} + +func (a *AutomationTest) SetUseLogBufferV1(flag bool) { + a.useLogBufferV1 = flag } func (a *AutomationTest) SetTransmitterKeyIndex(index int) { @@ -381,6 +391,17 @@ func (a *AutomationTest) AddAutomationJobs() error { } else { return fmt.Errorf("v2.0, v2.1, and v2.2 are the only supported versions") } + pluginCfg := map[string]interface{}{ + "contractVersion": "\"" + contractVersion + "\"", + } + if strings.Contains(contractVersion, "v2.1") { + if a.mercuryCredentialName != "" { + pluginCfg["mercuryCredentialName"] = "\"" + a.mercuryCredentialName + "\"" + } + if a.useLogBufferV1 { + pluginCfg["useBufferV1"] = "true" + } + } for i := 1; i < len(a.ChainlinkNodes); i++ { autoOCR2JobSpec := client.OCR2TaskJobSpec{ Name: "automation-" + contractVersion + "-" + a.Registry.Address(), @@ -392,10 +413,7 @@ func (a *AutomationTest) AddAutomationJobs() error { RelayConfig: map[string]interface{}{ "chainID": int(a.ChainClient.GetChainID().Int64()), }, - PluginConfig: map[string]interface{}{ - "mercuryCredentialName": "\"" + a.MercuryCredentialName + "\"", - "contractVersion": "\"" + contractVersion + "\"", - }, + PluginConfig: pluginCfg, ContractConfigTrackerPollInterval: *models.NewInterval(time.Second * 15), TransmitterID: null.StringFrom(a.NodeDetails[i].TransmitterAddresses[a.TransmitterKeyIndex]), P2PV2Bootstrappers: pq.StringArray{a.DefaultP2Pv2Bootstrapper}, @@ -570,15 +588,7 @@ func calculateOCR3ConfigArgs(a *AutomationTest, S []int, oracleIdentities []conf offchainConfig []byte, err error, ) { - offC, _ := json.Marshal(ocr2keepers30config.OffchainConfig{ - TargetProbability: a.PluginConfig.TargetProbability, - TargetInRounds: a.PluginConfig.TargetInRounds, - PerformLockoutWindow: a.PluginConfig.PerformLockoutWindow, - GasLimitPerReport: a.PluginConfig.GasLimitPerReport, - GasOverheadPerUpkeep: a.PluginConfig.GasOverheadPerUpkeep, - MinConfirmations: a.PluginConfig.MinConfirmations, - MaxUpkeepBatchSize: a.PluginConfig.MaxUpkeepBatchSize, - }) + offC, _ := json.Marshal(a.PluginConfig) return ocr3.ContractSetConfigArgsForTests( a.PublicConfig.DeltaProgress, a.PublicConfig.DeltaResend, a.PublicConfig.DeltaInitial, @@ -671,7 +681,7 @@ func (a *AutomationTest) AddJobsAndSetConfig(t *testing.T) { err = a.AddAutomationJobs() require.NoError(t, err, "Error adding automation jobs") - l.Debug(). + l.Info(). Interface("Plugin Config", a.PluginConfig). Interface("Public Config", a.PublicConfig). Interface("Registry Settings", a.RegistrySettings). diff --git a/integration-tests/actions/private_network.go b/integration-tests/actions/private_network.go index 7f8bfe8bb2c..01a084b66d8 100644 --- a/integration-tests/actions/private_network.go +++ b/integration-tests/actions/private_network.go @@ -12,7 +12,7 @@ func EthereumNetworkConfigFromConfig(l zerolog.Logger, config tc.GlobalTestConfi l.Warn().Msg("No TOML private ethereum network config found, will use old geth") ethBuilder := ctf_test_env.NewEthereumNetworkBuilder() network, err = ethBuilder. - WithConsensusType(ctf_test_env.ConsensusType_PoW). + WithEthereumVersion(ctf_test_env.EthereumVersion_Eth1). WithExecutionLayer(ctf_test_env.ExecutionLayer_Geth). Build() diff --git a/integration-tests/actions/seth/actions.go b/integration-tests/actions/seth/actions.go index 8de166f0fce..d4bcbc7d867 100644 --- a/integration-tests/actions/seth/actions.go +++ b/integration-tests/actions/seth/actions.go @@ -116,7 +116,7 @@ func SendFunds(logger zerolog.Logger, client *seth.Client, payload FundsToSendPa return nil, err } - gasLimit := uint64(client.Cfg.Network.GasLimit) + gasLimit := uint64(client.Cfg.Network.TransferGasFee) if payload.GasLimit != nil { gasLimit = *payload.GasLimit } @@ -177,10 +177,10 @@ func SendFunds(logger zerolog.Logger, client *seth.Client, payload FundsToSendPa func DeployForwarderContracts( t *testing.T, seth *seth.Client, - linkTokenData seth.DeploymentData, + linkTokenAddress common.Address, numberOfOperatorForwarderPairs int, ) (operators []common.Address, authorizedForwarders []common.Address, operatorFactoryInstance contracts.OperatorFactory) { - instance, err := contracts.DeployEthereumOperatorFactory(seth, linkTokenData.Address) + instance, err := contracts.DeployEthereumOperatorFactory(seth, linkTokenAddress) require.NoError(t, err, "failed to create new instance of operator factory") operatorFactoryInstance = &instance @@ -209,10 +209,10 @@ func DeployForwarderContracts( return operators, authorizedForwarders, operatorFactoryInstance } -// WatchNewRound watches for a new OCR round, similarly to StartNewRound, but it does not explicitly request a new +// WatchNewOCRRound watches for a new OCR round, similarly to StartNewRound, but it does not explicitly request a new // round from the contract, as this can cause some odd behavior in some cases. It announces success if latest round // is >= roundNumber. -func WatchNewRound( +func WatchNewOCRRound( l zerolog.Logger, seth *seth.Client, roundNumber int64, @@ -291,13 +291,13 @@ func TrackForwarder( t *testing.T, seth *seth.Client, authorizedForwarder common.Address, - node *client.ChainlinkK8sClient, + node contracts.ChainlinkNodeWithForwarder, ) { l := logging.GetTestLogger(t) chainID := big.NewInt(seth.ChainID) _, _, err := node.TrackForwarder(chainID, authorizedForwarder) require.NoError(t, err, "Forwarder track should be created") - l.Info().Str("NodeURL", node.Config.URL). + l.Info().Str("NodeURL", node.GetConfig().URL). Str("ForwarderAddress", authorizedForwarder.Hex()). Str("ChaindID", chainID.String()). Msg("Forwarder tracked") @@ -574,3 +574,36 @@ func privateKeyToAddress(privateKey *ecdsa.PrivateKey) (common.Address, error) { } return crypto.PubkeyToAddress(*publicKeyECDSA), nil } + +func WatchNewFluxRound( + l zerolog.Logger, + seth *seth.Client, + roundNumber int64, + fluxInstance contracts.FluxAggregator, + timeout time.Duration, +) error { + timeoutC := time.After(timeout) + ticker := time.NewTicker(time.Millisecond * 200) + defer ticker.Stop() + + l.Info().Msgf("Waiting for flux round %d to be confirmed by flux aggregator", roundNumber) + + for { + select { + case <-timeoutC: + return fmt.Errorf("timeout waiting for round %d to be confirmed", roundNumber) + case <-ticker.C: + ctx, cancel := context.WithTimeout(context.Background(), seth.Cfg.Network.TxnTimeout.Duration()) + roundId, err := fluxInstance.LatestRoundID(ctx) + if err != nil { + cancel() + return fmt.Errorf("getting latest round from flux instance has failed: %w", err) + } + cancel() + if roundId.Cmp(big.NewInt(roundNumber)) >= 0 { + l.Debug().Msgf("Flux instance confirmed round %d", roundNumber) + return nil + } + } + } +} diff --git a/integration-tests/actions/seth/refund.go b/integration-tests/actions/seth/refund.go index e0f82f18aa1..4b267ffeeb9 100644 --- a/integration-tests/actions/seth/refund.go +++ b/integration-tests/actions/seth/refund.go @@ -11,6 +11,7 @@ import ( "strings" "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/pkg/errors" "github.com/rs/zerolog" @@ -50,7 +51,7 @@ func (r *InsufficientFundTransferRetrier) Retry(ctx context.Context, logger zero if r.nextRetrier != nil { logger.Debug(). Str("retier", "InsufficientFundTransferRetrier"). - Msg("Max gas limit reached. Passing to next retrier") + Msg("Max retries reached. Passing to next retrier") return r.nextRetrier.Retry(ctx, logger, client, txErr, payload, 0) } return txErr @@ -241,6 +242,8 @@ func ReturnFunds(log zerolog.Logger, seth *seth.Client, chainlinkNodes []contrac return nil } + failedReturns := []common.Address{} + for _, chainlinkNode := range chainlinkNodes { fundedKeys, err := chainlinkNode.ExportEVMKeysForChain(fmt.Sprint(seth.ChainID)) if err != nil { @@ -272,9 +275,9 @@ func ReturnFunds(log zerolog.Logger, seth *seth.Client, chainlinkNodes []contrac var totalGasCost *big.Int if seth.Cfg.Network.EIP1559DynamicFees { - totalGasCost = new(big.Int).Mul(big.NewInt(0).SetUint64(seth.Cfg.Network.GasLimit), big.NewInt(0).SetInt64(seth.Cfg.Network.GasFeeCap)) + totalGasCost = new(big.Int).Mul(big.NewInt(0).SetInt64(seth.Cfg.Network.TransferGasFee), big.NewInt(0).SetInt64(seth.Cfg.Network.GasFeeCap)) } else { - totalGasCost = new(big.Int).Mul(big.NewInt(0).SetUint64(seth.Cfg.Network.GasLimit), big.NewInt(0).SetInt64(seth.Cfg.Network.GasPrice)) + totalGasCost = new(big.Int).Mul(big.NewInt(0).SetInt64(seth.Cfg.Network.TransferGasFee), big.NewInt(0).SetInt64(seth.Cfg.Network.GasPrice)) } toSend := new(big.Int).Sub(balance, totalGasCost) @@ -286,17 +289,33 @@ func ReturnFunds(log zerolog.Logger, seth *seth.Client, chainlinkNodes []contrac Str("Balance", balance.String()). Str("To send", toSend.String()). Msg("Not enough balance to cover gas cost. Skipping return.") + + failedReturns = append(failedReturns, fromAddress) + continue } payload := FundsToSendPayload{ToAddress: seth.Addresses[0], Amount: toSend, PrivateKey: decryptedKey.PrivateKey} _, err = SendFunds(log, seth, payload) if err != nil { - handler := OvershotTransferRetrier{maxRetries: 3, nextRetrier: &InsufficientFundTransferRetrier{maxRetries: 3, nextRetrier: &GasTooLowTransferRetrier{maxGasLimit: seth.Cfg.Network.GasLimit * 3}}} - return handler.Retry(context.Background(), log, seth, err, payload, 0) + handler := OvershotTransferRetrier{maxRetries: 10, nextRetrier: &InsufficientFundTransferRetrier{maxRetries: 10, nextRetrier: &GasTooLowTransferRetrier{maxGasLimit: uint64(seth.Cfg.Network.TransferGasFee * 10)}}} + err = handler.Retry(context.Background(), log, seth, err, payload, 0) + if err != nil { + log.Error(). + Err(err). + Str("Address", fromAddress.String()). + Msg("Failed to return funds from Chainlink node to default network wallet") + failedReturns = append(failedReturns, fromAddress) + } } } } + if len(failedReturns) > 0 { + return fmt.Errorf("failed to return funds from Chainlink nodes to default network wallet for addresses: %v", failedReturns) + } + + log.Info().Msg("Successfully returned funds from all Chainlink nodes to default network wallets") + return nil } diff --git a/integration-tests/actions/vrf/common/actions.go b/integration-tests/actions/vrf/common/actions.go index 20d44e60de2..4af9fd05572 100644 --- a/integration-tests/actions/vrf/common/actions.go +++ b/integration-tests/actions/vrf/common/actions.go @@ -12,6 +12,7 @@ import ( "github.com/rs/zerolog" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" @@ -78,8 +79,13 @@ func SetupBHSNode( l zerolog.Logger, bhsNode *VRFNode, ) error { + evmClient, err := env.GetEVMClient(chainID.Int64()) + if err != nil { + return err + } + bhsTXKeyAddressStrings, _, err := CreateFundAndGetSendingKeys( - env.EVMClient, + evmClient, bhsNode, txKeyFunding, numberOfTxKeysToCreate, @@ -140,6 +146,86 @@ func CreateBHSJob( return job, nil } +func SetupBHFNode( + env *test_env.CLClusterTestEnv, + config *vrf_common_config.General, + numberOfTxKeysToCreate int, + chainID *big.Int, + coordinatorAddress string, + BHSAddress string, + batchBHSAddress string, + txKeyFunding float64, + l zerolog.Logger, + bhfNode *VRFNode, +) error { + evmClient, err := env.GetEVMClient(chainID.Int64()) + if err != nil { + return err + } + bhfTXKeyAddressStrings, _, err := CreateFundAndGetSendingKeys( + evmClient, + bhfNode, + txKeyFunding, + numberOfTxKeysToCreate, + chainID, + ) + if err != nil { + return err + } + bhfNode.TXKeyAddressStrings = bhfTXKeyAddressStrings + bhfSpec := client.BlockHeaderFeederJobSpec{ + ForwardingAllowed: false, + CoordinatorV2Address: coordinatorAddress, + CoordinatorV2PlusAddress: coordinatorAddress, + BlockhashStoreAddress: BHSAddress, + BatchBlockhashStoreAddress: batchBHSAddress, + FromAddresses: bhfTXKeyAddressStrings, + EVMChainID: chainID.String(), + WaitBlocks: *config.BHFJobWaitBlocks, + LookbackBlocks: *config.BHFJobLookBackBlocks, + PollPeriod: config.BHFJobPollPeriod.Duration, + RunTimeout: config.BHFJobRunTimeout.Duration, + } + l.Info().Msg("Creating BHF Job") + bhfJob, err := CreateBHFJob( + bhfNode.CLNode.API, + bhfSpec, + ) + if err != nil { + return fmt.Errorf("%s, err %w", "", err) + } + bhfNode.Job = bhfJob + return nil +} + +func CreateBHFJob( + chainlinkNode *client.ChainlinkClient, + bhfJobSpecConfig client.BlockHeaderFeederJobSpec, +) (*client.Job, error) { + jobUUID := uuid.New() + spec := &client.BlockHeaderFeederJobSpec{ + Name: fmt.Sprintf("bhf-%s", jobUUID), + ForwardingAllowed: bhfJobSpecConfig.ForwardingAllowed, + CoordinatorV2Address: bhfJobSpecConfig.CoordinatorV2Address, + CoordinatorV2PlusAddress: bhfJobSpecConfig.CoordinatorV2PlusAddress, + BlockhashStoreAddress: bhfJobSpecConfig.BlockhashStoreAddress, + BatchBlockhashStoreAddress: bhfJobSpecConfig.BatchBlockhashStoreAddress, + FromAddresses: bhfJobSpecConfig.FromAddresses, + EVMChainID: bhfJobSpecConfig.EVMChainID, + ExternalJobID: jobUUID.String(), + WaitBlocks: bhfJobSpecConfig.WaitBlocks, + LookbackBlocks: bhfJobSpecConfig.LookbackBlocks, + PollPeriod: bhfJobSpecConfig.PollPeriod, + RunTimeout: bhfJobSpecConfig.RunTimeout, + } + + job, err := chainlinkNode.MustCreateJob(spec) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrCreatingBHSJob, err) + } + return job, nil +} + func WaitForRequestCountEqualToFulfilmentCount( ctx context.Context, consumer VRFLoadTestConsumer, @@ -191,14 +277,17 @@ func retrieveLoadTestMetrics( metricsChannel <- metrics } -func CreateNodeTypeToNodeMap(cluster *test_env.ClCluster, nodesToCreate []VRFNodeType) map[VRFNodeType]*VRFNode { +func CreateNodeTypeToNodeMap(cluster *test_env.ClCluster, nodesToCreate []VRFNodeType) (map[VRFNodeType]*VRFNode, error) { var nodesMap = make(map[VRFNodeType]*VRFNode) + if len(cluster.Nodes) < len(nodesToCreate) { + return nil, fmt.Errorf("not enough nodes in the cluster (cluster size is %d nodes) to create %d nodes", len(cluster.Nodes), len(nodesToCreate)) + } for i, nodeType := range nodesToCreate { nodesMap[nodeType] = &VRFNode{ CLNode: cluster.Nodes[i], } } - return nodesMap + return nodesMap, nil } func CreateVRFKeyOnVRFNode(vrfNode *VRFNode, l zerolog.Logger) (*client.VRFKey, string, error) { @@ -216,3 +305,35 @@ func CreateVRFKeyOnVRFNode(vrfNode *VRFNode, l zerolog.Logger) (*client.VRFKey, Msg("VRF Key created on the Node") return vrfKey, pubKeyCompressed, nil } + +func FundNodesIfNeeded(ctx context.Context, existingEnvConfig *vrf_common_config.ExistingEnvConfig, client blockchain.EVMClient, l zerolog.Logger) error { + if *existingEnvConfig.NodeSendingKeyFundingMin > 0 { + for _, sendingKey := range existingEnvConfig.NodeSendingKeys { + address := common.HexToAddress(sendingKey) + sendingKeyBalance, err := client.BalanceAt(ctx, address) + if err != nil { + return err + } + fundingAtLeast := conversions.EtherToWei(big.NewFloat(*existingEnvConfig.NodeSendingKeyFundingMin)) + fundingToSendWei := new(big.Int).Sub(fundingAtLeast, sendingKeyBalance) + fundingToSendEth := conversions.WeiToEther(fundingToSendWei) + log := l.Info(). + Str("Sending Key", sendingKey). + Str("Sending Key Current Balance", sendingKeyBalance.String()). + Str("Should have at least", fundingAtLeast.String()) + if fundingToSendWei.Cmp(big.NewInt(0)) == 1 { + log. + Str("Funding Amount in ETH", fundingToSendEth.String()). + Msg("Funding Node's Sending Key") + err := actions.FundAddress(client, sendingKey, fundingToSendEth) + if err != nil { + return err + } + } else { + log. + Msg("Skipping Node's Sending Key funding as it has enough funds") + } + } + } + return nil +} diff --git a/integration-tests/actions/vrf/common/errors.go b/integration-tests/actions/vrf/common/errors.go index ba852a4c555..287403ecfdf 100644 --- a/integration-tests/actions/vrf/common/errors.go +++ b/integration-tests/actions/vrf/common/errors.go @@ -1,27 +1,28 @@ package common const ( - ErrNodePrimaryKey = "error getting node's primary ETH key" - ErrNodeNewTxKey = "error creating node's EVM transaction key" - ErrCreatingProvingKeyHash = "error creating a keyHash from the proving key" - ErrRegisteringProvingKey = "error registering a proving key on Coordinator contract" - ErrRegisterProvingKey = "error registering proving keys" - ErrEncodingProvingKey = "error encoding proving key" - ErrDeployBlockHashStore = "error deploying blockhash store" - ErrDeployCoordinator = "error deploying VRF CoordinatorV2" - ErrABIEncodingFunding = "error Abi encoding subscriptionID" - ErrSendingLinkToken = "error sending Link token" - ErrCreatingBHSJob = "error creating BHS job" - ErrParseJob = "error parsing job definition" - ErrSetVRFCoordinatorConfig = "error setting config for VRF Coordinator contract" - ErrCreateVRFSubscription = "error creating VRF Subscription" - ErrAddConsumerToSub = "error adding consumer to VRF Subscription" - ErrFundSubWithLinkToken = "error funding subscription with Link tokens" - ErrRestartCLNode = "error restarting CL node" - ErrWaitTXsComplete = "error waiting for TXs to complete" - ErrRequestRandomness = "error requesting randomness" - ErrLoadingCoordinator = "error loading coordinator contract" - ErrCreatingVRFKey = "error creating VRF key" + ErrNodePrimaryKey = "error getting node's primary ETH key" + ErrNodeNewTxKey = "error creating node's EVM transaction key" + ErrCreatingProvingKeyHash = "error creating a keyHash from the proving key" + ErrRegisteringProvingKey = "error registering a proving key on Coordinator contract" + ErrRegisterProvingKey = "error registering proving keys" + ErrEncodingProvingKey = "error encoding proving key" + ErrDeployBlockHashStore = "error deploying blockhash store" + ErrDeployBatchBlockHashStore = "error deploying batch blockhash store" + ErrDeployCoordinator = "error deploying VRF CoordinatorV2" + ErrABIEncodingFunding = "error Abi encoding subscriptionID" + ErrSendingLinkToken = "error sending Link token" + ErrCreatingBHSJob = "error creating BHS job" + ErrParseJob = "error parsing job definition" + ErrSetVRFCoordinatorConfig = "error setting config for VRF Coordinator contract" + ErrCreateVRFSubscription = "error creating VRF Subscription" + ErrAddConsumerToSub = "error adding consumer to VRF Subscription" + ErrFundSubWithLinkToken = "error funding subscription with Link tokens" + ErrRestartCLNode = "error restarting CL node" + ErrWaitTXsComplete = "error waiting for TXs to complete" + ErrRequestRandomness = "error requesting randomness" + ErrLoadingCoordinator = "error loading coordinator contract" + ErrCreatingVRFKey = "error creating VRF key" ErrWaitRandomWordsRequestedEvent = "error waiting for RandomWordsRequested event" ErrWaitRandomWordsFulfilledEvent = "error waiting for RandomWordsFulfilled event" diff --git a/integration-tests/actions/vrf/common/models.go b/integration-tests/actions/vrf/common/models.go index 177410d9606..d5c1c2b95b0 100644 --- a/integration-tests/actions/vrf/common/models.go +++ b/integration-tests/actions/vrf/common/models.go @@ -25,10 +25,11 @@ type VRFNodeType int const ( VRF VRFNodeType = iota + 1 BHS + BHF ) func (n VRFNodeType) String() string { - return [...]string{"VRF", "BHS"}[n-1] + return [...]string{"VRF", "BHS", "BHF"}[n-1] } func (n VRFNodeType) Index() int { @@ -46,8 +47,11 @@ type VRFContracts struct { CoordinatorV2Plus contracts.VRFCoordinatorV2_5 VRFOwner contracts.VRFOwner BHS contracts.BlockHashStore - VRFV2Consumer []contracts.VRFv2LoadTestConsumer + BatchBHS contracts.BatchBlockhashStore + VRFV2Consumers []contracts.VRFv2LoadTestConsumer VRFV2PlusConsumer []contracts.VRFv2PlusLoadTestConsumer + LinkToken contracts.LinkToken + MockETHLINKFeed contracts.VRFMockETHLINKFeed } type VRFOwnerConfig struct { @@ -74,3 +78,10 @@ type VRFJobSpecConfig struct { type VRFLoadTestConsumer interface { GetLoadTestMetrics(ctx context.Context) (*contracts.VRFLoadTestMetrics, error) } + +type NewEnvConfig struct { + NodesToCreate []VRFNodeType + NumberOfTxKeysToCreate int + UseVRFOwner bool + UseTestCoordinator bool +} diff --git a/integration-tests/actions/vrf/vrfv1/actions.go b/integration-tests/actions/vrf/vrfv1/actions.go index f8d7190709f..67110c543e5 100644 --- a/integration-tests/actions/vrf/vrfv1/actions.go +++ b/integration-tests/actions/vrf/vrfv1/actions.go @@ -3,7 +3,8 @@ package vrfv1 import ( "fmt" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/seth" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" ) @@ -19,21 +20,18 @@ type Contracts struct { Consumer contracts.VRFConsumer } -func DeployVRFContracts(cd contracts.ContractDeployer, bc blockchain.EVMClient, lt contracts.LinkToken) (*Contracts, error) { - bhs, err := cd.DeployBlockhashStore() +func DeployVRFContracts(client *seth.Client, linkTokenAddress string) (*Contracts, error) { + bhs, err := contracts.DeployBlockhashStore(client) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrDeployBHSV1, err) } - coordinator, err := cd.DeployVRFCoordinator(lt.Address(), bhs.Address()) + coordinator, err := contracts.DeployVRFCoordinator(client, linkTokenAddress, bhs.Address()) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrDeployVRFCootrinatorV1, err) } - consumer, err := cd.DeployVRFConsumer(lt.Address(), coordinator.Address()) + consumer, err := contracts.DeployVRFConsumer(client, linkTokenAddress, coordinator.Address()) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrDeployVRFConsumerV1, err) } - if err := bc.WaitForEvents(); err != nil { - return nil, err - } return &Contracts{bhs, coordinator, consumer}, nil } diff --git a/integration-tests/actions/vrf/vrfv2/vrfv2_steps.go b/integration-tests/actions/vrf/vrfv2/contract_steps.go similarity index 54% rename from integration-tests/actions/vrf/vrfv2/vrfv2_steps.go rename to integration-tests/actions/vrf/vrfv2/contract_steps.go index 121c259278a..46b84eb836b 100644 --- a/integration-tests/actions/vrf/vrfv2/vrfv2_steps.go +++ b/integration-tests/actions/vrf/vrfv2/contract_steps.go @@ -8,35 +8,26 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/rs/zerolog" - "golang.org/x/sync/errgroup" - - commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" - "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" - "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" - testconfig "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2" - "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_owner" - - "github.com/google/uuid" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" - + "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" "github.com/smartcontractkit/chainlink/integration-tests/actions" vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" - "github.com/smartcontractkit/chainlink/integration-tests/types" + testconfig "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2" + chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_owner" ) func DeployVRFV2Contracts( env *test_env.CLClusterTestEnv, + chainID int64, linkTokenContract contracts.LinkToken, - linkEthFeedContract contracts.MockETHLINKFeed, - consumerContractsAmount int, + linkEthFeedContract contracts.VRFMockETHLINKFeed, useVRFOwner bool, useTestCoordinator bool, ) (*vrfcommon.VRFContracts, error) { @@ -44,7 +35,13 @@ func DeployVRFV2Contracts( if err != nil { return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrDeployBlockHashStore, err) } - err = env.EVMClient.WaitForEvents() + + evmClient, err := env.GetEVMClient(chainID) + if err != nil { + return nil, err + } + + err = evmClient.WaitForEvents() if err != nil { return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } @@ -55,7 +52,7 @@ func DeployVRFV2Contracts( if err != nil { return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrDeployCoordinator, err) } - err = env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() if err != nil { return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } @@ -65,20 +62,12 @@ func DeployVRFV2Contracts( if err != nil { return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrDeployCoordinator, err) } - err = env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() if err != nil { return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } coordinatorAddress = coordinator.Address() } - consumers, err := DeployVRFV2Consumers(env.ContractDeployer, coordinatorAddress, consumerContractsAmount) - if err != nil { - return nil, err - } - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } coordinator, err := env.ContractLoader.LoadVRFCoordinatorV2(coordinatorAddress) if err != nil { @@ -89,22 +78,26 @@ func DeployVRFV2Contracts( if err != nil { return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrDeployCoordinator, err) } - err = env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() if err != nil { return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } return &vrfcommon.VRFContracts{ - CoordinatorV2: coordinator, - VRFOwner: vrfOwner, - BHS: bhs, - VRFV2Consumer: consumers, + CoordinatorV2: coordinator, + VRFOwner: vrfOwner, + BHS: bhs, + VRFV2Consumers: nil, + LinkToken: linkTokenContract, + MockETHLINKFeed: linkEthFeedContract, }, nil } return &vrfcommon.VRFContracts{ - CoordinatorV2: coordinator, - VRFOwner: nil, - BHS: bhs, - VRFV2Consumer: consumers, + CoordinatorV2: coordinator, + VRFOwner: nil, + BHS: bhs, + VRFV2Consumers: nil, + LinkToken: linkTokenContract, + MockETHLINKFeed: linkEthFeedContract, }, nil } @@ -160,53 +153,6 @@ func DeployVRFV2DirectFundingContracts( return &VRFV2WrapperContracts{vrfv2Wrapper, consumers}, nil } -func CreateVRFV2Job( - chainlinkNode *client.ChainlinkClient, - vrfJobSpecConfig vrfcommon.VRFJobSpecConfig, -) (*client.Job, error) { - jobUUID := uuid.New() - os := &client.VRFV2TxPipelineSpec{ - Address: vrfJobSpecConfig.CoordinatorAddress, - EstimateGasMultiplier: vrfJobSpecConfig.EstimateGasMultiplier, - FromAddress: vrfJobSpecConfig.FromAddresses[0], - SimulationBlock: vrfJobSpecConfig.SimulationBlock, - } - ost, err := os.String() - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrParseJob, err) - } - - spec := &client.VRFV2JobSpec{ - Name: fmt.Sprintf("vrf-v2-%s", jobUUID), - ForwardingAllowed: vrfJobSpecConfig.ForwardingAllowed, - CoordinatorAddress: vrfJobSpecConfig.CoordinatorAddress, - FromAddresses: vrfJobSpecConfig.FromAddresses, - EVMChainID: vrfJobSpecConfig.EVMChainID, - MinIncomingConfirmations: vrfJobSpecConfig.MinIncomingConfirmations, - PublicKey: vrfJobSpecConfig.PublicKey, - ExternalJobID: jobUUID.String(), - ObservationSource: ost, - BatchFulfillmentEnabled: vrfJobSpecConfig.BatchFulfillmentEnabled, - BatchFulfillmentGasMultiplier: vrfJobSpecConfig.BatchFulfillmentGasMultiplier, - PollPeriod: vrfJobSpecConfig.PollPeriod, - RequestTimeout: vrfJobSpecConfig.RequestTimeout, - } - if vrfJobSpecConfig.VRFOwnerConfig.UseVRFOwner { - spec.VRFOwner = vrfJobSpecConfig.VRFOwnerConfig.OwnerAddress - spec.UseVRFOwner = true - } - - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrParseJob, err) - - } - job, err := chainlinkNode.MustCreateJob(spec) - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2Job, err) - } - return job, nil -} - func VRFV2RegisterProvingKey( vrfKey *client.VRFKey, oracleAddress string, @@ -226,216 +172,27 @@ func VRFV2RegisterProvingKey( return provingKey, nil } -func FundVRFCoordinatorV2Subscription( - linkToken contracts.LinkToken, - coordinator contracts.VRFCoordinatorV2, - chainClient blockchain.EVMClient, - subscriptionID uint64, - linkFundingAmountJuels *big.Int, -) error { - encodedSubId, err := chainlinkutils.ABIEncode(`[{"type":"uint64"}]`, subscriptionID) - if err != nil { - return fmt.Errorf("%s, err %w", vrfcommon.ErrABIEncodingFunding, err) - } - _, err = linkToken.TransferAndCall(coordinator.Address(), linkFundingAmountJuels, encodedSubId) - if err != nil { - return fmt.Errorf("%s, err %w", vrfcommon.ErrSendingLinkToken, err) - } - return chainClient.WaitForEvents() -} - -// SetupVRFV2Environment will create specified number of subscriptions and add the same conumer/s to each of them -func SetupVRFV2Environment( - env *test_env.CLClusterTestEnv, - nodesToCreate []vrfcommon.VRFNodeType, - vrfv2TestConfig types.VRFv2TestConfig, - useVRFOwner bool, - useTestCoordinator bool, - linkToken contracts.LinkToken, - mockNativeLINKFeed contracts.MockETHLINKFeed, - registerProvingKeyAgainstAddress string, - numberOfTxKeysToCreate int, - numberOfConsumers int, - numberOfSubToCreate int, - l zerolog.Logger, -) (*vrfcommon.VRFContracts, []uint64, *vrfcommon.VRFKeyData, map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode, error) { - l.Info().Msg("Starting VRFV2 environment setup") - configGeneral := vrfv2TestConfig.GetVRFv2Config().General - vrfContracts, subIDs, err := SetupVRFV2Contracts( - env, - linkToken, - mockNativeLINKFeed, - numberOfConsumers, - useVRFOwner, - useTestCoordinator, - configGeneral, - numberOfSubToCreate, - l, - ) - if err != nil { - return nil, nil, nil, nil, err - } - - nodeTypeToNodeMap := vrfcommon.CreateNodeTypeToNodeMap(env.ClCluster, nodesToCreate) - vrfKey, pubKeyCompressed, err := vrfcommon.CreateVRFKeyOnVRFNode(nodeTypeToNodeMap[vrfcommon.VRF], l) - if err != nil { - return nil, nil, nil, nil, err - } - - l.Info().Str("Coordinator", vrfContracts.CoordinatorV2.Address()).Msg("Registering Proving Key") - provingKey, err := VRFV2RegisterProvingKey(vrfKey, registerProvingKeyAgainstAddress, vrfContracts.CoordinatorV2) - if err != nil { - return nil, nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrRegisteringProvingKey, err) - } - keyHash, err := vrfContracts.CoordinatorV2.HashOfKey(context.Background(), provingKey) - if err != nil { - return nil, nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrCreatingProvingKeyHash, err) - } - - chainID := env.EVMClient.GetChainID() - vrfTXKeyAddressStrings, vrfTXKeyAddresses, err := vrfcommon.CreateFundAndGetSendingKeys( - env.EVMClient, - nodeTypeToNodeMap[vrfcommon.VRF], - *vrfv2TestConfig.GetCommonConfig().ChainlinkNodeFunding, - numberOfTxKeysToCreate, - chainID, - ) - if err != nil { - return nil, nil, nil, nil, err - } - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - - nodeTypeToNodeMap[vrfcommon.VRF].TXKeyAddressStrings = vrfTXKeyAddressStrings - - var vrfOwnerConfig *vrfcommon.VRFOwnerConfig - if useVRFOwner { - err := setupVRFOwnerContract(env, vrfContracts, vrfTXKeyAddressStrings, vrfTXKeyAddresses, l) - if err != nil { - return nil, nil, nil, nil, err - } - vrfOwnerConfig = &vrfcommon.VRFOwnerConfig{ - OwnerAddress: vrfContracts.VRFOwner.Address(), - UseVRFOwner: useVRFOwner, - } - } else { - vrfOwnerConfig = &vrfcommon.VRFOwnerConfig{ - OwnerAddress: "", - UseVRFOwner: useVRFOwner, - } - } - - g := errgroup.Group{} - if vrfNode, exists := nodeTypeToNodeMap[vrfcommon.VRF]; exists { - g.Go(func() error { - err := setupVRFNode(vrfContracts, chainID, configGeneral, pubKeyCompressed, vrfOwnerConfig, l, vrfNode) - if err != nil { - return err - } - return nil - }) - } - - if bhsNode, exists := nodeTypeToNodeMap[vrfcommon.BHS]; exists { - g.Go(func() error { - err := vrfcommon.SetupBHSNode( - env, - configGeneral.General, - numberOfTxKeysToCreate, - chainID, - vrfContracts.CoordinatorV2.Address(), - vrfContracts.BHS.Address(), - *vrfv2TestConfig.GetCommonConfig().ChainlinkNodeFunding, - l, - bhsNode, - ) - if err != nil { - return err - } - return nil - }) - } - - if err := g.Wait(); err != nil { - return nil, nil, nil, nil, fmt.Errorf("VRF node setup ended up with an error: %w", err) - } - - vrfKeyData := vrfcommon.VRFKeyData{ - VRFKey: vrfKey, - EncodedProvingKey: provingKey, - KeyHash: keyHash, - } - - l.Info().Msg("VRFV2 environment setup is finished") - return vrfContracts, subIDs, &vrfKeyData, nodeTypeToNodeMap, nil -} - -func setupVRFNode(contracts *vrfcommon.VRFContracts, chainID *big.Int, vrfv2Config *testconfig.General, pubKeyCompressed string, vrfOwnerConfig *vrfcommon.VRFOwnerConfig, l zerolog.Logger, vrfNode *vrfcommon.VRFNode) error { - vrfJobSpecConfig := vrfcommon.VRFJobSpecConfig{ - ForwardingAllowed: *vrfv2Config.VRFJobForwardingAllowed, - CoordinatorAddress: contracts.CoordinatorV2.Address(), - FromAddresses: vrfNode.TXKeyAddressStrings, - EVMChainID: chainID.String(), - MinIncomingConfirmations: int(*vrfv2Config.MinimumConfirmations), - PublicKey: pubKeyCompressed, - EstimateGasMultiplier: *vrfv2Config.VRFJobEstimateGasMultiplier, - BatchFulfillmentEnabled: *vrfv2Config.VRFJobBatchFulfillmentEnabled, - BatchFulfillmentGasMultiplier: *vrfv2Config.VRFJobBatchFulfillmentGasMultiplier, - PollPeriod: vrfv2Config.VRFJobPollPeriod.Duration, - RequestTimeout: vrfv2Config.VRFJobRequestTimeout.Duration, - SimulationBlock: vrfv2Config.VRFJobSimulationBlock, - VRFOwnerConfig: vrfOwnerConfig, - } - - l.Info().Msg("Creating VRFV2 Job") - vrfV2job, err := CreateVRFV2Job( - vrfNode.CLNode.API, - vrfJobSpecConfig, - ) - if err != nil { - return fmt.Errorf("%s, err %w", ErrCreateVRFV2Jobs, err) - } - vrfNode.Job = vrfV2job - - // this part is here because VRFv2 can work with only a specific key - // [[EVM.KeySpecific]] - // Key = '...' - nodeConfig := node.NewConfig(vrfNode.CLNode.NodeConfig, - node.WithLogPollInterval(1*time.Second), - node.WithVRFv2EVMEstimator(vrfNode.TXKeyAddressStrings, *vrfv2Config.CLNodeMaxGasPriceGWei), - ) - l.Info().Msg("Restarting Node with new sending key PriceMax configuration") - err = vrfNode.CLNode.Restart(nodeConfig) - if err != nil { - return fmt.Errorf("%s, err %w", vrfcommon.ErrRestartCLNode, err) - } - return nil -} - func SetupVRFV2Contracts( env *test_env.CLClusterTestEnv, + chainID int64, linkToken contracts.LinkToken, - mockNativeLINKFeed contracts.MockETHLINKFeed, - numberOfConsumers int, + mockNativeLINKFeed contracts.VRFMockETHLINKFeed, useVRFOwner bool, useTestCoordinator bool, vrfv2Config *testconfig.General, - numberOfSubToCreate int, l zerolog.Logger, -) (*vrfcommon.VRFContracts, []uint64, error) { +) (*vrfcommon.VRFContracts, error) { l.Info().Msg("Deploying VRFV2 contracts") vrfContracts, err := DeployVRFV2Contracts( env, + chainID, linkToken, mockNativeLINKFeed, - numberOfConsumers, useVRFOwner, useTestCoordinator, ) if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrDeployVRFV2Contracts, err) + return nil, fmt.Errorf("%s, err %w", ErrDeployVRFV2Contracts, err) } vrfCoordinatorV2FeeConfig := vrf_coordinator_v2.VRFCoordinatorV2FeeConfig{ @@ -459,28 +216,22 @@ func SetupVRFV2Contracts( vrfCoordinatorV2FeeConfig, ) if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrSetVRFCoordinatorConfig, err) + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrSetVRFCoordinatorConfig, err) } - err = env.EVMClient.WaitForEvents() + + evmClient, err := env.GetEVMClient(chainID) if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + return nil, err } - l.Info(). - Str("Coordinator", vrfContracts.CoordinatorV2.Address()). - Int("Number of Subs to create", numberOfSubToCreate). - Msg("Creating and funding subscriptions, adding consumers") - subIDs, err := CreateFundSubsAndAddConsumers( - env, - big.NewFloat(*vrfv2Config.SubscriptionFundingAmountLink), - linkToken, - vrfContracts.CoordinatorV2, vrfContracts.VRFV2Consumer, numberOfSubToCreate) + + err = evmClient.WaitForEvents() if err != nil { - return nil, nil, err + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } - return vrfContracts, subIDs, nil + return vrfContracts, nil } -func setupVRFOwnerContract(env *test_env.CLClusterTestEnv, contracts *vrfcommon.VRFContracts, allNativeTokenKeyAddressStrings []string, allNativeTokenKeyAddresses []common.Address, l zerolog.Logger) error { +func setupVRFOwnerContract(env *test_env.CLClusterTestEnv, chainID int64, contracts *vrfcommon.VRFContracts, allNativeTokenKeyAddressStrings []string, allNativeTokenKeyAddresses []common.Address, l zerolog.Logger) error { l.Info().Msg("Setting up VRFOwner contract") l.Info(). Str("Coordinator", contracts.CoordinatorV2.Address()). @@ -490,7 +241,12 @@ func setupVRFOwnerContract(env *test_env.CLClusterTestEnv, contracts *vrfcommon. if err != nil { return nil } - err = env.EVMClient.WaitForEvents() + evmClient, err := env.GetEVMClient(chainID) + if err != nil { + return err + } + + err = evmClient.WaitForEvents() if err != nil { return nil } @@ -501,7 +257,7 @@ func setupVRFOwnerContract(env *test_env.CLClusterTestEnv, contracts *vrfcommon. if err != nil { return nil } - err = env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() if err != nil { return nil } @@ -513,98 +269,23 @@ func setupVRFOwnerContract(env *test_env.CLClusterTestEnv, contracts *vrfcommon. if err != nil { return nil } - err = env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() if err != nil { return fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } return err } -func SetupVRFV2WrapperEnvironment( - env *test_env.CLClusterTestEnv, - vrfv2TestConfig tc.VRFv2TestConfig, - linkToken contracts.LinkToken, - mockNativeLINKFeed contracts.MockETHLINKFeed, - coordinator contracts.VRFCoordinatorV2, - keyHash [32]byte, - wrapperConsumerContractsAmount int, -) (*VRFV2WrapperContracts, *uint64, error) { - // Deploy VRF v2 direct funding contracts - wrapperContracts, err := DeployVRFV2DirectFundingContracts( - env.ContractDeployer, - env.EVMClient, - linkToken.Address(), - mockNativeLINKFeed.Address(), - coordinator, - wrapperConsumerContractsAmount, - ) - if err != nil { - return nil, nil, err - } - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - - vrfv2Config := vrfv2TestConfig.GetVRFv2Config() - - // Configure VRF v2 wrapper contract - err = wrapperContracts.VRFV2Wrapper.SetConfig( - *vrfv2Config.General.WrapperGasOverhead, - *vrfv2Config.General.CoordinatorGasOverhead, - *vrfv2Config.General.WrapperPremiumPercentage, - keyHash, - *vrfv2Config.General.WrapperMaxNumberOfWords, - ) - if err != nil { - return nil, nil, err - } - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - - // Fetch wrapper subscription ID - wrapperSubID, err := wrapperContracts.VRFV2Wrapper.GetSubID(context.Background()) - if err != nil { - return nil, nil, err - } - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - - // Fund wrapper subscription - err = FundSubscriptions(env, big.NewFloat(*vrfv2Config.General.SubscriptionFundingAmountLink), linkToken, coordinator, []uint64{wrapperSubID}) - if err != nil { - return nil, nil, err - } - - // Fund consumer with LINK - err = linkToken.Transfer( - wrapperContracts.LoadTestConsumers[0].Address(), - big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(*vrfv2Config.General.WrapperConsumerFundingAmountLink)), - ) - if err != nil { - return nil, nil, err - } - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - - return wrapperContracts, &wrapperSubID, nil -} - func CreateFundSubsAndAddConsumers( env *test_env.CLClusterTestEnv, + chainID int64, subscriptionFundingAmountLink *big.Float, linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV2, consumers []contracts.VRFv2LoadTestConsumer, numberOfSubToCreate int, ) ([]uint64, error) { - subIDs, err := CreateSubsAndFund(env, subscriptionFundingAmountLink, linkToken, coordinator, numberOfSubToCreate) + subIDs, err := CreateSubsAndFund(env, chainID, subscriptionFundingAmountLink, linkToken, coordinator, numberOfSubToCreate) if err != nil { return nil, err } @@ -623,7 +304,12 @@ func CreateFundSubsAndAddConsumers( return nil, err } - err = env.EVMClient.WaitForEvents() + evmClient, err := env.GetEVMClient(chainID) + if err != nil { + return nil, err + } + + err = evmClient.WaitForEvents() if err != nil { return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } @@ -632,20 +318,26 @@ func CreateFundSubsAndAddConsumers( func CreateSubsAndFund( env *test_env.CLClusterTestEnv, + chainID int64, subscriptionFundingAmountLink *big.Float, linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV2, subAmountToCreate int, ) ([]uint64, error) { - subs, err := CreateSubs(env, coordinator, subAmountToCreate) + subs, err := CreateSubs(env, chainID, coordinator, subAmountToCreate) + if err != nil { + return nil, err + } + evmClient, err := env.GetEVMClient(chainID) if err != nil { return nil, err } - err = env.EVMClient.WaitForEvents() + + err = evmClient.WaitForEvents() if err != nil { return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } - err = FundSubscriptions(env, subscriptionFundingAmountLink, linkToken, coordinator, subs) + err = FundSubscriptions(env, chainID, subscriptionFundingAmountLink, linkToken, coordinator, subs) if err != nil { return nil, err } @@ -654,13 +346,14 @@ func CreateSubsAndFund( func CreateSubs( env *test_env.CLClusterTestEnv, + chainID int64, coordinator contracts.VRFCoordinatorV2, subAmountToCreate int, ) ([]uint64, error) { var subIDArr []uint64 for i := 0; i < subAmountToCreate; i++ { - subID, err := CreateSubAndFindSubID(env, coordinator) + subID, err := CreateSubAndFindSubID(env, chainID, coordinator) if err != nil { return nil, err } @@ -684,17 +377,22 @@ func AddConsumersToSubs( return nil } -func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, coordinator contracts.VRFCoordinatorV2) (uint64, error) { +func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, chainID int64, coordinator contracts.VRFCoordinatorV2) (uint64, error) { tx, err := coordinator.CreateSubscription() if err != nil { return 0, fmt.Errorf("%s, err %w", vrfcommon.ErrCreateVRFSubscription, err) } - err = env.EVMClient.WaitForEvents() + evmClient, err := env.GetEVMClient(chainID) + if err != nil { + return 0, err + } + + err = evmClient.WaitForEvents() if err != nil { return 0, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } - receipt, err := env.EVMClient.GetTxReceipt(tx.Hash()) + receipt, err := evmClient.GetTxReceipt(tx.Hash()) if err != nil { return 0, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } @@ -707,26 +405,50 @@ func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, coordinator contracts func FundSubscriptions( env *test_env.CLClusterTestEnv, + chainID int64, subscriptionFundingAmountLink *big.Float, linkAddress contracts.LinkToken, coordinator contracts.VRFCoordinatorV2, subIDs []uint64, ) error { + evmClient, err := env.GetEVMClient(chainID) + if err != nil { + return err + } + for _, subID := range subIDs { //Link Billing amountJuels := conversions.EtherToWei(subscriptionFundingAmountLink) - err := FundVRFCoordinatorV2Subscription(linkAddress, coordinator, env.EVMClient, subID, amountJuels) + err := FundVRFCoordinatorV2Subscription(linkAddress, coordinator, evmClient, subID, amountJuels) if err != nil { return fmt.Errorf("%s, err %w", vrfcommon.ErrFundSubWithLinkToken, err) } } - err := env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() if err != nil { return fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) } return nil } +func FundVRFCoordinatorV2Subscription( + linkToken contracts.LinkToken, + coordinator contracts.VRFCoordinatorV2, + chainClient blockchain.EVMClient, + subscriptionID uint64, + linkFundingAmountJuels *big.Int, +) error { + encodedSubId, err := chainlinkutils.ABIEncode(`[{"type":"uint64"}]`, subscriptionID) + if err != nil { + return fmt.Errorf("%s, err %w", vrfcommon.ErrABIEncodingFunding, err) + } + _, err = linkToken.TransferAndCall(coordinator.Address(), linkFundingAmountJuels, encodedSubId) + if err != nil { + return fmt.Errorf("%s, err %w", vrfcommon.ErrSendingLinkToken, err) + } + return chainClient.WaitForEvents() +} + func DirectFundingRequestRandomnessAndWaitForFulfillment( l zerolog.Logger, consumer contracts.VRFv2WrapperLoadTestConsumer, @@ -740,8 +462,20 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( randomnessRequestCountPerRequestDeviation uint16, randomWordsFulfilledEventTimeout time.Duration, ) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) { - logRandRequest(l, consumer.Address(), coordinator.Address(), subID, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation) - _, err := consumer.RequestRandomness( + logRandRequest( + l, + consumer.Address(), + coordinator.Address(), + subID, + minimumConfirmations, + callbackGasLimit, + numberOfWords, + randomnessRequestCountPerRequest, + randomnessRequestCountPerRequestDeviation, + vrfv2KeyData.KeyHash, + ) + randomWordsRequestedEvent, err := consumer.RequestRandomness( + coordinator, minimumConfirmations, callbackGasLimit, numberOfWords, @@ -750,15 +484,9 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( if err != nil { return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrRequestRandomness, err) } - wrapperAddress, err := consumer.GetWrapper(context.Background()) - if err != nil { - return nil, fmt.Errorf("error getting wrapper address, err: %w", err) - } - fulfillmentEvents, err := WaitForRequestAndFulfillmentEvents( - wrapperAddress.String(), + fulfillmentEvents, err := WaitRandomWordsFulfilledEvent( coordinator, - vrfv2KeyData, - subID, + randomWordsRequestedEvent.RequestId, randomWordsFulfilledEventTimeout, l, ) @@ -778,28 +506,72 @@ func RequestRandomnessAndWaitForFulfillment( randomnessRequestCountPerRequestDeviation uint16, randomWordsFulfilledEventTimeout time.Duration, ) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) { - logRandRequest(l, consumer.Address(), coordinator.Address(), subID, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation) - _, err := consumer.RequestRandomness( - vrfKeyData.KeyHash, + randomWordsRequestedEvent, err := RequestRandomness( + l, + consumer, + coordinator, subID, + vrfKeyData, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, + randomnessRequestCountPerRequestDeviation, ) if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrRequestRandomness, err) + return nil, err + } + fulfillmentEvents, err := WaitRandomWordsFulfilledEvent( + coordinator, + randomWordsRequestedEvent.RequestId, + randomWordsFulfilledEventTimeout, + l, + ) + if err != nil { + return nil, err } + return fulfillmentEvents, nil +} - fulfillmentEvents, err := WaitForRequestAndFulfillmentEvents( +func RequestRandomness( + l zerolog.Logger, + consumer contracts.VRFv2LoadTestConsumer, + coordinator contracts.VRFCoordinatorV2, + subID uint64, + vrfKeyData *vrfcommon.VRFKeyData, + minimumConfirmations uint16, + callbackGasLimit uint32, + numberOfWords uint32, + randomnessRequestCountPerRequest uint16, + randomnessRequestCountPerRequestDeviation uint16, +) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) { + logRandRequest( + l, consumer.Address(), + coordinator.Address(), + subID, + minimumConfirmations, + callbackGasLimit, + numberOfWords, + randomnessRequestCountPerRequest, + randomnessRequestCountPerRequestDeviation, + vrfKeyData.KeyHash, + ) + randomWordsRequestedEvent, err := consumer.RequestRandomness( coordinator, - vrfKeyData, + vrfKeyData.KeyHash, subID, - randomWordsFulfilledEventTimeout, - l, + minimumConfirmations, + callbackGasLimit, + numberOfWords, + randomnessRequestCountPerRequest, ) - return fulfillmentEvents, err + if err != nil { + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrRequestRandomness, err) + } + LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent) + + return randomWordsRequestedEvent, err } func RequestRandomnessWithForceFulfillAndWaitForFulfillment( @@ -817,7 +589,7 @@ func RequestRandomnessWithForceFulfillAndWaitForFulfillment( linkAddress common.Address, randomWordsFulfilledEventTimeout time.Duration, ) (*vrf_coordinator_v2.VRFCoordinatorV2ConfigSet, *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, *vrf_owner.VRFOwnerRandomWordsForced, error) { - logRandRequest(l, consumer.Address(), coordinator.Address(), 0, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation) + logRandRequest(l, consumer.Address(), coordinator.Address(), 0, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation, vrfv2KeyData.KeyHash) _, err := consumer.RequestRandomWordsWithForceFulfill( vrfv2KeyData.KeyHash, minimumConfirmations, @@ -903,27 +675,14 @@ func RequestRandomnessWithForceFulfillAndWaitForFulfillment( return configSetEvent, randomWordsFulfilledEvent, randomWordsForcedEvent, err } -func WaitForRequestAndFulfillmentEvents( - consumerAddress string, +func WaitRandomWordsFulfilledEvent( coordinator contracts.VRFCoordinatorV2, - vrfv2KeyData *vrfcommon.VRFKeyData, - subID uint64, + requestId *big.Int, randomWordsFulfilledEventTimeout time.Duration, l zerolog.Logger, ) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) { - randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( - [][32]byte{vrfv2KeyData.KeyHash}, - []uint64{subID}, - []common.Address{common.HexToAddress(consumerAddress)}, - time.Minute*1, - ) - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitRandomWordsRequestedEvent, err) - } - LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent) - randomWordsFulfilledEvent, err := coordinator.WaitForRandomWordsFulfilledEvent( - []*big.Int{randomWordsRequestedEvent.RequestId}, + []*big.Int{requestId}, randomWordsFulfilledEventTimeout, ) if err != nil { @@ -933,85 +692,84 @@ func WaitForRequestAndFulfillmentEvents( return randomWordsFulfilledEvent, err } -func LogSubDetails(l zerolog.Logger, subscription vrf_coordinator_v2.GetSubscription, subID uint64, coordinator contracts.VRFCoordinatorV2) { - l.Debug(). - Str("Coordinator", coordinator.Address()). - Str("Link Balance", (*commonassets.Link)(subscription.Balance).Link()). - Uint64("Subscription ID", subID). - Str("Subscription Owner", subscription.Owner.String()). - Interface("Subscription Consumers", subscription.Consumers). - Msg("Subscription Data") +func SetupVRFOwnerContractIfNeeded(useVRFOwner bool, env *test_env.CLClusterTestEnv, chainID int64, vrfContracts *vrfcommon.VRFContracts, vrfTXKeyAddressStrings []string, vrfTXKeyAddresses []common.Address, l zerolog.Logger) (*vrfcommon.VRFOwnerConfig, error) { + var vrfOwnerConfig *vrfcommon.VRFOwnerConfig + if useVRFOwner { + err := setupVRFOwnerContract(env, chainID, vrfContracts, vrfTXKeyAddressStrings, vrfTXKeyAddresses, l) + if err != nil { + return nil, err + } + vrfOwnerConfig = &vrfcommon.VRFOwnerConfig{ + OwnerAddress: vrfContracts.VRFOwner.Address(), + UseVRFOwner: useVRFOwner, + } + } else { + vrfOwnerConfig = &vrfcommon.VRFOwnerConfig{ + OwnerAddress: "", + UseVRFOwner: useVRFOwner, + } + } + return vrfOwnerConfig, nil } -func LogRandomnessRequestedEvent( - l zerolog.Logger, +func SetupNewConsumersAndSubs( + env *test_env.CLClusterTestEnv, + chainID int64, coordinator contracts.VRFCoordinatorV2, - randomWordsRequestedEvent *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, -) { - l.Info(). - Str("Coordinator", coordinator.Address()). - Str("Request ID", randomWordsRequestedEvent.RequestId.String()). - Uint64("Subscription ID", randomWordsRequestedEvent.SubId). - Str("Sender Address", randomWordsRequestedEvent.Sender.String()). - Str("Keyhash", fmt.Sprintf("0x%x", randomWordsRequestedEvent.KeyHash)). - Uint32("Callback Gas Limit", randomWordsRequestedEvent.CallbackGasLimit). - Uint32("Number of Words", randomWordsRequestedEvent.NumWords). - Uint16("Minimum Request Confirmations", randomWordsRequestedEvent.MinimumRequestConfirmations). - Str("TX Hash", randomWordsRequestedEvent.Raw.TxHash.String()). - Uint64("BlockNumber", randomWordsRequestedEvent.Raw.BlockNumber). - Str("BlockHash", randomWordsRequestedEvent.Raw.BlockHash.String()). - Msg("RandomnessRequested Event") -} - -func LogRandomWordsFulfilledEvent( + testConfig tc.TestConfig, + linkToken contracts.LinkToken, + numberOfConsumerContractsToDeployAndAddToSub int, + numberOfSubToCreate int, l zerolog.Logger, - coordinator contracts.VRFCoordinatorV2, - randomWordsFulfilledEvent *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, -) { +) ([]contracts.VRFv2LoadTestConsumer, []uint64, error) { + consumers, err := DeployVRFV2Consumers(env.ContractDeployer, coordinator.Address(), numberOfConsumerContractsToDeployAndAddToSub) + if err != nil { + return nil, nil, fmt.Errorf("err: %w", err) + } + evmClient, err := env.GetEVMClient(chainID) + if err != nil { + return nil, []uint64{}, err + } + err = evmClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err: %w", vrfcommon.ErrWaitTXsComplete, err) + } l.Info(). - Str("Coordinator", coordinator.Address()). - Str("Total Payment", randomWordsFulfilledEvent.Payment.String()). - Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). - Str("Request ID", randomWordsFulfilledEvent.RequestId.String()). - Bool("Success", randomWordsFulfilledEvent.Success). - Uint64("BlockNumber", randomWordsFulfilledEvent.Raw.BlockNumber). - Str("BlockHash", randomWordsFulfilledEvent.Raw.BlockHash.String()). - Msg("RandomWordsFulfilled Event (TX metadata)") -} - -func LogRandomWordsForcedEvent( - l zerolog.Logger, - vrfOwner contracts.VRFOwner, - randomWordsForcedEvent *vrf_owner.VRFOwnerRandomWordsForced, -) { - l.Debug(). - Str("VRFOwner", vrfOwner.Address()). - Uint64("Sub ID", randomWordsForcedEvent.SubId). - Str("TX Hash", randomWordsForcedEvent.Raw.TxHash.String()). - Str("Request ID", randomWordsForcedEvent.RequestId.String()). - Str("Sender", randomWordsForcedEvent.Sender.String()). - Msg("RandomWordsForced Event (TX metadata)") + Str("Coordinator", *testConfig.VRFv2.ExistingEnvConfig.ExistingEnvConfig.CoordinatorAddress). + Int("Number of Subs to create", numberOfSubToCreate). + Msg("Creating and funding subscriptions, deploying and adding consumers to subs") + subIDs, err := CreateFundSubsAndAddConsumers( + env, + chainID, + big.NewFloat(*testConfig.VRFv2.General.SubscriptionFundingAmountLink), + linkToken, + coordinator, + consumers, + numberOfSubToCreate, + ) + if err != nil { + return nil, nil, fmt.Errorf("err: %w", err) + } + return consumers, subIDs, nil } -func logRandRequest( - l zerolog.Logger, - consumer string, - coordinator string, - subID uint64, - minimumConfirmations uint16, - callbackGasLimit uint32, - numberOfWords uint32, - randomnessRequestCountPerRequest uint16, - randomnessRequestCountPerRequestDeviation uint16, -) { - l.Info(). - Str("Consumer", consumer). - Str("Coordinator", coordinator). - Uint64("SubID", subID). - Uint16("MinimumConfirmations", minimumConfirmations). - Uint32("CallbackGasLimit", callbackGasLimit). - Uint32("NumberOfWords", numberOfWords). - Uint16("RandomnessRequestCountPerRequest", randomnessRequestCountPerRequest). - Uint16("RandomnessRequestCountPerRequestDeviation", randomnessRequestCountPerRequestDeviation). - Msg("Requesting randomness") +func CancelSubsAndReturnFunds(ctx context.Context, vrfContracts *vrfcommon.VRFContracts, eoaWalletAddress string, subIDs []uint64, l zerolog.Logger) { + for _, subID := range subIDs { + l.Info(). + Uint64("Returning funds from SubID", subID). + Str("Returning funds to", eoaWalletAddress). + Msg("Canceling subscription and returning funds to subscription owner") + pendingRequestsExist, err := vrfContracts.CoordinatorV2.PendingRequestsExist(ctx, subID) + if err != nil { + l.Error().Err(err).Msg("Error checking if pending requests exist") + } + if !pendingRequestsExist { + _, err := vrfContracts.CoordinatorV2.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) + if err != nil { + l.Error().Err(err).Msg("Error canceling subscription") + } + } else { + l.Error().Uint64("Sub ID", subID).Msg("Pending requests exist for subscription, cannot cancel subscription and return funds") + } + } } diff --git a/integration-tests/actions/vrf/vrfv2/logging_helpers.go b/integration-tests/actions/vrf/vrfv2/logging_helpers.go new file mode 100644 index 00000000000..82c45267aaf --- /dev/null +++ b/integration-tests/actions/vrf/vrfv2/logging_helpers.go @@ -0,0 +1,97 @@ +package vrfv2 + +import ( + "fmt" + + "github.com/rs/zerolog" + + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_owner" +) + +func LogSubDetails(l zerolog.Logger, subscription vrf_coordinator_v2.GetSubscription, subID uint64, coordinator contracts.VRFCoordinatorV2) { + l.Debug(). + Str("Coordinator", coordinator.Address()). + Str("Link Balance", (*commonassets.Link)(subscription.Balance).Link()). + Uint64("Subscription ID", subID). + Str("Subscription Owner", subscription.Owner.String()). + Interface("Subscription Consumers", subscription.Consumers). + Msg("Subscription Data") +} + +func LogRandomnessRequestedEvent( + l zerolog.Logger, + coordinator contracts.VRFCoordinatorV2, + randomWordsRequestedEvent *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, +) { + l.Info(). + Str("Coordinator", coordinator.Address()). + Str("Request ID", randomWordsRequestedEvent.RequestId.String()). + Uint64("Subscription ID", randomWordsRequestedEvent.SubId). + Str("Sender Address", randomWordsRequestedEvent.Sender.String()). + Str("Keyhash", fmt.Sprintf("0x%x", randomWordsRequestedEvent.KeyHash)). + Uint32("Callback Gas Limit", randomWordsRequestedEvent.CallbackGasLimit). + Uint32("Number of Words", randomWordsRequestedEvent.NumWords). + Uint16("Minimum Request Confirmations", randomWordsRequestedEvent.MinimumRequestConfirmations). + Str("TX Hash", randomWordsRequestedEvent.Raw.TxHash.String()). + Uint64("BlockNumber", randomWordsRequestedEvent.Raw.BlockNumber). + Str("BlockHash", randomWordsRequestedEvent.Raw.BlockHash.String()). + Msg("RandomnessRequested Event") +} + +func LogRandomWordsFulfilledEvent( + l zerolog.Logger, + coordinator contracts.VRFCoordinatorV2, + randomWordsFulfilledEvent *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, +) { + l.Info(). + Str("Coordinator", coordinator.Address()). + Str("Total Payment", randomWordsFulfilledEvent.Payment.String()). + Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). + Str("Request ID", randomWordsFulfilledEvent.RequestId.String()). + Bool("Success", randomWordsFulfilledEvent.Success). + Uint64("BlockNumber", randomWordsFulfilledEvent.Raw.BlockNumber). + Str("BlockHash", randomWordsFulfilledEvent.Raw.BlockHash.String()). + Msg("RandomWordsFulfilled Event (TX metadata)") +} + +func LogRandomWordsForcedEvent( + l zerolog.Logger, + vrfOwner contracts.VRFOwner, + randomWordsForcedEvent *vrf_owner.VRFOwnerRandomWordsForced, +) { + l.Debug(). + Str("VRFOwner", vrfOwner.Address()). + Uint64("Sub ID", randomWordsForcedEvent.SubId). + Str("TX Hash", randomWordsForcedEvent.Raw.TxHash.String()). + Str("Request ID", randomWordsForcedEvent.RequestId.String()). + Str("Sender", randomWordsForcedEvent.Sender.String()). + Msg("RandomWordsForced Event (TX metadata)") +} + +func logRandRequest( + l zerolog.Logger, + consumer string, + coordinator string, + subID uint64, + minimumConfirmations uint16, + callbackGasLimit uint32, + numberOfWords uint32, + randomnessRequestCountPerRequest uint16, + randomnessRequestCountPerRequestDeviation uint16, + keyhash [32]byte, +) { + l.Info(). + Str("Consumer", consumer). + Str("Coordinator", coordinator). + Uint64("SubID", subID). + Uint16("MinimumConfirmations", minimumConfirmations). + Uint32("CallbackGasLimit", callbackGasLimit). + Uint32("NumberOfWords", numberOfWords). + Uint16("RandomnessRequestCountPerRequest", randomnessRequestCountPerRequest). + Uint16("RandomnessRequestCountPerRequestDeviation", randomnessRequestCountPerRequestDeviation). + Str("Keyhash", fmt.Sprintf("0x%x", keyhash)). + Msg("Requesting randomness") +} diff --git a/integration-tests/actions/vrf/vrfv2/vrfv2_models.go b/integration-tests/actions/vrf/vrfv2/models.go similarity index 100% rename from integration-tests/actions/vrf/vrfv2/vrfv2_models.go rename to integration-tests/actions/vrf/vrfv2/models.go diff --git a/integration-tests/actions/vrf/vrfv2/setup_steps.go b/integration-tests/actions/vrf/vrfv2/setup_steps.go new file mode 100644 index 00000000000..bd41fb33e4e --- /dev/null +++ b/integration-tests/actions/vrf/vrfv2/setup_steps.go @@ -0,0 +1,507 @@ +package vrfv2 + +import ( + "context" + "fmt" + "math/big" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/rs/zerolog" + "golang.org/x/sync/errgroup" + + "github.com/google/uuid" + + "github.com/smartcontractkit/chainlink/integration-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + testconfig "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2" + "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" + + vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" + "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + "github.com/smartcontractkit/chainlink/integration-tests/types" +) + +func CreateVRFV2Job( + chainlinkNode *client.ChainlinkClient, + vrfJobSpecConfig vrfcommon.VRFJobSpecConfig, +) (*client.Job, error) { + jobUUID := uuid.New() + os := &client.VRFV2TxPipelineSpec{ + Address: vrfJobSpecConfig.CoordinatorAddress, + EstimateGasMultiplier: vrfJobSpecConfig.EstimateGasMultiplier, + FromAddress: vrfJobSpecConfig.FromAddresses[0], + SimulationBlock: vrfJobSpecConfig.SimulationBlock, + } + ost, err := os.String() + if err != nil { + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrParseJob, err) + } + + spec := &client.VRFV2JobSpec{ + Name: fmt.Sprintf("vrf-v2-%s", jobUUID), + ForwardingAllowed: vrfJobSpecConfig.ForwardingAllowed, + CoordinatorAddress: vrfJobSpecConfig.CoordinatorAddress, + FromAddresses: vrfJobSpecConfig.FromAddresses, + EVMChainID: vrfJobSpecConfig.EVMChainID, + MinIncomingConfirmations: vrfJobSpecConfig.MinIncomingConfirmations, + PublicKey: vrfJobSpecConfig.PublicKey, + ExternalJobID: jobUUID.String(), + ObservationSource: ost, + BatchFulfillmentEnabled: vrfJobSpecConfig.BatchFulfillmentEnabled, + BatchFulfillmentGasMultiplier: vrfJobSpecConfig.BatchFulfillmentGasMultiplier, + PollPeriod: vrfJobSpecConfig.PollPeriod, + RequestTimeout: vrfJobSpecConfig.RequestTimeout, + } + if vrfJobSpecConfig.VRFOwnerConfig.UseVRFOwner { + spec.VRFOwner = vrfJobSpecConfig.VRFOwnerConfig.OwnerAddress + spec.UseVRFOwner = true + } + + if err != nil { + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrParseJob, err) + + } + job, err := chainlinkNode.MustCreateJob(spec) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2Job, err) + } + return job, nil +} + +// SetupVRFV2Environment will create specified number of subscriptions and add the same conumer/s to each of them +func SetupVRFV2Environment( + ctx context.Context, + env *test_env.CLClusterTestEnv, + chainID int64, + nodesToCreate []vrfcommon.VRFNodeType, + vrfv2TestConfig types.VRFv2TestConfig, + useVRFOwner bool, + useTestCoordinator bool, + linkToken contracts.LinkToken, + mockNativeLINKFeed contracts.VRFMockETHLINKFeed, + registerProvingKeyAgainstAddress string, + numberOfTxKeysToCreate int, + l zerolog.Logger, +) (*vrfcommon.VRFContracts, *vrfcommon.VRFKeyData, map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode, error) { + l.Info().Msg("Starting VRFV2 environment setup") + configGeneral := vrfv2TestConfig.GetVRFv2Config().General + vrfContracts, err := SetupVRFV2Contracts( + env, + chainID, + linkToken, + mockNativeLINKFeed, + useVRFOwner, + useTestCoordinator, + configGeneral, + l, + ) + if err != nil { + return nil, nil, nil, err + } + + nodeTypeToNodeMap, err := vrfcommon.CreateNodeTypeToNodeMap(env.ClCluster, nodesToCreate) + if err != nil { + return nil, nil, nil, err + } + vrfKey, pubKeyCompressed, err := vrfcommon.CreateVRFKeyOnVRFNode(nodeTypeToNodeMap[vrfcommon.VRF], l) + if err != nil { + return nil, nil, nil, err + } + + l.Info().Str("Coordinator", vrfContracts.CoordinatorV2.Address()).Msg("Registering Proving Key") + provingKey, err := VRFV2RegisterProvingKey(vrfKey, registerProvingKeyAgainstAddress, vrfContracts.CoordinatorV2) + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrRegisteringProvingKey, err) + } + keyHash, err := vrfContracts.CoordinatorV2.HashOfKey(ctx, provingKey) + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrCreatingProvingKeyHash, err) + } + + evmClient, err := env.GetEVMClient(chainID) + if err != nil { + return nil, nil, nil, err + } + + vrfTXKeyAddressStrings, vrfTXKeyAddresses, err := vrfcommon.CreateFundAndGetSendingKeys( + evmClient, + nodeTypeToNodeMap[vrfcommon.VRF], + *vrfv2TestConfig.GetCommonConfig().ChainlinkNodeFunding, + numberOfTxKeysToCreate, + big.NewInt(chainID), + ) + if err != nil { + return nil, nil, nil, err + } + err = evmClient.WaitForEvents() + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + } + + nodeTypeToNodeMap[vrfcommon.VRF].TXKeyAddressStrings = vrfTXKeyAddressStrings + + vrfOwnerConfig, err := SetupVRFOwnerContractIfNeeded(useVRFOwner, env, chainID, vrfContracts, vrfTXKeyAddressStrings, vrfTXKeyAddresses, l) + if err != nil { + return nil, nil, nil, err + } + + g := errgroup.Group{} + if vrfNode, exists := nodeTypeToNodeMap[vrfcommon.VRF]; exists { + g.Go(func() error { + err := setupVRFNode(vrfContracts, big.NewInt(chainID), configGeneral, pubKeyCompressed, vrfOwnerConfig, l, vrfNode) + if err != nil { + return err + } + return nil + }) + } + + if bhsNode, exists := nodeTypeToNodeMap[vrfcommon.BHS]; exists { + g.Go(func() error { + err := vrfcommon.SetupBHSNode( + env, + configGeneral.General, + numberOfTxKeysToCreate, + big.NewInt(chainID), + vrfContracts.CoordinatorV2.Address(), + vrfContracts.BHS.Address(), + *vrfv2TestConfig.GetCommonConfig().ChainlinkNodeFunding, + l, + bhsNode, + ) + if err != nil { + return err + } + return nil + }) + } + + if err := g.Wait(); err != nil { + return nil, nil, nil, fmt.Errorf("VRF node setup ended up with an error: %w", err) + } + + vrfKeyData := vrfcommon.VRFKeyData{ + VRFKey: vrfKey, + EncodedProvingKey: provingKey, + KeyHash: keyHash, + PubKeyCompressed: pubKeyCompressed, + } + + l.Info().Msg("VRFV2 environment setup is finished") + return vrfContracts, &vrfKeyData, nodeTypeToNodeMap, nil +} + +func setupVRFNode(contracts *vrfcommon.VRFContracts, chainID *big.Int, vrfv2Config *testconfig.General, pubKeyCompressed string, vrfOwnerConfig *vrfcommon.VRFOwnerConfig, l zerolog.Logger, vrfNode *vrfcommon.VRFNode) error { + vrfJobSpecConfig := vrfcommon.VRFJobSpecConfig{ + ForwardingAllowed: *vrfv2Config.VRFJobForwardingAllowed, + CoordinatorAddress: contracts.CoordinatorV2.Address(), + FromAddresses: vrfNode.TXKeyAddressStrings, + EVMChainID: chainID.String(), + MinIncomingConfirmations: int(*vrfv2Config.MinimumConfirmations), + PublicKey: pubKeyCompressed, + EstimateGasMultiplier: *vrfv2Config.VRFJobEstimateGasMultiplier, + BatchFulfillmentEnabled: *vrfv2Config.VRFJobBatchFulfillmentEnabled, + BatchFulfillmentGasMultiplier: *vrfv2Config.VRFJobBatchFulfillmentGasMultiplier, + PollPeriod: vrfv2Config.VRFJobPollPeriod.Duration, + RequestTimeout: vrfv2Config.VRFJobRequestTimeout.Duration, + SimulationBlock: vrfv2Config.VRFJobSimulationBlock, + VRFOwnerConfig: vrfOwnerConfig, + } + + l.Info().Msg("Creating VRFV2 Job") + vrfV2job, err := CreateVRFV2Job( + vrfNode.CLNode.API, + vrfJobSpecConfig, + ) + if err != nil { + return fmt.Errorf("%s, err %w", ErrCreateVRFV2Jobs, err) + } + vrfNode.Job = vrfV2job + + // this part is here because VRFv2 can work with only a specific key + // [[EVM.KeySpecific]] + // Key = '...' + nodeConfig := node.NewConfig(vrfNode.CLNode.NodeConfig, + node.WithLogPollInterval(1*time.Second), + node.WithVRFv2EVMEstimator(vrfNode.TXKeyAddressStrings, *vrfv2Config.CLNodeMaxGasPriceGWei), + ) + l.Info().Msg("Restarting Node with new sending key PriceMax configuration") + err = vrfNode.CLNode.Restart(nodeConfig) + if err != nil { + return fmt.Errorf("%s, err %w", vrfcommon.ErrRestartCLNode, err) + } + return nil +} + +func SetupVRFV2WrapperEnvironment( + ctx context.Context, + env *test_env.CLClusterTestEnv, + chainID int64, + vrfv2TestConfig tc.VRFv2TestConfig, + linkToken contracts.LinkToken, + mockNativeLINKFeed contracts.VRFMockETHLINKFeed, + coordinator contracts.VRFCoordinatorV2, + keyHash [32]byte, + wrapperConsumerContractsAmount int, +) (*VRFV2WrapperContracts, *uint64, error) { + evmClient, err := env.GetEVMClient(chainID) + if err != nil { + return nil, nil, err + } + + // Deploy VRF v2 direct funding contracts + wrapperContracts, err := DeployVRFV2DirectFundingContracts( + env.ContractDeployer, + evmClient, + linkToken.Address(), + mockNativeLINKFeed.Address(), + coordinator, + wrapperConsumerContractsAmount, + ) + if err != nil { + return nil, nil, err + } + err = evmClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + } + + vrfv2Config := vrfv2TestConfig.GetVRFv2Config() + + // Configure VRF v2 wrapper contract + err = wrapperContracts.VRFV2Wrapper.SetConfig( + *vrfv2Config.General.WrapperGasOverhead, + *vrfv2Config.General.CoordinatorGasOverhead, + *vrfv2Config.General.WrapperPremiumPercentage, + keyHash, + *vrfv2Config.General.WrapperMaxNumberOfWords, + ) + if err != nil { + return nil, nil, err + } + err = evmClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + } + + // Fetch wrapper subscription ID + wrapperSubID, err := wrapperContracts.VRFV2Wrapper.GetSubID(ctx) + if err != nil { + return nil, nil, err + } + err = evmClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + } + + // Fund wrapper subscription + err = FundSubscriptions(env, chainID, big.NewFloat(*vrfv2Config.General.SubscriptionFundingAmountLink), linkToken, coordinator, []uint64{wrapperSubID}) + if err != nil { + return nil, nil, err + } + + // Fund consumer with LINK + err = linkToken.Transfer( + wrapperContracts.LoadTestConsumers[0].Address(), + big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(*vrfv2Config.General.WrapperConsumerFundingAmountLink)), + ) + if err != nil { + return nil, nil, err + } + err = evmClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + } + + return wrapperContracts, &wrapperSubID, nil +} + +func SetupVRFV2Universe(ctx context.Context, t *testing.T, testConfig tc.TestConfig, chainID int64, cleanupFn func(), newEnvConfig vrfcommon.NewEnvConfig, l zerolog.Logger) (*test_env.CLClusterTestEnv, *vrfcommon.VRFContracts, *vrfcommon.VRFKeyData, map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode, error) { + var ( + env *test_env.CLClusterTestEnv + vrfContracts *vrfcommon.VRFContracts + vrfKey *vrfcommon.VRFKeyData + nodeTypeToNodeMap map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode + err error + ) + if *testConfig.VRFv2.General.UseExistingEnv { + vrfContracts, vrfKey, env, err = SetupVRFV2ForExistingEnv(ctx, t, testConfig, chainID, cleanupFn, l) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "Error setting up VRF V2 for Existing env", err) + } + } else { + vrfContracts, vrfKey, env, nodeTypeToNodeMap, err = SetupVRFV2ForNewEnv(ctx, t, testConfig, chainID, cleanupFn, newEnvConfig, l) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "Error setting up VRF V2 for New env", err) + } + } + return env, vrfContracts, vrfKey, nodeTypeToNodeMap, nil +} + +func SetupVRFV2ForNewEnv( + ctx context.Context, + t *testing.T, + testConfig tc.TestConfig, + chainID int64, + cleanupFn func(), + newEnvConfig vrfcommon.NewEnvConfig, + l zerolog.Logger, +) (*vrfcommon.VRFContracts, *vrfcommon.VRFKeyData, *test_env.CLClusterTestEnv, map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode, error) { + network, err := actions.EthereumNetworkConfigFromConfig(l, &testConfig) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "Error building ethereum network config", err) + } + env, err := test_env.NewCLTestEnvBuilder(). + WithTestInstance(t). + WithTestConfig(&testConfig). + WithPrivateEthereumNetwork(network). + WithCLNodes(len(newEnvConfig.NodesToCreate)). + WithFunding(big.NewFloat(*testConfig.Common.ChainlinkNodeFunding)). + WithCustomCleanup(cleanupFn). + Build() + + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error creating test env", err) + } + + env.ParallelTransactions(true) + + mockETHLinkFeed, err := env.ContractDeployer.DeployVRFMockETHLINKFeed(big.NewInt(*testConfig.VRFv2.General.LinkNativeFeedResponse)) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error deploying mock ETH/LINK feed", err) + } + + linkToken, err := actions.DeployLINKToken(env.ContractDeployer) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error deploying LINK contract", err) + } + + evmClient, err := env.GetEVMClient(chainID) + if err != nil { + return nil, nil, nil, nil, err + } + + vrfContracts, vrfKey, nodeTypeToNode, err := SetupVRFV2Environment( + ctx, + env, + chainID, + newEnvConfig.NodesToCreate, + &testConfig, + newEnvConfig.UseVRFOwner, + newEnvConfig.UseTestCoordinator, + linkToken, + mockETHLinkFeed, + //register proving key against EOA address in order to return funds to this address + evmClient.GetDefaultWallet().Address(), + newEnvConfig.NumberOfTxKeysToCreate, + l, + ) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error setting up VRF v2 env", err) + } + return vrfContracts, vrfKey, env, nodeTypeToNode, nil +} + +func SetupVRFV2ForExistingEnv(ctx context.Context, t *testing.T, testConfig tc.TestConfig, chainID int64, cleanupFn func(), l zerolog.Logger) (*vrfcommon.VRFContracts, *vrfcommon.VRFKeyData, *test_env.CLClusterTestEnv, error) { + commonExistingEnvConfig := testConfig.VRFv2.ExistingEnvConfig.ExistingEnvConfig + env, err := test_env.NewCLTestEnvBuilder(). + WithTestInstance(t). + WithTestConfig(&testConfig). + WithCustomCleanup(cleanupFn). + Build() + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err: %w", "error creating test env", err) + } + coordinator, err := env.ContractLoader.LoadVRFCoordinatorV2(*commonExistingEnvConfig.CoordinatorAddress) + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err: %w", "error loading VRFCoordinator2", err) + } + linkToken, err := env.ContractLoader.LoadLINKToken(*commonExistingEnvConfig.LinkAddress) + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err: %w", "error loading LinkToken", err) + } + + evmClient, err := env.GetEVMClient(chainID) + if err != nil { + return nil, nil, nil, err + } + + err = vrfcommon.FundNodesIfNeeded(ctx, commonExistingEnvConfig, evmClient, l) + if err != nil { + return nil, nil, nil, fmt.Errorf("err: %w", err) + } + vrfContracts := &vrfcommon.VRFContracts{ + CoordinatorV2: coordinator, + VRFV2Consumers: nil, + LinkToken: linkToken, + BHS: nil, + } + vrfKey := &vrfcommon.VRFKeyData{ + VRFKey: nil, + EncodedProvingKey: [2]*big.Int{}, + KeyHash: common.HexToHash(*commonExistingEnvConfig.KeyHash), + } + return vrfContracts, vrfKey, env, nil +} + +func SetupSubsAndConsumersForExistingEnv( + env *test_env.CLClusterTestEnv, + chainID int64, + coordinator contracts.VRFCoordinatorV2, + linkToken contracts.LinkToken, + numberOfConsumerContractsToDeployAndAddToSub int, + numberOfSubToCreate int, + testConfig tc.TestConfig, + l zerolog.Logger, +) ([]uint64, []contracts.VRFv2LoadTestConsumer, error) { + var ( + subIDs []uint64 + consumers []contracts.VRFv2LoadTestConsumer + err error + ) + if *testConfig.VRFv2.General.UseExistingEnv { + commonExistingEnvConfig := testConfig.VRFv2.ExistingEnvConfig.ExistingEnvConfig + if *commonExistingEnvConfig.CreateFundSubsAndAddConsumers { + consumers, subIDs, err = SetupNewConsumersAndSubs( + env, + chainID, + coordinator, + testConfig, + linkToken, + numberOfConsumerContractsToDeployAndAddToSub, + numberOfSubToCreate, + l, + ) + if err != nil { + return nil, nil, fmt.Errorf("err: %w", err) + } + } else { + consumer, err := env.ContractLoader.LoadVRFv2LoadTestConsumer(*commonExistingEnvConfig.ConsumerAddress) + if err != nil { + return nil, nil, fmt.Errorf("err: %w", err) + } + consumers = append(consumers, consumer) + subIDs = append(subIDs, *testConfig.VRFv2.ExistingEnvConfig.SubID) + } + } else { + consumers, subIDs, err = SetupNewConsumersAndSubs( + env, + chainID, + coordinator, + testConfig, + linkToken, + numberOfConsumerContractsToDeployAndAddToSub, + numberOfSubToCreate, + l, + ) + if err != nil { + return nil, nil, fmt.Errorf("err: %w", err) + } + } + return subIDs, consumers, nil +} diff --git a/integration-tests/actions/vrf/vrfv2plus/contract_steps.go b/integration-tests/actions/vrf/vrfv2plus/contract_steps.go new file mode 100644 index 00000000000..5df33a6d997 --- /dev/null +++ b/integration-tests/actions/vrf/vrfv2plus/contract_steps.go @@ -0,0 +1,817 @@ +package vrfv2plus + +import ( + "context" + "fmt" + "math/big" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/rs/zerolog" + + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" + "github.com/smartcontractkit/chainlink/integration-tests/actions" + vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" + "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + vrfv2plus_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2plus" + chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" +) + +func DeployVRFV2_5Contracts( + contractDeployer contracts.ContractDeployer, + chainClient blockchain.EVMClient, +) (*vrfcommon.VRFContracts, error) { + bhs, err := contractDeployer.DeployBlockhashStore() + if err != nil { + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrDeployBlockHashStore, err) + } + err = chainClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + } + batchBHS, err := contractDeployer.DeployBatchBlockhashStore(bhs.Address()) + if err != nil { + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrDeployBatchBlockHashStore, err) + } + err = chainClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, batchBHS err %w", vrfcommon.ErrWaitTXsComplete, err) + } + coordinator, err := contractDeployer.DeployVRFCoordinatorV2_5(bhs.Address()) + if err != nil { + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrDeployCoordinator, err) + } + err = chainClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + } + return &vrfcommon.VRFContracts{ + CoordinatorV2Plus: coordinator, + BHS: bhs, + BatchBHS: batchBHS, + VRFV2PlusConsumer: nil, + }, nil +} + +func DeployVRFV2PlusConsumers(contractDeployer contracts.ContractDeployer, coordinator contracts.VRFCoordinatorV2_5, consumerContractsAmount int) ([]contracts.VRFv2PlusLoadTestConsumer, error) { + var consumers []contracts.VRFv2PlusLoadTestConsumer + for i := 1; i <= consumerContractsAmount; i++ { + loadTestConsumer, err := contractDeployer.DeployVRFv2PlusLoadTestConsumer(coordinator.Address()) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrAdvancedConsumer, err) + } + consumers = append(consumers, loadTestConsumer) + } + return consumers, nil +} + +func VRFV2_5RegisterProvingKey( + vrfKey *client.VRFKey, + coordinator contracts.VRFCoordinatorV2_5, + gasLaneMaxGas uint64, +) (vrfcommon.VRFEncodedProvingKey, error) { + provingKey, err := actions.EncodeOnChainVRFProvingKey(*vrfKey) + if err != nil { + return vrfcommon.VRFEncodedProvingKey{}, fmt.Errorf("%s, err %w", vrfcommon.ErrEncodingProvingKey, err) + } + err = coordinator.RegisterProvingKey( + provingKey, + gasLaneMaxGas, + ) + if err != nil { + return vrfcommon.VRFEncodedProvingKey{}, fmt.Errorf("%s, err %w", vrfcommon.ErrRegisterProvingKey, err) + } + return provingKey, nil +} + +func VRFV2PlusUpgradedVersionRegisterProvingKey( + vrfKey *client.VRFKey, + coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, +) (vrfcommon.VRFEncodedProvingKey, error) { + provingKey, err := actions.EncodeOnChainVRFProvingKey(*vrfKey) + if err != nil { + return vrfcommon.VRFEncodedProvingKey{}, fmt.Errorf("%s, err %w", vrfcommon.ErrEncodingProvingKey, err) + } + err = coordinator.RegisterProvingKey( + provingKey, + ) + if err != nil { + return vrfcommon.VRFEncodedProvingKey{}, fmt.Errorf("%s, err %w", vrfcommon.ErrRegisterProvingKey, err) + } + return provingKey, nil +} + +func FundVRFCoordinatorV2_5Subscription( + linkToken contracts.LinkToken, + coordinator contracts.VRFCoordinatorV2_5, + chainClient blockchain.EVMClient, + subscriptionID *big.Int, + linkFundingAmountJuels *big.Int, +) error { + encodedSubId, err := chainlinkutils.ABIEncode(`[{"type":"uint256"}]`, subscriptionID) + if err != nil { + return fmt.Errorf("%s, err %w", vrfcommon.ErrABIEncodingFunding, err) + } + _, err = linkToken.TransferAndCall(coordinator.Address(), linkFundingAmountJuels, encodedSubId) + if err != nil { + return fmt.Errorf("%s, err %w", vrfcommon.ErrSendingLinkToken, err) + } + return chainClient.WaitForEvents() +} + +func CreateFundSubsAndAddConsumers( + env *test_env.CLClusterTestEnv, + chainID int64, + subscriptionFundingAmountNative *big.Float, + subscriptionFundingAmountLink *big.Float, + linkToken contracts.LinkToken, + coordinator contracts.VRFCoordinatorV2_5, + consumers []contracts.VRFv2PlusLoadTestConsumer, + numberOfSubToCreate int, +) ([]*big.Int, error) { + subIDs, err := CreateSubsAndFund( + env, + chainID, + subscriptionFundingAmountNative, + subscriptionFundingAmountLink, + linkToken, + coordinator, + numberOfSubToCreate, + ) + if err != nil { + return nil, err + } + subToConsumersMap := map[*big.Int][]contracts.VRFv2PlusLoadTestConsumer{} + + //each subscription will have the same consumers + for _, subID := range subIDs { + subToConsumersMap[subID] = consumers + } + + err = AddConsumersToSubs( + subToConsumersMap, + coordinator, + ) + if err != nil { + return nil, err + } + + evmClient, err := env.GetEVMClient(chainID) + if err != nil { + return nil, err + } + + err = evmClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + } + return subIDs, nil +} + +func CreateSubsAndFund( + env *test_env.CLClusterTestEnv, + chainID int64, + subscriptionFundingAmountNative *big.Float, + subscriptionFundingAmountLink *big.Float, + linkToken contracts.LinkToken, + coordinator contracts.VRFCoordinatorV2_5, + subAmountToCreate int, +) ([]*big.Int, error) { + subs, err := CreateSubs(env, chainID, coordinator, subAmountToCreate) + if err != nil { + return nil, err + } + evmClient, err := env.GetEVMClient(chainID) + if err != nil { + return nil, err + } + + err = evmClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + } + err = FundSubscriptions( + env, + chainID, + subscriptionFundingAmountNative, + subscriptionFundingAmountLink, + linkToken, + coordinator, + subs, + ) + if err != nil { + return nil, err + } + return subs, nil +} + +func CreateSubs( + env *test_env.CLClusterTestEnv, + chainID int64, + coordinator contracts.VRFCoordinatorV2_5, + subAmountToCreate int, +) ([]*big.Int, error) { + var subIDArr []*big.Int + + for i := 0; i < subAmountToCreate; i++ { + subID, err := CreateSubAndFindSubID(env, chainID, coordinator) + if err != nil { + return nil, err + } + subIDArr = append(subIDArr, subID) + } + return subIDArr, nil +} + +func AddConsumersToSubs( + subToConsumerMap map[*big.Int][]contracts.VRFv2PlusLoadTestConsumer, + coordinator contracts.VRFCoordinatorV2_5, +) error { + for subID, consumers := range subToConsumerMap { + for _, consumer := range consumers { + err := coordinator.AddConsumer(subID, consumer.Address()) + if err != nil { + return fmt.Errorf("%s, err %w", ErrAddConsumerToSub, err) + } + } + } + return nil +} + +func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, chainID int64, coordinator contracts.VRFCoordinatorV2_5) (*big.Int, error) { + tx, err := coordinator.CreateSubscription() + if err != nil { + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrCreateVRFSubscription, err) + } + evmClient, err := env.GetEVMClient(chainID) + if err != nil { + return nil, err + } + err = evmClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + } + + receipt, err := evmClient.GetTxReceipt(tx.Hash()) + if err != nil { + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + } + + //SubscriptionsCreated Log should be emitted with the subscription ID + subID := receipt.Logs[0].Topics[1].Big() + + return subID, nil +} + +func FundSubscriptions( + env *test_env.CLClusterTestEnv, + chainID int64, + subscriptionFundingAmountNative *big.Float, + subscriptionFundingAmountLink *big.Float, + linkAddress contracts.LinkToken, + coordinator contracts.VRFCoordinatorV2_5, + subIDs []*big.Int, +) error { + evmClient, err := env.GetEVMClient(chainID) + if err != nil { + return err + } + + for _, subID := range subIDs { + //Native Billing + amountWei := conversions.EtherToWei(subscriptionFundingAmountNative) + err := coordinator.FundSubscriptionWithNative( + subID, + amountWei, + ) + if err != nil { + return fmt.Errorf("%s, err %w", ErrFundSubWithNativeToken, err) + } + //Link Billing + amountJuels := conversions.EtherToWei(subscriptionFundingAmountLink) + err = FundVRFCoordinatorV2_5Subscription(linkAddress, coordinator, evmClient, subID, amountJuels) + if err != nil { + return fmt.Errorf("%s, err %w", vrfcommon.ErrFundSubWithLinkToken, err) + } + } + err = evmClient.WaitForEvents() + if err != nil { + return fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + } + return nil +} + +func GetUpgradedCoordinatorTotalBalance(coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion) (linkTotalBalance *big.Int, nativeTokenTotalBalance *big.Int, err error) { + linkTotalBalance, err = coordinator.GetLinkTotalBalance(context.Background()) + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", ErrLinkTotalBalance, err) + } + nativeTokenTotalBalance, err = coordinator.GetNativeTokenTotalBalance(context.Background()) + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", ErrNativeTokenBalance, err) + } + return +} + +func GetCoordinatorTotalBalance(coordinator contracts.VRFCoordinatorV2_5) (linkTotalBalance *big.Int, nativeTokenTotalBalance *big.Int, err error) { + linkTotalBalance, err = coordinator.GetLinkTotalBalance(context.Background()) + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", ErrLinkTotalBalance, err) + } + nativeTokenTotalBalance, err = coordinator.GetNativeTokenTotalBalance(context.Background()) + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", ErrNativeTokenBalance, err) + } + return +} + +func RequestRandomnessAndWaitForRequestedEvent( + consumer contracts.VRFv2PlusLoadTestConsumer, + coordinator contracts.VRFCoordinatorV2_5, + vrfKeyData *vrfcommon.VRFKeyData, + subID *big.Int, + isNativeBilling bool, + config *vrfv2plus_config.General, + l zerolog.Logger, +) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsRequested, error) { + LogRandRequest( + l, + consumer.Address(), + coordinator.Address(), + subID, + isNativeBilling, + vrfKeyData.KeyHash, + config, + ) + ch := make(chan *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsRequested) + errorChannel := make(chan error) + go func() { + _, err := consumer.RequestRandomness( + vrfKeyData.KeyHash, + subID, + *config.MinimumConfirmations, + *config.CallbackGasLimit, + isNativeBilling, + *config.NumberOfWords, + *config.RandomnessRequestCountPerRequest, + ) + if err != nil { + l.Error().Err(err).Msg(err.Error()) + errorChannel <- err + } + }() + go func() { + randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( + [][32]byte{vrfKeyData.KeyHash}, + []*big.Int{subID}, + []common.Address{common.HexToAddress(consumer.Address())}, + time.Minute*1, + ) + if err != nil { + l.Error().Err(err).Msg("error waiting for RandomnessRequested events") + errorChannel <- err + } + LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent, isNativeBilling) + ch <- randomWordsRequestedEvent + }() + for { + select { + case err := <-errorChannel: + return nil, err + case event := <-ch: + return event, nil + case <-time.After(config.RandomWordsFulfilledEventTimeout.Duration): + return nil, fmt.Errorf("timeout waiting for RandomnessRequested events") + } + } +} + +func RequestRandomnessAndWaitForFulfillment( + consumer contracts.VRFv2PlusLoadTestConsumer, + coordinator contracts.VRFCoordinatorV2_5, + vrfKeyData *vrfcommon.VRFKeyData, + subID *big.Int, + isNativeBilling bool, + config *vrfv2plus_config.General, + l zerolog.Logger, +) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { + LogRandRequest( + l, + consumer.Address(), + coordinator.Address(), + subID, + isNativeBilling, + vrfKeyData.KeyHash, + config, + ) + ch := make(chan *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled) + errorChannel := make(chan error) + go func() { + _, err := consumer.RequestRandomness( + vrfKeyData.KeyHash, + subID, + *config.MinimumConfirmations, + *config.CallbackGasLimit, + isNativeBilling, + *config.NumberOfWords, + *config.RandomnessRequestCountPerRequest, + ) + if err != nil { + l.Error().Err(err).Msg(err.Error()) + errorChannel <- err + } + }() + go func() { + fulfillmentEvents, err := WaitForRequestAndFulfillmentEvents( + consumer.Address(), + coordinator, + vrfKeyData, + subID, + isNativeBilling, + config.RandomWordsFulfilledEventTimeout.Duration, + l, + ) + if err != nil { + l.Error().Err(err).Msg("error waiting for RandomnessRequested and RandomWordsFulfilled events") + errorChannel <- err + } + ch <- fulfillmentEvents + }() + for { + select { + case err := <-errorChannel: + return nil, err + case fulfillmentEvent := <-ch: + return fulfillmentEvent, nil + case <-time.After(config.RandomWordsFulfilledEventTimeout.Duration): + return nil, fmt.Errorf("timeout waiting for RandomnessRequested and RandomWordsFulfilled events") + } + } +} + +func RequestRandomnessAndWaitForFulfillmentUpgraded( + consumer contracts.VRFv2PlusLoadTestConsumer, + coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, + vrfKeyData *vrfcommon.VRFKeyData, + subID *big.Int, + isNativeBilling bool, + config *vrfv2plus_config.General, + l zerolog.Logger, +) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, error) { + LogRandRequest( + l, + consumer.Address(), + coordinator.Address(), + subID, + isNativeBilling, + vrfKeyData.KeyHash, + config, + ) + _, err := consumer.RequestRandomness( + vrfKeyData.KeyHash, + subID, + *config.MinimumConfirmations, + *config.CallbackGasLimit, + isNativeBilling, + *config.NumberOfWords, + *config.RandomnessRequestCountPerRequest, + ) + if err != nil { + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrRequestRandomness, err) + } + + return WaitForRequestAndFulfillmentEventsUpgraded( + consumer.Address(), + coordinator, + vrfKeyData, + subID, + isNativeBilling, + config.RandomWordsFulfilledEventTimeout.Duration, + l, + ) +} + +func DeployVRFV2PlusDirectFundingContracts( + contractDeployer contracts.ContractDeployer, + chainClient blockchain.EVMClient, + linkTokenAddress string, + linkEthFeedAddress string, + coordinator contracts.VRFCoordinatorV2_5, + consumerContractsAmount int, + wrapperSubId *big.Int, +) (*VRFV2PlusWrapperContracts, error) { + + vrfv2PlusWrapper, err := contractDeployer.DeployVRFV2PlusWrapper(linkTokenAddress, linkEthFeedAddress, coordinator.Address(), wrapperSubId) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrDeployWrapper, err) + } + err = chainClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + } + + consumers, err := DeployVRFV2PlusWrapperConsumers(contractDeployer, vrfv2PlusWrapper, consumerContractsAmount) + if err != nil { + return nil, err + } + err = chainClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + } + return &VRFV2PlusWrapperContracts{vrfv2PlusWrapper, consumers}, nil +} + +func WrapperRequestRandomness( + consumer contracts.VRFv2PlusWrapperLoadTestConsumer, + coordinatorAddress string, + vrfKeyData *vrfcommon.VRFKeyData, + subID *big.Int, + isNativeBilling bool, + config *vrfv2plus_config.General, + l zerolog.Logger) (string, error) { + LogRandRequest( + l, + consumer.Address(), + coordinatorAddress, + subID, + isNativeBilling, + vrfKeyData.KeyHash, + config, + ) + if isNativeBilling { + _, err := consumer.RequestRandomnessNative( + *config.MinimumConfirmations, + *config.CallbackGasLimit, + *config.NumberOfWords, + *config.RandomnessRequestCountPerRequest, + ) + if err != nil { + return "", fmt.Errorf("%s, err %w", ErrRequestRandomnessDirectFundingNativePayment, err) + } + } else { + _, err := consumer.RequestRandomness( + *config.MinimumConfirmations, + *config.CallbackGasLimit, + *config.NumberOfWords, + *config.RandomnessRequestCountPerRequest, + ) + if err != nil { + return "", fmt.Errorf("%s, err %w", ErrRequestRandomnessDirectFundingLinkPayment, err) + } + } + wrapperAddress, err := consumer.GetWrapper(context.Background()) + if err != nil { + return "", fmt.Errorf("error getting wrapper address, err: %w", err) + } + return wrapperAddress.Hex(), nil +} + +func DirectFundingRequestRandomnessAndWaitForFulfillment( + consumer contracts.VRFv2PlusWrapperLoadTestConsumer, + coordinator contracts.VRFCoordinatorV2_5, + vrfKeyData *vrfcommon.VRFKeyData, + subID *big.Int, + isNativeBilling bool, + config *vrfv2plus_config.General, + l zerolog.Logger, +) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { + wrapperAddress, err := WrapperRequestRandomness(consumer, coordinator.Address(), vrfKeyData, subID, + isNativeBilling, config, l) + if err != nil { + return nil, fmt.Errorf("error getting wrapper address, err: %w", err) + } + return WaitForRequestAndFulfillmentEvents( + wrapperAddress, + coordinator, + vrfKeyData, + subID, + isNativeBilling, + config.RandomWordsFulfilledEventTimeout.Duration, + l, + ) +} + +func DirectFundingRequestRandomnessAndWaitForFulfillmentUpgraded( + consumer contracts.VRFv2PlusWrapperLoadTestConsumer, + coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, + vrfKeyData *vrfcommon.VRFKeyData, + subID *big.Int, + isNativeBilling bool, + config *vrfv2plus_config.General, + l zerolog.Logger, +) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, error) { + wrapperAddress, err := WrapperRequestRandomness(consumer, coordinator.Address(), vrfKeyData, subID, + isNativeBilling, config, l) + if err != nil { + return nil, fmt.Errorf("error getting wrapper address, err: %w", err) + } + return WaitForRequestAndFulfillmentEventsUpgraded( + wrapperAddress, + coordinator, + vrfKeyData, + subID, + isNativeBilling, + config.RandomWordsFulfilledEventTimeout.Duration, + l, + ) +} + +func WaitForRequestAndFulfillmentEvents( + consumerAddress string, + coordinator contracts.VRFCoordinatorV2_5, + vrfKeyData *vrfcommon.VRFKeyData, + subID *big.Int, + isNativeBilling bool, + randomWordsFulfilledEventTimeout time.Duration, + l zerolog.Logger, +) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { + randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( + [][32]byte{vrfKeyData.KeyHash}, + []*big.Int{subID}, + []common.Address{common.HexToAddress(consumerAddress)}, + time.Minute*1, + ) + if err != nil { + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitRandomWordsRequestedEvent, err) + } + + LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent, isNativeBilling) + + randomWordsFulfilledEvent, err := coordinator.WaitForRandomWordsFulfilledEvent( + []*big.Int{subID}, + []*big.Int{randomWordsRequestedEvent.RequestId}, + randomWordsFulfilledEventTimeout, + ) + if err != nil { + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitRandomWordsFulfilledEvent, err) + } + + LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent, isNativeBilling) + return randomWordsFulfilledEvent, err +} + +func WaitForRequestAndFulfillmentEventsUpgraded( + consumerAddress string, + coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, + vrfKeyData *vrfcommon.VRFKeyData, + subID *big.Int, + isNativeBilling bool, + randomWordsFulfilledEventTimeout time.Duration, + l zerolog.Logger, +) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, error) { + randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( + [][32]byte{vrfKeyData.KeyHash}, + []*big.Int{subID}, + []common.Address{common.HexToAddress(consumerAddress)}, + time.Minute*1, + ) + if err != nil { + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitRandomWordsRequestedEvent, err) + } + + LogRandomnessRequestedEventUpgraded(l, coordinator, randomWordsRequestedEvent, isNativeBilling) + + randomWordsFulfilledEvent, err := coordinator.WaitForRandomWordsFulfilledEvent( + []*big.Int{subID}, + []*big.Int{randomWordsRequestedEvent.RequestId}, + randomWordsFulfilledEventTimeout, + ) + if err != nil { + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitRandomWordsFulfilledEvent, err) + } + LogRandomWordsFulfilledEventUpgraded(l, coordinator, randomWordsFulfilledEvent, isNativeBilling) + return randomWordsFulfilledEvent, err +} + +func DeployVRFV2PlusWrapperConsumers(contractDeployer contracts.ContractDeployer, vrfV2PlusWrapper contracts.VRFV2PlusWrapper, consumerContractsAmount int) ([]contracts.VRFv2PlusWrapperLoadTestConsumer, error) { + var consumers []contracts.VRFv2PlusWrapperLoadTestConsumer + for i := 1; i <= consumerContractsAmount; i++ { + loadTestConsumer, err := contractDeployer.DeployVRFV2PlusWrapperLoadTestConsumer(vrfV2PlusWrapper.Address()) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrAdvancedConsumer, err) + } + consumers = append(consumers, loadTestConsumer) + } + return consumers, nil +} + +func SetupVRFV2PlusContracts( + env *test_env.CLClusterTestEnv, + chainID int64, + linkToken contracts.LinkToken, + mockNativeLINKFeed contracts.VRFMockETHLINKFeed, + configGeneral *vrfv2plus_config.General, + l zerolog.Logger, +) (*vrfcommon.VRFContracts, error) { + l.Info().Msg("Deploying VRFV2 Plus contracts") + evmClient, err := env.GetEVMClient(chainID) + if err != nil { + return nil, err + } + vrfContracts, err := DeployVRFV2_5Contracts(env.ContractDeployer, evmClient) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrDeployVRFV2_5Contracts, err) + } + vrfContracts.LinkToken = linkToken + vrfContracts.MockETHLINKFeed = mockNativeLINKFeed + + l.Info().Str("Coordinator", vrfContracts.CoordinatorV2Plus.Address()).Msg("Setting Coordinator Config") + err = vrfContracts.CoordinatorV2Plus.SetConfig( + *configGeneral.MinimumConfirmations, + *configGeneral.MaxGasLimitCoordinatorConfig, + *configGeneral.StalenessSeconds, + *configGeneral.GasAfterPaymentCalculation, + big.NewInt(*configGeneral.FallbackWeiPerUnitLink), + *configGeneral.FulfillmentFlatFeeNativePPM, + *configGeneral.FulfillmentFlatFeeLinkDiscountPPM, + *configGeneral.NativePremiumPercentage, + *configGeneral.LinkPremiumPercentage, + ) + if err != nil { + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrSetVRFCoordinatorConfig, err) + } + + l.Info().Str("Coordinator", vrfContracts.CoordinatorV2Plus.Address()).Msg("Setting Link and ETH/LINK feed") + err = vrfContracts.CoordinatorV2Plus.SetLINKAndLINKNativeFeed(linkToken.Address(), mockNativeLINKFeed.Address()) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrSetLinkNativeLinkFeed, err) + } + err = evmClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + } + + return vrfContracts, nil +} + +func SetupNewConsumersAndSubs( + env *test_env.CLClusterTestEnv, + chainID int64, + coordinator contracts.VRFCoordinatorV2_5, + testConfig tc.TestConfig, + linkToken contracts.LinkToken, + consumerContractsAmount int, + numberOfSubToCreate int, + l zerolog.Logger, +) ([]contracts.VRFv2PlusLoadTestConsumer, []*big.Int, error) { + consumers, err := DeployVRFV2PlusConsumers(env.ContractDeployer, coordinator, consumerContractsAmount) + if err != nil { + if err != nil { + return nil, nil, fmt.Errorf("err: %w", err) + } + } + evmClient, err := env.GetEVMClient(chainID) + if err != nil { + return nil, nil, err + } + + err = evmClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err: %w", vrfcommon.ErrWaitTXsComplete, err) + } + l.Info(). + Str("Coordinator", *testConfig.VRFv2Plus.ExistingEnvConfig.ExistingEnvConfig.CoordinatorAddress). + Int("Number of Subs to create", numberOfSubToCreate). + Msg("Creating and funding subscriptions, deploying and adding consumers to subs") + subIDs, err := CreateFundSubsAndAddConsumers( + env, + chainID, + big.NewFloat(*testConfig.VRFv2Plus.General.SubscriptionFundingAmountNative), + big.NewFloat(*testConfig.VRFv2Plus.General.SubscriptionFundingAmountLink), + linkToken, + coordinator, + consumers, + *testConfig.VRFv2Plus.General.NumberOfSubToCreate, + ) + if err != nil { + return nil, nil, fmt.Errorf("err: %w", err) + } + return consumers, subIDs, nil +} + +func CancelSubsAndReturnFunds(ctx context.Context, vrfContracts *vrfcommon.VRFContracts, eoaWalletAddress string, subIDs []*big.Int, l zerolog.Logger) { + for _, subID := range subIDs { + l.Info(). + Str("Returning funds from SubID", subID.String()). + Str("Returning funds to", eoaWalletAddress). + Msg("Canceling subscription and returning funds to subscription owner") + pendingRequestsExist, err := vrfContracts.CoordinatorV2Plus.PendingRequestsExist(ctx, subID) + if err != nil { + l.Error().Err(err).Msg("Error checking if pending requests exist") + } + if !pendingRequestsExist { + _, err := vrfContracts.CoordinatorV2Plus.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) + if err != nil { + l.Error().Err(err).Msg("Error canceling subscription") + } + } else { + l.Error().Str("Sub ID", subID.String()).Msg("Pending requests exist for subscription, cannot cancel subscription and return funds") + } + } +} diff --git a/integration-tests/actions/vrf/vrfv2plus/logging_helpers.go b/integration-tests/actions/vrf/vrfv2plus/logging_helpers.go new file mode 100644 index 00000000000..995af9ee76c --- /dev/null +++ b/integration-tests/actions/vrf/vrfv2plus/logging_helpers.go @@ -0,0 +1,188 @@ +package vrfv2plus + +import ( + "fmt" + "math/big" + + "github.com/rs/zerolog" + + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" + vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + vrfv2plus_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2plus" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer" +) + +func LogSubDetails(l zerolog.Logger, subscription vrf_coordinator_v2_5.GetSubscription, subID *big.Int, coordinator contracts.VRFCoordinatorV2_5) { + l.Debug(). + Str("Coordinator", coordinator.Address()). + Str("Link Balance", (*commonassets.Link)(subscription.Balance).Link()). + Str("Native Token Balance", assets.FormatWei(subscription.NativeBalance)). + Str("Subscription ID", subID.String()). + Str("Subscription Owner", subscription.SubOwner.String()). + Interface("Subscription Consumers", subscription.Consumers). + Msg("Subscription Data") +} + +func LogRandomnessRequestedEventUpgraded( + l zerolog.Logger, + coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, + randomWordsRequestedEvent *vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsRequested, + isNativeBilling bool, +) { + l.Debug(). + Str("Coordinator", coordinator.Address()). + Bool("Native Billing", isNativeBilling). + Str("Request ID", randomWordsRequestedEvent.RequestId.String()). + Str("Subscription ID", randomWordsRequestedEvent.SubId.String()). + Str("Sender Address", randomWordsRequestedEvent.Sender.String()). + Str("Keyhash", fmt.Sprintf("0x%x", randomWordsRequestedEvent.KeyHash)). + Uint32("Callback Gas Limit", randomWordsRequestedEvent.CallbackGasLimit). + Uint32("Number of Words", randomWordsRequestedEvent.NumWords). + Uint16("Minimum Request Confirmations", randomWordsRequestedEvent.MinimumRequestConfirmations). + Msg("RandomnessRequested Event") +} + +func LogRandomWordsFulfilledEventUpgraded( + l zerolog.Logger, + coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, + randomWordsFulfilledEvent *vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, + isNativeBilling bool, +) { + l.Debug(). + Str("Coordinator", coordinator.Address()). + Bool("Native Billing", isNativeBilling). + Str("Total Payment in Juels", randomWordsFulfilledEvent.Payment.String()). + Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). + Str("Subscription ID", randomWordsFulfilledEvent.SubID.String()). + Str("Request ID", randomWordsFulfilledEvent.RequestId.String()). + Bool("Success", randomWordsFulfilledEvent.Success). + Msg("RandomWordsFulfilled Event (TX metadata)") +} + +func LogRandomnessRequestedEvent( + l zerolog.Logger, + coordinator contracts.VRFCoordinatorV2_5, + randomWordsRequestedEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsRequested, + isNativeBilling bool, +) { + l.Info(). + Str("Coordinator", coordinator.Address()). + Bool("Native Billing", isNativeBilling). + Str("Request ID", randomWordsRequestedEvent.RequestId.String()). + Str("Subscription ID", randomWordsRequestedEvent.SubId.String()). + Str("Sender Address", randomWordsRequestedEvent.Sender.String()). + Str("Keyhash", fmt.Sprintf("0x%x", randomWordsRequestedEvent.KeyHash)). + Uint32("Callback Gas Limit", randomWordsRequestedEvent.CallbackGasLimit). + Uint32("Number of Words", randomWordsRequestedEvent.NumWords). + Uint16("Minimum Request Confirmations", randomWordsRequestedEvent.MinimumRequestConfirmations). + Str("TX Hash", randomWordsRequestedEvent.Raw.TxHash.String()). + Uint64("BlockNumber", randomWordsRequestedEvent.Raw.BlockNumber). + Str("BlockHash", randomWordsRequestedEvent.Raw.BlockHash.String()). + Msg("RandomnessRequested Event") +} + +func LogRandomWordsFulfilledEvent( + l zerolog.Logger, + coordinator contracts.VRFCoordinatorV2_5, + randomWordsFulfilledEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, + isNativeBilling bool, +) { + l.Info(). + Bool("Native Billing", isNativeBilling). + Str("Coordinator", coordinator.Address()). + Str("Total Payment", randomWordsFulfilledEvent.Payment.String()). + Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). + Str("Subscription ID", randomWordsFulfilledEvent.SubId.String()). + Str("Request ID", randomWordsFulfilledEvent.RequestId.String()). + Bool("Success", randomWordsFulfilledEvent.Success). + Uint64("BlockNumber", randomWordsFulfilledEvent.Raw.BlockNumber). + Str("BlockHash", randomWordsFulfilledEvent.Raw.BlockHash.String()). + Msg("RandomWordsFulfilled Event (TX metadata)") +} + +func LogMigrationCompletedEvent(l zerolog.Logger, migrationCompletedEvent *vrf_coordinator_v2_5.VRFCoordinatorV25MigrationCompleted, vrfv2PlusContracts *vrfcommon.VRFContracts) { + l.Info(). + Str("Subscription ID", migrationCompletedEvent.SubId.String()). + Str("Migrated From Coordinator", vrfv2PlusContracts.CoordinatorV2Plus.Address()). + Str("Migrated To Coordinator", migrationCompletedEvent.NewCoordinator.String()). + Msg("MigrationCompleted Event") +} + +func LogSubDetailsAfterMigration(l zerolog.Logger, newCoordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, subID *big.Int, migratedSubscription vrf_v2plus_upgraded_version.GetSubscription) { + l.Info(). + Str("New Coordinator", newCoordinator.Address()). + Str("Subscription ID", subID.String()). + Str("Juels Balance", migratedSubscription.Balance.String()). + Str("Native Token Balance", migratedSubscription.NativeBalance.String()). + Str("Subscription Owner", migratedSubscription.SubOwner.String()). + Interface("Subscription Consumers", migratedSubscription.Consumers). + Msg("Subscription Data After Migration to New Coordinator") +} + +func LogFulfillmentDetailsLinkBilling( + l zerolog.Logger, + wrapperConsumerJuelsBalanceBeforeRequest *big.Int, + wrapperConsumerJuelsBalanceAfterRequest *big.Int, + consumerStatus vrfv2plus_wrapper_load_test_consumer.GetRequestStatus, + randomWordsFulfilledEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, +) { + l.Info(). + Str("Consumer Balance Before Request (Link)", (*commonassets.Link)(wrapperConsumerJuelsBalanceBeforeRequest).Link()). + Str("Consumer Balance After Request (Link)", (*commonassets.Link)(wrapperConsumerJuelsBalanceAfterRequest).Link()). + Bool("Fulfilment Status", consumerStatus.Fulfilled). + Str("Paid by Consumer Contract (Link)", (*commonassets.Link)(consumerStatus.Paid).Link()). + Str("Paid by Coordinator Sub (Link)", (*commonassets.Link)(randomWordsFulfilledEvent.Payment).Link()). + Str("RequestTimestamp", consumerStatus.RequestTimestamp.String()). + Str("FulfilmentTimestamp", consumerStatus.FulfilmentTimestamp.String()). + Str("RequestBlockNumber", consumerStatus.RequestBlockNumber.String()). + Str("FulfilmentBlockNumber", consumerStatus.FulfilmentBlockNumber.String()). + Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). + Msg("Random Words Fulfilment Details For Link Billing") +} + +func LogFulfillmentDetailsNativeBilling( + l zerolog.Logger, + wrapperConsumerBalanceBeforeRequestWei *big.Int, + wrapperConsumerBalanceAfterRequestWei *big.Int, + consumerStatus vrfv2plus_wrapper_load_test_consumer.GetRequestStatus, + randomWordsFulfilledEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, +) { + l.Info(). + Str("Consumer Balance Before Request", assets.FormatWei(wrapperConsumerBalanceBeforeRequestWei)). + Str("Consumer Balance After Request", assets.FormatWei(wrapperConsumerBalanceAfterRequestWei)). + Bool("Fulfilment Status", consumerStatus.Fulfilled). + Str("Paid by Consumer Contract", assets.FormatWei(consumerStatus.Paid)). + Str("Paid by Coordinator Sub", assets.FormatWei(randomWordsFulfilledEvent.Payment)). + Str("RequestTimestamp", consumerStatus.RequestTimestamp.String()). + Str("FulfilmentTimestamp", consumerStatus.FulfilmentTimestamp.String()). + Str("RequestBlockNumber", consumerStatus.RequestBlockNumber.String()). + Str("FulfilmentBlockNumber", consumerStatus.FulfilmentBlockNumber.String()). + Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). + Msg("Random Words Request Fulfilment Details For Native Billing") +} + +func LogRandRequest( + l zerolog.Logger, + consumer string, + coordinator string, + subID *big.Int, + isNativeBilling bool, + keyHash [32]byte, + config *vrfv2plus_config.General) { + l.Info(). + Str("Consumer", consumer). + Str("Coordinator", coordinator). + Str("SubID", subID.String()). + Bool("IsNativePayment", isNativeBilling). + Uint16("MinimumConfirmations", *config.MinimumConfirmations). + Uint32("CallbackGasLimit", *config.CallbackGasLimit). + Uint32("NumberOfWords", *config.NumberOfWords). + Str("KeyHash", fmt.Sprintf("0x%x", keyHash)). + Uint16("RandomnessRequestCountPerRequest", *config.RandomnessRequestCountPerRequest). + Uint16("RandomnessRequestCountPerRequestDeviation", *config.RandomnessRequestCountPerRequestDeviation). + Msg("Requesting randomness") +} diff --git a/integration-tests/actions/vrf/vrfv2plus/vrfv2plus_models.go b/integration-tests/actions/vrf/vrfv2plus/models.go similarity index 100% rename from integration-tests/actions/vrf/vrfv2plus/vrfv2plus_models.go rename to integration-tests/actions/vrf/vrfv2plus/models.go diff --git a/integration-tests/actions/vrf/vrfv2plus/setup_steps.go b/integration-tests/actions/vrf/vrfv2plus/setup_steps.go new file mode 100644 index 00000000000..3d698ffec32 --- /dev/null +++ b/integration-tests/actions/vrf/vrfv2plus/setup_steps.go @@ -0,0 +1,545 @@ +package vrfv2plus + +import ( + "context" + "fmt" + "math/big" + "testing" + "time" + + "golang.org/x/sync/errgroup" + + "github.com/ethereum/go-ethereum/common" + "github.com/google/uuid" + "github.com/rs/zerolog" + + vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + + "github.com/smartcontractkit/chainlink/integration-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + vrfv2plus_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2plus" + "github.com/smartcontractkit/chainlink/integration-tests/types" +) + +func CreateVRFV2PlusJob( + chainlinkNode *client.ChainlinkClient, + vrfJobSpecConfig vrfcommon.VRFJobSpecConfig, +) (*client.Job, error) { + jobUUID := uuid.New() + os := &client.VRFV2PlusTxPipelineSpec{ + Address: vrfJobSpecConfig.CoordinatorAddress, + EstimateGasMultiplier: vrfJobSpecConfig.EstimateGasMultiplier, + FromAddress: vrfJobSpecConfig.FromAddresses[0], + SimulationBlock: vrfJobSpecConfig.SimulationBlock, + } + ost, err := os.String() + if err != nil { + return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrParseJob, err) + } + + job, err := chainlinkNode.MustCreateJob(&client.VRFV2PlusJobSpec{ + Name: fmt.Sprintf("vrf-v2-plus-%s", jobUUID), + CoordinatorAddress: vrfJobSpecConfig.CoordinatorAddress, + FromAddresses: vrfJobSpecConfig.FromAddresses, + EVMChainID: vrfJobSpecConfig.EVMChainID, + MinIncomingConfirmations: vrfJobSpecConfig.MinIncomingConfirmations, + PublicKey: vrfJobSpecConfig.PublicKey, + ExternalJobID: jobUUID.String(), + ObservationSource: ost, + BatchFulfillmentEnabled: vrfJobSpecConfig.BatchFulfillmentEnabled, + BatchFulfillmentGasMultiplier: vrfJobSpecConfig.BatchFulfillmentGasMultiplier, + PollPeriod: vrfJobSpecConfig.PollPeriod, + RequestTimeout: vrfJobSpecConfig.RequestTimeout, + }) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2PlusJob, err) + } + + return job, nil +} + +// SetupVRFV2_5Environment will create specified number of subscriptions and add the same conumer/s to each of them +func SetupVRFV2_5Environment( + ctx context.Context, + env *test_env.CLClusterTestEnv, + chainID int64, + nodesToCreate []vrfcommon.VRFNodeType, + vrfv2PlusTestConfig types.VRFv2PlusTestConfig, + linkToken contracts.LinkToken, + mockNativeLINKFeed contracts.VRFMockETHLINKFeed, + numberOfTxKeysToCreate int, + l zerolog.Logger, +) (*vrfcommon.VRFContracts, *vrfcommon.VRFKeyData, map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode, error) { + l.Info().Msg("Starting VRFV2 Plus environment setup") + configGeneral := vrfv2PlusTestConfig.GetVRFv2PlusConfig().General + vrfContracts, err := SetupVRFV2PlusContracts( + env, + chainID, + linkToken, + mockNativeLINKFeed, + configGeneral, + l, + ) + if err != nil { + return nil, nil, nil, err + } + + nodeTypeToNodeMap, err := vrfcommon.CreateNodeTypeToNodeMap(env.ClCluster, nodesToCreate) + if err != nil { + return nil, nil, nil, err + } + vrfKey, pubKeyCompressed, err := vrfcommon.CreateVRFKeyOnVRFNode(nodeTypeToNodeMap[vrfcommon.VRF], l) + if err != nil { + return nil, nil, nil, err + } + l.Info().Str("Coordinator", vrfContracts.CoordinatorV2Plus.Address()).Msg("Registering Proving Key") + provingKey, err := VRFV2_5RegisterProvingKey(vrfKey, vrfContracts.CoordinatorV2Plus, uint64(assets.GWei(*configGeneral.CLNodeMaxGasPriceGWei).Int64())) + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrRegisteringProvingKey, err) + } + keyHash, err := vrfContracts.CoordinatorV2Plus.HashOfKey(ctx, provingKey) + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrCreatingProvingKeyHash, err) + } + + evmClient, err := env.GetEVMClient(chainID) + if err != nil { + return nil, nil, nil, err + } + + vrfTXKeyAddressStrings, _, err := vrfcommon.CreateFundAndGetSendingKeys( + evmClient, + nodeTypeToNodeMap[vrfcommon.VRF], + *vrfv2PlusTestConfig.GetCommonConfig().ChainlinkNodeFunding, + numberOfTxKeysToCreate, + big.NewInt(chainID), + ) + if err != nil { + return nil, nil, nil, err + } + err = evmClient.WaitForEvents() + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + } + + nodeTypeToNodeMap[vrfcommon.VRF].TXKeyAddressStrings = vrfTXKeyAddressStrings + + g := errgroup.Group{} + if vrfNode, exists := nodeTypeToNodeMap[vrfcommon.VRF]; exists { + g.Go(func() error { + err := setupVRFNode(vrfContracts, big.NewInt(chainID), configGeneral, pubKeyCompressed, l, vrfNode) + if err != nil { + return err + } + return nil + }) + } + + if bhsNode, exists := nodeTypeToNodeMap[vrfcommon.BHS]; exists { + g.Go(func() error { + err := vrfcommon.SetupBHSNode( + env, + configGeneral.General, + numberOfTxKeysToCreate, + big.NewInt(chainID), + vrfContracts.CoordinatorV2Plus.Address(), + vrfContracts.BHS.Address(), + *vrfv2PlusTestConfig.GetCommonConfig().ChainlinkNodeFunding, + l, + bhsNode, + ) + if err != nil { + return err + } + return nil + }) + } + + if bhfNode, exists := nodeTypeToNodeMap[vrfcommon.BHF]; exists { + g.Go(func() error { + err := vrfcommon.SetupBHFNode( + env, + configGeneral.General, + numberOfTxKeysToCreate, + big.NewInt(chainID), + vrfContracts.CoordinatorV2Plus.Address(), + vrfContracts.BHS.Address(), + vrfContracts.BatchBHS.Address(), + *vrfv2PlusTestConfig.GetCommonConfig().ChainlinkNodeFunding, + l, + bhfNode, + ) + if err != nil { + return err + } + return nil + }) + } + + if err := g.Wait(); err != nil { + return nil, nil, nil, fmt.Errorf("VRF node setup ended up with an error: %w", err) + } + + vrfKeyData := vrfcommon.VRFKeyData{ + VRFKey: vrfKey, + EncodedProvingKey: provingKey, + KeyHash: keyHash, + PubKeyCompressed: pubKeyCompressed, + } + + l.Info().Msg("VRFV2 Plus environment setup is finished") + return vrfContracts, &vrfKeyData, nodeTypeToNodeMap, nil +} + +func setupVRFNode(contracts *vrfcommon.VRFContracts, chainID *big.Int, config *vrfv2plus_config.General, pubKeyCompressed string, l zerolog.Logger, vrfNode *vrfcommon.VRFNode) error { + vrfJobSpecConfig := vrfcommon.VRFJobSpecConfig{ + ForwardingAllowed: *config.VRFJobForwardingAllowed, + CoordinatorAddress: contracts.CoordinatorV2Plus.Address(), + FromAddresses: vrfNode.TXKeyAddressStrings, + EVMChainID: chainID.String(), + MinIncomingConfirmations: int(*config.MinimumConfirmations), + PublicKey: pubKeyCompressed, + EstimateGasMultiplier: *config.VRFJobEstimateGasMultiplier, + BatchFulfillmentEnabled: *config.VRFJobBatchFulfillmentEnabled, + BatchFulfillmentGasMultiplier: *config.VRFJobBatchFulfillmentGasMultiplier, + PollPeriod: config.VRFJobPollPeriod.Duration, + RequestTimeout: config.VRFJobRequestTimeout.Duration, + SimulationBlock: config.VRFJobSimulationBlock, + VRFOwnerConfig: nil, + } + + l.Info().Msg("Creating VRFV2 Plus Job") + job, err := CreateVRFV2PlusJob( + vrfNode.CLNode.API, + vrfJobSpecConfig, + ) + if err != nil { + return fmt.Errorf("%s, err %w", ErrCreateVRFV2PlusJobs, err) + } + vrfNode.Job = job + + // this part is here because VRFv2 can work with only a specific key + // [[EVM.KeySpecific]] + // Key = '...' + nodeConfig := node.NewConfig(vrfNode.CLNode.NodeConfig, + node.WithLogPollInterval(1*time.Second), + node.WithVRFv2EVMEstimator(vrfNode.TXKeyAddressStrings, *config.CLNodeMaxGasPriceGWei), + ) + l.Info().Msg("Restarting Node with new sending key PriceMax configuration") + err = vrfNode.CLNode.Restart(nodeConfig) + if err != nil { + return fmt.Errorf("%s, err %w", vrfcommon.ErrRestartCLNode, err) + } + return nil +} + +func SetupVRFV2PlusWrapperEnvironment( + ctx context.Context, + env *test_env.CLClusterTestEnv, + chainID int64, + vrfv2PlusTestConfig types.VRFv2PlusTestConfig, + linkToken contracts.LinkToken, + mockNativeLINKFeed contracts.MockETHLINKFeed, + coordinator contracts.VRFCoordinatorV2_5, + keyHash [32]byte, + wrapperConsumerContractsAmount int, +) (*VRFV2PlusWrapperContracts, *big.Int, error) { + // external EOA has to create a subscription for the wrapper first + wrapperSubId, err := CreateSubAndFindSubID(env, chainID, coordinator) + if err != nil { + return nil, nil, err + } + + vrfv2PlusConfig := vrfv2PlusTestConfig.GetVRFv2PlusConfig().General + + evmClient, err := env.GetEVMClient(chainID) + if err != nil { + return nil, nil, err + } + + wrapperContracts, err := DeployVRFV2PlusDirectFundingContracts( + env.ContractDeployer, + evmClient, + linkToken.Address(), + mockNativeLINKFeed.Address(), + coordinator, + wrapperConsumerContractsAmount, + wrapperSubId, + ) + if err != nil { + return nil, nil, err + } + + err = evmClient.WaitForEvents() + + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + } + + // once the wrapper is deployed, wrapper address will become consumer of external EOA subscription + err = coordinator.AddConsumer(wrapperSubId, wrapperContracts.VRFV2PlusWrapper.Address()) + if err != nil { + return nil, nil, err + } + + err = evmClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + } + + err = wrapperContracts.VRFV2PlusWrapper.SetConfig( + *vrfv2PlusConfig.WrapperGasOverhead, + *vrfv2PlusConfig.CoordinatorGasOverhead, + //todo - introduce separate config for Wrapper Premium Percentage + *vrfv2PlusConfig.NativePremiumPercentage, + *vrfv2PlusConfig.LinkPremiumPercentage, + keyHash, + *vrfv2PlusConfig.WrapperMaxNumberOfWords, + *vrfv2PlusConfig.StalenessSeconds, + big.NewInt(*vrfv2PlusConfig.FallbackWeiPerUnitLink), + *vrfv2PlusConfig.FulfillmentFlatFeeLinkPPM, + *vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, + ) + if err != nil { + return nil, nil, err + } + + err = evmClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + } + + //fund sub + wrapperSubID, err := wrapperContracts.VRFV2PlusWrapper.GetSubID(ctx) + if err != nil { + return nil, nil, err + } + + err = evmClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + } + + err = FundSubscriptions( + env, + chainID, + big.NewFloat(*vrfv2PlusTestConfig.GetVRFv2PlusConfig().General.SubscriptionFundingAmountNative), + big.NewFloat(*vrfv2PlusTestConfig.GetVRFv2PlusConfig().General.SubscriptionFundingAmountLink), + linkToken, + coordinator, + []*big.Int{wrapperSubID}, + ) + if err != nil { + return nil, nil, err + } + + //fund consumer with Link + err = linkToken.Transfer( + wrapperContracts.LoadTestConsumers[0].Address(), + big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(*vrfv2PlusConfig.WrapperConsumerFundingAmountLink)), + ) + if err != nil { + return nil, nil, err + } + err = evmClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + } + + //fund consumer with Eth + err = wrapperContracts.LoadTestConsumers[0].Fund(big.NewFloat(*vrfv2PlusConfig.WrapperConsumerFundingAmountNativeToken)) + if err != nil { + return nil, nil, err + } + err = evmClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) + } + return wrapperContracts, wrapperSubID, nil +} + +func SetupVRFV2PlusUniverse(ctx context.Context, t *testing.T, testConfig tc.TestConfig, chainID int64, cleanupFn func(), newEnvConfig vrfcommon.NewEnvConfig, l zerolog.Logger) (*test_env.CLClusterTestEnv, *vrfcommon.VRFContracts, *vrfcommon.VRFKeyData, map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode, error) { + var ( + env *test_env.CLClusterTestEnv + vrfContracts *vrfcommon.VRFContracts + vrfKey *vrfcommon.VRFKeyData + nodeTypeToNode map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode + err error + ) + if *testConfig.VRFv2Plus.General.UseExistingEnv { + vrfContracts, vrfKey, env, err = SetupVRFV2PlusForExistingEnv(ctx, t, testConfig, chainID, cleanupFn, l) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "Error setting up VRF V2 Plus for Existing env", err) + } + } else { + vrfContracts, vrfKey, env, nodeTypeToNode, err = SetupVRFV2PlusForNewEnv(ctx, t, testConfig, chainID, cleanupFn, newEnvConfig, l) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "Error setting up VRF V2 Plus for New env", err) + } + } + return env, vrfContracts, vrfKey, nodeTypeToNode, nil +} + +func SetupVRFV2PlusForNewEnv( + ctx context.Context, + t *testing.T, + testConfig tc.TestConfig, + chainID int64, + cleanupFn func(), + newEnvConfig vrfcommon.NewEnvConfig, + l zerolog.Logger, +) (*vrfcommon.VRFContracts, *vrfcommon.VRFKeyData, *test_env.CLClusterTestEnv, map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode, error) { + network, err := actions.EthereumNetworkConfigFromConfig(l, &testConfig) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "Error building ethereum network config", err) + } + env, err := test_env.NewCLTestEnvBuilder(). + WithTestInstance(t). + WithTestConfig(&testConfig). + WithPrivateEthereumNetwork(network). + WithCLNodes(len(newEnvConfig.NodesToCreate)). + WithFunding(big.NewFloat(*testConfig.Common.ChainlinkNodeFunding)). + WithCustomCleanup(cleanupFn). + Build() + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error creating test env", err) + } + + env.ParallelTransactions(true) + + mockETHLinkFeed, err := env.ContractDeployer.DeployVRFMockETHLINKFeed(big.NewInt(*testConfig.VRFv2Plus.General.LinkNativeFeedResponse)) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error deploying mock ETH/LINK feed", err) + } + + linkToken, err := actions.DeployLINKToken(env.ContractDeployer) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error deploying LINK contract", err) + } + + vrfContracts, vrfKey, nodeTypeToNode, err := SetupVRFV2_5Environment( + ctx, + env, + chainID, + newEnvConfig.NodesToCreate, + &testConfig, + linkToken, + mockETHLinkFeed, + newEnvConfig.NumberOfTxKeysToCreate, + l, + ) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error setting up VRF v2_5 env", err) + } + return vrfContracts, vrfKey, env, nodeTypeToNode, nil +} + +func SetupVRFV2PlusForExistingEnv(ctx context.Context, t *testing.T, testConfig tc.TestConfig, chainID int64, cleanupFn func(), l zerolog.Logger) (*vrfcommon.VRFContracts, *vrfcommon.VRFKeyData, *test_env.CLClusterTestEnv, error) { + commonExistingEnvConfig := testConfig.VRFv2Plus.ExistingEnvConfig.ExistingEnvConfig + env, err := test_env.NewCLTestEnvBuilder(). + WithTestInstance(t). + WithTestConfig(&testConfig). + WithCustomCleanup(cleanupFn). + Build() + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err: %w", "error creating test env", err) + } + coordinator, err := env.ContractLoader.LoadVRFCoordinatorV2_5(*commonExistingEnvConfig.CoordinatorAddress) + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err: %w", "error loading VRFCoordinator2_5", err) + } + linkToken, err := env.ContractLoader.LoadLINKToken(*commonExistingEnvConfig.LinkAddress) + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err: %w", "error loading LinkToken", err) + } + + evmClient, err := env.GetEVMClient(chainID) + if err != nil { + return nil, nil, nil, err + } + + err = vrfcommon.FundNodesIfNeeded(ctx, commonExistingEnvConfig, evmClient, l) + if err != nil { + return nil, nil, nil, fmt.Errorf("err: %w", err) + } + vrfContracts := &vrfcommon.VRFContracts{ + CoordinatorV2Plus: coordinator, + VRFV2PlusConsumer: nil, + LinkToken: linkToken, + BHS: nil, + } + + vrfKey := &vrfcommon.VRFKeyData{ + VRFKey: nil, + EncodedProvingKey: [2]*big.Int{}, + KeyHash: common.HexToHash(*commonExistingEnvConfig.KeyHash), + } + return vrfContracts, vrfKey, env, nil +} + +func SetupSubsAndConsumersForExistingEnv( + env *test_env.CLClusterTestEnv, + chainID int64, + coordinator contracts.VRFCoordinatorV2_5, + linkToken contracts.LinkToken, + numberOfConsumerContractsToDeployAndAddToSub int, + numberOfSubToCreate int, + testConfig tc.TestConfig, + l zerolog.Logger, +) ([]*big.Int, []contracts.VRFv2PlusLoadTestConsumer, error) { + var ( + subIDs []*big.Int + consumers []contracts.VRFv2PlusLoadTestConsumer + err error + ) + if *testConfig.VRFv2Plus.General.UseExistingEnv { + commonExistingEnvConfig := testConfig.VRFv2Plus.ExistingEnvConfig.ExistingEnvConfig + if *commonExistingEnvConfig.CreateFundSubsAndAddConsumers { + consumers, subIDs, err = SetupNewConsumersAndSubs( + env, + chainID, + coordinator, + testConfig, + linkToken, + numberOfConsumerContractsToDeployAndAddToSub, + numberOfSubToCreate, + l, + ) + if err != nil { + return nil, nil, fmt.Errorf("err: %w", err) + } + } else { + consumer, err := env.ContractLoader.LoadVRFv2PlusLoadTestConsumer(*commonExistingEnvConfig.ConsumerAddress) + if err != nil { + return nil, nil, fmt.Errorf("err: %w", err) + } + consumers = append(consumers, consumer) + var ok bool + subID, ok := new(big.Int).SetString(*testConfig.VRFv2Plus.ExistingEnvConfig.SubID, 10) + if !ok { + return nil, nil, fmt.Errorf("unable to parse subID: %s %w", *testConfig.VRFv2Plus.ExistingEnvConfig.SubID, err) + } + subIDs = append(subIDs, subID) + } + } else { + consumers, subIDs, err = SetupNewConsumersAndSubs( + env, + chainID, + coordinator, + testConfig, + linkToken, + numberOfConsumerContractsToDeployAndAddToSub, + numberOfSubToCreate, + l, + ) + if err != nil { + return nil, nil, fmt.Errorf("err: %w", err) + } + } + return subIDs, consumers, nil +} diff --git a/integration-tests/actions/vrf/vrfv2plus/vrfv2plus_steps.go b/integration-tests/actions/vrf/vrfv2plus/vrfv2plus_steps.go deleted file mode 100644 index 658fce7f6d9..00000000000 --- a/integration-tests/actions/vrf/vrfv2plus/vrfv2plus_steps.go +++ /dev/null @@ -1,1145 +0,0 @@ -package vrfv2plus - -import ( - "context" - "fmt" - "math/big" - "time" - - "golang.org/x/sync/errgroup" - - commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" - "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" - vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" - testconfig "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2plus" - "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer" - - "github.com/ethereum/go-ethereum/common" - "github.com/google/uuid" - "github.com/rs/zerolog" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" - vrfv2plus_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2plus" - "github.com/smartcontractkit/chainlink/integration-tests/types" - chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" -) - -func DeployVRFV2_5Contracts( - contractDeployer contracts.ContractDeployer, - chainClient blockchain.EVMClient, - consumerContractsAmount int, -) (*vrfcommon.VRFContracts, error) { - bhs, err := contractDeployer.DeployBlockhashStore() - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrDeployBlockHashStore, err) - } - err = chainClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - coordinator, err := contractDeployer.DeployVRFCoordinatorV2_5(bhs.Address()) - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrDeployCoordinator, err) - } - err = chainClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - consumers, err := DeployVRFV2PlusConsumers(contractDeployer, coordinator, consumerContractsAmount) - if err != nil { - return nil, err - } - err = chainClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - return &vrfcommon.VRFContracts{ - CoordinatorV2Plus: coordinator, - BHS: bhs, - VRFV2PlusConsumer: consumers, - }, nil -} - -func DeployVRFV2PlusConsumers(contractDeployer contracts.ContractDeployer, coordinator contracts.VRFCoordinatorV2_5, consumerContractsAmount int) ([]contracts.VRFv2PlusLoadTestConsumer, error) { - var consumers []contracts.VRFv2PlusLoadTestConsumer - for i := 1; i <= consumerContractsAmount; i++ { - loadTestConsumer, err := contractDeployer.DeployVRFv2PlusLoadTestConsumer(coordinator.Address()) - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrAdvancedConsumer, err) - } - consumers = append(consumers, loadTestConsumer) - } - return consumers, nil -} - -func CreateVRFV2PlusJob( - chainlinkNode *client.ChainlinkClient, - vrfJobSpecConfig vrfcommon.VRFJobSpecConfig, -) (*client.Job, error) { - jobUUID := uuid.New() - os := &client.VRFV2PlusTxPipelineSpec{ - Address: vrfJobSpecConfig.CoordinatorAddress, - EstimateGasMultiplier: vrfJobSpecConfig.EstimateGasMultiplier, - FromAddress: vrfJobSpecConfig.FromAddresses[0], - SimulationBlock: vrfJobSpecConfig.SimulationBlock, - } - ost, err := os.String() - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrParseJob, err) - } - - job, err := chainlinkNode.MustCreateJob(&client.VRFV2PlusJobSpec{ - Name: fmt.Sprintf("vrf-v2-plus-%s", jobUUID), - CoordinatorAddress: vrfJobSpecConfig.CoordinatorAddress, - FromAddresses: vrfJobSpecConfig.FromAddresses, - EVMChainID: vrfJobSpecConfig.EVMChainID, - MinIncomingConfirmations: vrfJobSpecConfig.MinIncomingConfirmations, - PublicKey: vrfJobSpecConfig.PublicKey, - ExternalJobID: jobUUID.String(), - ObservationSource: ost, - BatchFulfillmentEnabled: vrfJobSpecConfig.BatchFulfillmentEnabled, - BatchFulfillmentGasMultiplier: vrfJobSpecConfig.BatchFulfillmentGasMultiplier, - PollPeriod: vrfJobSpecConfig.PollPeriod, - RequestTimeout: vrfJobSpecConfig.RequestTimeout, - }) - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2PlusJob, err) - } - return job, nil -} - -func VRFV2_5RegisterProvingKey( - vrfKey *client.VRFKey, - coordinator contracts.VRFCoordinatorV2_5, - gasLaneMaxGas uint64, -) (vrfcommon.VRFEncodedProvingKey, error) { - provingKey, err := actions.EncodeOnChainVRFProvingKey(*vrfKey) - if err != nil { - return vrfcommon.VRFEncodedProvingKey{}, fmt.Errorf("%s, err %w", vrfcommon.ErrEncodingProvingKey, err) - } - err = coordinator.RegisterProvingKey( - provingKey, - gasLaneMaxGas, - ) - if err != nil { - return vrfcommon.VRFEncodedProvingKey{}, fmt.Errorf("%s, err %w", vrfcommon.ErrRegisterProvingKey, err) - } - return provingKey, nil -} - -func VRFV2PlusUpgradedVersionRegisterProvingKey( - vrfKey *client.VRFKey, - coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, -) (vrfcommon.VRFEncodedProvingKey, error) { - provingKey, err := actions.EncodeOnChainVRFProvingKey(*vrfKey) - if err != nil { - return vrfcommon.VRFEncodedProvingKey{}, fmt.Errorf("%s, err %w", vrfcommon.ErrEncodingProvingKey, err) - } - err = coordinator.RegisterProvingKey( - provingKey, - ) - if err != nil { - return vrfcommon.VRFEncodedProvingKey{}, fmt.Errorf("%s, err %w", vrfcommon.ErrRegisterProvingKey, err) - } - return provingKey, nil -} - -func FundVRFCoordinatorV2_5Subscription( - linkToken contracts.LinkToken, - coordinator contracts.VRFCoordinatorV2_5, - chainClient blockchain.EVMClient, - subscriptionID *big.Int, - linkFundingAmountJuels *big.Int, -) error { - encodedSubId, err := chainlinkutils.ABIEncode(`[{"type":"uint256"}]`, subscriptionID) - if err != nil { - return fmt.Errorf("%s, err %w", vrfcommon.ErrABIEncodingFunding, err) - } - _, err = linkToken.TransferAndCall(coordinator.Address(), linkFundingAmountJuels, encodedSubId) - if err != nil { - return fmt.Errorf("%s, err %w", vrfcommon.ErrSendingLinkToken, err) - } - return chainClient.WaitForEvents() -} - -// SetupVRFV2_5Environment will create specified number of subscriptions and add the same conumer/s to each of them -func SetupVRFV2_5Environment( - env *test_env.CLClusterTestEnv, - nodesToCreate []vrfcommon.VRFNodeType, - vrfv2PlusTestConfig types.VRFv2PlusTestConfig, - linkToken contracts.LinkToken, - mockNativeLINKFeed contracts.MockETHLINKFeed, - numberOfTxKeysToCreate int, - numberOfConsumers int, - numberOfSubToCreate int, - l zerolog.Logger, -) (*vrfcommon.VRFContracts, []*big.Int, *vrfcommon.VRFKeyData, map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode, error) { - l.Info().Msg("Starting VRFV2 Plus environment setup") - configGeneral := vrfv2PlusTestConfig.GetVRFv2PlusConfig().General - vrfContracts, subIDs, err := SetupVRFV2PlusContracts( - env, - linkToken, - mockNativeLINKFeed, - configGeneral, - numberOfSubToCreate, - numberOfConsumers, - l, - ) - if err != nil { - return nil, nil, nil, nil, err - } - - nodeTypeToNodeMap := vrfcommon.CreateNodeTypeToNodeMap(env.ClCluster, nodesToCreate) - vrfKey, pubKeyCompressed, err := vrfcommon.CreateVRFKeyOnVRFNode(nodeTypeToNodeMap[vrfcommon.VRF], l) - if err != nil { - return nil, nil, nil, nil, err - } - - l.Info().Str("Coordinator", vrfContracts.CoordinatorV2Plus.Address()).Msg("Registering Proving Key") - provingKey, err := VRFV2_5RegisterProvingKey(vrfKey, vrfContracts.CoordinatorV2Plus, uint64(assets.GWei(*configGeneral.CLNodeMaxGasPriceGWei).Int64())) - if err != nil { - return nil, nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrRegisteringProvingKey, err) - } - keyHash, err := vrfContracts.CoordinatorV2Plus.HashOfKey(context.Background(), provingKey) - if err != nil { - return nil, nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrCreatingProvingKeyHash, err) - } - - chainID := env.EVMClient.GetChainID() - vrfTXKeyAddressStrings, _, err := vrfcommon.CreateFundAndGetSendingKeys( - env.EVMClient, - nodeTypeToNodeMap[vrfcommon.VRF], - *vrfv2PlusTestConfig.GetCommonConfig().ChainlinkNodeFunding, - numberOfTxKeysToCreate, - chainID, - ) - if err != nil { - return nil, nil, nil, nil, err - } - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, nil, nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - - nodeTypeToNodeMap[vrfcommon.VRF].TXKeyAddressStrings = vrfTXKeyAddressStrings - - g := errgroup.Group{} - if vrfNode, exists := nodeTypeToNodeMap[vrfcommon.VRF]; exists { - g.Go(func() error { - err := SetupVRFNode(vrfContracts, chainID, configGeneral, pubKeyCompressed, l, vrfNode) - if err != nil { - return err - } - return nil - }) - } - - if bhsNode, exists := nodeTypeToNodeMap[vrfcommon.BHS]; exists { - g.Go(func() error { - err := vrfcommon.SetupBHSNode( - env, - configGeneral.General, - numberOfTxKeysToCreate, - chainID, - vrfContracts.CoordinatorV2Plus.Address(), - vrfContracts.BHS.Address(), - *vrfv2PlusTestConfig.GetCommonConfig().ChainlinkNodeFunding, - l, - bhsNode, - ) - if err != nil { - return err - } - return nil - }) - } - - if err := g.Wait(); err != nil { - return nil, nil, nil, nil, fmt.Errorf("VRF node setup ended up with an error: %w", err) - } - - vrfKeyData := vrfcommon.VRFKeyData{ - VRFKey: vrfKey, - EncodedProvingKey: provingKey, - KeyHash: keyHash, - PubKeyCompressed: pubKeyCompressed, - } - - l.Info().Msg("VRFV2 Plus environment setup is finished") - return vrfContracts, subIDs, &vrfKeyData, nodeTypeToNodeMap, nil -} - -func SetupVRFV2PlusContracts( - env *test_env.CLClusterTestEnv, - linkToken contracts.LinkToken, - mockNativeLINKFeed contracts.MockETHLINKFeed, - configGeneral *testconfig.General, - numberOfSubToCreate int, - numberOfConsumers int, - l zerolog.Logger, -) (*vrfcommon.VRFContracts, []*big.Int, error) { - l.Info().Msg("Deploying VRFV2 Plus contracts") - vrfContracts, err := DeployVRFV2_5Contracts(env.ContractDeployer, env.EVMClient, numberOfConsumers) - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrDeployVRFV2_5Contracts, err) - } - - l.Info().Str("Coordinator", vrfContracts.CoordinatorV2Plus.Address()).Msg("Setting Coordinator Config") - err = vrfContracts.CoordinatorV2Plus.SetConfig( - *configGeneral.MinimumConfirmations, - *configGeneral.MaxGasLimitCoordinatorConfig, - *configGeneral.StalenessSeconds, - *configGeneral.GasAfterPaymentCalculation, - big.NewInt(*configGeneral.FallbackWeiPerUnitLink), - *configGeneral.FulfillmentFlatFeeNativePPM, - *configGeneral.FulfillmentFlatFeeLinkDiscountPPM, - *configGeneral.NativePremiumPercentage, - *configGeneral.LinkPremiumPercentage, - ) - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrSetVRFCoordinatorConfig, err) - } - - l.Info().Str("Coordinator", vrfContracts.CoordinatorV2Plus.Address()).Msg("Setting Link and ETH/LINK feed") - err = vrfContracts.CoordinatorV2Plus.SetLINKAndLINKNativeFeed(linkToken.Address(), mockNativeLINKFeed.Address()) - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrSetLinkNativeLinkFeed, err) - } - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - l.Info(). - Str("Coordinator", vrfContracts.CoordinatorV2Plus.Address()). - Int("Number of Subs to create", numberOfSubToCreate). - Msg("Creating and funding subscriptions, adding consumers") - subIDs, err := CreateFundSubsAndAddConsumers( - env, - big.NewFloat(*configGeneral.SubscriptionFundingAmountNative), - big.NewFloat(*configGeneral.SubscriptionFundingAmountLink), - linkToken, - vrfContracts.CoordinatorV2Plus, vrfContracts.VRFV2PlusConsumer, - numberOfSubToCreate, - ) - if err != nil { - return nil, nil, err - } - return vrfContracts, subIDs, nil -} - -func SetupVRFNode(contracts *vrfcommon.VRFContracts, chainID *big.Int, config *vrfv2plus_config.General, pubKeyCompressed string, l zerolog.Logger, vrfNode *vrfcommon.VRFNode) error { - vrfJobSpecConfig := vrfcommon.VRFJobSpecConfig{ - ForwardingAllowed: *config.VRFJobForwardingAllowed, - CoordinatorAddress: contracts.CoordinatorV2Plus.Address(), - FromAddresses: vrfNode.TXKeyAddressStrings, - EVMChainID: chainID.String(), - MinIncomingConfirmations: int(*config.MinimumConfirmations), - PublicKey: pubKeyCompressed, - EstimateGasMultiplier: *config.VRFJobEstimateGasMultiplier, - BatchFulfillmentEnabled: *config.VRFJobBatchFulfillmentEnabled, - BatchFulfillmentGasMultiplier: *config.VRFJobBatchFulfillmentGasMultiplier, - PollPeriod: config.VRFJobPollPeriod.Duration, - RequestTimeout: config.VRFJobRequestTimeout.Duration, - SimulationBlock: config.VRFJobSimulationBlock, - VRFOwnerConfig: nil, - } - - l.Info().Msg("Creating VRFV2 Plus Job") - job, err := CreateVRFV2PlusJob( - vrfNode.CLNode.API, - vrfJobSpecConfig, - ) - if err != nil { - return fmt.Errorf("%s, err %w", ErrCreateVRFV2PlusJobs, err) - } - vrfNode.Job = job - - // this part is here because VRFv2 can work with only a specific key - // [[EVM.KeySpecific]] - // Key = '...' - nodeConfig := node.NewConfig(vrfNode.CLNode.NodeConfig, - node.WithLogPollInterval(1*time.Second), - node.WithVRFv2EVMEstimator(vrfNode.TXKeyAddressStrings, *config.CLNodeMaxGasPriceGWei), - ) - l.Info().Msg("Restarting Node with new sending key PriceMax configuration") - err = vrfNode.CLNode.Restart(nodeConfig) - if err != nil { - return fmt.Errorf("%s, err %w", vrfcommon.ErrRestartCLNode, err) - } - return nil -} - -func CreateFundSubsAndAddConsumers( - env *test_env.CLClusterTestEnv, - subscriptionFundingAmountNative *big.Float, - subscriptionFundingAmountLink *big.Float, - linkToken contracts.LinkToken, - coordinator contracts.VRFCoordinatorV2_5, - consumers []contracts.VRFv2PlusLoadTestConsumer, - numberOfSubToCreate int, -) ([]*big.Int, error) { - subIDs, err := CreateSubsAndFund( - env, - subscriptionFundingAmountNative, - subscriptionFundingAmountLink, - linkToken, - coordinator, - numberOfSubToCreate, - ) - if err != nil { - return nil, err - } - subToConsumersMap := map[*big.Int][]contracts.VRFv2PlusLoadTestConsumer{} - - //each subscription will have the same consumers - for _, subID := range subIDs { - subToConsumersMap[subID] = consumers - } - - err = AddConsumersToSubs( - subToConsumersMap, - coordinator, - ) - if err != nil { - return nil, err - } - - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - return subIDs, nil -} - -func CreateSubsAndFund( - env *test_env.CLClusterTestEnv, - subscriptionFundingAmountNative *big.Float, - subscriptionFundingAmountLink *big.Float, - linkToken contracts.LinkToken, - coordinator contracts.VRFCoordinatorV2_5, - subAmountToCreate int, -) ([]*big.Int, error) { - subs, err := CreateSubs(env, coordinator, subAmountToCreate) - if err != nil { - return nil, err - } - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - err = FundSubscriptions( - env, - subscriptionFundingAmountNative, - subscriptionFundingAmountLink, - linkToken, - coordinator, - subs, - ) - if err != nil { - return nil, err - } - return subs, nil -} - -func CreateSubs( - env *test_env.CLClusterTestEnv, - coordinator contracts.VRFCoordinatorV2_5, - subAmountToCreate int, -) ([]*big.Int, error) { - var subIDArr []*big.Int - - for i := 0; i < subAmountToCreate; i++ { - subID, err := CreateSubAndFindSubID(env, coordinator) - if err != nil { - return nil, err - } - subIDArr = append(subIDArr, subID) - } - return subIDArr, nil -} - -func AddConsumersToSubs( - subToConsumerMap map[*big.Int][]contracts.VRFv2PlusLoadTestConsumer, - coordinator contracts.VRFCoordinatorV2_5, -) error { - for subID, consumers := range subToConsumerMap { - for _, consumer := range consumers { - err := coordinator.AddConsumer(subID, consumer.Address()) - if err != nil { - return fmt.Errorf("%s, err %w", ErrAddConsumerToSub, err) - } - } - } - return nil -} - -func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, coordinator contracts.VRFCoordinatorV2_5) (*big.Int, error) { - tx, err := coordinator.CreateSubscription() - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrCreateVRFSubscription, err) - } - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - - receipt, err := env.EVMClient.GetTxReceipt(tx.Hash()) - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - - //SubscriptionsCreated Log should be emitted with the subscription ID - subID := receipt.Logs[0].Topics[1].Big() - - return subID, nil -} - -func FundSubscriptions( - env *test_env.CLClusterTestEnv, - subscriptionFundingAmountNative *big.Float, - subscriptionFundingAmountLink *big.Float, - linkAddress contracts.LinkToken, - coordinator contracts.VRFCoordinatorV2_5, - subIDs []*big.Int, -) error { - for _, subID := range subIDs { - //Native Billing - amountWei := conversions.EtherToWei(subscriptionFundingAmountNative) - err := coordinator.FundSubscriptionWithNative( - subID, - amountWei, - ) - if err != nil { - return fmt.Errorf("%s, err %w", ErrFundSubWithNativeToken, err) - } - //Link Billing - amountJuels := conversions.EtherToWei(subscriptionFundingAmountLink) - err = FundVRFCoordinatorV2_5Subscription(linkAddress, coordinator, env.EVMClient, subID, amountJuels) - if err != nil { - return fmt.Errorf("%s, err %w", vrfcommon.ErrFundSubWithLinkToken, err) - } - } - err := env.EVMClient.WaitForEvents() - if err != nil { - return fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - return nil -} - -func GetUpgradedCoordinatorTotalBalance(coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion) (linkTotalBalance *big.Int, nativeTokenTotalBalance *big.Int, err error) { - linkTotalBalance, err = coordinator.GetLinkTotalBalance(context.Background()) - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrLinkTotalBalance, err) - } - nativeTokenTotalBalance, err = coordinator.GetNativeTokenTotalBalance(context.Background()) - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrNativeTokenBalance, err) - } - return -} - -func GetCoordinatorTotalBalance(coordinator contracts.VRFCoordinatorV2_5) (linkTotalBalance *big.Int, nativeTokenTotalBalance *big.Int, err error) { - linkTotalBalance, err = coordinator.GetLinkTotalBalance(context.Background()) - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrLinkTotalBalance, err) - } - nativeTokenTotalBalance, err = coordinator.GetNativeTokenTotalBalance(context.Background()) - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", ErrNativeTokenBalance, err) - } - return -} - -func RequestRandomnessAndWaitForFulfillment( - consumer contracts.VRFv2PlusLoadTestConsumer, - coordinator contracts.VRFCoordinatorV2_5, - vrfKeyData *vrfcommon.VRFKeyData, - subID *big.Int, - isNativeBilling bool, - config *vrfv2plus_config.General, - l zerolog.Logger, -) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { - LogRandRequest( - l, - consumer.Address(), - coordinator.Address(), - subID, - isNativeBilling, - vrfKeyData.KeyHash, - config, - ) - _, err := consumer.RequestRandomness( - vrfKeyData.KeyHash, - subID, - *config.MinimumConfirmations, - *config.CallbackGasLimit, - isNativeBilling, - *config.NumberOfWords, - *config.RandomnessRequestCountPerRequest, - ) - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrRequestRandomness, err) - } - - return WaitForRequestAndFulfillmentEvents( - consumer.Address(), - coordinator, - vrfKeyData, - subID, - isNativeBilling, - config.RandomWordsFulfilledEventTimeout.Duration, - l, - ) -} - -func RequestRandomnessAndWaitForFulfillmentUpgraded( - consumer contracts.VRFv2PlusLoadTestConsumer, - coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, - vrfKeyData *vrfcommon.VRFKeyData, - subID *big.Int, - isNativeBilling bool, - config *vrfv2plus_config.General, - l zerolog.Logger, -) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, error) { - LogRandRequest( - l, - consumer.Address(), - coordinator.Address(), - subID, - isNativeBilling, - vrfKeyData.KeyHash, - config, - ) - _, err := consumer.RequestRandomness( - vrfKeyData.KeyHash, - subID, - *config.MinimumConfirmations, - *config.CallbackGasLimit, - isNativeBilling, - *config.NumberOfWords, - *config.RandomnessRequestCountPerRequest, - ) - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrRequestRandomness, err) - } - - return WaitForRequestAndFulfillmentEventsUpgraded( - consumer.Address(), - coordinator, - vrfKeyData, - subID, - isNativeBilling, - config.RandomWordsFulfilledEventTimeout.Duration, - l, - ) -} - -func SetupVRFV2PlusWrapperEnvironment( - env *test_env.CLClusterTestEnv, - vrfv2PlusTestConfig types.VRFv2PlusTestConfig, - linkToken contracts.LinkToken, - mockNativeLINKFeed contracts.MockETHLINKFeed, - coordinator contracts.VRFCoordinatorV2_5, - keyHash [32]byte, - wrapperConsumerContractsAmount int, -) (*VRFV2PlusWrapperContracts, *big.Int, error) { - vrfv2PlusConfig := vrfv2PlusTestConfig.GetVRFv2PlusConfig().General - wrapperContracts, err := DeployVRFV2PlusDirectFundingContracts( - env.ContractDeployer, - env.EVMClient, - linkToken.Address(), - mockNativeLINKFeed.Address(), - coordinator, - wrapperConsumerContractsAmount, - ) - if err != nil { - return nil, nil, err - } - - err = env.EVMClient.WaitForEvents() - - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - err = wrapperContracts.VRFV2PlusWrapper.SetConfig( - *vrfv2PlusConfig.WrapperGasOverhead, - *vrfv2PlusConfig.CoordinatorGasOverhead, - *vrfv2PlusConfig.WrapperPremiumPercentage, - keyHash, - *vrfv2PlusConfig.WrapperMaxNumberOfWords, - *vrfv2PlusConfig.StalenessSeconds, - big.NewInt(*vrfv2PlusConfig.FallbackWeiPerUnitLink), - *vrfv2PlusConfig.FulfillmentFlatFeeLinkPPM, - *vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, - ) - if err != nil { - return nil, nil, err - } - - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - - //fund sub - wrapperSubID, err := wrapperContracts.VRFV2PlusWrapper.GetSubID(context.Background()) - if err != nil { - return nil, nil, err - } - - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - - err = FundSubscriptions( - env, - big.NewFloat(*vrfv2PlusTestConfig.GetVRFv2PlusConfig().General.SubscriptionFundingAmountNative), - big.NewFloat(*vrfv2PlusTestConfig.GetVRFv2PlusConfig().General.SubscriptionFundingAmountLink), - linkToken, - coordinator, - []*big.Int{wrapperSubID}, - ) - if err != nil { - return nil, nil, err - } - - //fund consumer with Link - err = linkToken.Transfer( - wrapperContracts.LoadTestConsumers[0].Address(), - big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(*vrfv2PlusConfig.WrapperConsumerFundingAmountLink)), - ) - if err != nil { - return nil, nil, err - } - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - - //fund consumer with Eth - err = wrapperContracts.LoadTestConsumers[0].Fund(big.NewFloat(*vrfv2PlusConfig.WrapperConsumerFundingAmountNativeToken)) - if err != nil { - return nil, nil, err - } - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - return wrapperContracts, wrapperSubID, nil -} - -func DeployVRFV2PlusWrapperConsumers(contractDeployer contracts.ContractDeployer, linkTokenAddress string, vrfV2PlusWrapper contracts.VRFV2PlusWrapper, consumerContractsAmount int) ([]contracts.VRFv2PlusWrapperLoadTestConsumer, error) { - var consumers []contracts.VRFv2PlusWrapperLoadTestConsumer - for i := 1; i <= consumerContractsAmount; i++ { - loadTestConsumer, err := contractDeployer.DeployVRFV2PlusWrapperLoadTestConsumer(linkTokenAddress, vrfV2PlusWrapper.Address()) - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrAdvancedConsumer, err) - } - consumers = append(consumers, loadTestConsumer) - } - return consumers, nil -} - -func DeployVRFV2PlusDirectFundingContracts( - contractDeployer contracts.ContractDeployer, - chainClient blockchain.EVMClient, - linkTokenAddress string, - linkEthFeedAddress string, - coordinator contracts.VRFCoordinatorV2_5, - consumerContractsAmount int, -) (*VRFV2PlusWrapperContracts, error) { - - vrfv2PlusWrapper, err := contractDeployer.DeployVRFV2PlusWrapper(linkTokenAddress, linkEthFeedAddress, coordinator.Address()) - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrDeployWrapper, err) - } - err = chainClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - - consumers, err := DeployVRFV2PlusWrapperConsumers(contractDeployer, linkTokenAddress, vrfv2PlusWrapper, consumerContractsAmount) - if err != nil { - return nil, err - } - err = chainClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitTXsComplete, err) - } - return &VRFV2PlusWrapperContracts{vrfv2PlusWrapper, consumers}, nil -} - -func WrapperRequestRandomness( - consumer contracts.VRFv2PlusWrapperLoadTestConsumer, - coordinatorAddress string, - vrfKeyData *vrfcommon.VRFKeyData, - subID *big.Int, - isNativeBilling bool, - config *vrfv2plus_config.General, - l zerolog.Logger) (string, error) { - LogRandRequest( - l, - consumer.Address(), - coordinatorAddress, - subID, - isNativeBilling, - vrfKeyData.KeyHash, - config, - ) - if isNativeBilling { - _, err := consumer.RequestRandomnessNative( - *config.MinimumConfirmations, - *config.CallbackGasLimit, - *config.NumberOfWords, - *config.RandomnessRequestCountPerRequest, - ) - if err != nil { - return "", fmt.Errorf("%s, err %w", ErrRequestRandomnessDirectFundingNativePayment, err) - } - } else { - _, err := consumer.RequestRandomness( - *config.MinimumConfirmations, - *config.CallbackGasLimit, - *config.NumberOfWords, - *config.RandomnessRequestCountPerRequest, - ) - if err != nil { - return "", fmt.Errorf("%s, err %w", ErrRequestRandomnessDirectFundingLinkPayment, err) - } - } - wrapperAddress, err := consumer.GetWrapper(context.Background()) - if err != nil { - return "", fmt.Errorf("error getting wrapper address, err: %w", err) - } - return wrapperAddress.Hex(), nil -} - -func DirectFundingRequestRandomnessAndWaitForFulfillment( - consumer contracts.VRFv2PlusWrapperLoadTestConsumer, - coordinator contracts.VRFCoordinatorV2_5, - vrfKeyData *vrfcommon.VRFKeyData, - subID *big.Int, - isNativeBilling bool, - config *vrfv2plus_config.General, - l zerolog.Logger, -) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { - wrapperAddress, err := WrapperRequestRandomness(consumer, coordinator.Address(), vrfKeyData, subID, - isNativeBilling, config, l) - if err != nil { - return nil, fmt.Errorf("error getting wrapper address, err: %w", err) - } - return WaitForRequestAndFulfillmentEvents( - wrapperAddress, - coordinator, - vrfKeyData, - subID, - isNativeBilling, - config.RandomWordsFulfilledEventTimeout.Duration, - l, - ) -} - -func DirectFundingRequestRandomnessAndWaitForFulfillmentUpgraded( - consumer contracts.VRFv2PlusWrapperLoadTestConsumer, - coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, - vrfKeyData *vrfcommon.VRFKeyData, - subID *big.Int, - isNativeBilling bool, - config *vrfv2plus_config.General, - l zerolog.Logger, -) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, error) { - wrapperAddress, err := WrapperRequestRandomness(consumer, coordinator.Address(), vrfKeyData, subID, - isNativeBilling, config, l) - if err != nil { - return nil, fmt.Errorf("error getting wrapper address, err: %w", err) - } - return WaitForRequestAndFulfillmentEventsUpgraded( - wrapperAddress, - coordinator, - vrfKeyData, - subID, - isNativeBilling, - config.RandomWordsFulfilledEventTimeout.Duration, - l, - ) -} - -func WaitForRequestAndFulfillmentEvents( - consumerAddress string, - coordinator contracts.VRFCoordinatorV2_5, - vrfKeyData *vrfcommon.VRFKeyData, - subID *big.Int, - isNativeBilling bool, - randomWordsFulfilledEventTimeout time.Duration, - l zerolog.Logger, -) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { - randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( - [][32]byte{vrfKeyData.KeyHash}, - []*big.Int{subID}, - []common.Address{common.HexToAddress(consumerAddress)}, - time.Minute*1, - ) - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitRandomWordsRequestedEvent, err) - } - - LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent, isNativeBilling) - - randomWordsFulfilledEvent, err := coordinator.WaitForRandomWordsFulfilledEvent( - []*big.Int{subID}, - []*big.Int{randomWordsRequestedEvent.RequestId}, - randomWordsFulfilledEventTimeout, - ) - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitRandomWordsFulfilledEvent, err) - } - - LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent, isNativeBilling) - return randomWordsFulfilledEvent, err -} - -func WaitForRequestAndFulfillmentEventsUpgraded( - consumerAddress string, - coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, - vrfKeyData *vrfcommon.VRFKeyData, - subID *big.Int, - isNativeBilling bool, - randomWordsFulfilledEventTimeout time.Duration, - l zerolog.Logger, -) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, error) { - randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( - [][32]byte{vrfKeyData.KeyHash}, - []*big.Int{subID}, - []common.Address{common.HexToAddress(consumerAddress)}, - time.Minute*1, - ) - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitRandomWordsRequestedEvent, err) - } - - LogRandomnessRequestedEventUpgraded(l, coordinator, randomWordsRequestedEvent, isNativeBilling) - - randomWordsFulfilledEvent, err := coordinator.WaitForRandomWordsFulfilledEvent( - []*big.Int{subID}, - []*big.Int{randomWordsRequestedEvent.RequestId}, - randomWordsFulfilledEventTimeout, - ) - if err != nil { - return nil, fmt.Errorf("%s, err %w", vrfcommon.ErrWaitRandomWordsFulfilledEvent, err) - } - LogRandomWordsFulfilledEventUpgraded(l, coordinator, randomWordsFulfilledEvent, isNativeBilling) - return randomWordsFulfilledEvent, err -} - -func ReturnFundsForFulfilledRequests(client blockchain.EVMClient, coordinator contracts.VRFCoordinatorV2_5, l zerolog.Logger) error { - linkTotalBalance, err := coordinator.GetLinkTotalBalance(context.Background()) - if err != nil { - return fmt.Errorf("Error getting LINK total balance, err: %w", err) - } - defaultWallet := client.GetDefaultWallet().Address() - l.Info(). - Str("LINK amount", linkTotalBalance.String()). - Str("Returning to", defaultWallet). - Msg("Returning LINK for fulfilled requests") - err = coordinator.Withdraw( - common.HexToAddress(defaultWallet), - ) - if err != nil { - return fmt.Errorf("Error withdrawing LINK from coordinator to default wallet, err: %w", err) - } - nativeTotalBalance, err := coordinator.GetNativeTokenTotalBalance(context.Background()) - if err != nil { - return fmt.Errorf("Error getting NATIVE total balance, err: %w", err) - } - l.Info(). - Str("Native Token amount", nativeTotalBalance.String()). - Str("Returning to", defaultWallet). - Msg("Returning Native Token for fulfilled requests") - err = coordinator.WithdrawNative( - common.HexToAddress(defaultWallet), - ) - if err != nil { - return fmt.Errorf("Error withdrawing NATIVE from coordinator to default wallet, err: %w", err) - } - return nil -} - -func LogSubDetails(l zerolog.Logger, subscription vrf_coordinator_v2_5.GetSubscription, subID *big.Int, coordinator contracts.VRFCoordinatorV2_5) { - l.Debug(). - Str("Coordinator", coordinator.Address()). - Str("Link Balance", (*commonassets.Link)(subscription.Balance).Link()). - Str("Native Token Balance", assets.FormatWei(subscription.NativeBalance)). - Str("Subscription ID", subID.String()). - Str("Subscription Owner", subscription.Owner.String()). - Interface("Subscription Consumers", subscription.Consumers). - Msg("Subscription Data") -} - -func LogRandomnessRequestedEventUpgraded( - l zerolog.Logger, - coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, - randomWordsRequestedEvent *vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsRequested, - isNativeBilling bool, -) { - l.Debug(). - Str("Coordinator", coordinator.Address()). - Bool("Native Billing", isNativeBilling). - Str("Request ID", randomWordsRequestedEvent.RequestId.String()). - Str("Subscription ID", randomWordsRequestedEvent.SubId.String()). - Str("Sender Address", randomWordsRequestedEvent.Sender.String()). - Str("Keyhash", fmt.Sprintf("0x%x", randomWordsRequestedEvent.KeyHash)). - Uint32("Callback Gas Limit", randomWordsRequestedEvent.CallbackGasLimit). - Uint32("Number of Words", randomWordsRequestedEvent.NumWords). - Uint16("Minimum Request Confirmations", randomWordsRequestedEvent.MinimumRequestConfirmations). - Msg("RandomnessRequested Event") -} - -func LogRandomWordsFulfilledEventUpgraded( - l zerolog.Logger, - coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, - randomWordsFulfilledEvent *vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, - isNativeBilling bool, -) { - l.Debug(). - Str("Coordinator", coordinator.Address()). - Bool("Native Billing", isNativeBilling). - Str("Total Payment in Juels", randomWordsFulfilledEvent.Payment.String()). - Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). - Str("Subscription ID", randomWordsFulfilledEvent.SubID.String()). - Str("Request ID", randomWordsFulfilledEvent.RequestId.String()). - Bool("Success", randomWordsFulfilledEvent.Success). - Msg("RandomWordsFulfilled Event (TX metadata)") -} - -func LogRandomnessRequestedEvent( - l zerolog.Logger, - coordinator contracts.VRFCoordinatorV2_5, - randomWordsRequestedEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsRequested, - isNativeBilling bool, -) { - l.Info(). - Str("Coordinator", coordinator.Address()). - Bool("Native Billing", isNativeBilling). - Str("Request ID", randomWordsRequestedEvent.RequestId.String()). - Str("Subscription ID", randomWordsRequestedEvent.SubId.String()). - Str("Sender Address", randomWordsRequestedEvent.Sender.String()). - Str("Keyhash", fmt.Sprintf("0x%x", randomWordsRequestedEvent.KeyHash)). - Uint32("Callback Gas Limit", randomWordsRequestedEvent.CallbackGasLimit). - Uint32("Number of Words", randomWordsRequestedEvent.NumWords). - Uint16("Minimum Request Confirmations", randomWordsRequestedEvent.MinimumRequestConfirmations). - Str("TX Hash", randomWordsRequestedEvent.Raw.TxHash.String()). - Uint64("BlockNumber", randomWordsRequestedEvent.Raw.BlockNumber). - Str("BlockHash", randomWordsRequestedEvent.Raw.BlockHash.String()). - Msg("RandomnessRequested Event") -} - -func LogRandomWordsFulfilledEvent( - l zerolog.Logger, - coordinator contracts.VRFCoordinatorV2_5, - randomWordsFulfilledEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, - isNativeBilling bool, -) { - l.Info(). - Bool("Native Billing", isNativeBilling). - Str("Coordinator", coordinator.Address()). - Str("Total Payment", randomWordsFulfilledEvent.Payment.String()). - Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). - Str("Subscription ID", randomWordsFulfilledEvent.SubId.String()). - Str("Request ID", randomWordsFulfilledEvent.RequestId.String()). - Bool("Success", randomWordsFulfilledEvent.Success). - Uint64("BlockNumber", randomWordsFulfilledEvent.Raw.BlockNumber). - Str("BlockHash", randomWordsFulfilledEvent.Raw.BlockHash.String()). - Msg("RandomWordsFulfilled Event (TX metadata)") -} - -func LogMigrationCompletedEvent(l zerolog.Logger, migrationCompletedEvent *vrf_coordinator_v2_5.VRFCoordinatorV25MigrationCompleted, vrfv2PlusContracts *vrfcommon.VRFContracts) { - l.Info(). - Str("Subscription ID", migrationCompletedEvent.SubId.String()). - Str("Migrated From Coordinator", vrfv2PlusContracts.CoordinatorV2Plus.Address()). - Str("Migrated To Coordinator", migrationCompletedEvent.NewCoordinator.String()). - Msg("MigrationCompleted Event") -} - -func LogSubDetailsAfterMigration(l zerolog.Logger, newCoordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, subID *big.Int, migratedSubscription vrf_v2plus_upgraded_version.GetSubscription) { - l.Info(). - Str("New Coordinator", newCoordinator.Address()). - Str("Subscription ID", subID.String()). - Str("Juels Balance", migratedSubscription.Balance.String()). - Str("Native Token Balance", migratedSubscription.NativeBalance.String()). - Str("Subscription Owner", migratedSubscription.Owner.String()). - Interface("Subscription Consumers", migratedSubscription.Consumers). - Msg("Subscription Data After Migration to New Coordinator") -} - -func LogFulfillmentDetailsLinkBilling( - l zerolog.Logger, - wrapperConsumerJuelsBalanceBeforeRequest *big.Int, - wrapperConsumerJuelsBalanceAfterRequest *big.Int, - consumerStatus vrfv2plus_wrapper_load_test_consumer.GetRequestStatus, - randomWordsFulfilledEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, -) { - l.Info(). - Str("Consumer Balance Before Request (Link)", (*commonassets.Link)(wrapperConsumerJuelsBalanceBeforeRequest).Link()). - Str("Consumer Balance After Request (Link)", (*commonassets.Link)(wrapperConsumerJuelsBalanceAfterRequest).Link()). - Bool("Fulfilment Status", consumerStatus.Fulfilled). - Str("Paid by Consumer Contract (Link)", (*commonassets.Link)(consumerStatus.Paid).Link()). - Str("Paid by Coordinator Sub (Link)", (*commonassets.Link)(randomWordsFulfilledEvent.Payment).Link()). - Str("RequestTimestamp", consumerStatus.RequestTimestamp.String()). - Str("FulfilmentTimestamp", consumerStatus.FulfilmentTimestamp.String()). - Str("RequestBlockNumber", consumerStatus.RequestBlockNumber.String()). - Str("FulfilmentBlockNumber", consumerStatus.FulfilmentBlockNumber.String()). - Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). - Msg("Random Words Fulfilment Details For Link Billing") -} - -func LogFulfillmentDetailsNativeBilling( - l zerolog.Logger, - wrapperConsumerBalanceBeforeRequestWei *big.Int, - wrapperConsumerBalanceAfterRequestWei *big.Int, - consumerStatus vrfv2plus_wrapper_load_test_consumer.GetRequestStatus, - randomWordsFulfilledEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, -) { - l.Info(). - Str("Consumer Balance Before Request", assets.FormatWei(wrapperConsumerBalanceBeforeRequestWei)). - Str("Consumer Balance After Request", assets.FormatWei(wrapperConsumerBalanceAfterRequestWei)). - Bool("Fulfilment Status", consumerStatus.Fulfilled). - Str("Paid by Consumer Contract", assets.FormatWei(consumerStatus.Paid)). - Str("Paid by Coordinator Sub", assets.FormatWei(randomWordsFulfilledEvent.Payment)). - Str("RequestTimestamp", consumerStatus.RequestTimestamp.String()). - Str("FulfilmentTimestamp", consumerStatus.FulfilmentTimestamp.String()). - Str("RequestBlockNumber", consumerStatus.RequestBlockNumber.String()). - Str("FulfilmentBlockNumber", consumerStatus.FulfilmentBlockNumber.String()). - Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). - Msg("Random Words Request Fulfilment Details For Native Billing") -} - -func LogRandRequest( - l zerolog.Logger, - consumer string, - coordinator string, - subID *big.Int, - isNativeBilling bool, - keyHash [32]byte, - config *vrfv2plus_config.General) { - l.Info(). - Str("Consumer", consumer). - Str("Coordinator", coordinator). - Str("SubID", subID.String()). - Bool("IsNativePayment", isNativeBilling). - Uint16("MinimumConfirmations", *config.MinimumConfirmations). - Uint32("CallbackGasLimit", *config.CallbackGasLimit). - Uint32("NumberOfWords", *config.NumberOfWords). - Str("KeyHash", fmt.Sprintf("0x%x", keyHash)). - Uint16("RandomnessRequestCountPerRequest", *config.RandomnessRequestCountPerRequest). - Uint16("RandomnessRequestCountPerRequestDeviation", *config.RandomnessRequestCountPerRequestDeviation). - Msg("Requesting randomness") -} diff --git a/integration-tests/benchmark/keeper_test.go b/integration-tests/benchmark/keeper_test.go index e6cda6d7f27..dad3d19610a 100644 --- a/integration-tests/benchmark/keeper_test.go +++ b/integration-tests/benchmark/keeper_test.go @@ -165,6 +165,7 @@ func TestAutomationBenchmark(t *testing.T) { FallbackLinkPrice: big.NewInt(2e18), MaxCheckDataSize: uint32(5_000), MaxPerformDataSize: uint32(5_000), + MaxRevertDataSize: uint32(5_000), }, Upkeeps: &testsetups.UpkeepConfig{ NumberOfUpkeeps: *config.Keeper.Common.NumberOfUpkeeps, @@ -244,7 +245,7 @@ func getNetworkConfig(config *tc.TestConfig) NetworkConfig { var nc NetworkConfig var ok bool if nc, ok = networkConfig[evmNetwork.Name]; !ok { - return defaultNetworkConfig + nc = defaultNetworkConfig } if evmNetwork.Name == networks.SimulatedEVM.Name || evmNetwork.Name == networks.SimulatedEVMNonDev.Name { @@ -284,7 +285,7 @@ var networkConfig = map[string]NetworkConfig{ blockTime: 12 * time.Second, deltaStage: time.Duration(0), }, - networks.BaseGoerli.Name: { + networks.BaseSepolia.Name: { upkeepSLA: int64(60), blockTime: 2 * time.Second, deltaStage: 20 * time.Second, diff --git a/integration-tests/chaos/automation_chaos_test.go b/integration-tests/chaos/automation_chaos_test.go index fac9f83ba79..56b0d1e32b6 100644 --- a/integration-tests/chaos/automation_chaos_test.go +++ b/integration-tests/chaos/automation_chaos_test.go @@ -92,6 +92,7 @@ ListenAddresses = ["0.0.0.0:6690"]` FallbackLinkPrice: big.NewInt(2e18), MaxCheckDataSize: uint32(5000), MaxPerformDataSize: uint32(5000), + MaxRevertDataSize: uint32(5000), } ) diff --git a/integration-tests/chaos/ocr_chaos_test.go b/integration-tests/chaos/ocr_chaos_test.go index c99318d51dd..6e397694cc9 100644 --- a/integration-tests/chaos/ocr_chaos_test.go +++ b/integration-tests/chaos/ocr_chaos_test.go @@ -5,6 +5,7 @@ import ( "math/big" "testing" + "github.com/ethereum/go-ethereum/common" "github.com/onsi/gomega" "github.com/smartcontractkit/seth" "github.com/stretchr/testify/require" @@ -187,13 +188,13 @@ func TestOCRChaos(t *testing.T) { ms, err := ctfClient.ConnectMockServer(testEnvironment) require.NoError(t, err, "Creating mockserver clients shouldn't fail") - linkDeploymentData, err := contracts.DeployLinkTokenContract(seth) + linkContract, err := contracts.DeployLinkTokenContract(l, seth) require.NoError(t, err, "Error deploying link token contract") err = actions_seth.FundChainlinkNodesFromRootAddress(l, seth, contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(chainlinkNodes), big.NewFloat(10)) require.NoError(t, err) - ocrInstances, err := actions_seth.DeployOCRv1Contracts(l, seth, 1, linkDeploymentData.Address, contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(workerNodes)) + ocrInstances, err := actions_seth.DeployOCRv1Contracts(l, seth, 1, common.HexToAddress(linkContract.Address()), contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(workerNodes)) require.NoError(t, err) err = actions.CreateOCRJobs(ocrInstances, bootstrapNode, workerNodes, 5, ms, fmt.Sprint(seth.ChainID)) require.NoError(t, err) diff --git a/integration-tests/client/chainlink.go b/integration-tests/client/chainlink.go index 1de41ab9b5d..1d743b4c979 100644 --- a/integration-tests/client/chainlink.go +++ b/integration-tests/client/chainlink.go @@ -120,6 +120,10 @@ func (c *ChainlinkClient) MustCreateJob(spec JobSpec) (*Job, error) { return job, VerifyStatusCodeWithResponse(resp, http.StatusOK) } +func (c *ChainlinkClient) GetConfig() ChainlinkConfig { + return *c.Config +} + // CreateJob creates a Chainlink job based on the provided spec struct func (c *ChainlinkClient) CreateJob(spec JobSpec) (*Job, *resty.Response, error) { job := &Job{} diff --git a/integration-tests/client/chainlink_k8s.go b/integration-tests/client/chainlink_k8s.go index ab4ce341584..147238b7950 100644 --- a/integration-tests/client/chainlink_k8s.go +++ b/integration-tests/client/chainlink_k8s.go @@ -144,3 +144,7 @@ func ConnectChainlinkNodeURL(url string) (*ChainlinkK8sClient, error) { "connectedNodeByURL", // an intentionally bad decision ) } + +func (c *ChainlinkK8sClient) GetConfig() ChainlinkConfig { + return *c.Config +} diff --git a/integration-tests/client/chainlink_models.go b/integration-tests/client/chainlink_models.go index f95089f36fa..d19888fb706 100644 --- a/integration-tests/client/chainlink_models.go +++ b/integration-tests/client/chainlink_models.go @@ -673,7 +673,7 @@ estimate_gas [type=estimategaslimit data="$(generate_proof.output)" %s] simulate_fulfillment [type=ethcall - from="{{ .FromAddress }}" + from="{{ .FromAddress }}" to="{{ .Address }}" gas="$(estimate_gas)" gasPrice="$(jobSpec.maxGasPrice)" @@ -1121,17 +1121,17 @@ relay = "{{.Relay}}" schemaVersion = 1 contractID = "{{.ContractID}}" {{- if .FeedID}} -feedID = "{{.FeedID}}" +feedID = "{{.FeedID}}" {{end}} {{- if eq .JobType "offchainreporting2" }} ocrKeyBundleID = "{{.OCRKeyBundleID}}" {{end}} {{- if eq .JobType "offchainreporting2" }} transmitterID = "{{.TransmitterID}}" {{end}} {{- if .BlockchainTimeout}} -blockchainTimeout = "{{.BlockchainTimeout}}" +blockchainTimeout = "{{.BlockchainTimeout}}" {{end}} {{- if .ContractConfirmations}} -contractConfigConfirmations = {{.ContractConfirmations}} +contractConfigConfirmations = {{.ContractConfirmations}} {{end}} {{- if .TrackerPollInterval}} contractConfigTrackerPollInterval = "{{.TrackerPollInterval}}" @@ -1328,6 +1328,48 @@ runTimeout = "{{.RunTimeout}}" return MarshallTemplate(b, "BlockhashStore Job", vrfTemplateString) } +// BlockHeaderFeederJobSpec represents a blockheaderfeeder job +type BlockHeaderFeederJobSpec struct { + Name string `toml:"name"` + CoordinatorV2Address string `toml:"coordinatorV2Address"` + CoordinatorV2PlusAddress string `toml:"coordinatorV2PlusAddress"` + BlockhashStoreAddress string `toml:"blockhashStoreAddress"` + BatchBlockhashStoreAddress string `toml:"batchBlockhashStoreAddress"` + ExternalJobID string `toml:"externalJobID"` + FromAddresses []string `toml:"fromAddresses"` + EVMChainID string `toml:"evmChainID"` + ForwardingAllowed bool `toml:"forwardingAllowed"` + PollPeriod time.Duration `toml:"pollPeriod"` + RunTimeout time.Duration `toml:"runTimeout"` + WaitBlocks int `toml:"waitBlocks"` + LookbackBlocks int `toml:"lookbackBlocks"` +} + +// Type returns the type of the job +func (b *BlockHeaderFeederJobSpec) Type() string { return "blockheaderfeeder" } + +// String representation of the job +func (b *BlockHeaderFeederJobSpec) String() (string, error) { + vrfTemplateString := ` +type = "blockheaderfeeder" +schemaVersion = 1 +name = "{{.Name}}" +forwardingAllowed = {{.ForwardingAllowed}} +coordinatorV2Address = "{{.CoordinatorV2Address}}" +coordinatorV2PlusAddress = "{{.CoordinatorV2PlusAddress}}" +blockhashStoreAddress = "{{.BlockhashStoreAddress}}" +batchBlockhashStoreAddress = "{{.BatchBlockhashStoreAddress}}" +fromAddresses = [{{range .FromAddresses}}"{{.}}",{{end}}] +evmChainID = "{{.EVMChainID}}" +externalJobID = "{{.ExternalJobID}}" +waitBlocks = {{.WaitBlocks}} +lookbackBlocks = {{.LookbackBlocks}} +pollPeriod = "{{.PollPeriod}}" +runTimeout = "{{.RunTimeout}}" +` + return MarshallTemplate(b, "BlockHeaderFeeder Job", vrfTemplateString) +} + // WebhookJobSpec reprsents a webhook job type WebhookJobSpec struct { Name string `toml:"name"` diff --git a/integration-tests/contracts/contract_deployer.go b/integration-tests/contracts/contract_deployer.go index e72b49bb302..c85c927b8d4 100644 --- a/integration-tests/contracts/contract_deployer.go +++ b/integration-tests/contracts/contract_deployer.go @@ -24,6 +24,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + "github.com/smartcontractkit/chainlink/integration-tests/wrappers" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_load_test_client" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_v1_events_mock" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/arbitrum_module" @@ -110,7 +111,7 @@ type ContractDeployer interface { LoadKeeperRegistry(address common.Address, registryVersion eth_contracts.KeeperRegistryVersion) (KeeperRegistry, error) DeployKeeperConsumer(updateInterval *big.Int) (KeeperConsumer, error) DeployAutomationLogTriggerConsumer(testInterval *big.Int) (KeeperConsumer, error) - DeployAutomationSimpleLogTriggerConsumer() (KeeperConsumer, error) + DeployAutomationSimpleLogTriggerConsumer(isStreamsLookup bool) (KeeperConsumer, error) DeployAutomationStreamsLookupUpkeepConsumer(testRange *big.Int, interval *big.Int, useArbBlock bool, staging bool, verify bool) (KeeperConsumer, error) DeployAutomationLogTriggeredStreamsLookupUpkeepConsumer() (KeeperConsumer, error) DeployKeeperConsumerPerformance( @@ -132,13 +133,13 @@ type ContractDeployer interface { DeployVRFv2LoadTestConsumer(coordinatorAddr string) (VRFv2LoadTestConsumer, error) DeployVRFV2WrapperLoadTestConsumer(linkAddr string, vrfV2WrapperAddr string) (VRFv2WrapperLoadTestConsumer, error) DeployVRFv2PlusLoadTestConsumer(coordinatorAddr string) (VRFv2PlusLoadTestConsumer, error) - DeployVRFV2PlusWrapperLoadTestConsumer(linkAddr string, vrfV2PlusWrapperAddr string) (VRFv2PlusWrapperLoadTestConsumer, error) + DeployVRFV2PlusWrapperLoadTestConsumer(vrfV2PlusWrapperAddr string) (VRFv2PlusWrapperLoadTestConsumer, error) DeployVRFCoordinator(linkAddr string, bhsAddr string) (VRFCoordinator, error) DeployVRFCoordinatorV2(linkAddr string, bhsAddr string, linkEthFeedAddr string) (VRFCoordinatorV2, error) DeployVRFCoordinatorV2_5(bhsAddr string) (VRFCoordinatorV2_5, error) DeployVRFCoordinatorV2PlusUpgradedVersion(bhsAddr string) (VRFCoordinatorV2PlusUpgradedVersion, error) DeployVRFV2Wrapper(linkAddr string, linkEthFeedAddr string, coordinatorAddr string) (VRFV2Wrapper, error) - DeployVRFV2PlusWrapper(linkAddr string, linkEthFeedAddr string, coordinatorAddr string) (VRFV2PlusWrapper, error) + DeployVRFV2PlusWrapper(linkAddr string, linkEthFeedAddr string, coordinatorAddr string, subId *big.Int) (VRFV2PlusWrapper, error) DeployDKG() (DKG, error) DeployOCR2VRFCoordinator(beaconPeriodBlocksCount *big.Int, linkAddr string) (VRFCoordinatorV3, error) DeployVRFBeacon(vrfCoordinatorAddress string, linkAddress string, dkgAddress string, keyId string) (VRFBeacon, error) @@ -349,7 +350,7 @@ func (e *EthereumContractDeployer) DeployFluxAggregatorContract( if err != nil { return nil, err } - return &EthereumFluxAggregator{ + return &LegacyEthereumFluxAggregator{ client: e.client, fluxAggregator: instance.(*flux_aggregator_wrapper.FluxAggregator), address: address, @@ -383,7 +384,7 @@ func (e *EthereumContractDeployer) DeployFunctionsLoadTestClient(router string) if err != nil { return nil, err } - return &EthereumFunctionsLoadTestClient{ + return &LegacyEthereumFunctionsLoadTestClient{ client: e.client, instance: instance.(*functions_load_test_client.FunctionsLoadTestClient), address: *address, @@ -532,13 +533,13 @@ func (e *EthereumContractDeployer) DeployLinkTokenContract() (LinkToken, error) auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return link_token_interface.DeployLinkToken(auth, backend) + return link_token_interface.DeployLinkToken(auth, wrappers.MustNewWrappedContractBackend(e.client, nil)) }) if err != nil { return nil, err } - return &EthereumLinkToken{ + return &LegacyEthereumLinkToken{ client: e.client, instance: instance.(*link_token_interface.LinkToken), address: *linkTokenAddress, @@ -557,7 +558,7 @@ func (e *EthereumContractDeployer) LoadLinkToken(address common.Address) (LinkTo if err != nil { return nil, err } - return &EthereumLinkToken{ + return &LegacyEthereumLinkToken{ address: address, client: e.client, instance: instance.(*link_token_interface.LinkToken), @@ -678,7 +679,7 @@ func (e *EthereumContractDeployer) DeployAPIConsumer(linkAddr string) (APIConsum if err != nil { return nil, err } - return &EthereumAPIConsumer{ + return &LegacyEthereumAPIConsumer{ address: addr, client: e.client, consumer: instance.(*test_api_consumer_wrapper.TestAPIConsumer), @@ -696,7 +697,7 @@ func (e *EthereumContractDeployer) DeployOracle(linkAddr string) (Oracle, error) if err != nil { return nil, err } - return &EthereumOracle{ + return &LegacyEthereumOracle{ address: addr, client: e.client, oracle: instance.(*oracle_wrapper.Oracle), @@ -708,7 +709,7 @@ func (e *EthereumContractDeployer) DeployMockETHLINKFeed(answer *big.Int) (MockE auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return mock_ethlink_aggregator_wrapper.DeployMockETHLINKAggregator(auth, backend, answer) + return mock_ethlink_aggregator_wrapper.DeployMockETHLINKAggregator(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), answer) }) if err != nil { return nil, err @@ -760,7 +761,7 @@ func (e *EthereumContractDeployer) DeployMockGasFeed(answer *big.Int) (MockGasFe auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return mock_gas_aggregator_wrapper.DeployMockGASAggregator(auth, backend, answer) + return mock_gas_aggregator_wrapper.DeployMockGASAggregator(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), answer) }) if err != nil { return nil, err @@ -795,7 +796,7 @@ func (e *EthereumContractDeployer) DeployUpkeepTranscoder() (UpkeepTranscoder, e opts *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return upkeep_transcoder.DeployUpkeepTranscoder(opts, backend) + return upkeep_transcoder.DeployUpkeepTranscoder(opts, wrappers.MustNewWrappedContractBackend(e.client, nil)) }) if err != nil { @@ -837,7 +838,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistrar(registryVersion eth_con opts *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return keeper_registrar_wrapper2_0.DeployKeeperRegistrar(opts, backend, common.HexToAddress(linkAddr), registrarSettings.AutoApproveConfigType, + return keeper_registrar_wrapper2_0.DeployKeeperRegistrar(opts, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(linkAddr), registrarSettings.AutoApproveConfigType, registrarSettings.AutoApproveMaxAllowed, common.HexToAddress(registrarSettings.RegistryAddr), registrarSettings.MinLinkJuels) }) @@ -866,7 +867,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistrar(registryVersion eth_con return registrar21.DeployAutomationRegistrar( opts, - backend, + wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(linkAddr), common.HexToAddress(registrarSettings.RegistryAddr), registrarSettings.MinLinkJuels, @@ -979,7 +980,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( ) (common.Address, *types.Transaction, interface{}, error) { return keeper_registry_wrapper1_1.DeployKeeperRegistry( auth, - backend, + wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(opts.LinkAddr), common.HexToAddress(opts.ETHFeedAddr), common.HexToAddress(opts.GasFeedAddr), @@ -1011,7 +1012,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( ) (common.Address, *types.Transaction, interface{}, error) { return keeper_registry_wrapper1_2.DeployKeeperRegistry( auth, - backend, + wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(opts.LinkAddr), common.HexToAddress(opts.ETHFeedAddr), common.HexToAddress(opts.GasFeedAddr), @@ -1049,7 +1050,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( ) (common.Address, *types.Transaction, interface{}, error) { return keeper_registry_logic1_3.DeployKeeperRegistryLogic( auth, - backend, + wrappers.MustNewWrappedContractBackend(e.client, nil), mode, // Default payment model registryGasOverhead, // Registry gas overhead common.HexToAddress(opts.LinkAddr), @@ -1071,7 +1072,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( ) (common.Address, *types.Transaction, interface{}, error) { return keeper_registry_wrapper1_3.DeployKeeperRegistry( auth, - backend, + wrappers.MustNewWrappedContractBackend(e.client, nil), *logicAddress, keeper_registry_wrapper1_3.Config{ PaymentPremiumPPB: opts.Settings.PaymentPremiumPPB, @@ -1107,7 +1108,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( ) (common.Address, *types.Transaction, interface{}, error) { return keeper_registry_logic2_0.DeployKeeperRegistryLogic( auth, - backend, + wrappers.MustNewWrappedContractBackend(e.client, nil), mode, // Default payment model common.HexToAddress(opts.LinkAddr), common.HexToAddress(opts.ETHFeedAddr), @@ -1129,7 +1130,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( return keeper_registry_wrapper2_0.DeployKeeperRegistry( auth, - backend, + wrappers.MustNewWrappedContractBackend(e.client, nil), *logicAddress, ) }) @@ -1156,7 +1157,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( return registrylogicb21.DeployKeeperRegistryLogicB( auth, - backend, + wrappers.MustNewWrappedContractBackend(e.client, nil), mode, common.HexToAddress(opts.LinkAddr), common.HexToAddress(opts.ETHFeedAddr), @@ -1179,7 +1180,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( return registrylogica21.DeployKeeperRegistryLogicA( auth, - backend, + wrappers.MustNewWrappedContractBackend(e.client, nil), *registryLogicBAddr, ) }) @@ -1196,7 +1197,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( ) (common.Address, *types.Transaction, interface{}, error) { return registry21.DeployKeeperRegistry( auth, - backend, + wrappers.MustNewWrappedContractBackend(e.client, nil), *registryLogicAAddr, ) }) @@ -1209,7 +1210,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( registryMaster, err := iregistry21.NewIKeeperRegistryMaster( *address, - e.client.Backend(), + wrappers.MustNewWrappedContractBackend(e.client, nil), ) if err != nil { return nil, err @@ -1230,28 +1231,28 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return scroll_module.DeployScrollModule(auth, backend) + return scroll_module.DeployScrollModule(auth, wrappers.MustNewWrappedContractBackend(e.client, nil)) }) } else if chainId == networks.ArbitrumMainnet.ChainID || chainId == networks.ArbitrumSepolia.ChainID { chainModuleAddr, _, _, err = e.client.DeployContract("ArbitrumModule", func( auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return arbitrum_module.DeployArbitrumModule(auth, backend) + return arbitrum_module.DeployArbitrumModule(auth, wrappers.MustNewWrappedContractBackend(e.client, nil)) }) } else if chainId == networks.OptimismMainnet.ChainID || chainId == networks.OptimismSepolia.ChainID { chainModuleAddr, _, _, err = e.client.DeployContract("OptimismModule", func( auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return optimism_module.DeployOptimismModule(auth, backend) + return optimism_module.DeployOptimismModule(auth, wrappers.MustNewWrappedContractBackend(e.client, nil)) }) } else { chainModuleAddr, _, _, err = e.client.DeployContract("ChainModuleBase", func( auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return chain_module_base.DeployChainModuleBase(auth, backend) + return chain_module_base.DeployChainModuleBase(auth, wrappers.MustNewWrappedContractBackend(e.client, nil)) }) } if err != nil { @@ -1279,7 +1280,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( return registrylogicb22.DeployAutomationRegistryLogicB( auth, - backend, + wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(opts.LinkAddr), common.HexToAddress(opts.ETHFeedAddr), common.HexToAddress(opts.GasFeedAddr), @@ -1302,7 +1303,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( return registrylogica22.DeployAutomationRegistryLogicA( auth, - backend, + wrappers.MustNewWrappedContractBackend(e.client, nil), *registryLogicBAddr, ) }) @@ -1319,7 +1320,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( ) (common.Address, *types.Transaction, interface{}, error) { return registry22.DeployAutomationRegistry( auth, - backend, + wrappers.MustNewWrappedContractBackend(e.client, nil), *registryLogicAAddr, ) }) @@ -1332,7 +1333,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( registryMaster, err := iregistry22.NewIAutomationRegistryMaster( *address, - e.client.Backend(), + wrappers.MustNewWrappedContractBackend(e.client, nil), ) if err != nil { return nil, err @@ -1340,7 +1341,7 @@ func (e *EthereumContractDeployer) DeployKeeperRegistry( chainModule, err := i_chain_module.NewIChainModule( *chainModuleAddr, - e.client.Backend(), + wrappers.MustNewWrappedContractBackend(e.client, nil), ) if err != nil { return nil, err @@ -1503,7 +1504,7 @@ func (e *EthereumContractDeployer) DeployAutomationLogTriggerConsumer(testInterv backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return log_upkeep_counter_wrapper.DeployLogUpkeepCounter( - auth, backend, testInterval, + auth, wrappers.MustNewWrappedContractBackend(e.client, nil), testInterval, ) }) if err != nil { @@ -1516,13 +1517,13 @@ func (e *EthereumContractDeployer) DeployAutomationLogTriggerConsumer(testInterv }, err } -func (e *EthereumContractDeployer) DeployAutomationSimpleLogTriggerConsumer() (KeeperConsumer, error) { +func (e *EthereumContractDeployer) DeployAutomationSimpleLogTriggerConsumer(isStreamsLookup bool) (KeeperConsumer, error) { address, _, instance, err := e.client.DeployContract("SimpleLogUpkeepCounter", func( auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return simple_log_upkeep_counter_wrapper.DeploySimpleLogUpkeepCounter( - auth, backend, + auth, backend, isStreamsLookup, ) }) if err != nil { @@ -1541,7 +1542,7 @@ func (e *EthereumContractDeployer) DeployAutomationStreamsLookupUpkeepConsumer(t backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return streams_lookup_upkeep_wrapper.DeployStreamsLookupUpkeep( - auth, backend, testRange, interval, useArbBlock, staging, verify, + auth, wrappers.MustNewWrappedContractBackend(e.client, nil), testRange, interval, useArbBlock, staging, verify, ) }) if err != nil { @@ -1560,7 +1561,7 @@ func (e *EthereumContractDeployer) DeployAutomationLogTriggeredStreamsLookupUpke backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { return log_triggered_streams_lookup_wrapper.DeployLogTriggeredStreamsLookup( - auth, backend, false, false, false, + auth, wrappers.MustNewWrappedContractBackend(e.client, nil), false, false, false, ) }) if err != nil { @@ -1578,7 +1579,7 @@ func (e *EthereumContractDeployer) DeployUpkeepCounter(testRange *big.Int, inter auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return upkeep_counter_wrapper.DeployUpkeepCounter(auth, backend, testRange, interval) + return upkeep_counter_wrapper.DeployUpkeepCounter(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), testRange, interval) }) if err != nil { return nil, err diff --git a/integration-tests/contracts/contract_loader.go b/integration-tests/contracts/contract_loader.go index a2a4fb60be5..f492adc3286 100644 --- a/integration-tests/contracts/contract_loader.go +++ b/integration-tests/contracts/contract_loader.go @@ -3,6 +3,7 @@ package contracts import ( "errors" + "github.com/smartcontractkit/chainlink/integration-tests/wrappers" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics" @@ -180,7 +181,7 @@ func (e *EthereumContractLoader) LoadLINKToken(addr string) (LinkToken, error) { if err != nil { return nil, err } - return &EthereumLinkToken{ + return &LegacyEthereumLinkToken{ client: e.client, instance: instance.(*link_token_interface.LinkToken), address: common.HexToAddress(addr), @@ -199,7 +200,7 @@ func (e *EthereumContractLoader) LoadFunctionsCoordinator(addr string) (Function if err != nil { return nil, err } - return &EthereumFunctionsCoordinator{ + return &LegacyEthereumFunctionsCoordinator{ client: e.client, instance: instance.(*functions_coordinator.FunctionsCoordinator), address: common.HexToAddress(addr), @@ -217,7 +218,7 @@ func (e *EthereumContractLoader) LoadFunctionsRouter(addr string) (FunctionsRout if err != nil { return nil, err } - return &EthereumFunctionsRouter{ + return &LegacyEthereumFunctionsRouter{ client: e.client, instance: instance.(*functions_router.FunctionsRouter), address: common.HexToAddress(addr), @@ -236,7 +237,7 @@ func (e *EthereumContractLoader) LoadFunctionsLoadTestClient(addr string) (Funct if err != nil { return nil, err } - return &EthereumFunctionsLoadTestClient{ + return &LegacyEthereumFunctionsLoadTestClient{ client: e.client, instance: instance.(*functions_load_test_client.FunctionsLoadTestClient), address: common.HexToAddress(addr), @@ -409,7 +410,7 @@ func (e *EthereumContractLoader) LoadVRFCoordinatorV2(addr string) (VRFCoordinat address common.Address, backend bind.ContractBackend, ) (interface{}, error) { - return vrf_coordinator_v2.NewVRFCoordinatorV2(address, backend) + return vrf_coordinator_v2.NewVRFCoordinatorV2(address, wrappers.MustNewWrappedContractBackend(e.client, nil)) }) if err != nil { return nil, err diff --git a/integration-tests/contracts/contract_models.go b/integration-tests/contracts/contract_models.go index 3aaf4f4f39d..c61356130ee 100644 --- a/integration-tests/contracts/contract_models.go +++ b/integration-tests/contracts/contract_models.go @@ -4,6 +4,7 @@ package contracts import ( "context" "math/big" + "net/http" "time" "github.com/ethereum/go-ethereum/common" @@ -141,6 +142,11 @@ type ChainlinkNodeWithKeysAndAddress interface { PrimaryEthAddress() (string, error) } +type ChainlinkNodeWithForwarder interface { + TrackForwarder(chainID *big.Int, address common.Address) (*client.Forwarder, *http.Response, error) + GetConfig() client.ChainlinkConfig +} + type OffChainAggregatorWithRounds interface { Address() string GetLatestRound(ctx context.Context) (*RoundData, error) diff --git a/integration-tests/contracts/contract_vrf_models.go b/integration-tests/contracts/contract_vrf_models.go index 0fa171fb243..a0dd0f55938 100644 --- a/integration-tests/contracts/contract_vrf_models.go +++ b/integration-tests/contracts/contract_vrf_models.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_load_test_with_metrics" @@ -63,6 +64,9 @@ type VRFCoordinatorV2 interface { GetOwner(ctx context.Context) (common.Address, error) PendingRequestsExist(ctx context.Context, subID uint64) (bool, error) OwnerCancelSubscription(subID uint64) (*types.Transaction, error) + ParseSubscriptionCanceled(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled, error) + ParseRandomWordsRequested(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) + ParseLog(log types.Log) (generated.AbigenLog, error) CancelSubscription(subID uint64, to common.Address) (*types.Transaction, error) FindSubscriptionID(subID uint64) (uint64, error) WaitForRandomWordsFulfilledEvent(requestID []*big.Int, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) @@ -164,9 +168,8 @@ type VRFV2Wrapper interface { type VRFV2PlusWrapper interface { Address() string - SetConfig(wrapperGasOverhead uint32, coordinatorGasOverhead uint32, wrapperPremiumPercentage uint8, keyHash [32]byte, maxNumWords uint8, stalenessSeconds uint32, fallbackWeiPerUnitLink *big.Int, fulfillmentFlatFeeLinkPPM uint32, fulfillmentFlatFeeNativePPM uint32) error + SetConfig(wrapperGasOverhead uint32, coordinatorGasOverhead uint32, wrapperNativePremiumPercentage uint8, wrapperLinkPremiumPercentage uint8, keyHash [32]byte, maxNumWords uint8, stalenessSeconds uint32, fallbackWeiPerUnitLink *big.Int, fulfillmentFlatFeeNativePPM uint32, fulfillmentFlatFeeLinkDiscountPPM uint32) error GetSubID(ctx context.Context) (*big.Int, error) - Migrate(newCoordinator common.Address) error Coordinator(ctx context.Context) (common.Address, error) } @@ -175,6 +178,7 @@ type VRFOwner interface { SetAuthorizedSenders(senders []common.Address) error AcceptVRFOwnership() error WaitForRandomWordsForcedEvent(requestIDs []*big.Int, subIds []uint64, senders []common.Address, timeout time.Duration) (*vrf_owner.VRFOwnerRandomWordsForced, error) + OwnerCancelSubscription(subID uint64) (*types.Transaction, error) } type VRFConsumer interface { @@ -206,7 +210,15 @@ type VRFv2Consumer interface { type VRFv2LoadTestConsumer interface { Address() string - RequestRandomness(hash [32]byte, subID uint64, confs uint16, gasLimit uint32, numWords uint32, requestCount uint16) (*types.Transaction, error) + RequestRandomness( + coordinator VRFCoordinatorV2, + keyHash [32]byte, + subID uint64, + requestConfirmations uint16, + callbackGasLimit uint32, + numWords uint32, + requestCount uint16, + ) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) RequestRandomWordsWithForceFulfill( keyHash [32]byte, requestConfirmations uint16, @@ -225,7 +237,7 @@ type VRFv2LoadTestConsumer interface { type VRFv2WrapperLoadTestConsumer interface { Address() string Fund(ethAmount *big.Float) error - RequestRandomness(requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, requestCount uint16) (*types.Transaction, error) + RequestRandomness(coordinator VRFCoordinatorV2, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, requestCount uint16) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) GetRequestStatus(ctx context.Context, requestID *big.Int) (vrfv2_wrapper_load_test_consumer.GetRequestStatus, error) GetLastRequestId(ctx context.Context) (*big.Int, error) GetWrapper(ctx context.Context) (common.Address, error) @@ -345,6 +357,8 @@ type VRFLoadTestMetrics struct { AverageFulfillmentInMillions *big.Int SlowestFulfillment *big.Int FastestFulfillment *big.Int + P90FulfillmentBlockTime float64 + P95FulfillmentBlockTime float64 AverageResponseTimeInSecondsMillions *big.Int SlowestResponseTimeInSeconds *big.Int FastestResponseTimeInSeconds *big.Int diff --git a/integration-tests/contracts/ethereum_contracts.go b/integration-tests/contracts/ethereum_contracts.go index 1035a073f51..e8b2f184ce9 100644 --- a/integration-tests/contracts/ethereum_contracts.go +++ b/integration-tests/contracts/ethereum_contracts.go @@ -55,18 +55,18 @@ import ( eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" ) -// EthereumOracle oracle for "directrequest" job tests -type EthereumOracle struct { +// LegacyEthereumOracle oracle for "directrequest" job tests +type LegacyEthereumOracle struct { address *common.Address client blockchain.EVMClient oracle *oracle_wrapper.Oracle } -func (e *EthereumOracle) Address() string { +func (e *LegacyEthereumOracle) Address() string { return e.address.Hex() } -func (e *EthereumOracle) Fund(ethAmount *big.Float) error { +func (e *LegacyEthereumOracle) Fund(ethAmount *big.Float) error { gasEstimates, err := e.client.EstimateGas(ethereum.CallMsg{ To: e.address, }) @@ -77,7 +77,7 @@ func (e *EthereumOracle) Fund(ethAmount *big.Float) error { } // SetFulfillmentPermission sets fulfillment permission for particular address -func (e *EthereumOracle) SetFulfillmentPermission(address string, allowed bool) error { +func (e *LegacyEthereumOracle) SetFulfillmentPermission(address string, allowed bool) error { opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) if err != nil { return err @@ -89,18 +89,18 @@ func (e *EthereumOracle) SetFulfillmentPermission(address string, allowed bool) return e.client.ProcessTransaction(tx) } -// EthereumAPIConsumer API consumer for job type "directrequest" tests -type EthereumAPIConsumer struct { +// LegacyEthereumAPIConsumer API consumer for job type "directrequest" tests +type LegacyEthereumAPIConsumer struct { address *common.Address client blockchain.EVMClient consumer *test_api_consumer_wrapper.TestAPIConsumer } -func (e *EthereumAPIConsumer) Address() string { +func (e *LegacyEthereumAPIConsumer) Address() string { return e.address.Hex() } -func (e *EthereumAPIConsumer) RoundID(ctx context.Context) (*big.Int, error) { +func (e *LegacyEthereumAPIConsumer) RoundID(ctx context.Context) (*big.Int, error) { opts := &bind.CallOpts{ From: common.HexToAddress(e.client.GetDefaultWallet().Address()), Context: ctx, @@ -108,7 +108,7 @@ func (e *EthereumAPIConsumer) RoundID(ctx context.Context) (*big.Int, error) { return e.consumer.CurrentRoundID(opts) } -func (e *EthereumAPIConsumer) Fund(ethAmount *big.Float) error { +func (e *LegacyEthereumAPIConsumer) Fund(ethAmount *big.Float) error { gasEstimates, err := e.client.EstimateGas(ethereum.CallMsg{ To: e.address, }) @@ -118,7 +118,7 @@ func (e *EthereumAPIConsumer) Fund(ethAmount *big.Float) error { return e.client.Fund(e.address.Hex(), ethAmount, gasEstimates) } -func (e *EthereumAPIConsumer) Data(ctx context.Context) (*big.Int, error) { +func (e *LegacyEthereumAPIConsumer) Data(ctx context.Context) (*big.Int, error) { opts := &bind.CallOpts{ From: common.HexToAddress(e.client.GetDefaultWallet().Address()), Context: ctx, @@ -131,7 +131,7 @@ func (e *EthereumAPIConsumer) Data(ctx context.Context) (*big.Int, error) { } // CreateRequestTo creates request to an oracle for particular jobID with params -func (e *EthereumAPIConsumer) CreateRequestTo( +func (e *LegacyEthereumAPIConsumer) CreateRequestTo( oracleAddr string, jobID [32]byte, payment *big.Int, @@ -896,19 +896,19 @@ func (f *EthereumFunctionsV1EventsMock) EmitContractUpdated(id [32]byte, from co return f.client.ProcessTransaction(tx) } -// EthereumFluxAggregator represents the basic flux aggregation contract -type EthereumFluxAggregator struct { +// LegacyEthereumFluxAggregator represents the basic flux aggregation contract +type LegacyEthereumFluxAggregator struct { client blockchain.EVMClient fluxAggregator *flux_aggregator_wrapper.FluxAggregator address *common.Address } -func (f *EthereumFluxAggregator) Address() string { +func (f *LegacyEthereumFluxAggregator) Address() string { return f.address.Hex() } // Fund sends specified currencies to the contract -func (f *EthereumFluxAggregator) Fund(ethAmount *big.Float) error { +func (f *LegacyEthereumFluxAggregator) Fund(ethAmount *big.Float) error { gasEstimates, err := f.client.EstimateGas(ethereum.CallMsg{ To: f.address, }) @@ -918,7 +918,7 @@ func (f *EthereumFluxAggregator) Fund(ethAmount *big.Float) error { return f.client.Fund(f.address.Hex(), ethAmount, gasEstimates) } -func (f *EthereumFluxAggregator) UpdateAvailableFunds() error { +func (f *LegacyEthereumFluxAggregator) UpdateAvailableFunds() error { opts, err := f.client.TransactionOpts(f.client.GetDefaultWallet()) if err != nil { return err @@ -930,7 +930,7 @@ func (f *EthereumFluxAggregator) UpdateAvailableFunds() error { return f.client.ProcessTransaction(tx) } -func (f *EthereumFluxAggregator) PaymentAmount(ctx context.Context) (*big.Int, error) { +func (f *LegacyEthereumFluxAggregator) PaymentAmount(ctx context.Context) (*big.Int, error) { opts := &bind.CallOpts{ From: common.HexToAddress(f.client.GetDefaultWallet().Address()), Context: ctx, @@ -942,7 +942,7 @@ func (f *EthereumFluxAggregator) PaymentAmount(ctx context.Context) (*big.Int, e return payment, nil } -func (f *EthereumFluxAggregator) RequestNewRound(_ context.Context) error { +func (f *LegacyEthereumFluxAggregator) RequestNewRound(_ context.Context) error { opts, err := f.client.TransactionOpts(f.client.GetDefaultWallet()) if err != nil { return err @@ -955,7 +955,7 @@ func (f *EthereumFluxAggregator) RequestNewRound(_ context.Context) error { } // WatchSubmissionReceived subscribes to any submissions on a flux feed -func (f *EthereumFluxAggregator) WatchSubmissionReceived(ctx context.Context, eventChan chan<- *SubmissionEvent) error { +func (f *LegacyEthereumFluxAggregator) WatchSubmissionReceived(ctx context.Context, eventChan chan<- *SubmissionEvent) error { ethEventChan := make(chan *flux_aggregator_wrapper.FluxAggregatorSubmissionReceived) sub, err := f.fluxAggregator.WatchSubmissionReceived(&bind.WatchOpts{}, ethEventChan, nil, nil, nil) if err != nil { @@ -981,7 +981,7 @@ func (f *EthereumFluxAggregator) WatchSubmissionReceived(ctx context.Context, ev } } -func (f *EthereumFluxAggregator) SetRequesterPermissions(_ context.Context, addr common.Address, authorized bool, roundsDelay uint32) error { +func (f *LegacyEthereumFluxAggregator) SetRequesterPermissions(_ context.Context, addr common.Address, authorized bool, roundsDelay uint32) error { opts, err := f.client.TransactionOpts(f.client.GetDefaultWallet()) if err != nil { return err @@ -993,7 +993,7 @@ func (f *EthereumFluxAggregator) SetRequesterPermissions(_ context.Context, addr return f.client.ProcessTransaction(tx) } -func (f *EthereumFluxAggregator) GetOracles(ctx context.Context) ([]string, error) { +func (f *LegacyEthereumFluxAggregator) GetOracles(ctx context.Context) ([]string, error) { opts := &bind.CallOpts{ From: common.HexToAddress(f.client.GetDefaultWallet().Address()), Context: ctx, @@ -1009,7 +1009,7 @@ func (f *EthereumFluxAggregator) GetOracles(ctx context.Context) ([]string, erro return oracleAddrs, nil } -func (f *EthereumFluxAggregator) LatestRoundID(ctx context.Context) (*big.Int, error) { +func (f *LegacyEthereumFluxAggregator) LatestRoundID(ctx context.Context) (*big.Int, error) { opts := &bind.CallOpts{ From: common.HexToAddress(f.client.GetDefaultWallet().Address()), Context: ctx, @@ -1021,7 +1021,7 @@ func (f *EthereumFluxAggregator) LatestRoundID(ctx context.Context) (*big.Int, e return rID, nil } -func (f *EthereumFluxAggregator) WithdrawPayment( +func (f *LegacyEthereumFluxAggregator) WithdrawPayment( _ context.Context, from common.Address, to common.Address, @@ -1037,7 +1037,7 @@ func (f *EthereumFluxAggregator) WithdrawPayment( return f.client.ProcessTransaction(tx) } -func (f *EthereumFluxAggregator) WithdrawablePayment(ctx context.Context, addr common.Address) (*big.Int, error) { +func (f *LegacyEthereumFluxAggregator) WithdrawablePayment(ctx context.Context, addr common.Address) (*big.Int, error) { opts := &bind.CallOpts{ From: common.HexToAddress(f.client.GetDefaultWallet().Address()), Context: ctx, @@ -1049,7 +1049,7 @@ func (f *EthereumFluxAggregator) WithdrawablePayment(ctx context.Context, addr c return balance, nil } -func (f *EthereumFluxAggregator) LatestRoundData(ctx context.Context) (flux_aggregator_wrapper.LatestRoundData, error) { +func (f *LegacyEthereumFluxAggregator) LatestRoundData(ctx context.Context) (flux_aggregator_wrapper.LatestRoundData, error) { opts := &bind.CallOpts{ From: common.HexToAddress(f.client.GetDefaultWallet().Address()), Context: ctx, @@ -1062,7 +1062,7 @@ func (f *EthereumFluxAggregator) LatestRoundData(ctx context.Context) (flux_aggr } // GetContractData retrieves basic data for the flux aggregator contract -func (f *EthereumFluxAggregator) GetContractData(ctx context.Context) (*FluxAggregatorData, error) { +func (f *LegacyEthereumFluxAggregator) GetContractData(ctx context.Context) (*FluxAggregatorData, error) { opts := &bind.CallOpts{ From: common.HexToAddress(f.client.GetDefaultWallet().Address()), Context: ctx, @@ -1098,7 +1098,7 @@ func (f *EthereumFluxAggregator) GetContractData(ctx context.Context) (*FluxAggr } // SetOracles allows the ability to add and/or remove oracles from the contract, and to set admins -func (f *EthereumFluxAggregator) SetOracles(o FluxAggregatorSetOraclesOptions) error { +func (f *LegacyEthereumFluxAggregator) SetOracles(o FluxAggregatorSetOraclesOptions) error { opts, err := f.client.TransactionOpts(f.client.GetDefaultWallet()) if err != nil { return err @@ -1112,7 +1112,7 @@ func (f *EthereumFluxAggregator) SetOracles(o FluxAggregatorSetOraclesOptions) e } // Description returns the description of the flux aggregator contract -func (f *EthereumFluxAggregator) Description(ctxt context.Context) (string, error) { +func (f *LegacyEthereumFluxAggregator) Description(ctxt context.Context) (string, error) { opts := &bind.CallOpts{ From: common.HexToAddress(f.client.GetDefaultWallet().Address()), Context: ctxt, @@ -1192,8 +1192,8 @@ func (f *FluxAggregatorRoundConfirmer) Complete() bool { return f.complete } -// EthereumLinkToken represents a LinkToken address -type EthereumLinkToken struct { +// LegacyEthereumLinkToken represents a LinkToken address +type LegacyEthereumLinkToken struct { client blockchain.EVMClient instance *link_token_interface.LinkToken address common.Address @@ -1201,7 +1201,7 @@ type EthereumLinkToken struct { } // Fund the LINK Token contract with ETH to distribute the token -func (l *EthereumLinkToken) Fund(ethAmount *big.Float) error { +func (l *LegacyEthereumLinkToken) Fund(ethAmount *big.Float) error { gasEstimates, err := l.client.EstimateGas(ethereum.CallMsg{ To: &l.address, }) @@ -1211,7 +1211,7 @@ func (l *EthereumLinkToken) Fund(ethAmount *big.Float) error { return l.client.Fund(l.address.Hex(), ethAmount, gasEstimates) } -func (l *EthereumLinkToken) BalanceOf(ctx context.Context, addr string) (*big.Int, error) { +func (l *LegacyEthereumLinkToken) BalanceOf(ctx context.Context, addr string) (*big.Int, error) { opts := &bind.CallOpts{ From: common.HexToAddress(l.client.GetDefaultWallet().Address()), Context: ctx, @@ -1224,7 +1224,7 @@ func (l *EthereumLinkToken) BalanceOf(ctx context.Context, addr string) (*big.In } // Name returns the name of the link token -func (l *EthereumLinkToken) Name(ctxt context.Context) (string, error) { +func (l *LegacyEthereumLinkToken) Name(ctxt context.Context) (string, error) { opts := &bind.CallOpts{ From: common.HexToAddress(l.client.GetDefaultWallet().Address()), Context: ctxt, @@ -1232,11 +1232,11 @@ func (l *EthereumLinkToken) Name(ctxt context.Context) (string, error) { return l.instance.Name(opts) } -func (l *EthereumLinkToken) Address() string { +func (l *LegacyEthereumLinkToken) Address() string { return l.address.Hex() } -func (l *EthereumLinkToken) Approve(to string, amount *big.Int) error { +func (l *LegacyEthereumLinkToken) Approve(to string, amount *big.Int) error { opts, err := l.client.TransactionOpts(l.client.GetDefaultWallet()) if err != nil { return err @@ -1254,7 +1254,7 @@ func (l *EthereumLinkToken) Approve(to string, amount *big.Int) error { return l.client.ProcessTransaction(tx) } -func (l *EthereumLinkToken) Transfer(to string, amount *big.Int) error { +func (l *LegacyEthereumLinkToken) Transfer(to string, amount *big.Int) error { opts, err := l.client.TransactionOpts(l.client.GetDefaultWallet()) if err != nil { return err @@ -1272,7 +1272,7 @@ func (l *EthereumLinkToken) Transfer(to string, amount *big.Int) error { return l.client.ProcessTransaction(tx) } -func (l *EthereumLinkToken) TransferAndCall(to string, amount *big.Int, data []byte) (*types.Transaction, error) { +func (l *LegacyEthereumLinkToken) TransferAndCall(to string, amount *big.Int, data []byte) (*types.Transaction, error) { opts, err := l.client.TransactionOpts(l.client.GetDefaultWallet()) if err != nil { return nil, err @@ -2078,18 +2078,18 @@ func (e *EthereumKeeperRegistryCheckUpkeepGasUsageWrapper) Address() string { /* Functions 1_0_0 */ -type EthereumFunctionsRouter struct { +type LegacyEthereumFunctionsRouter struct { address common.Address client blockchain.EVMClient instance *functions_router.FunctionsRouter l zerolog.Logger } -func (e *EthereumFunctionsRouter) Address() string { +func (e *LegacyEthereumFunctionsRouter) Address() string { return e.address.Hex() } -func (e *EthereumFunctionsRouter) CreateSubscriptionWithConsumer(consumer string) (uint64, error) { +func (e *LegacyEthereumFunctionsRouter) CreateSubscriptionWithConsumer(consumer string) (uint64, error) { opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) if err != nil { return 0, err @@ -2129,13 +2129,13 @@ func (e *EthereumFunctionsRouter) CreateSubscriptionWithConsumer(consumer string return topicsMap["subscriptionId"].(uint64), nil } -type EthereumFunctionsCoordinator struct { +type LegacyEthereumFunctionsCoordinator struct { address common.Address client blockchain.EVMClient instance *functions_coordinator.FunctionsCoordinator } -func (e *EthereumFunctionsCoordinator) GetThresholdPublicKey() ([]byte, error) { +func (e *LegacyEthereumFunctionsCoordinator) GetThresholdPublicKey() ([]byte, error) { opts := &bind.CallOpts{ From: common.HexToAddress(e.client.GetDefaultWallet().Address()), Context: context.Background(), @@ -2143,7 +2143,7 @@ func (e *EthereumFunctionsCoordinator) GetThresholdPublicKey() ([]byte, error) { return e.instance.GetThresholdPublicKey(opts) } -func (e *EthereumFunctionsCoordinator) GetDONPublicKey() ([]byte, error) { +func (e *LegacyEthereumFunctionsCoordinator) GetDONPublicKey() ([]byte, error) { opts := &bind.CallOpts{ From: common.HexToAddress(e.client.GetDefaultWallet().Address()), Context: context.Background(), @@ -2151,17 +2151,17 @@ func (e *EthereumFunctionsCoordinator) GetDONPublicKey() ([]byte, error) { return e.instance.GetDONPublicKey(opts) } -func (e *EthereumFunctionsCoordinator) Address() string { +func (e *LegacyEthereumFunctionsCoordinator) Address() string { return e.address.Hex() } -type EthereumFunctionsLoadTestClient struct { +type LegacyEthereumFunctionsLoadTestClient struct { address common.Address client blockchain.EVMClient instance *functions_load_test_client.FunctionsLoadTestClient } -func (e *EthereumFunctionsLoadTestClient) Address() string { +func (e *LegacyEthereumFunctionsLoadTestClient) Address() string { return e.address.Hex() } @@ -2180,7 +2180,7 @@ func Bytes32ToSlice(a [32]byte) (r []byte) { return } -func (e *EthereumFunctionsLoadTestClient) GetStats() (*EthereumFunctionsLoadStats, error) { +func (e *LegacyEthereumFunctionsLoadTestClient) GetStats() (*EthereumFunctionsLoadStats, error) { opts := &bind.CallOpts{ From: common.HexToAddress(e.client.GetDefaultWallet().Address()), Context: context.Background(), @@ -2200,7 +2200,7 @@ func (e *EthereumFunctionsLoadTestClient) GetStats() (*EthereumFunctionsLoadStat }, nil } -func (e *EthereumFunctionsLoadTestClient) ResetStats() error { +func (e *LegacyEthereumFunctionsLoadTestClient) ResetStats() error { opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) if err != nil { return err @@ -2212,7 +2212,7 @@ func (e *EthereumFunctionsLoadTestClient) ResetStats() error { return e.client.ProcessTransaction(tx) } -func (e *EthereumFunctionsLoadTestClient) SendRequest(times uint32, source string, encryptedSecretsReferences []byte, args []string, subscriptionId uint64, jobId [32]byte) error { +func (e *LegacyEthereumFunctionsLoadTestClient) SendRequest(times uint32, source string, encryptedSecretsReferences []byte, args []string, subscriptionId uint64, jobId [32]byte) error { opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) if err != nil { return err @@ -2224,7 +2224,7 @@ func (e *EthereumFunctionsLoadTestClient) SendRequest(times uint32, source strin return e.client.ProcessTransaction(tx) } -func (e *EthereumFunctionsLoadTestClient) SendRequestWithDONHostedSecrets(times uint32, source string, slotID uint8, slotVersion uint64, args []string, subscriptionId uint64, donID [32]byte) error { +func (e *LegacyEthereumFunctionsLoadTestClient) SendRequestWithDONHostedSecrets(times uint32, source string, slotID uint8, slotVersion uint64, args []string, subscriptionId uint64, donID [32]byte) error { opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) if err != nil { return err diff --git a/integration-tests/contracts/ethereum_contracts_seth.go b/integration-tests/contracts/ethereum_contracts_seth.go index 237d6896234..1d02c77bbe8 100644 --- a/integration-tests/contracts/ethereum_contracts_seth.go +++ b/integration-tests/contracts/ethereum_contracts_seth.go @@ -3,9 +3,12 @@ package contracts import ( "context" "encoding/hex" + "errors" "fmt" "math/big" + "strings" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -18,10 +21,17 @@ import ( ocrConfigHelper "github.com/smartcontractkit/libocr/offchainreporting/confighelper" ocrTypes "github.com/smartcontractkit/libocr/offchainreporting/types" + "github.com/smartcontractkit/chainlink/integration-tests/wrappers" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_coordinator" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_load_test_client" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_router" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flux_aggregator_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_factory" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_wrapper" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/link_token" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/oracle_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/test_api_consumer_wrapper" ) // EthereumOffchainAggregator represents the offchain aggregation contract @@ -33,11 +43,11 @@ type EthereumOffchainAggregator struct { } func LoadOffchainAggregator(l zerolog.Logger, seth *seth.Client, contractAddress common.Address) (EthereumOffchainAggregator, error) { - oAbi, err := offchainaggregator.OffchainAggregatorMetaData.GetAbi() + abi, err := offchainaggregator.OffchainAggregatorMetaData.GetAbi() if err != nil { return EthereumOffchainAggregator{}, fmt.Errorf("failed to get OffChain Aggregator ABI: %w", err) } - seth.ContractStore.AddABI("OffChainAggregator", *oAbi) + seth.ContractStore.AddABI("OffChainAggregator", *abi) seth.ContractStore.AddBIN("OffChainAggregator", common.FromHex(offchainaggregator.OffchainAggregatorMetaData.Bin)) ocr, err := offchainaggregator.NewOffchainAggregator(contractAddress, seth.Client) @@ -80,7 +90,7 @@ func DeployOffchainAggregator(l zerolog.Logger, seth *seth.Client, linkTokenAddr return EthereumOffchainAggregator{}, fmt.Errorf("OCR instance deployment have failed: %w", err) } - ocr, err := offchainaggregator.NewOffchainAggregator(ocrDeploymentData.Address, seth.Client) + ocr, err := offchainaggregator.NewOffchainAggregator(ocrDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) if err != nil { return EthereumOffchainAggregator{}, fmt.Errorf("failed to instantiate OCR instance: %w", err) } @@ -458,7 +468,7 @@ func DeployOffchainAggregatorV2(l zerolog.Logger, seth *seth.Client, linkTokenAd return EthereumOffchainAggregatorV2{}, fmt.Errorf("OCR instance deployment have failed: %w", err) } - ocr2, err := ocr2aggregator.NewOCR2Aggregator(ocrDeploymentData2.Address, seth.Client) + ocr2, err := ocr2aggregator.NewOCR2Aggregator(ocrDeploymentData2.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) if err != nil { return EthereumOffchainAggregatorV2{}, fmt.Errorf("failed to instantiate OCR instance: %w", err) } @@ -567,15 +577,578 @@ func (e *EthereumOffchainAggregatorV2) ParseEventAnswerUpdated(log types.Log) (* return e.contract.ParseAnswerUpdated(log) } -func DeployLinkTokenContract(client *seth.Client) (seth.DeploymentData, error) { - linkTokenAbi, err := link_token.LinkTokenMetaData.GetAbi() +// EthereumLinkToken represents a LinkToken address +type EthereumLinkToken struct { + client *seth.Client + instance *link_token_interface.LinkToken + address common.Address + l zerolog.Logger +} + +func DeployLinkTokenContract(l zerolog.Logger, client *seth.Client) (*EthereumLinkToken, error) { + linkTokenAbi, err := link_token_interface.LinkTokenMetaData.GetAbi() + if err != nil { + return &EthereumLinkToken{}, fmt.Errorf("failed to get LinkToken ABI: %w", err) + } + linkDeploymentData, err := client.DeployContract(client.NewTXOpts(), "LinkToken", *linkTokenAbi, common.FromHex(link_token_interface.LinkTokenMetaData.Bin)) + if err != nil { + return &EthereumLinkToken{}, fmt.Errorf("LinkToken instance deployment have failed: %w", err) + } + + linkToken, err := link_token_interface.NewLinkToken(linkDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, client)) + if err != nil { + return &EthereumLinkToken{}, fmt.Errorf("failed to instantiate LinkToken instance: %w", err) + } + + return &EthereumLinkToken{ + client: client, + instance: linkToken, + address: linkDeploymentData.Address, + l: l, + }, nil +} + +// Fund the LINK Token contract with ETH to distribute the token +func (l *EthereumLinkToken) Fund(_ *big.Float) error { + panic("do not use this function, use actions_seth.SendFunds instead") +} + +func (l *EthereumLinkToken) BalanceOf(ctx context.Context, addr string) (*big.Int, error) { + return l.instance.BalanceOf(&bind.CallOpts{ + From: l.client.Addresses[0], + Context: ctx, + }, common.HexToAddress(addr)) + +} + +// Name returns the name of the link token +func (l *EthereumLinkToken) Name(ctx context.Context) (string, error) { + return l.instance.Name(&bind.CallOpts{ + From: l.client.Addresses[0], + Context: ctx, + }) +} + +func (l *EthereumLinkToken) Address() string { + return l.address.Hex() +} + +func (l *EthereumLinkToken) Approve(to string, amount *big.Int) error { + l.l.Info(). + Str("From", l.client.Addresses[0].Hex()). + Str("To", to). + Str("Amount", amount.String()). + Msg("Approving LINK Transfer") + _, err := l.client.Decode(l.instance.Approve(l.client.NewTXOpts(), common.HexToAddress(to), amount)) + return err +} + +func (l *EthereumLinkToken) Transfer(to string, amount *big.Int) error { + l.l.Info(). + Str("From", l.client.Addresses[0].Hex()). + Str("To", to). + Str("Amount", amount.String()). + Msg("Transferring LINK") + _, err := l.client.Decode(l.instance.Transfer(l.client.NewTXOpts(), common.HexToAddress(to), amount)) + return err +} + +func (l *EthereumLinkToken) TransferAndCall(to string, amount *big.Int, data []byte) (*types.Transaction, error) { + l.l.Info(). + Str("From", l.client.Addresses[0].Hex()). + Str("To", to). + Str("Amount", amount.String()). + Msg("Transferring and Calling LINK") + decodedTx, err := l.client.Decode(l.instance.TransferAndCall(l.client.NewTXOpts(), common.HexToAddress(to), amount, data)) + if err != nil { + return nil, err + } + return decodedTx.Transaction, nil +} + +// DeployFluxAggregatorContract deploys the Flux Aggregator Contract on an EVM chain +func DeployFluxAggregatorContract( + seth *seth.Client, + linkAddr string, + fluxOptions FluxAggregatorOptions, +) (FluxAggregator, error) { + abi, err := flux_aggregator_wrapper.FluxAggregatorMetaData.GetAbi() + if err != nil { + return &EthereumFluxAggregator{}, fmt.Errorf("failed to get FluxAggregator ABI: %w", err) + } + seth.ContractStore.AddABI("FluxAggregator", *abi) + seth.ContractStore.AddBIN("FluxAggregator", common.FromHex(flux_aggregator_wrapper.FluxAggregatorMetaData.Bin)) + + fluxDeploymentData, err := seth.DeployContract(seth.NewTXOpts(), "FluxAggregator", *abi, common.FromHex(flux_aggregator_wrapper.FluxAggregatorMetaData.Bin), + common.HexToAddress(linkAddr), + fluxOptions.PaymentAmount, + fluxOptions.Timeout, + fluxOptions.Validator, + fluxOptions.MinSubValue, + fluxOptions.MaxSubValue, + fluxOptions.Decimals, + fluxOptions.Description, + ) + + if err != nil { + return &EthereumFluxAggregator{}, fmt.Errorf("FluxAggregator instance deployment have failed: %w", err) + } + + flux, err := flux_aggregator_wrapper.NewFluxAggregator(fluxDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumFluxAggregator{}, fmt.Errorf("failed to instantiate FluxAggregator instance: %w", err) + } + + return &EthereumFluxAggregator{ + client: seth, + address: &fluxDeploymentData.Address, + fluxAggregator: flux, + }, nil +} + +// EthereumFluxAggregator represents the basic flux aggregation contract +type EthereumFluxAggregator struct { + client *seth.Client + fluxAggregator *flux_aggregator_wrapper.FluxAggregator + address *common.Address +} + +func (f *EthereumFluxAggregator) Address() string { + return f.address.Hex() +} + +// Fund sends specified currencies to the contract +func (f *EthereumFluxAggregator) Fund(_ *big.Float) error { + panic("do not use this function, use actions_seth.SendFunds() instead, otherwise we will have to deal with circular dependencies") +} + +func (f *EthereumFluxAggregator) UpdateAvailableFunds() error { + _, err := f.client.Decode(f.fluxAggregator.UpdateAvailableFunds(f.client.NewTXOpts())) + return err +} + +func (f *EthereumFluxAggregator) PaymentAmount(ctx context.Context) (*big.Int, error) { + return f.fluxAggregator.PaymentAmount(&bind.CallOpts{ + From: f.client.Addresses[0], + Context: ctx, + }) +} + +func (f *EthereumFluxAggregator) RequestNewRound(context.Context) error { + _, err := f.client.Decode(f.fluxAggregator.RequestNewRound(f.client.NewTXOpts())) + return err +} + +// WatchSubmissionReceived subscribes to any submissions on a flux feed +func (f *EthereumFluxAggregator) WatchSubmissionReceived(_ context.Context, _ chan<- *SubmissionEvent) error { + panic("do not use this method, instead use XXXX") +} + +func (f *EthereumFluxAggregator) SetRequesterPermissions(_ context.Context, addr common.Address, authorized bool, roundsDelay uint32) error { + _, err := f.client.Decode(f.fluxAggregator.SetRequesterPermissions(f.client.NewTXOpts(), addr, authorized, roundsDelay)) + return err +} + +func (f *EthereumFluxAggregator) GetOracles(ctx context.Context) ([]string, error) { + addresses, err := f.fluxAggregator.GetOracles(&bind.CallOpts{ + From: f.client.Addresses[0], + Context: ctx, + }) + if err != nil { + return nil, err + } + var oracleAddrs []string + for _, o := range addresses { + oracleAddrs = append(oracleAddrs, o.Hex()) + } + return oracleAddrs, nil +} + +func (f *EthereumFluxAggregator) LatestRoundID(ctx context.Context) (*big.Int, error) { + return f.fluxAggregator.LatestRound(&bind.CallOpts{ + From: f.client.Addresses[0], + Context: ctx, + }) +} + +func (f *EthereumFluxAggregator) WithdrawPayment( + _ context.Context, + from common.Address, + to common.Address, + amount *big.Int) error { + _, err := f.client.Decode(f.fluxAggregator.WithdrawPayment(f.client.NewTXOpts(), from, to, amount)) + return err +} + +func (f *EthereumFluxAggregator) WithdrawablePayment(ctx context.Context, addr common.Address) (*big.Int, error) { + return f.fluxAggregator.WithdrawablePayment(&bind.CallOpts{ + From: f.client.Addresses[0], + Context: ctx, + }, addr) +} + +func (f *EthereumFluxAggregator) LatestRoundData(ctx context.Context) (flux_aggregator_wrapper.LatestRoundData, error) { + return f.fluxAggregator.LatestRoundData(&bind.CallOpts{ + From: f.client.Addresses[0], + Context: ctx, + }) +} + +// GetContractData retrieves basic data for the flux aggregator contract +func (f *EthereumFluxAggregator) GetContractData(ctx context.Context) (*FluxAggregatorData, error) { + opts := &bind.CallOpts{ + From: f.client.Addresses[0], + Context: ctx, + } + + allocated, err := f.fluxAggregator.AllocatedFunds(opts) + if err != nil { + return &FluxAggregatorData{}, err + } + + available, err := f.fluxAggregator.AvailableFunds(opts) + if err != nil { + return &FluxAggregatorData{}, err + } + + lr, err := f.fluxAggregator.LatestRoundData(opts) + if err != nil { + return &FluxAggregatorData{}, err + } + latestRound := RoundData(lr) + + oracles, err := f.fluxAggregator.GetOracles(opts) + if err != nil { + return &FluxAggregatorData{}, err + } + + return &FluxAggregatorData{ + AllocatedFunds: allocated, + AvailableFunds: available, + LatestRoundData: latestRound, + Oracles: oracles, + }, nil +} + +// SetOracles allows the ability to add and/or remove oracles from the contract, and to set admins +func (f *EthereumFluxAggregator) SetOracles(o FluxAggregatorSetOraclesOptions) error { + _, err := f.client.Decode(f.fluxAggregator.ChangeOracles(f.client.NewTXOpts(), o.RemoveList, o.AddList, o.AdminList, o.MinSubmissions, o.MaxSubmissions, o.RestartDelayRounds)) + if err != nil { + return err + } + return err +} + +// Description returns the description of the flux aggregator contract +func (f *EthereumFluxAggregator) Description(ctxt context.Context) (string, error) { + return f.fluxAggregator.Description(&bind.CallOpts{ + From: f.client.Addresses[0], + Context: ctxt, + }) +} + +func DeployOracle(seth *seth.Client, linkAddr string) (Oracle, error) { + abi, err := oracle_wrapper.OracleMetaData.GetAbi() + if err != nil { + return &EthereumOracle{}, fmt.Errorf("failed to get Oracle ABI: %w", err) + } + seth.ContractStore.AddABI("Oracle", *abi) + seth.ContractStore.AddBIN("Oracle", common.FromHex(oracle_wrapper.OracleMetaData.Bin)) + + oracleDeploymentData, err := seth.DeployContract(seth.NewTXOpts(), "Oracle", *abi, common.FromHex(oracle_wrapper.OracleMetaData.Bin), + common.HexToAddress(linkAddr), + ) + + if err != nil { + return &EthereumOracle{}, fmt.Errorf("Oracle instance deployment have failed: %w", err) + } + + oracle, err := oracle_wrapper.NewOracle(oracleDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumOracle{}, fmt.Errorf("Oracle to instantiate FluxAggregator instance: %w", err) + } + + return &EthereumOracle{ + client: seth, + address: &oracleDeploymentData.Address, + oracle: oracle, + }, nil +} + +// EthereumOracle oracle for "directrequest" job tests +type EthereumOracle struct { + address *common.Address + client *seth.Client + oracle *oracle_wrapper.Oracle +} + +func (e *EthereumOracle) Address() string { + return e.address.Hex() +} + +func (e *EthereumOracle) Fund(_ *big.Float) error { + panic("do not use this function, use actions_seth.SendFunds() instead, otherwise we will have to deal with circular dependencies") +} + +// SetFulfillmentPermission sets fulfillment permission for particular address +func (e *EthereumOracle) SetFulfillmentPermission(address string, allowed bool) error { + _, err := e.client.Decode(e.oracle.SetFulfillmentPermission(e.client.NewTXOpts(), common.HexToAddress(address), allowed)) + return err +} + +func DeployAPIConsumer(seth *seth.Client, linkAddr string) (APIConsumer, error) { + abi, err := test_api_consumer_wrapper.TestAPIConsumerMetaData.GetAbi() + if err != nil { + return &EthereumAPIConsumer{}, fmt.Errorf("failed to get TestAPIConsumer ABI: %w", err) + } + seth.ContractStore.AddABI("TestAPIConsumer", *abi) + seth.ContractStore.AddBIN("TestAPIConsumer", common.FromHex(test_api_consumer_wrapper.TestAPIConsumerMetaData.Bin)) + + consumerDeploymentData, err := seth.DeployContract(seth.NewTXOpts(), "TestAPIConsumer", *abi, common.FromHex(test_api_consumer_wrapper.TestAPIConsumerMetaData.Bin), + common.HexToAddress(linkAddr), + ) + + if err != nil { + return &EthereumAPIConsumer{}, fmt.Errorf("TestAPIConsumer instance deployment have failed: %w", err) + } + + consumer, err := test_api_consumer_wrapper.NewTestAPIConsumer(consumerDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumAPIConsumer{}, fmt.Errorf("failed to instantiate TestAPIConsumer instance: %w", err) + } + + return &EthereumAPIConsumer{ + client: seth, + address: &consumerDeploymentData.Address, + consumer: consumer, + }, nil +} + +// EthereumAPIConsumer API consumer for job type "directrequest" tests +type EthereumAPIConsumer struct { + address *common.Address + client *seth.Client + consumer *test_api_consumer_wrapper.TestAPIConsumer +} + +func (e *EthereumAPIConsumer) Address() string { + return e.address.Hex() +} + +func (e *EthereumAPIConsumer) RoundID(ctx context.Context) (*big.Int, error) { + return e.consumer.CurrentRoundID(&bind.CallOpts{ + From: e.client.Addresses[0], + Context: ctx, + }) +} + +func (e *EthereumAPIConsumer) Fund(_ *big.Float) error { + panic("do not use this function, use actions_seth.SendFunds() instead, otherwise we will have to deal with circular dependencies") +} + +func (e *EthereumAPIConsumer) Data(ctx context.Context) (*big.Int, error) { + return e.consumer.Data(&bind.CallOpts{ + From: e.client.Addresses[0], + Context: ctx, + }) +} + +// CreateRequestTo creates request to an oracle for particular jobID with params +func (e *EthereumAPIConsumer) CreateRequestTo( + oracleAddr string, + jobID [32]byte, + payment *big.Int, + url string, + path string, + times *big.Int, +) error { + _, err := e.client.Decode(e.consumer.CreateRequestTo(e.client.NewTXOpts(), common.HexToAddress(oracleAddr), jobID, payment, url, path, times)) + return err +} + +func LoadFunctionsCoordinator(seth *seth.Client, addr string) (FunctionsCoordinator, error) { + abi, err := functions_coordinator.FunctionsCoordinatorMetaData.GetAbi() + if err != nil { + return &EthereumFunctionsCoordinator{}, fmt.Errorf("failed to get FunctionsCoordinator ABI: %w", err) + } + seth.ContractStore.AddABI("FunctionsCoordinator", *abi) + seth.ContractStore.AddBIN("FunctionsCoordinator", common.FromHex(functions_coordinator.FunctionsCoordinatorMetaData.Bin)) + + instance, err := functions_coordinator.NewFunctionsCoordinator(common.HexToAddress(addr), seth.Client) + if err != nil { + return &EthereumFunctionsCoordinator{}, fmt.Errorf("failed to instantiate FunctionsCoordinator instance: %w", err) + } + + return &EthereumFunctionsCoordinator{ + client: seth, + instance: instance, + address: common.HexToAddress(addr), + }, err +} + +type EthereumFunctionsCoordinator struct { + address common.Address + client *seth.Client + instance *functions_coordinator.FunctionsCoordinator +} + +func (e *EthereumFunctionsCoordinator) GetThresholdPublicKey() ([]byte, error) { + return e.instance.GetThresholdPublicKey(e.client.NewCallOpts()) +} + +func (e *EthereumFunctionsCoordinator) GetDONPublicKey() ([]byte, error) { + return e.instance.GetDONPublicKey(e.client.NewCallOpts()) +} + +func (e *EthereumFunctionsCoordinator) Address() string { + return e.address.Hex() +} + +func LoadFunctionsRouter(l zerolog.Logger, seth *seth.Client, addr string) (FunctionsRouter, error) { + abi, err := functions_router.FunctionsRouterMetaData.GetAbi() + if err != nil { + return &EthereumFunctionsRouter{}, fmt.Errorf("failed to get FunctionsRouter ABI: %w", err) + } + seth.ContractStore.AddABI("FunctionsRouter", *abi) + seth.ContractStore.AddBIN("FunctionsRouter", common.FromHex(functions_router.FunctionsRouterMetaData.Bin)) + + instance, err := functions_router.NewFunctionsRouter(common.HexToAddress(addr), seth.Client) if err != nil { - return seth.DeploymentData{}, fmt.Errorf("failed to get LinkToken ABI: %w", err) + return &EthereumFunctionsRouter{}, fmt.Errorf("failed to instantiate FunctionsRouter instance: %w", err) } - linkDeploymentData, err := client.DeployContract(client.NewTXOpts(), "LinkToken", *linkTokenAbi, common.FromHex(link_token.LinkTokenMetaData.Bin)) + + return &EthereumFunctionsRouter{ + client: seth, + instance: instance, + address: common.HexToAddress(addr), + l: l, + }, err +} + +type EthereumFunctionsRouter struct { + address common.Address + client *seth.Client + instance *functions_router.FunctionsRouter + l zerolog.Logger +} + +func (e *EthereumFunctionsRouter) Address() string { + return e.address.Hex() +} + +func (e *EthereumFunctionsRouter) CreateSubscriptionWithConsumer(consumer string) (uint64, error) { + tx, err := e.client.Decode(e.instance.CreateSubscriptionWithConsumer(e.client.NewTXOpts(), common.HexToAddress(consumer))) if err != nil { - return seth.DeploymentData{}, fmt.Errorf("LinkToken instance deployment have failed: %w", err) + return 0, err } - return linkDeploymentData, nil + if tx.Receipt == nil { + return 0, errors.New("transaction did not err, but the receipt is nil") + } + for _, l := range tx.Receipt.Logs { + e.l.Info().Interface("Log", common.Bytes2Hex(l.Data)).Send() + } + topicsMap := map[string]interface{}{} + + fabi, err := abi.JSON(strings.NewReader(functions_router.FunctionsRouterABI)) + if err != nil { + return 0, err + } + for _, ev := range fabi.Events { + e.l.Info().Str("EventName", ev.Name).Send() + } + topicOneInputs := abi.Arguments{fabi.Events["SubscriptionCreated"].Inputs[0]} + topicOneHash := []common.Hash{tx.Receipt.Logs[0].Topics[1:][0]} + if err := abi.ParseTopicsIntoMap(topicsMap, topicOneInputs, topicOneHash); err != nil { + return 0, fmt.Errorf("failed to decode topic value, err: %w", err) + } + e.l.Info().Interface("NewTopicsDecoded", topicsMap).Send() + if topicsMap["subscriptionId"] == 0 { + return 0, fmt.Errorf("failed to decode subscription ID after creation") + } + return topicsMap["subscriptionId"].(uint64), nil +} + +func DeployFunctionsLoadTestClient(seth *seth.Client, router string) (FunctionsLoadTestClient, error) { + operatorAbi, err := functions_load_test_client.FunctionsLoadTestClientMetaData.GetAbi() + if err != nil { + return &EthereumFunctionsLoadTestClient{}, fmt.Errorf("failed to get FunctionsLoadTestClient ABI: %w", err) + } + data, err := seth.DeployContract(seth.NewTXOpts(), "FunctionsLoadTestClient", *operatorAbi, common.FromHex(functions_load_test_client.FunctionsLoadTestClientMetaData.Bin), common.HexToAddress(router)) + if err != nil { + return &EthereumFunctionsLoadTestClient{}, fmt.Errorf("FunctionsLoadTestClient instance deployment have failed: %w", err) + } + + instance, err := functions_load_test_client.NewFunctionsLoadTestClient(data.Address, seth.Client) + if err != nil { + return &EthereumFunctionsLoadTestClient{}, fmt.Errorf("failed to instantiate FunctionsLoadTestClient instance: %w", err) + } + + return &EthereumFunctionsLoadTestClient{ + client: seth, + instance: instance, + address: data.Address, + }, nil +} + +// LoadFunctionsLoadTestClient returns deployed on given address FunctionsLoadTestClient contract instance +func LoadFunctionsLoadTestClient(seth *seth.Client, addr string) (FunctionsLoadTestClient, error) { + abi, err := functions_load_test_client.FunctionsLoadTestClientMetaData.GetAbi() + if err != nil { + return &EthereumFunctionsLoadTestClient{}, fmt.Errorf("failed to get FunctionsLoadTestClient ABI: %w", err) + } + seth.ContractStore.AddABI("FunctionsLoadTestClient", *abi) + seth.ContractStore.AddBIN("FunctionsLoadTestClient", common.FromHex(functions_load_test_client.FunctionsLoadTestClientMetaData.Bin)) + + instance, err := functions_load_test_client.NewFunctionsLoadTestClient(common.HexToAddress(addr), seth.Client) + if err != nil { + return &EthereumFunctionsLoadTestClient{}, fmt.Errorf("failed to instantiate FunctionsLoadTestClient instance: %w", err) + } + + return &EthereumFunctionsLoadTestClient{ + client: seth, + instance: instance, + address: common.HexToAddress(addr), + }, err +} + +type EthereumFunctionsLoadTestClient struct { + address common.Address + client *seth.Client + instance *functions_load_test_client.FunctionsLoadTestClient +} + +func (e *EthereumFunctionsLoadTestClient) Address() string { + return e.address.Hex() +} + +func (e *EthereumFunctionsLoadTestClient) GetStats() (*EthereumFunctionsLoadStats, error) { + lr, lbody, lerr, total, succeeded, errored, empty, err := e.instance.GetStats(e.client.NewCallOpts()) + if err != nil { + return nil, err + } + return &EthereumFunctionsLoadStats{ + LastRequestID: string(Bytes32ToSlice(lr)), + LastResponse: string(lbody), + LastError: string(lerr), + Total: total, + Succeeded: succeeded, + Errored: errored, + Empty: empty, + }, nil +} + +func (e *EthereumFunctionsLoadTestClient) ResetStats() error { + _, err := e.client.Decode(e.instance.ResetStats(e.client.NewTXOpts())) + return err +} + +func (e *EthereumFunctionsLoadTestClient) SendRequest(times uint32, source string, encryptedSecretsReferences []byte, args []string, subscriptionId uint64, jobId [32]byte) error { + _, err := e.client.Decode(e.instance.SendRequest(e.client.NewTXOpts(), times, source, encryptedSecretsReferences, args, subscriptionId, jobId)) + return err +} + +func (e *EthereumFunctionsLoadTestClient) SendRequestWithDONHostedSecrets(times uint32, source string, slotID uint8, slotVersion uint64, args []string, subscriptionId uint64, donID [32]byte) error { + _, err := e.client.Decode(e.instance.SendRequestWithDONHostedSecrets(e.client.NewTXOpts(), times, source, slotID, slotVersion, args, subscriptionId, donID)) + return err } diff --git a/integration-tests/contracts/ethereum_keeper_contracts.go b/integration-tests/contracts/ethereum_keeper_contracts.go index 0a516d5029b..337e3009f16 100644 --- a/integration-tests/contracts/ethereum_keeper_contracts.go +++ b/integration-tests/contracts/ethereum_keeper_contracts.go @@ -174,6 +174,7 @@ type KeeperRegistrySettings struct { FallbackLinkPrice *big.Int // LINK price used if the LINK price feed is stale MaxCheckDataSize uint32 MaxPerformDataSize uint32 + MaxRevertDataSize uint32 RegistryVersion ethereum.KeeperRegistryVersion } @@ -258,7 +259,7 @@ func (rcs *KeeperRegistrySettings) Create22OnchainConfig(registrar string, regis MaxPerformGas: rcs.MaxPerformGas, MaxCheckDataSize: rcs.MaxCheckDataSize, MaxPerformDataSize: rcs.MaxPerformDataSize, - MaxRevertDataSize: uint32(1000), + MaxRevertDataSize: rcs.MaxRevertDataSize, FallbackGasPrice: rcs.FallbackGasPrice, FallbackLinkPrice: rcs.FallbackLinkPrice, Transcoder: common.Address{}, @@ -280,7 +281,7 @@ func (rcs *KeeperRegistrySettings) Create21OnchainConfig(registrar string, regis MaxPerformGas: rcs.MaxPerformGas, MaxCheckDataSize: rcs.MaxCheckDataSize, MaxPerformDataSize: rcs.MaxPerformDataSize, - MaxRevertDataSize: uint32(1000), + MaxRevertDataSize: rcs.MaxRevertDataSize, FallbackGasPrice: rcs.FallbackGasPrice, FallbackLinkPrice: rcs.FallbackLinkPrice, Transcoder: common.Address{}, diff --git a/integration-tests/contracts/ethereum_ocr2vrf_contracts.go b/integration-tests/contracts/ethereum_ocr2vrf_contracts.go index cb52d1941a8..473b308dc42 100644 --- a/integration-tests/contracts/ethereum_ocr2vrf_contracts.go +++ b/integration-tests/contracts/ethereum_ocr2vrf_contracts.go @@ -49,8 +49,8 @@ type EthereumVRFBeaconConsumer struct { vrfBeaconConsumer *vrf_beacon_consumer.BeaconVRFConsumer } -// EthereumVRFCoordinator represents VRF coordinator contract -type EthereumVRFCoordinator struct { +// LegacyEthereumVRFCoordinator represents VRF coordinator contract +type LegacyEthereumVRFCoordinator struct { address *common.Address client blockchain.EVMClient coordinator *solidity_vrf_coordinator_interface.VRFCoordinator @@ -125,7 +125,7 @@ func (e *EthereumContractDeployer) DeployBatchBlockhashStore(blockhashStoreAddr if err != nil { return nil, err } - return &EthereumBatchBlockhashStore{ + return &LegacyEthereumBatchBlockhashStore{ client: e.client, batchBlockhashStore: instance.(*batch_blockhash_store.BatchBlockhashStore), address: address, diff --git a/integration-tests/contracts/ethereum_vrf_contracts.go b/integration-tests/contracts/ethereum_vrf_contracts.go index ea8a4f94817..c2f12e29446 100644 --- a/integration-tests/contracts/ethereum_vrf_contracts.go +++ b/integration-tests/contracts/ethereum_vrf_contracts.go @@ -13,6 +13,7 @@ import ( "github.com/rs/zerolog/log" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink/integration-tests/wrappers" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_consumer_interface" @@ -20,22 +21,22 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_wrapper" ) -// EthereumBatchBlockhashStore represents BatchBlockhashStore contract -type EthereumBatchBlockhashStore struct { +// LegacyEthereumBatchBlockhashStore represents BatchBlockhashStore contract +type LegacyEthereumBatchBlockhashStore struct { address *common.Address client blockchain.EVMClient batchBlockhashStore *batch_blockhash_store.BatchBlockhashStore } -// EthereumBlockhashStore represents a blockhash store for VRF contract -type EthereumBlockhashStore struct { +// LegacyEthereumBlockhashStore represents a blockhash store for VRF contract +type LegacyEthereumBlockhashStore struct { address *common.Address client blockchain.EVMClient blockHashStore *blockhash_store.BlockhashStore } -// EthereumVRFConsumer represents VRF consumer contract -type EthereumVRFConsumer struct { +// LegacyEthereumVRFConsumer represents VRF consumer contract +type LegacyEthereumVRFConsumer struct { address *common.Address client blockchain.EVMClient consumer *solidity_vrf_consumer_interface.VRFConsumer @@ -51,8 +52,8 @@ type VRFConsumerRoundConfirmer struct { done bool } -// EthereumVRF represents a VRF contract -type EthereumVRF struct { +// LegacyEthereumVRF represents a VRF contract +type LegacyEthereumVRF struct { client blockchain.EVMClient vrf *solidity_vrf_wrapper.VRF address *common.Address @@ -64,12 +65,12 @@ func (e *EthereumContractDeployer) DeployVRFContract() (VRF, error) { auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return solidity_vrf_wrapper.DeployVRF(auth, backend) + return solidity_vrf_wrapper.DeployVRF(auth, wrappers.MustNewWrappedContractBackend(e.client, nil)) }) if err != nil { return nil, err } - return &EthereumVRF{ + return &LegacyEthereumVRF{ client: e.client, vrf: instance.(*solidity_vrf_wrapper.VRF), address: address, @@ -82,12 +83,12 @@ func (e *EthereumContractDeployer) DeployBlockhashStore() (BlockHashStore, error auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return blockhash_store.DeployBlockhashStore(auth, backend) + return blockhash_store.DeployBlockhashStore(auth, wrappers.MustNewWrappedContractBackend(e.client, nil)) }) if err != nil { return nil, err } - return &EthereumBlockhashStore{ + return &LegacyEthereumBlockhashStore{ client: e.client, blockHashStore: instance.(*blockhash_store.BlockhashStore), address: address, @@ -100,12 +101,12 @@ func (e *EthereumContractDeployer) DeployVRFCoordinator(linkAddr string, bhsAddr auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return solidity_vrf_coordinator_interface.DeployVRFCoordinator(auth, backend, common.HexToAddress(linkAddr), common.HexToAddress(bhsAddr)) + return solidity_vrf_coordinator_interface.DeployVRFCoordinator(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(linkAddr), common.HexToAddress(bhsAddr)) }) if err != nil { return nil, err } - return &EthereumVRFCoordinator{ + return &LegacyEthereumVRFCoordinator{ client: e.client, coordinator: instance.(*solidity_vrf_coordinator_interface.VRFCoordinator), address: address, @@ -118,23 +119,23 @@ func (e *EthereumContractDeployer) DeployVRFConsumer(linkAddr string, coordinato auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return solidity_vrf_consumer_interface.DeployVRFConsumer(auth, backend, common.HexToAddress(coordinatorAddr), common.HexToAddress(linkAddr)) + return solidity_vrf_consumer_interface.DeployVRFConsumer(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(coordinatorAddr), common.HexToAddress(linkAddr)) }) if err != nil { return nil, err } - return &EthereumVRFConsumer{ + return &LegacyEthereumVRFConsumer{ client: e.client, consumer: instance.(*solidity_vrf_consumer_interface.VRFConsumer), address: address, }, err } -func (v *EthereumBlockhashStore) Address() string { +func (v *LegacyEthereumBlockhashStore) Address() string { return v.address.Hex() } -func (v *EthereumBlockhashStore) GetBlockHash(ctx context.Context, blockNumber *big.Int) ([32]byte, error) { +func (v *LegacyEthereumBlockhashStore) GetBlockHash(ctx context.Context, blockNumber *big.Int) ([32]byte, error) { opts := &bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), Context: ctx, @@ -146,12 +147,12 @@ func (v *EthereumBlockhashStore) GetBlockHash(ctx context.Context, blockNumber * return blockHash, nil } -func (v *EthereumVRFCoordinator) Address() string { +func (v *LegacyEthereumVRFCoordinator) Address() string { return v.address.Hex() } // HashOfKey get a hash of proving key to use it as a request ID part for VRF -func (v *EthereumVRFCoordinator) HashOfKey(ctx context.Context, pubKey [2]*big.Int) ([32]byte, error) { +func (v *LegacyEthereumVRFCoordinator) HashOfKey(ctx context.Context, pubKey [2]*big.Int) ([32]byte, error) { opts := &bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), Context: ctx, @@ -164,7 +165,7 @@ func (v *EthereumVRFCoordinator) HashOfKey(ctx context.Context, pubKey [2]*big.I } // RegisterProvingKey register VRF proving key -func (v *EthereumVRFCoordinator) RegisterProvingKey( +func (v *LegacyEthereumVRFCoordinator) RegisterProvingKey( fee *big.Int, oracleAddr string, publicProvingKey [2]*big.Int, @@ -181,11 +182,11 @@ func (v *EthereumVRFCoordinator) RegisterProvingKey( return v.client.ProcessTransaction(tx) } -func (v *EthereumVRFConsumer) Address() string { +func (v *LegacyEthereumVRFConsumer) Address() string { return v.address.Hex() } -func (v *EthereumVRFConsumer) Fund(ethAmount *big.Float) error { +func (v *LegacyEthereumVRFConsumer) Fund(ethAmount *big.Float) error { gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{ To: v.address, }) @@ -196,7 +197,7 @@ func (v *EthereumVRFConsumer) Fund(ethAmount *big.Float) error { } // RequestRandomness requests VRF randomness -func (v *EthereumVRFConsumer) RequestRandomness(hash [32]byte, fee *big.Int) error { +func (v *LegacyEthereumVRFConsumer) RequestRandomness(hash [32]byte, fee *big.Int) error { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { return err @@ -209,7 +210,7 @@ func (v *EthereumVRFConsumer) RequestRandomness(hash [32]byte, fee *big.Int) err } // CurrentRoundID helper roundID counter in consumer to check when all randomness requests are finished -func (v *EthereumVRFConsumer) CurrentRoundID(ctx context.Context) (*big.Int, error) { +func (v *LegacyEthereumVRFConsumer) CurrentRoundID(ctx context.Context) (*big.Int, error) { opts := &bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), Context: ctx, @@ -218,7 +219,7 @@ func (v *EthereumVRFConsumer) CurrentRoundID(ctx context.Context) (*big.Int, err } // RandomnessOutput get VRF randomness output -func (v *EthereumVRFConsumer) RandomnessOutput(ctx context.Context) (*big.Int, error) { +func (v *LegacyEthereumVRFConsumer) RandomnessOutput(ctx context.Context) (*big.Int, error) { opts := &bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), Context: ctx, @@ -289,7 +290,7 @@ func (f *VRFConsumerRoundConfirmer) Wait() error { } // Fund sends specified currencies to the contract -func (v *EthereumVRF) Fund(ethAmount *big.Float) error { +func (v *LegacyEthereumVRF) Fund(ethAmount *big.Float) error { gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{ To: v.address, }) @@ -300,7 +301,7 @@ func (v *EthereumVRF) Fund(ethAmount *big.Float) error { } // ProofLength returns the PROOFLENGTH call from the VRF contract -func (v *EthereumVRF) ProofLength(ctxt context.Context) (*big.Int, error) { +func (v *LegacyEthereumVRF) ProofLength(ctxt context.Context) (*big.Int, error) { opts := &bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), Context: ctxt, @@ -308,6 +309,6 @@ func (v *EthereumVRF) ProofLength(ctxt context.Context) (*big.Int, error) { return v.vrf.PROOFLENGTH(opts) } -func (v *EthereumBatchBlockhashStore) Address() string { +func (v *LegacyEthereumBatchBlockhashStore) Address() string { return v.address.Hex() } diff --git a/integration-tests/contracts/ethereum_vrf_contracts_seth.go b/integration-tests/contracts/ethereum_vrf_contracts_seth.go new file mode 100644 index 00000000000..f352e901a0c --- /dev/null +++ b/integration-tests/contracts/ethereum_vrf_contracts_seth.go @@ -0,0 +1,247 @@ +package contracts + +import ( + "context" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/seth" + + "github.com/smartcontractkit/chainlink/integration-tests/wrappers" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_consumer_interface" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_wrapper" +) + +// EthereumBlockhashStore represents a blockhash store for VRF contract +type EthereumBlockhashStore struct { + address *common.Address + client *seth.Client + blockHashStore *blockhash_store.BlockhashStore +} + +// EthereumVRFCoordinator represents VRF coordinator contract +type EthereumVRFCoordinator struct { + address *common.Address + client *seth.Client + coordinator *solidity_vrf_coordinator_interface.VRFCoordinator +} + +// EthereumVRFConsumer represents VRF consumer contract +type EthereumVRFConsumer struct { + address *common.Address + client *seth.Client + consumer *solidity_vrf_consumer_interface.VRFConsumer +} + +// EthereumVRF represents a VRF contract +type EthereumVRF struct { + client *seth.Client + vrf *solidity_vrf_wrapper.VRF + address *common.Address +} + +// DeployVRFContract deploy VRFv1 contract +func DeployVRFv1Contract(seth *seth.Client) (VRF, error) { + abi, err := solidity_vrf_wrapper.VRFMetaData.GetAbi() + if err != nil { + return &EthereumVRF{}, fmt.Errorf("failed to get VRF ABI: %w", err) + } + + vrfDeploymentData, err := seth.DeployContract( + seth.NewTXOpts(), + "VRF", + *abi, + common.FromHex(solidity_vrf_wrapper.VRFMetaData.Bin)) + if err != nil { + return &EthereumVRF{}, fmt.Errorf("VRF instance deployment have failed: %w", err) + } + + vrf, err := solidity_vrf_wrapper.NewVRF(vrfDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRF{}, fmt.Errorf("failed to instantiate VRF instance: %w", err) + } + + return &EthereumVRF{ + client: seth, + vrf: vrf, + address: &vrfDeploymentData.Address, + }, err +} + +// DeployBlockhashStore deploys blockhash store used with VRF contract +func DeployBlockhashStore(seth *seth.Client) (BlockHashStore, error) { + abi, err := blockhash_store.BlockhashStoreMetaData.GetAbi() + if err != nil { + return &EthereumBlockhashStore{}, fmt.Errorf("failed to get BlockhashStore ABI: %w", err) + } + + storeDeploymentData, err := seth.DeployContract( + seth.NewTXOpts(), + "BlockhashStore", + *abi, + common.FromHex(blockhash_store.BlockhashStoreMetaData.Bin)) + if err != nil { + return &EthereumBlockhashStore{}, fmt.Errorf("BlockhashStore instance deployment have failed: %w", err) + } + + store, err := blockhash_store.NewBlockhashStore(storeDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumBlockhashStore{}, fmt.Errorf("failed to instantiate BlockhashStore instance: %w", err) + } + + return &EthereumBlockhashStore{ + client: seth, + blockHashStore: store, + address: &storeDeploymentData.Address, + }, err +} + +// DeployVRFCoordinator deploys VRF coordinator contract +func DeployVRFCoordinator(seth *seth.Client, linkAddr, bhsAddr string) (VRFCoordinator, error) { + abi, err := solidity_vrf_coordinator_interface.VRFCoordinatorMetaData.GetAbi() + if err != nil { + return &EthereumVRFCoordinator{}, fmt.Errorf("failed to get VRFCoordinator ABI: %w", err) + } + + coordinatorDeploymentData, err := seth.DeployContract( + seth.NewTXOpts(), + "VRFCoordinator", + *abi, + common.FromHex(solidity_vrf_coordinator_interface.VRFCoordinatorMetaData.Bin), + common.HexToAddress(linkAddr), + common.HexToAddress(bhsAddr)) + if err != nil { + return &EthereumVRFCoordinator{}, fmt.Errorf("VRFCoordinator instance deployment have failed: %w", err) + } + + coordinator, err := solidity_vrf_coordinator_interface.NewVRFCoordinator(coordinatorDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRFCoordinator{}, fmt.Errorf("failed to instantiate VRFCoordinator instance: %w", err) + } + + return &EthereumVRFCoordinator{ + client: seth, + coordinator: coordinator, + address: &coordinatorDeploymentData.Address, + }, err +} + +// DeployVRFConsumer deploys VRF consumer contract +func DeployVRFConsumer(seth *seth.Client, linkAddr, coordinatorAddr string) (VRFConsumer, error) { + abi, err := solidity_vrf_consumer_interface.VRFConsumerMetaData.GetAbi() + if err != nil { + return &EthereumVRFConsumer{}, fmt.Errorf("failed to get VRFConsumer ABI: %w", err) + } + + consumerDeploymentData, err := seth.DeployContract( + seth.NewTXOpts(), + "VRFConsumer", + *abi, + common.FromHex(solidity_vrf_consumer_interface.VRFConsumerMetaData.Bin), + common.HexToAddress(coordinatorAddr), + common.HexToAddress(linkAddr), + ) + if err != nil { + return &EthereumVRFConsumer{}, fmt.Errorf("VRFConsumer instance deployment have failed: %w", err) + } + + consumer, err := solidity_vrf_consumer_interface.NewVRFConsumer(consumerDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRFConsumer{}, fmt.Errorf("failed to instantiate VRFConsumer instance: %w", err) + } + + return &EthereumVRFConsumer{ + client: seth, + consumer: consumer, + address: &consumerDeploymentData.Address, + }, err +} + +func (v *EthereumBlockhashStore) Address() string { + return v.address.Hex() +} + +func (v *EthereumBlockhashStore) GetBlockHash(ctx context.Context, blockNumber *big.Int) ([32]byte, error) { + blockHash, err := v.blockHashStore.GetBlockhash(&bind.CallOpts{ + From: v.client.Addresses[0], + Context: ctx, + }, blockNumber) + if err != nil { + return [32]byte{}, err + } + return blockHash, nil +} + +func (v *EthereumVRFCoordinator) Address() string { + return v.address.Hex() +} + +// HashOfKey get a hash of proving key to use it as a request ID part for VRF +func (v *EthereumVRFCoordinator) HashOfKey(ctx context.Context, pubKey [2]*big.Int) ([32]byte, error) { + hash, err := v.coordinator.HashOfKey(&bind.CallOpts{ + From: v.client.Addresses[0], + Context: ctx, + }, pubKey) + if err != nil { + return [32]byte{}, err + } + return hash, nil +} + +// RegisterProvingKey register VRF proving key +func (v *EthereumVRFCoordinator) RegisterProvingKey( + fee *big.Int, + oracleAddr string, + publicProvingKey [2]*big.Int, + jobID [32]byte, +) error { + _, err := v.client.Decode(v.coordinator.RegisterProvingKey(v.client.NewTXOpts(), fee, common.HexToAddress(oracleAddr), publicProvingKey, jobID)) + return err +} + +func (v *EthereumVRFConsumer) Address() string { + return v.address.Hex() +} + +func (v *EthereumVRFConsumer) Fund(_ *big.Float) error { + panic("do not use this function, use actions_seth.SendFunds() instead, otherwise we will have to deal with circular dependencies") +} + +// RequestRandomness requests VRF randomness +func (v *EthereumVRFConsumer) RequestRandomness(hash [32]byte, fee *big.Int) error { + _, err := v.client.Decode(v.consumer.TestRequestRandomness(v.client.NewTXOpts(), hash, fee)) + return err +} + +// CurrentRoundID helper roundID counter in consumer to check when all randomness requests are finished +func (v *EthereumVRFConsumer) CurrentRoundID(ctx context.Context) (*big.Int, error) { + return v.consumer.CurrentRoundID(&bind.CallOpts{ + From: v.client.Addresses[0], + Context: ctx, + }) +} + +// RandomnessOutput get VRF randomness output +func (v *EthereumVRFConsumer) RandomnessOutput(ctx context.Context) (*big.Int, error) { + return v.consumer.RandomnessOutput(&bind.CallOpts{ + From: v.client.Addresses[0], + Context: ctx, + }) +} + +// Fund sends specified currencies to the contract +func (v *EthereumVRF) Fund(_ *big.Float) error { + panic("do not use this function, use actions_seth.SendFunds() instead, otherwise we will have to deal with circular dependencies") +} + +// ProofLength returns the PROOFLENGTH call from the VRF contract +func (v *EthereumVRF) ProofLength(ctx context.Context) (*big.Int, error) { + return v.vrf.PROOFLENGTH(&bind.CallOpts{ + From: v.client.Addresses[0], + Context: ctx, + }) +} diff --git a/integration-tests/contracts/ethereum_vrfv2_contracts.go b/integration-tests/contracts/ethereum_vrfv2_contracts.go index fc7a5a7a138..ed99fb91109 100644 --- a/integration-tests/contracts/ethereum_vrfv2_contracts.go +++ b/integration-tests/contracts/ethereum_vrfv2_contracts.go @@ -14,6 +14,8 @@ import ( "github.com/rs/zerolog/log" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink/integration-tests/wrappers" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_test_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_mock_ethlink_aggregator" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_owner" @@ -97,7 +99,7 @@ func (e *EthereumContractDeployer) DeployVRFCoordinatorV2(linkAddr string, bhsAd auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return vrf_coordinator_v2.DeployVRFCoordinatorV2(auth, backend, common.HexToAddress(linkAddr), common.HexToAddress(bhsAddr), common.HexToAddress(linkEthFeedAddr)) + return vrf_coordinator_v2.DeployVRFCoordinatorV2(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(linkAddr), common.HexToAddress(bhsAddr), common.HexToAddress(linkEthFeedAddr)) }) if err != nil { return nil, err @@ -114,7 +116,7 @@ func (e *EthereumContractDeployer) DeployVRFOwner(coordinatorAddr string) (VRFOw auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return vrf_owner.DeployVRFOwner(auth, backend, common.HexToAddress(coordinatorAddr)) + return vrf_owner.DeployVRFOwner(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(coordinatorAddr)) }) if err != nil { return nil, err @@ -131,7 +133,7 @@ func (e *EthereumContractDeployer) DeployVRFCoordinatorTestV2(linkAddr string, b auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return vrf_coordinator_test_v2.DeployVRFCoordinatorTestV2(auth, backend, common.HexToAddress(linkAddr), common.HexToAddress(bhsAddr), common.HexToAddress(linkEthFeedAddr)) + return vrf_coordinator_test_v2.DeployVRFCoordinatorTestV2(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(linkAddr), common.HexToAddress(bhsAddr), common.HexToAddress(linkEthFeedAddr)) }) if err != nil { return nil, err @@ -184,7 +186,7 @@ func (e *EthereumContractDeployer) DeployVRFv2LoadTestConsumer(coordinatorAddr s auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return vrf_load_test_with_metrics.DeployVRFV2LoadTestWithMetrics(auth, backend, common.HexToAddress(coordinatorAddr)) + return vrf_load_test_with_metrics.DeployVRFV2LoadTestWithMetrics(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(coordinatorAddr)) }) if err != nil { return nil, err @@ -201,7 +203,7 @@ func (e *EthereumContractDeployer) DeployVRFV2Wrapper(linkAddr string, linkEthFe auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return vrfv2_wrapper.DeployVRFV2Wrapper(auth, backend, common.HexToAddress(linkAddr), common.HexToAddress(linkEthFeedAddr), common.HexToAddress(coordinatorAddr)) + return vrfv2_wrapper.DeployVRFV2Wrapper(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(linkAddr), common.HexToAddress(linkEthFeedAddr), common.HexToAddress(coordinatorAddr)) }) if err != nil { return nil, err @@ -218,7 +220,7 @@ func (e *EthereumContractDeployer) DeployVRFV2WrapperLoadTestConsumer(linkAddr s auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return vrfv2_wrapper_load_test_consumer.DeployVRFV2WrapperLoadTestConsumer(auth, backend, common.HexToAddress(linkAddr), common.HexToAddress(vrfV2WrapperAddr)) + return vrfv2_wrapper_load_test_consumer.DeployVRFV2WrapperLoadTestConsumer(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(linkAddr), common.HexToAddress(vrfV2WrapperAddr)) }) if err != nil { return nil, err @@ -442,6 +444,18 @@ func (v *EthereumVRFCoordinatorV2) OwnerCancelSubscription(subID uint64) (*types return tx, v.client.ProcessTransaction(tx) } +func (v *EthereumVRFCoordinatorV2) ParseSubscriptionCanceled(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled, error) { + return v.coordinator.ParseSubscriptionCanceled(log) +} + +func (v *EthereumVRFCoordinatorV2) ParseRandomWordsRequested(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) { + return v.coordinator.ParseRandomWordsRequested(log) +} + +func (v *EthereumVRFCoordinatorV2) ParseLog(log types.Log) (generated.AbigenLog, error) { + return v.coordinator.ParseLog(log) +} + // CancelSubscription cancels subscription by Sub owner, // return funds to specified address, // checks if pending requests for a sub exist @@ -499,8 +513,8 @@ func (v *EthereumVRFCoordinatorV2) WaitForRandomWordsFulfilledEvent(requestID [] } func (v *EthereumVRFCoordinatorV2) WaitForRandomWordsRequestedEvent(keyHash [][32]byte, subID []uint64, sender []common.Address, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) { - randomWordsFulfilledEventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested) - subscription, err := v.coordinator.WatchRandomWordsRequested(nil, randomWordsFulfilledEventsChannel, keyHash, subID, sender) + eventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested) + subscription, err := v.coordinator.WatchRandomWordsRequested(nil, eventsChannel, keyHash, subID, sender) if err != nil { return nil, err } @@ -512,8 +526,8 @@ func (v *EthereumVRFCoordinatorV2) WaitForRandomWordsRequestedEvent(keyHash [][3 return nil, err case <-time.After(timeout): return nil, fmt.Errorf("timeout waiting for RandomWordsRequested event") - case randomWordsFulfilledEvent := <-randomWordsFulfilledEventsChannel: - return randomWordsFulfilledEvent, nil + case event := <-eventsChannel: + return event, nil } } } @@ -780,23 +794,36 @@ func (v *EthereumVRFv2LoadTestConsumer) Address() string { } func (v *EthereumVRFv2LoadTestConsumer) RequestRandomness( + coordinator VRFCoordinatorV2, keyHash [32]byte, subID uint64, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, requestCount uint16, -) (*types.Transaction, error) { +) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { return nil, err } - tx, err := v.consumer.RequestRandomWords(opts, subID, requestConfirmations, keyHash, callbackGasLimit, numWords, requestCount) if err != nil { - return nil, err + return nil, fmt.Errorf("RequestRandomWords failed, err: %w", err) } - return tx, v.client.ProcessTransaction(tx) + err = v.client.ProcessTransaction(tx) + if err != nil { + return nil, fmt.Errorf("ProcessTransaction failed, err: %w", err) + } + err = v.client.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("WaitForEvents failed, err: %w", err) + } + receipt, err := v.client.GetTxReceipt(tx.Hash()) + if err != nil { + return nil, fmt.Errorf("GetTxReceipt failed, err: %w", err) + } + randomWordsRequestedEvent, err := parseRequestRandomnessLogs(coordinator, receipt.Logs) + return randomWordsRequestedEvent, err } func (v *EthereumVRFv2LoadTestConsumer) RequestRandomWordsWithForceFulfill( @@ -908,14 +935,16 @@ func (v *EthereumVRFv2LoadTestConsumer) GetLoadTestMetrics(ctx context.Context) } return &VRFLoadTestMetrics{ - requestCount, - fulfilmentCount, - averageFulfillmentInMillions, - slowestFulfillment, - fastestFulfillment, - nil, - nil, - nil, + RequestCount: requestCount, + FulfilmentCount: fulfilmentCount, + AverageFulfillmentInMillions: averageFulfillmentInMillions, + SlowestFulfillment: slowestFulfillment, + FastestFulfillment: fastestFulfillment, + P90FulfillmentBlockTime: 0.0, + P95FulfillmentBlockTime: 0.0, + AverageResponseTimeInSecondsMillions: nil, + SlowestResponseTimeInSeconds: nil, + FastestResponseTimeInSeconds: nil, }, nil } @@ -961,7 +990,7 @@ func (v *EthereumVRFV2WrapperLoadTestConsumer) Fund(ethAmount *big.Float) error return v.client.Fund(v.address.Hex(), ethAmount, gasEstimates) } -func (v *EthereumVRFV2WrapperLoadTestConsumer) RequestRandomness(requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, requestCount uint16) (*types.Transaction, error) { +func (v *EthereumVRFV2WrapperLoadTestConsumer) RequestRandomness(coordinator VRFCoordinatorV2, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, requestCount uint16) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { return nil, err @@ -970,7 +999,23 @@ func (v *EthereumVRFV2WrapperLoadTestConsumer) RequestRandomness(requestConfirma if err != nil { return nil, err } - return tx, v.client.ProcessTransaction(tx) + err = v.client.ProcessTransaction(tx) + if err != nil { + return nil, err + } + err = v.client.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("WaitForEvents failed, err: %w", err) + } + receipt, err := v.client.GetTxReceipt(tx.Hash()) + if err != nil { + return nil, fmt.Errorf("GetTxReceipt failed, err: %w", err) + } + randomWordsRequestedEvent, err := parseRequestRandomnessLogs(coordinator, receipt.Logs) + if err != nil { + return nil, err + } + return randomWordsRequestedEvent, err } func (v *EthereumVRFV2WrapperLoadTestConsumer) GetRequestStatus(ctx context.Context, requestID *big.Int) (vrfv2_wrapper_load_test_consumer.GetRequestStatus, error) { @@ -1034,14 +1079,16 @@ func (v *EthereumVRFV2WrapperLoadTestConsumer) GetLoadTestMetrics(ctx context.Co } return &VRFLoadTestMetrics{ - requestCount, - fulfilmentCount, - averageFulfillmentInMillions, - slowestFulfillment, - fastestFulfillment, - nil, - nil, - nil, + RequestCount: requestCount, + FulfilmentCount: fulfilmentCount, + AverageFulfillmentInMillions: averageFulfillmentInMillions, + SlowestFulfillment: slowestFulfillment, + FastestFulfillment: fastestFulfillment, + P90FulfillmentBlockTime: 0.0, + P95FulfillmentBlockTime: 0.0, + AverageResponseTimeInSecondsMillions: nil, + SlowestResponseTimeInSeconds: nil, + FastestResponseTimeInSeconds: nil, }, nil } @@ -1096,6 +1143,21 @@ func (v *EthereumVRFOwner) WaitForRandomWordsForcedEvent(requestIDs []*big.Int, } } +func (v *EthereumVRFOwner) OwnerCancelSubscription(subID uint64) (*types.Transaction, error) { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return nil, err + } + tx, err := v.vrfOwner.OwnerCancelSubscription( + opts, + subID, + ) + if err != nil { + return nil, err + } + return tx, v.client.ProcessTransaction(tx) +} + func (v *EthereumVRFCoordinatorTestV2) Address() string { return v.address.Hex() } @@ -1137,3 +1199,19 @@ func (v *EthereumVRFMockETHLINKFeed) SetBlockTimestampDeduction(blockTimestampDe } return v.client.ProcessTransaction(tx) } + +func parseRequestRandomnessLogs(coordinator VRFCoordinatorV2, logs []*types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) { + var randomWordsRequestedEvent *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested + var err error + for _, eventLog := range logs { + for _, topic := range eventLog.Topics { + if topic.Cmp(vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested{}.Topic()) == 0 { + randomWordsRequestedEvent, err = coordinator.ParseRandomWordsRequested(*eventLog) + if err != nil { + return nil, fmt.Errorf("parse RandomWordsRequested log failed, err: %w", err) + } + } + } + } + return randomWordsRequestedEvent, nil +} diff --git a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go index 64afb4c466d..ddf0231742c 100644 --- a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go +++ b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go @@ -10,8 +10,10 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/montanaflynn/stats" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink/integration-tests/wrappers" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" @@ -56,13 +58,14 @@ func (v *EthereumVRFV2PlusWrapper) Address() string { func (v *EthereumVRFV2PlusWrapper) SetConfig(wrapperGasOverhead uint32, coordinatorGasOverhead uint32, - wrapperPremiumPercentage uint8, + wrapperNativePremiumPercentage uint8, + wrapperLinkPremiumPercentage uint8, keyHash [32]byte, maxNumWords uint8, stalenessSeconds uint32, fallbackWeiPerUnitLink *big.Int, - fulfillmentFlatFeeLinkPPM uint32, fulfillmentFlatFeeNativePPM uint32, + fulfillmentFlatFeeLinkDiscountPPM uint32, ) error { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { @@ -72,13 +75,14 @@ func (v *EthereumVRFV2PlusWrapper) SetConfig(wrapperGasOverhead uint32, opts, wrapperGasOverhead, coordinatorGasOverhead, - wrapperPremiumPercentage, + wrapperNativePremiumPercentage, + wrapperLinkPremiumPercentage, keyHash, maxNumWords, stalenessSeconds, fallbackWeiPerUnitLink, - fulfillmentFlatFeeLinkPPM, fulfillmentFlatFeeNativePPM, + fulfillmentFlatFeeLinkDiscountPPM, ) if err != nil { return err @@ -93,18 +97,6 @@ func (v *EthereumVRFV2PlusWrapper) GetSubID(ctx context.Context) (*big.Int, erro }) } -func (v *EthereumVRFV2PlusWrapper) Migrate(newCoordinator common.Address) error { - opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) - if err != nil { - return err - } - tx, err := v.wrapper.Migrate(opts, newCoordinator) - if err != nil { - return err - } - return v.client.ProcessTransaction(tx) -} - func (v *EthereumVRFV2PlusWrapper) Coordinator(ctx context.Context) (common.Address, error) { opts := &bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), @@ -119,7 +111,7 @@ func (e *EthereumContractDeployer) DeployVRFCoordinatorV2_5(bhsAddr string) (VRF auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return vrf_coordinator_v2_5.DeployVRFCoordinatorV25(auth, backend, common.HexToAddress(bhsAddr)) + return vrf_coordinator_v2_5.DeployVRFCoordinatorV25(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(bhsAddr)) }) if err != nil { return nil, err @@ -607,7 +599,6 @@ func (v *EthereumVRFv2PlusLoadTestConsumer) GetLoadTestMetrics(ctx context.Conte if err != nil { return nil, err } - averageResponseTimeInSeconds, err := v.consumer.SAverageResponseTimeInSecondsMillions(&bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), Context: ctx, @@ -619,7 +610,6 @@ func (v *EthereumVRFv2PlusLoadTestConsumer) GetLoadTestMetrics(ctx context.Conte From: common.HexToAddress(v.client.GetDefaultWallet().Address()), Context: ctx, }) - if err != nil { return nil, err } @@ -630,13 +620,46 @@ func (v *EthereumVRFv2PlusLoadTestConsumer) GetLoadTestMetrics(ctx context.Conte if err != nil { return nil, err } - + var responseTimesInBlocks []uint32 + for { + currentResponseTimesInBlocks, err := v.consumer.GetRequestBlockTimes(&bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + }, big.NewInt(int64(len(responseTimesInBlocks))), big.NewInt(1000)) + if err != nil { + return nil, err + } + if len(currentResponseTimesInBlocks) == 0 { + break + } + responseTimesInBlocks = append(responseTimesInBlocks, currentResponseTimesInBlocks...) + } + var p90FulfillmentBlockTime, p95FulfillmentBlockTime float64 + if len(responseTimesInBlocks) == 0 { + p90FulfillmentBlockTime = 0 + p95FulfillmentBlockTime = 0 + } else { + responseTimesInBlocksFloat64 := make([]float64, len(responseTimesInBlocks)) + for i, value := range responseTimesInBlocks { + responseTimesInBlocksFloat64[i] = float64(value) + } + p90FulfillmentBlockTime, err = stats.Percentile(responseTimesInBlocksFloat64, 90) + if err != nil { + return nil, err + } + p95FulfillmentBlockTime, err = stats.Percentile(responseTimesInBlocksFloat64, 95) + if err != nil { + return nil, err + } + } return &VRFLoadTestMetrics{ RequestCount: requestCount, FulfilmentCount: fulfilmentCount, AverageFulfillmentInMillions: averageFulfillmentInMillions, SlowestFulfillment: slowestFulfillment, FastestFulfillment: fastestFulfillment, + P90FulfillmentBlockTime: p90FulfillmentBlockTime, + P95FulfillmentBlockTime: p95FulfillmentBlockTime, AverageResponseTimeInSecondsMillions: averageResponseTimeInSeconds, SlowestResponseTimeInSeconds: slowestResponseTimeInSeconds, FastestResponseTimeInSeconds: fastestResponseTimeInSeconds, @@ -935,7 +958,7 @@ func (e *EthereumContractDeployer) DeployVRFv2PlusLoadTestConsumer(coordinatorAd auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return vrf_v2plus_load_test_with_metrics.DeployVRFV2PlusLoadTestWithMetrics(auth, backend, common.HexToAddress(coordinatorAddr)) + return vrf_v2plus_load_test_with_metrics.DeployVRFV2PlusLoadTestWithMetrics(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(coordinatorAddr)) }) if err != nil { return nil, err @@ -947,12 +970,12 @@ func (e *EthereumContractDeployer) DeployVRFv2PlusLoadTestConsumer(coordinatorAd }, err } -func (e *EthereumContractDeployer) DeployVRFV2PlusWrapper(linkAddr string, linkEthFeedAddr string, coordinatorAddr string) (VRFV2PlusWrapper, error) { +func (e *EthereumContractDeployer) DeployVRFV2PlusWrapper(linkAddr string, linkEthFeedAddr string, coordinatorAddr string, subId *big.Int) (VRFV2PlusWrapper, error) { address, _, instance, err := e.client.DeployContract("VRFV2PlusWrapper", func( auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return vrfv2plus_wrapper.DeployVRFV2PlusWrapper(auth, backend, common.HexToAddress(linkAddr), common.HexToAddress(linkEthFeedAddr), common.HexToAddress(coordinatorAddr)) + return vrfv2plus_wrapper.DeployVRFV2PlusWrapper(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(linkAddr), common.HexToAddress(linkEthFeedAddr), common.HexToAddress(coordinatorAddr), subId) }) if err != nil { return nil, err @@ -964,12 +987,12 @@ func (e *EthereumContractDeployer) DeployVRFV2PlusWrapper(linkAddr string, linkE }, err } -func (e *EthereumContractDeployer) DeployVRFV2PlusWrapperLoadTestConsumer(linkAddr string, vrfV2PlusWrapperAddr string) (VRFv2PlusWrapperLoadTestConsumer, error) { +func (e *EthereumContractDeployer) DeployVRFV2PlusWrapperLoadTestConsumer(vrfV2PlusWrapperAddr string) (VRFv2PlusWrapperLoadTestConsumer, error) { address, _, instance, err := e.client.DeployContract("VRFV2PlusWrapperLoadTestConsumer", func( auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return vrfv2plus_wrapper_load_test_consumer.DeployVRFV2PlusWrapperLoadTestConsumer(auth, backend, common.HexToAddress(linkAddr), common.HexToAddress(vrfV2PlusWrapperAddr)) + return vrfv2plus_wrapper_load_test_consumer.DeployVRFV2PlusWrapperLoadTestConsumer(auth, wrappers.MustNewWrappedContractBackend(e.client, nil), common.HexToAddress(vrfV2PlusWrapperAddr)) }) if err != nil { return nil, err diff --git a/integration-tests/docker/cmd/test_env.go b/integration-tests/docker/cmd/test_env.go index 5fe2001350e..bbe86128330 100644 --- a/integration-tests/docker/cmd/test_env.go +++ b/integration-tests/docker/cmd/test_env.go @@ -12,6 +12,8 @@ import ( "github.com/spf13/cobra" "github.com/testcontainers/testcontainers-go" + ctf_test_env "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" + "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" ) @@ -35,8 +37,18 @@ func main() { log.Logger = logging.GetLogger(nil, "CORE_DOCKER_ENV_LOG_LEVEL") log.Info().Msg("Starting CL cluster test environment..") - _, err := test_env.NewCLTestEnvBuilder(). - WithGeth(). + ethBuilder := ctf_test_env.NewEthereumNetworkBuilder() + network, err := ethBuilder. + WithEthereumVersion(ctf_test_env.EthereumVersion_Eth1). + WithExecutionLayer(ctf_test_env.ExecutionLayer_Geth). + Build() + + if err != nil { + return err + } + + _, err = test_env.NewCLTestEnvBuilder(). + WithPrivateEthereumNetwork(network). WithMockAdapter(). WithCLNodes(6). Build() diff --git a/integration-tests/docker/test_env/cl_node.go b/integration-tests/docker/test_env/cl_node.go index a575768d62f..09da97b40f3 100644 --- a/integration-tests/docker/test_env/cl_node.go +++ b/integration-tests/docker/test_env/cl_node.go @@ -43,6 +43,11 @@ var ( ErrStartCLNodeContainer = "failed to start CL node container" ) +const ( + RestartContainer = true + StartNewContainer = false +) + type ClNode struct { test_env.EnvComponent API *client.ChainlinkClient `json:"-"` @@ -158,7 +163,7 @@ func (n *ClNode) Restart(cfg *chainlink.Config) error { return err } n.NodeConfig = cfg - return n.StartContainer() + return n.RestartContainer() } // UpgradeVersion restarts the cl node with new image and version @@ -275,6 +280,10 @@ func (n *ClNode) Fund(evmClient blockchain.EVMClient, amount *big.Float) error { if err != nil { return err } + n.l.Debug(). + Str("ChainId", evmClient.GetChainID().String()). + Str("Address", toAddress). + Msg("Funding Chainlink Node") toAddr := common.HexToAddress(toAddress) gasEstimates, err := evmClient.EstimateGas(ethereum.CallMsg{ To: &toAddr, @@ -285,8 +294,13 @@ func (n *ClNode) Fund(evmClient blockchain.EVMClient, amount *big.Float) error { return evmClient.Fund(toAddress, amount, gasEstimates) } -func (n *ClNode) StartContainer() error { - err := n.PostgresDb.StartContainer() +func (n *ClNode) containerStartOrRestart(restartDb bool) error { + var err error + if restartDb { + err = n.PostgresDb.RestartContainer() + } else { + err = n.PostgresDb.StartContainer() + } if err != nil { return err } @@ -359,6 +373,14 @@ func (n *ClNode) StartContainer() error { return nil } +func (n *ClNode) RestartContainer() error { + return n.containerStartOrRestart(RestartContainer) +} + +func (n *ClNode) StartContainer() error { + return n.containerStartOrRestart(StartNewContainer) +} + func (n *ClNode) ExecGetVersion() (string, error) { cmd := []string{"chainlink", "--version"} _, output, err := n.Container.Exec(context.Background(), cmd) diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index e91a3bba6ad..cbcb943e695 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "math/big" - "runtime/debug" "testing" "github.com/ethereum/go-ethereum/accounts/keystore" @@ -37,18 +36,18 @@ type CLClusterTestEnv struct { LogStream *logstream.LogStream /* components */ - ClCluster *ClCluster - PrivateChain []test_env.PrivateChain // for tests using non-dev networks -- unify it with new approach - MockAdapter *test_env.Killgrave - EVMClient blockchain.EVMClient - SethClient *seth.Client - ContractDeployer contracts.ContractDeployer - ContractLoader contracts.ContractLoader - RpcProvider test_env.RpcProvider - PrivateEthereumConfig *test_env.EthereumNetwork // new approach to private chains, supporting eth1 and eth2 - l zerolog.Logger - t *testing.T - isSimulatedNetwork bool + ClCluster *ClCluster + MockAdapter *test_env.Killgrave + evmClients map[int64]blockchain.EVMClient + sethClients map[int64]*seth.Client + ContractDeployer contracts.ContractDeployer + ContractLoader contracts.ContractLoader + PrivateEthereumConfigs []*test_env.EthereumNetwork // new approach to private chains, supporting eth1 and eth2 + EVMNetworks []*blockchain.EVMNetwork + rpcProviders map[int64]*test_env.RpcProvider + l zerolog.Logger + t *testing.T + isSimulatedNetwork bool } func NewTestEnv() (*CLClusterTestEnv, error) { @@ -84,51 +83,11 @@ func (te *CLClusterTestEnv) WithTestInstance(t *testing.T) *CLClusterTestEnv { } func (te *CLClusterTestEnv) ParallelTransactions(enabled bool) { - if te.EVMClient != nil { - te.EVMClient.ParallelTransactions(enabled) + for _, evmClient := range te.evmClients { + evmClient.ParallelTransactions(enabled) } } -func (te *CLClusterTestEnv) WithPrivateChain(evmNetworks []blockchain.EVMNetwork) *CLClusterTestEnv { - var chains []test_env.PrivateChain - for _, evmNetwork := range evmNetworks { - n := evmNetwork - pgc := test_env.NewPrivateGethChain(&n, []string{te.DockerNetwork.Name}) - if te.t != nil { - pgc.GetPrimaryNode().WithTestInstance(te.t) - } - chains = append(chains, pgc) - var privateChain test_env.PrivateChain - switch n.SimulationType { - case "besu": - privateChain = test_env.NewPrivateBesuChain(&n, []string{te.DockerNetwork.Name}) - default: - privateChain = test_env.NewPrivateGethChain(&n, []string{te.DockerNetwork.Name}) - } - chains = append(chains, privateChain) - } - te.PrivateChain = chains - return te -} - -func (te *CLClusterTestEnv) StartPrivateChain() error { - for _, chain := range te.PrivateChain { - primaryNode := chain.GetPrimaryNode() - if primaryNode == nil { - return fmt.Errorf("primary node is nil in PrivateChain interface, stack: %s", string(debug.Stack())) - } - err := primaryNode.Start() - if err != nil { - return err - } - err = primaryNode.ConnectToClient() - if err != nil { - return err - } - } - return nil -} - func (te *CLClusterTestEnv) StartEthereumNetwork(cfg *test_env.EthereumNetwork) (blockchain.EVMNetwork, test_env.RpcProvider, error) { // if environment is being restored from a previous state, use the existing config // this might fail terribly if temporary folders with chain data on the host machine were removed @@ -142,6 +101,13 @@ func (te *CLClusterTestEnv) StartEthereumNetwork(cfg *test_env.EthereumNetwork) } cfg = &c } + + te.l.Info(). + Str("Execution Layer", string(*cfg.ExecutionLayer)). + Str("Ethereum Version", string(*cfg.EthereumVersion)). + Str("Custom Docker Images", fmt.Sprintf("%v", cfg.CustomDockerImages)). + Msg("Starting Ethereum network") + n, rpc, err := cfg.Start() if err != nil { @@ -192,12 +158,37 @@ func (te *CLClusterTestEnv) StartClCluster(nodeConfig *chainlink.Config, count i // FundChainlinkNodes will fund all the provided Chainlink nodes with a set amount of native currency func (te *CLClusterTestEnv) FundChainlinkNodes(amount *big.Float) error { - for _, cl := range te.ClCluster.Nodes { - if err := cl.Fund(te.EVMClient, amount); err != nil { - return fmt.Errorf("%s, err: %w", ErrFundCLNode, err) + if len(te.sethClients) == 0 && len(te.evmClients) == 0 { + return fmt.Errorf("both EVMClients and SethClient are nil, unable to fund chainlink nodes") + } + + if len(te.sethClients) > 0 && len(te.evmClients) > 0 { + return fmt.Errorf("both EVMClients and SethClient are set, you can't use both at the same time") + } + + if len(te.sethClients) > 0 { + for _, sethClient := range te.sethClients { + if err := actions_seth.FundChainlinkNodesFromRootAddress(te.l, sethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(te.ClCluster.NodeAPIs()), amount); err != nil { + return err + } + } + } + + if len(te.evmClients) > 0 { + for _, evmClient := range te.evmClients { + for _, cl := range te.ClCluster.Nodes { + if err := cl.Fund(evmClient, amount); err != nil { + return fmt.Errorf("%s, err: %w", ErrFundCLNode, err) + } + } + err := evmClient.WaitForEvents() + if err != nil { + return err + } } } - return te.EVMClient.WaitForEvents() + + return nil } func (te *CLClusterTestEnv) Terminate() error { @@ -225,8 +216,8 @@ func (te *CLClusterTestEnv) Cleanup() error { te.logWhetherAllContainersAreRunning() - if te.EVMClient == nil && te.SethClient == nil { - return fmt.Errorf("both EVMClient and SethClient are nil, unable to return funds from chainlink nodes during cleanup") + if len(te.evmClients) == 0 && len(te.sethClients) == 0 { + return fmt.Errorf("both EVMClients and SethClient are nil, unable to return funds from chainlink nodes during cleanup") } else if te.isSimulatedNetwork { te.l.Info(). Msg("Network is a simulated network. Skipping fund return.") @@ -237,13 +228,13 @@ func (te *CLClusterTestEnv) Cleanup() error { } // close EVMClient connections - if te.EVMClient != nil { - err := te.EVMClient.Close() + for _, evmClient := range te.evmClients { + err := evmClient.Close() return err } - if te.SethClient != nil { - te.SethClient.Client.Close() + for _, sethClient := range te.sethClients { + sethClient.Client.Close() } return nil @@ -270,33 +261,43 @@ func (te *CLClusterTestEnv) logWhetherAllContainersAreRunning() { func (te *CLClusterTestEnv) returnFunds() error { te.l.Info().Msg("Attempting to return Chainlink node funds to default network wallets") - for _, chainlinkNode := range te.ClCluster.Nodes { - fundedKeys, err := chainlinkNode.API.ExportEVMKeysForChain(te.EVMClient.GetChainID().String()) - if err != nil { - return err - } - for _, key := range fundedKeys { - keyToDecrypt, err := json.Marshal(key) - if err != nil { - return err - } - // This can take up a good bit of RAM and time. When running on the remote-test-runner, this can lead to OOM - // issues. So we avoid running in parallel; slower, but safer. - decryptedKey, err := keystore.DecryptKey(keyToDecrypt, client.ChainlinkKeyPassword) + + if len(te.evmClients) == 0 && len(te.sethClients) == 0 { + return fmt.Errorf("both EVMClients and SethClient are nil, unable to return funds from chainlink nodes") + } + + for _, evmClient := range te.evmClients { + for _, chainlinkNode := range te.ClCluster.Nodes { + fundedKeys, err := chainlinkNode.API.ExportEVMKeysForChain(te.evmClients[0].GetChainID().String()) if err != nil { return err } - if te.EVMClient != nil { - if err = te.EVMClient.ReturnFunds(decryptedKey.PrivateKey); err != nil { - // If we fail to return funds from one, go on to try the others anyway - te.l.Error().Err(err).Str("Node", chainlinkNode.ContainerName).Msg("Error returning funds from node") + for _, key := range fundedKeys { + keyToDecrypt, err := json.Marshal(key) + if err != nil { + return err + } + // This can take up a good bit of RAM and time. When running on the remote-test-runner, this can lead to OOM + // issues. So we avoid running in parallel; slower, but safer. + decryptedKey, err := keystore.DecryptKey(keyToDecrypt, client.ChainlinkKeyPassword) + if err != nil { + return err + } + if te.evmClients[0] != nil { + te.l.Debug(). + Str("ChainId", evmClient.GetChainID().String()). + Msg("Returning funds from chainlink node") + if err = evmClient.ReturnFunds(decryptedKey.PrivateKey); err != nil { + // If we fail to return funds from one, go on to try the others anyway + te.l.Error().Err(err).Str("Node", chainlinkNode.ContainerName).Msg("Error returning funds from node") + } } } } } - if te.SethClient != nil { - if err := actions_seth.ReturnFunds(te.l, te.SethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(te.ClCluster.NodeAPIs())); err != nil { + for _, sethClient := range te.sethClients { + if err := actions_seth.ReturnFunds(te.l, sethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(te.ClCluster.NodeAPIs())); err != nil { te.l.Error().Err(err).Msg("Error returning funds from node") } } @@ -304,3 +305,27 @@ func (te *CLClusterTestEnv) returnFunds() error { te.l.Info().Msg("Returned funds from Chainlink nodes") return nil } + +func (te *CLClusterTestEnv) GetEVMClient(chainId int64) (blockchain.EVMClient, error) { + if evmClient, ok := te.evmClients[chainId]; ok { + return evmClient, nil + } + + return nil, fmt.Errorf("no EVMClient available for chain ID %d", chainId) +} + +func (te *CLClusterTestEnv) GetSethClient(chainId int64) (*seth.Client, error) { + if sethClient, ok := te.sethClients[chainId]; ok { + return sethClient, nil + } + + return nil, fmt.Errorf("no Seth client available for chain ID %d", chainId) +} + +func (te *CLClusterTestEnv) GetRpcProvider(chainId int64) (*test_env.RpcProvider, error) { + if rpc, ok := te.rpcProviders[chainId]; ok { + return rpc, nil + } + + return nil, fmt.Errorf("no RPC provider available for chain ID %d", chainId) +} diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index 7c50bd1c725..8b1f22137f7 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -5,7 +5,6 @@ import ( "fmt" "math/big" "os" - "runtime/debug" "testing" "github.com/rs/zerolog" @@ -38,28 +37,27 @@ const ( ) type CLTestEnvBuilder struct { - hasLogStream bool - hasKillgrave bool - hasForwarders bool - hasSeth bool - hasEVMClient bool - clNodeConfig *chainlink.Config - secretsConfig string - nonDevGethNetworks []blockchain.EVMNetwork - clNodesCount int - clNodesOpts []func(*ClNode) - customNodeCsaKeys []string - defaultNodeCsaKeys []string - l zerolog.Logger - t *testing.T - te *CLClusterTestEnv - isNonEVM bool - cleanUpType CleanUpType - cleanUpCustomFn func() - chainOptionsFn []ChainOption - evmClientNetworkOption []EVMClientNetworkOption - privateEthereumNetwork *test_env.EthereumNetwork - testConfig tc.GlobalTestConfig + hasLogStream bool + hasKillgrave bool + hasForwarders bool + hasSeth bool + hasEVMClient bool + clNodeConfig *chainlink.Config + secretsConfig string + clNodesCount int + clNodesOpts []func(*ClNode) + customNodeCsaKeys []string + defaultNodeCsaKeys []string + l zerolog.Logger + t *testing.T + te *CLClusterTestEnv + isNonEVM bool + cleanUpType CleanUpType + cleanUpCustomFn func() + chainOptionsFn []ChainOption + evmClientNetworkOption []EVMClientNetworkOption + privateEthereumNetworks []*test_env.EthereumNetwork + testConfig tc.GlobalTestConfig /* funding */ ETHFunds *big.Float @@ -142,25 +140,6 @@ func (b *CLTestEnvBuilder) WithFunding(eth *big.Float) *CLTestEnvBuilder { return b } -// deprecated -// left only for backward compatibility -func (b *CLTestEnvBuilder) WithGeth() *CLTestEnvBuilder { - ethBuilder := test_env.NewEthereumNetworkBuilder() - cfg, err := ethBuilder. - WithConsensusType(test_env.ConsensusType_PoW). - WithExecutionLayer(test_env.ExecutionLayer_Geth). - WithTest(b.t). - Build() - - if err != nil { - panic(err) - } - - b.privateEthereumNetwork = &cfg - - return b -} - func (b *CLTestEnvBuilder) WithSeth() *CLTestEnvBuilder { b.hasSeth = true b.hasEVMClient = false @@ -168,12 +147,12 @@ func (b *CLTestEnvBuilder) WithSeth() *CLTestEnvBuilder { } func (b *CLTestEnvBuilder) WithPrivateEthereumNetwork(en test_env.EthereumNetwork) *CLTestEnvBuilder { - b.privateEthereumNetwork = &en + b.privateEthereumNetworks = append(b.privateEthereumNetworks, &en) return b } -func (b *CLTestEnvBuilder) WithPrivateGethChains(evmNetworks []blockchain.EVMNetwork) *CLTestEnvBuilder { - b.nonDevGethNetworks = evmNetworks +func (b *CLTestEnvBuilder) WithPrivateEthereumNetworks(ens []*test_env.EthereumNetwork) *CLTestEnvBuilder { + b.privateEthereumNetworks = ens return b } @@ -305,28 +284,61 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } }) - } - if b.nonDevGethNetworks != nil { - b.te.WithPrivateChain(b.nonDevGethNetworks) - err := b.te.StartPrivateChain() - if err != nil { - return b.te, err - } - var nonDevNetworks []blockchain.EVMNetwork - for i, n := range b.te.PrivateChain { - primaryNode := n.GetPrimaryNode() - if primaryNode == nil { - return b.te, fmt.Errorf("primary node is nil in PrivateChain interface, stack: %s", string(debug.Stack())) + // this is not the cleanest way to do this, but when we originally build ethereum networks, we don't have the logstream reference + // so we need to rebuild them here and pass logstream to them + for i := range b.privateEthereumNetworks { + builder := test_env.NewEthereumNetworkBuilder() + netWithLs, err := builder. + WithExistingConfig(*b.privateEthereumNetworks[i]). + WithLogStream(b.te.LogStream). + Build() + if err != nil { + return nil, err } - nonDevNetworks = append(nonDevNetworks, *n.GetNetworkConfig()) - nonDevNetworks[i].URLs = []string{primaryNode.GetInternalWsUrl()} - nonDevNetworks[i].HTTPURLs = []string{primaryNode.GetInternalHttpUrl()} - } - if nonDevNetworks == nil { - return nil, fmt.Errorf("cannot create nodes with custom config without nonDevNetworks") + b.privateEthereumNetworks[i] = &netWithLs } + } + + // in this case we will use the builder only to start chains, not the cluster, because currently we support only 1 network config per cluster + if len(b.privateEthereumNetworks) > 1 { + b.te.rpcProviders = make(map[int64]*test_env.RpcProvider) + b.te.EVMNetworks = make([]*blockchain.EVMNetwork, 0) + b.te.evmClients = make(map[int64]blockchain.EVMClient) + for _, en := range b.privateEthereumNetworks { + en.DockerNetworkNames = []string{b.te.DockerNetwork.Name} + networkConfig, rpcProvider, err := b.te.StartEthereumNetwork(en) + if err != nil { + return nil, err + } + + if b.hasEVMClient { + evmClient, err := blockchain.NewEVMClientFromNetwork(networkConfig, b.l) + if err != nil { + return nil, err + } + b.te.evmClients[networkConfig.ChainID] = evmClient + } + + if b.hasSeth { + readSethCfg := b.testConfig.GetSethConfig() + sethCfg := utils.MergeSethAndEvmNetworkConfigs(b.l, networkConfig, *readSethCfg) + err = utils.ValidateSethNetworkConfig(sethCfg.Network) + if err != nil { + return nil, err + } + seth, err := seth.NewClientWithConfig(&sethCfg) + if err != nil { + return nil, err + } + + b.te.sethClients[networkConfig.ChainID] = seth + } + + b.te.rpcProviders[networkConfig.ChainID] = &rpcProvider + b.te.EVMNetworks = append(b.te.EVMNetworks, &networkConfig) + } err = b.te.StartClCluster(b.clNodeConfig, b.clNodesCount, b.secretsConfig, b.testConfig, b.clNodesOpts...) if err != nil { return nil, err @@ -337,25 +349,41 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { return b.te, nil } + b.te.rpcProviders = make(map[int64]*test_env.RpcProvider) networkConfig := networks.MustGetSelectedNetworkConfig(b.testConfig.GetNetworkConfig())[0] - var rpcProvider test_env.RpcProvider - if b.privateEthereumNetwork != nil && networkConfig.Simulated { - // TODO here we should save the ethereum network config to te.Cfg, but it doesn't exist at this point - // in general it seems we have no methods for saving config to file and we only load it from file - // but I don't know how that config file is to be created or whether anyone ever done that - b.privateEthereumNetwork.DockerNetworkNames = []string{b.te.DockerNetwork.Name} - networkConfig, rpcProvider, err = b.te.StartEthereumNetwork(b.privateEthereumNetwork) - if err != nil { - return nil, err + // This has some hidden behavior so I'm not the biggest fan, but it matches expected behavior. + // That is, when we specify we want to run on a live network in our config, we will run on the live network and not bother with a private network. + // Even if we explicitly declare that we want to run on a private network in the test. + // Keeping this a Kludge for now as SETH transition should change all of this anyway. + if len(b.privateEthereumNetworks) == 1 { + if networkConfig.Simulated { + // TODO here we should save the ethereum network config to te.Cfg, but it doesn't exist at this point + // in general it seems we have no methods for saving config to file and we only load it from file + // but I don't know how that config file is to be created or whether anyone ever done that + var rpcProvider test_env.RpcProvider + b.privateEthereumNetworks[0].DockerNetworkNames = []string{b.te.DockerNetwork.Name} + networkConfig, rpcProvider, err = b.te.StartEthereumNetwork(b.privateEthereumNetworks[0]) + if err != nil { + return nil, err + } + b.te.rpcProviders[networkConfig.ChainID] = &rpcProvider + b.te.PrivateEthereumConfigs = b.privateEthereumNetworks + + b.te.isSimulatedNetwork = true + } else { // Only start and connect to a private network if we are using a private simulated network + b.te.l.Warn(). + Str("Network", networkConfig.Name). + Int64("Chain ID", networkConfig.ChainID). + Msg("Private network config provided, but we are running on a live network. Ignoring private network config.") + rpcProvider := test_env.NewRPCProvider(networkConfig.HTTPURLs, networkConfig.URLs, networkConfig.HTTPURLs, networkConfig.URLs) + b.te.rpcProviders[networkConfig.ChainID] = &rpcProvider + b.te.isSimulatedNetwork = false } - b.te.RpcProvider = rpcProvider - b.te.PrivateEthereumConfig = b.privateEthereumNetwork - b.te.isSimulatedNetwork = true } if !b.hasSeth && !b.hasEVMClient { - return nil, errors.New("you need to specify, which evm client to use: Seth or EMVClient") + return nil, errors.New("you need to specify, which evm client to use: Seth or EVMClient") } if b.hasSeth && b.hasEVMClient { @@ -374,7 +402,9 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { return nil, err } - b.te.EVMClient = bc + b.te.evmClients = make(map[int64]blockchain.EVMClient) + b.te.evmClients[networkConfig.ChainID] = bc + cd, err := contracts.NewContractDeployer(bc, b.l) if err != nil { return nil, err @@ -389,6 +419,7 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } if b.hasSeth { + b.te.sethClients = make(map[int64]*seth.Client) readSethCfg := b.testConfig.GetSethConfig() sethCfg := utils.MergeSethAndEvmNetworkConfigs(b.l, networkConfig, *readSethCfg) err = utils.ValidateSethNetworkConfig(sethCfg.Network) @@ -400,7 +431,7 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { return nil, err } - b.te.SethClient = seth + b.te.sethClients[networkConfig.ChainID] = seth } } @@ -421,6 +452,10 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { if !b.isNonEVM { var httpUrls []string var wsUrls []string + rpcProvider, ok := b.te.rpcProviders[networkConfig.ChainID] + if !ok { + return nil, fmt.Errorf("rpc provider for chain %d not found", networkConfig.ChainID) + } if networkConfig.Simulated { httpUrls = rpcProvider.PrivateHttpUrls() wsUrls = rpcProvider.PrivateWsUrsl() @@ -452,7 +487,7 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { b.defaultNodeCsaKeys = nodeCsaKeys } - if b.privateEthereumNetwork != nil && b.clNodesCount > 0 && b.ETHFunds != nil { + if len(b.privateEthereumNetworks) > 0 && b.clNodesCount > 0 && b.ETHFunds != nil { if b.hasEVMClient { b.te.ParallelTransactions(true) defer b.te.ParallelTransactions(false) @@ -461,15 +496,19 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } } if b.hasSeth { - if err := actions_seth.FundChainlinkNodesFromRootAddress(b.l, b.te.SethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(b.te.ClCluster.NodeAPIs()), b.ETHFunds); err != nil { - return nil, err + for _, sethClient := range b.te.sethClients { + if err := actions_seth.FundChainlinkNodesFromRootAddress(b.l, sethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(b.te.ClCluster.NodeAPIs()), b.ETHFunds); err != nil { + return nil, err + } } } } var enDesc string - if b.te.PrivateEthereumConfig != nil { - enDesc = b.te.PrivateEthereumConfig.Describe() + if len(b.te.PrivateEthereumConfigs) > 0 { + for _, en := range b.te.PrivateEthereumConfigs { + enDesc += en.Describe() + } } else { enDesc = "none" } diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 70b95162e79..2bc01df21f7 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -15,6 +15,7 @@ require ( github.com/jmoiron/sqlx v1.3.5 github.com/lib/pq v1.10.9 github.com/manifoldco/promptui v0.9.0 + github.com/montanaflynn/stats v0.7.1 github.com/onsi/gomega v1.30.0 github.com/pelletier/go-toml/v2 v2.1.1 github.com/pkg/errors v0.9.1 @@ -22,12 +23,12 @@ require ( github.com/scylladb/go-reflectx v1.0.1 github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 - github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240311111125-22812a072c35 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240314172156-049609b8e1f9 - github.com/smartcontractkit/chainlink-testing-framework v1.26.0 + github.com/smartcontractkit/chainlink-automation v1.0.2 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240404141006-77085a02ce25 + github.com/smartcontractkit/chainlink-testing-framework v1.28.1 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 - github.com/smartcontractkit/libocr v0.0.0-20240229181116-bfb2432a7a66 + github.com/smartcontractkit/libocr v0.0.0-20240326191951-2bbe9382d052 github.com/smartcontractkit/seth v0.1.2 github.com/smartcontractkit/wasp v0.4.5 github.com/spf13/cobra v1.8.0 @@ -81,6 +82,8 @@ require ( github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/Microsoft/hcsshim v0.11.4 // indirect + github.com/NethermindEth/juno v0.3.1 // indirect + github.com/NethermindEth/starknet.go v0.6.1-0.20231218140327-915109ab5bc1 // indirect github.com/VictoriaMetrics/fastcache v1.12.1 // indirect github.com/XSAM/otelsql v0.27.0 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect @@ -92,6 +95,7 @@ require ( github.com/aws/constructs-go/constructs/v10 v10.1.255 // indirect github.com/aws/jsii-runtime-go v1.75.0 // indirect github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect + github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect @@ -154,6 +158,7 @@ require ( github.com/docker/docker v25.0.2+incompatible // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect + github.com/dominikbraun/graph v0.23.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.5.0 // indirect github.com/edsrzf/mmap-go v1.1.0 // indirect @@ -187,7 +192,7 @@ require ( github.com/go-kit/log v0.2.1 // indirect github.com/go-ldap/ldap/v3 v3.4.6 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-openapi/analysis v0.21.4 // indirect @@ -214,7 +219,7 @@ require ( github.com/golang-jwt/jwt/v5 v5.2.0 // indirect github.com/golang/glog v1.1.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/btree v1.1.2 // indirect github.com/google/gnostic v0.6.9 // indirect @@ -248,7 +253,7 @@ require ( github.com/gtank/merlin v0.1.1 // indirect github.com/gtank/ristretto255 v0.1.2 // indirect github.com/hashicorp/consul/api v1.25.1 // indirect - github.com/hashicorp/consul/sdk v0.14.1 // indirect + github.com/hashicorp/consul/sdk v0.16.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-envparse v0.1.0 // indirect @@ -273,14 +278,15 @@ require ( github.com/huin/goupnp v1.3.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/invopop/jsonschema v0.12.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.14.1 // indirect + github.com/jackc/pgconn v1.14.3 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.2 // indirect + github.com/jackc/pgproto3/v2 v2.3.3 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgtype v1.14.0 // indirect - github.com/jackc/pgx/v4 v4.18.1 // indirect + github.com/jackc/pgx/v4 v4.18.2 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect @@ -324,7 +330,6 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect - github.com/montanaflynn/stats v0.7.1 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 // indirect github.com/mr-tron/base58 v1.2.0 // indirect @@ -373,13 +378,12 @@ require ( github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect github.com/smartcontractkit/chain-selectors v1.0.10 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 // indirect github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e // indirect - github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240213121419-1272736c2ac0 // indirect + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/wsrpc v0.7.2 // indirect @@ -412,6 +416,7 @@ require ( github.com/ugorji/go/codec v1.2.12 // indirect github.com/umbracle/fastrlp v0.0.0-20220527094140-59d5dd30e722 // indirect github.com/valyala/fastjson v1.4.1 // indirect + github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xlab/treeprint v1.1.0 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect @@ -428,12 +433,12 @@ require ( go.opentelemetry.io/collector/semconv v0.87.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect - go.opentelemetry.io/otel v1.21.0 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 // indirect - go.opentelemetry.io/otel/metric v1.21.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/otel/sdk v1.21.0 // indirect - go.opentelemetry.io/otel/trace v1.21.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.starlark.net v0.0.0-20220817180228-f738f5508c12 // indirect go.uber.org/atomic v1.11.0 // indirect @@ -442,13 +447,13 @@ require ( go.uber.org/ratelimit v0.3.0 // indirect go4.org/netipx v0.0.0-20230125063823-8449b0a6169f // indirect golang.org/x/arch v0.7.0 // indirect - golang.org/x/crypto v0.19.0 // indirect + golang.org/x/crypto v0.21.0 // indirect golang.org/x/exp v0.0.0-20240213143201-ec583247a57a // indirect golang.org/x/mod v0.15.0 // indirect golang.org/x/net v0.21.0 // indirect golang.org/x/oauth2 v0.17.0 // indirect - golang.org/x/sys v0.17.0 // indirect - golang.org/x/term v0.17.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/term v0.18.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.18.0 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect @@ -458,7 +463,7 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect google.golang.org/grpc v1.59.0 // indirect - google.golang.org/protobuf v1.32.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect @@ -482,7 +487,7 @@ require ( sigs.k8s.io/kustomize/api v0.12.1 // indirect sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) replace ( diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 9275fabd5a8..658a77c4f04 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -148,6 +148,10 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8= github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w= +github.com/NethermindEth/juno v0.3.1 h1:AW72LiAm9gqUeCVJWvepnZcTnpU4Vkl0KzPMxS+42FA= +github.com/NethermindEth/juno v0.3.1/go.mod h1:SGbTpgGaCsxhFsKOid7Ylnz//WZ8swtILk+NbHGsk/Q= +github.com/NethermindEth/starknet.go v0.6.1-0.20231218140327-915109ab5bc1 h1:9SBvy3eZut1X+wEyAFqfb7ADGj8IQw7ZnlkMwz0YOTY= +github.com/NethermindEth/starknet.go v0.6.1-0.20231218140327-915109ab5bc1/go.mod h1:V6qrbi1+fTDCftETIT1grBXIf+TvWP/4Aois1a9EF1E= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -215,6 +219,8 @@ github.com/aws/jsii-runtime-go v1.75.0/go.mod h1:TKCyrtM0pygEPo4rDZzbMSDNCDNTSYS github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df h1:GSoSVRLoBaFpOOds6QyY1L8AX7uoY+Ln3BHc22W40X0= github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df/go.mod h1:hiVxq5OP2bUGBRNS3Z/bt/reCLFNbdcST6gISi1fiOM= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -448,6 +454,8 @@ github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6 github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucVPgCo= +github.com/dominikbraun/graph v0.23.0/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= @@ -582,8 +590,8 @@ github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A= @@ -749,8 +757,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -896,8 +904,8 @@ github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBt github.com/hashicorp/consul/api v1.25.1 h1:CqrdhYzc8XZuPnhIYZWH45toM0LB9ZeYr/gvpLVI3PE= github.com/hashicorp/consul/api v1.25.1/go.mod h1:iiLVwR/htV7mas/sy0O+XSuEnrdBUUydemjxcUrAt4g= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.14.1 h1:ZiwE2bKb+zro68sWzZ1SgHF3kRMBZ94TwOCFRF4ylPs= -github.com/hashicorp/consul/sdk v0.14.1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg= +github.com/hashicorp/consul/sdk v0.16.0 h1:SE9m0W6DEfgIVCJX7xU+iv/hUl4m/nxqMTnCdMxDpJ8= +github.com/hashicorp/consul/sdk v0.16.0/go.mod h1:7pxqqhqoaPqnBnzXD1StKed62LqJeClzVsUEy85Zr0A= github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A= github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -1000,6 +1008,8 @@ github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPt github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI= +github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= github.com/ionos-cloud/sdk-go/v6 v6.1.8 h1:493wE/BkZxJf7x79UCE0cYGPZoqQcPiEBALvt7uVGY0= github.com/ionos-cloud/sdk-go/v6 v6.1.8/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= @@ -1017,9 +1027,8 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= -github.com/jackc/pgconn v1.14.1 h1:smbxIaZA08n6YuxEX1sDyjV/qkbtUtkH20qLkR9MUR4= -github.com/jackc/pgconn v1.14.1/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= +github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w= +github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= @@ -1035,8 +1044,8 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.2 h1:7eY55bdBeCz1F2fTzSz69QC+pG46jYq9/jtSPiJ5nn0= -github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= +github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= @@ -1050,12 +1059,11 @@ github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08 github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0= -github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE= +github.com/jackc/pgx/v4 v4.18.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU= +github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -1470,6 +1478,8 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= @@ -1511,14 +1521,12 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/slack-go/slack v0.12.2 h1:x3OppyMyGIbbiyFhsBmpf9pwkUzMhthJMRNmNlA4LaQ= github.com/slack-go/slack v0.12.2/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= -github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= -github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCqR1LNS7aI3jT0V+xGrg= github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= -github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240311111125-22812a072c35 h1:GNhRKD3izyzAoGMXDvVUAwEuzz4Atdj3U3RH7eak5Is= -github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240311111125-22812a072c35/go.mod h1:2I0dWdYdK6jHPnSYYy7Y7Xp7L0YTnJ3KZtkhLQflsTU= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240314172156-049609b8e1f9 h1:rlvE17wHiSnrl2d42TWQ2VVx8ho8c9vgznysXj68sRU= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240314172156-049609b8e1f9/go.mod h1:/bJGelrpXvCcDCuaIgt91UN4B9YxZdK1O7VX5lzbysI= +github.com/smartcontractkit/chainlink-automation v1.0.2 h1:xsfyuswL15q2YBGQT3qn2SBz6fnSKiSW7XZ8IZQLpnI= +github.com/smartcontractkit/chainlink-automation v1.0.2/go.mod h1:RjboV0Qd7YP+To+OrzHGXaxUxoSONveCoAK2TQ1INLU= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240404141006-77085a02ce25 h1:fY2wMtlr/VQxPyVVQdi1jFvQHi0VbDnGGVXzLKOZTOY= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240404141006-77085a02ce25/go.mod h1:kstYjAGqBswdZpl7YkSPeXBDVwaY1VaR6tUMPWl8ykA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 h1:I326nw5GwHQHsLKHwtu5Sb9EBLylC8CfUd7BFAS0jtg= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8/go.mod h1:a65NtrK4xZb01mf0dDNghPkN2wXgcqFQ55ADthVBgMc= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= @@ -1527,18 +1535,18 @@ github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 h github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8/go.mod h1:vy1L7NybTy2F/Yv7BOh+oZBa1MACD6gzd1+DkcSkfp8= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e h1:k8HS3GsAFZnxXIW3141VsQP2+EL1XrTtOi/HDt7sdBE= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e/go.mod h1:JiykN+8W5TA4UD2ClrzQCVvcH3NcyLEVv7RwY0busrw= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240213121419-1272736c2ac0 h1:7m9PVtccb8/pvKTXMaGuyceFno1icRyC2SFH7KG7+70= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240213121419-1272736c2ac0/go.mod h1:SZ899lZYQ0maUulWbZg+SWqabHQ1wTbyk3jT8wJfyo8= -github.com/smartcontractkit/chainlink-testing-framework v1.26.0 h1:YlEWIqnHzFV5syEaWiL/COjpsjqvCKPZP6Xi0m+Kvhw= -github.com/smartcontractkit/chainlink-testing-framework v1.26.0/go.mod h1:gkmsafC85u6hIqWbxKjynKf4NuFuFJDRcgxIEFsSq6E= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595 h1:y6ks0HsSOhPUueOmTcoxDQ50RCS1XINlRDTemZyHjFw= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595/go.mod h1:vV6WfnVIbK5Q1JsIru4YcTG0T1uRpLJm6t2BgCnCSsg= +github.com/smartcontractkit/chainlink-testing-framework v1.28.1 h1:B0YEbaKjAGTPa9rkSfXS+RkH1phzBFjeV6ejPVGM/Jg= +github.com/smartcontractkit/chainlink-testing-framework v1.28.1/go.mod h1:jN+HgXbriq6fKRlIqLw9F3I81aYImV6kBJkIfz0mdIA= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= github.com/smartcontractkit/go-plugin v0.0.0-20240208201424-b3b91517de16 h1:TFe+FvzxClblt6qRfqEhUfa4kFQx5UobuoFGO2W4mMo= github.com/smartcontractkit/go-plugin v0.0.0-20240208201424-b3b91517de16/go.mod h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -github.com/smartcontractkit/libocr v0.0.0-20240229181116-bfb2432a7a66 h1:xsU00JB9GJxEiN6tDbqgN+fT98ySdxkUwTw6CfBXscw= -github.com/smartcontractkit/libocr v0.0.0-20240229181116-bfb2432a7a66/go.mod h1:SJEZCHgMCAzzBvo9vMV2DQ9onfEcIJCYSViyP4JI6c4= +github.com/smartcontractkit/libocr v0.0.0-20240326191951-2bbe9382d052 h1:1WFjrrVrWoQ9UpVMh7Mx4jDpzhmo1h8hFUKd9awIhIU= +github.com/smartcontractkit/libocr v0.0.0-20240326191951-2bbe9382d052/go.mod h1:SJEZCHgMCAzzBvo9vMV2DQ9onfEcIJCYSViyP4JI6c4= github.com/smartcontractkit/seth v0.1.2 h1:ImXJmniuq6yWB6b3eezjV+lkYb1GfQuaJkwRvrCfTKQ= github.com/smartcontractkit/seth v0.1.2/go.mod h1:aOaGwrIVFG/MYaLSj9UUMyE5QJnYQoAgnxm5cKfT9Ng= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= @@ -1682,6 +1690,8 @@ github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+ github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI= +github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= +github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= @@ -1758,14 +1768,14 @@ go.opentelemetry.io/collector/pdata v1.0.0-rcv0016/go.mod h1:OdN0alYOlYhHXu6BDlG go.opentelemetry.io/collector/semconv v0.87.0 h1:BsG1jdLLRCBRlvUujk4QA86af7r/ZXnizczQpEs/gg8= go.opentelemetry.io/collector/semconv v0.87.0/go.mod h1:j/8THcqVxFna1FpvA2zYIsUperEtOaRaqoLYIN4doWw= go.opentelemetry.io/contrib v0.20.0 h1:ubFQUn0VCZ0gPwIoJfBJVpeBlyRMxu8Mm/huKWYd9p0= -go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1 h1:mMv2jG58h6ZI5t5S9QCVGdzCmAsTakMa3oxVgpSD44g= -go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1/go.mod h1:oqRuNKG0upTaDPbLVCG8AD0G2ETrfDtmh7jViy7ox6M= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.49.0 h1:1f31+6grJmV3X4lxcEvUy13i5/kfDw1nJZwhd8mA4tg= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.49.0/go.mod h1:1P/02zM3OwkX9uki+Wmxw3a5GVb6KUXRsa7m7bOC9Fg= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q= -go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= -go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= go.opentelemetry.io/otel/exporters/otlp v0.20.0 h1:PTNgq9MRmQqqJY0REVbZFvwkYOA85vbdQU/nVfxDyqg= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg= @@ -1773,14 +1783,14 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqhe go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= -go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= -go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= go.opentelemetry.io/otel/sdk/metric v1.21.0 h1:smhI5oD714d6jHE6Tie36fPx4WDFIg+Y6RfAY4ICcR0= go.opentelemetry.io/otel/sdk/metric v1.21.0/go.mod h1:FJ8RAsoPGv/wYMgBdUJXOm+6pzFY3YdljnXtv1SBE8Q= -go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= -go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= @@ -1849,10 +1859,9 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -2092,8 +2101,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -2103,8 +2112,8 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= -golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2338,8 +2347,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -2436,5 +2445,5 @@ sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2 sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4= sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk= sigs.k8s.io/structured-merge-diff/v4 v4.3.0/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/integration-tests/load/automationv2_1/automationv2_1_test.go b/integration-tests/load/automationv2_1/automationv2_1_test.go index 0b902423339..0304ebd0c71 100644 --- a/integration-tests/load/automationv2_1/automationv2_1_test.go +++ b/integration-tests/load/automationv2_1/automationv2_1_test.go @@ -2,14 +2,21 @@ package automationv2_1 import ( "context" + "encoding/hex" "fmt" + "io" "math" "math/big" + "net/http" "strconv" "strings" "testing" "time" + "github.com/pkg/errors" + + "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/wiremock" + geth "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -32,6 +39,8 @@ import ( ctfconfig "github.com/smartcontractkit/chainlink-testing-framework/config" + gowiremock "github.com/wiremock/go-wiremock" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/automationv2" "github.com/smartcontractkit/chainlink/integration-tests/client" @@ -62,6 +71,11 @@ Enabled = true Enabled = true AnnounceAddresses = ["0.0.0.0:6690"] ListenAddresses = ["0.0.0.0:6690"]` + secretsTOML = `[Mercury.Credentials.%s] +LegacyURL = '%s' +URL = '%s' +Username = '%s' +Password = '%s'` minimumNodeSpec = map[string]interface{}{ "resources": map[string]interface{}{ @@ -118,6 +132,35 @@ ListenAddresses = ["0.0.0.0:6690"]` } ) +func setUpDataStreamsWireMock(url string) error { + wm := gowiremock.NewClient(url) + rule200 := gowiremock.Get(gowiremock.URLPathEqualTo("/api/v1/reports/bulk")). + WithQueryParam("feedIDs", gowiremock.EqualTo("0x000200")). + WillReturnResponse(gowiremock.NewResponse(). + WithBody(`{"reports":[{"feedID":"0x000200","validFromTimestamp":0,"observationsTimestamp":0,"fullReport":"0x000abc"}]}`). + WithStatus(200)) + err := wm.StubFor(rule200) + if err != nil { + return err + } + resp, err := http.Post(fmt.Sprintf("%s/__admin/mappings/save", url), "application/json", nil) + if err != nil { + return errors.New("error saving wiremock mappings") + } + defer func(Body io.ReadCloser) { + err := Body.Close() + if err != nil { + panic(err) + } + }(resp.Body) + + if resp.StatusCode != 200 { + return errors.New("error saving wiremock mappings") + } + + return nil +} + func TestLogTrigger(t *testing.T) { ctx := tests.Context(t) l := logging.GetTestLogger(t) @@ -126,6 +169,7 @@ func TestLogTrigger(t *testing.T) { if err != nil { t.Fatal(err) } + l.Info().Interface("loadedTestConfig", loadedTestConfig).Msg("Loaded Test Config") version := *loadedTestConfig.ChainlinkImage.Version image := *loadedTestConfig.ChainlinkImage.Image @@ -164,22 +208,6 @@ Load Config: loadDuration := time.Duration(*loadedTestConfig.Automation.General.Duration) * time.Second automationDefaultLinkFunds := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(int64(10000))) //10000 LINK - registrySettings := &contracts.KeeperRegistrySettings{ - PaymentPremiumPPB: uint32(0), - FlatFeeMicroLINK: uint32(40_000), - BlockCountPerTurn: big.NewInt(100), - CheckGasLimit: uint32(45_000_000), //45M - StalenessSeconds: big.NewInt(90_000), - GasCeilingMultiplier: uint16(2), - MaxPerformGas: uint32(5_000_000), - MinUpkeepSpend: big.NewInt(0), - FallbackGasPrice: big.NewInt(2e11), - FallbackLinkPrice: big.NewInt(2e18), - MaxCheckDataSize: uint32(5_000), - MaxPerformDataSize: uint32(5_000), - RegistryVersion: contractseth.RegistryVersion_2_1, - } - testEnvironment := environment.New(&environment.Config{ TTL: loadDuration.Round(time.Hour) + time.Hour, NamespacePrefix: fmt.Sprintf( @@ -199,8 +227,10 @@ Load Config: Values: map[string]interface{}{ "resources": gethNodeSpec, "geth": map[string]interface{}{ - "blocktime": *loadedTestConfig.Automation.General.BlockTime, - "capacity": "20Gi", + "blocktime": *loadedTestConfig.Automation.General.BlockTime, + "capacity": "20Gi", + "startGaslimit": "20000000", + "targetGasLimit": "30000000", }, }, })) @@ -233,6 +263,33 @@ Load Config: loadedTestConfig.Pyroscope.Environment = &testEnvironment.Cfg.Namespace } + if *loadedTestConfig.Automation.DataStreams.Enabled { + if loadedTestConfig.Automation.DataStreams.URL == nil || *loadedTestConfig.Automation.DataStreams.URL == "" { + testEnvironment.AddHelm(wiremock.New(nil)) + err := testEnvironment.Run() + require.NoError(t, err, "Error running wiremock server") + wiremockURL := testEnvironment.URLs[wiremock.InternalURLsKey][0] + secretsTOML = fmt.Sprintf( + secretsTOML, "cred1", + wiremockURL, wiremockURL, + "username", "password", + ) + if !testEnvironment.Cfg.InsideK8s { + wiremockURL = testEnvironment.URLs[wiremock.LocalURLsKey][0] + } + err = setUpDataStreamsWireMock(wiremockURL) + require.NoError(t, err, "Error setting up wiremock server") + } else { + secretsTOML = fmt.Sprintf( + secretsTOML, "cred1", + *loadedTestConfig.Automation.DataStreams.URL, *loadedTestConfig.Automation.DataStreams.URL, + *loadedTestConfig.Automation.DataStreams.Username, *loadedTestConfig.Automation.DataStreams.Password, + ) + } + } else { + secretsTOML = "" + } + numberOfUpkeeps := *loadedTestConfig.Automation.General.NumberOfNodes for i := 0; i < numberOfUpkeeps+1; i++ { // +1 for the OCR boot node @@ -250,10 +307,11 @@ Load Config: } cd := chainlink.NewWithOverride(i, map[string]any{ - "toml": nodeTOML, - "chainlink": nodeSpec, - "db": dbSpec, - "prometheus": *loadedTestConfig.Automation.General.UsePrometheus, + "toml": nodeTOML, + "chainlink": nodeSpec, + "db": dbSpec, + "prometheus": *loadedTestConfig.Automation.General.UsePrometheus, + "secretsToml": secretsTOML, }, loadedTestConfig.ChainlinkImage, overrideFn) testEnvironment.AddHelm(cd) @@ -277,35 +335,62 @@ Load Config: require.NoError(t, err, "Error deploying multicall contract") a := automationv2.NewAutomationTestK8s(chainClient, contractDeployer, chainlinkNodes) - a.RegistrySettings = *registrySettings + conf := loadedTestConfig.Automation.AutomationConfig + a.RegistrySettings = contracts.KeeperRegistrySettings{ + PaymentPremiumPPB: *conf.RegistrySettings.PaymentPremiumPPB, + FlatFeeMicroLINK: *conf.RegistrySettings.FlatFeeMicroLINK, + CheckGasLimit: *conf.RegistrySettings.CheckGasLimit, + StalenessSeconds: conf.RegistrySettings.StalenessSeconds, + GasCeilingMultiplier: *conf.RegistrySettings.GasCeilingMultiplier, + MaxPerformGas: *conf.RegistrySettings.MaxPerformGas, + MinUpkeepSpend: conf.RegistrySettings.MinUpkeepSpend, + FallbackGasPrice: conf.RegistrySettings.FallbackGasPrice, + FallbackLinkPrice: conf.RegistrySettings.FallbackLinkPrice, + MaxCheckDataSize: *conf.RegistrySettings.MaxCheckDataSize, + MaxPerformDataSize: *conf.RegistrySettings.MaxPerformDataSize, + MaxRevertDataSize: *conf.RegistrySettings.MaxRevertDataSize, + RegistryVersion: contractseth.RegistryVersion_2_1, + } a.RegistrarSettings = contracts.KeeperRegistrarSettings{ AutoApproveConfigType: uint8(2), AutoApproveMaxAllowed: math.MaxUint16, MinLinkJuels: big.NewInt(0), } a.PluginConfig = ocr2keepers30config.OffchainConfig{ - TargetProbability: "0.999", - TargetInRounds: 1, - PerformLockoutWindow: 80_000, // Copied from arbitrum mainnet prod value - GasLimitPerReport: 10_300_000, - GasOverheadPerUpkeep: 300_000, - MinConfirmations: 0, - MaxUpkeepBatchSize: 10, + TargetProbability: *conf.PluginConfig.TargetProbability, + TargetInRounds: *conf.PluginConfig.TargetInRounds, + PerformLockoutWindow: *conf.PluginConfig.PerformLockoutWindow, + GasLimitPerReport: *conf.PluginConfig.GasLimitPerReport, + GasOverheadPerUpkeep: *conf.PluginConfig.GasOverheadPerUpkeep, + MinConfirmations: *conf.PluginConfig.MinConfirmations, + MaxUpkeepBatchSize: *conf.PluginConfig.MaxUpkeepBatchSize, + LogProviderConfig: ocr2keepers30config.LogProviderConfig{ + BlockRate: *conf.PluginConfig.LogProviderConfig.BlockRate, + LogLimit: *conf.PluginConfig.LogProviderConfig.LogLimit, + }, } a.PublicConfig = ocr3.PublicConfig{ - DeltaProgress: 10 * time.Second, - DeltaResend: 15 * time.Second, - DeltaInitial: 500 * time.Millisecond, - DeltaRound: 1000 * time.Millisecond, - DeltaGrace: 200 * time.Millisecond, - DeltaCertifiedCommitRequest: 300 * time.Millisecond, - DeltaStage: 15 * time.Second, - RMax: 24, - MaxDurationQuery: 20 * time.Millisecond, - MaxDurationObservation: 20 * time.Millisecond, - MaxDurationShouldAcceptAttestedReport: 1200 * time.Millisecond, - MaxDurationShouldTransmitAcceptedReport: 20 * time.Millisecond, - F: 1, + DeltaProgress: *conf.PublicConfig.DeltaProgress, + DeltaResend: *conf.PublicConfig.DeltaResend, + DeltaInitial: *conf.PublicConfig.DeltaInitial, + DeltaRound: *conf.PublicConfig.DeltaRound, + DeltaGrace: *conf.PublicConfig.DeltaGrace, + DeltaCertifiedCommitRequest: *conf.PublicConfig.DeltaCertifiedCommitRequest, + DeltaStage: *conf.PublicConfig.DeltaStage, + RMax: *conf.PublicConfig.RMax, + MaxDurationQuery: *conf.PublicConfig.MaxDurationQuery, + MaxDurationObservation: *conf.PublicConfig.MaxDurationObservation, + MaxDurationShouldAcceptAttestedReport: *conf.PublicConfig.MaxDurationShouldAcceptAttestedReport, + MaxDurationShouldTransmitAcceptedReport: *conf.PublicConfig.MaxDurationShouldTransmitAcceptedReport, + F: *conf.PublicConfig.F, + } + + if *loadedTestConfig.Automation.DataStreams.Enabled { + a.SetMercuryCredentialName("cred1") + } + + if *conf.UseLogBufferV1 { + a.SetUseLogBufferV1(true) } startTimeTestSetup := time.Now() @@ -342,7 +427,7 @@ Load Config: for _, u := range loadedTestConfig.Automation.Load { for i := 0; i < *u.NumberOfUpkeeps; i++ { - consumerContract, err := contractDeployer.DeployAutomationSimpleLogTriggerConsumer() + consumerContract, err := contractDeployer.DeployAutomationSimpleLogTriggerConsumer(*u.IsStreamsLookup) require.NoError(t, err, "Error deploying automation consumer contract") consumerContracts = append(consumerContracts, consumerContract) l.Debug(). @@ -359,6 +444,11 @@ Load Config: PerformBurnAmount: u.PerformBurnAmount, UpkeepGasLimit: u.UpkeepGasLimit, SharedTrigger: u.SharedTrigger, + Feeds: []string{}, + } + + if *u.IsStreamsLookup { + loadCfg.Feeds = u.Feeds } loadConfigs = append(loadConfigs, loadCfg) @@ -392,17 +482,22 @@ Load Config: } encodedLogTriggerConfig, err := convenienceABI.Methods["_logTriggerConfig"].Inputs.Pack(&logTriggerConfigStruct) require.NoError(t, err, "Error encoding log trigger config") - l.Debug().Bytes("Encoded Log Trigger Config", encodedLogTriggerConfig).Msg("Encoded Log Trigger Config") + l.Debug(). + Interface("logTriggerConfigStruct", logTriggerConfigStruct). + Str("Encoded Log Trigger Config", hex.EncodeToString(encodedLogTriggerConfig)).Msg("Encoded Log Trigger Config") checkDataStruct := simple_log_upkeep_counter_wrapper.CheckData{ CheckBurnAmount: loadConfigs[i].CheckBurnAmount, PerformBurnAmount: loadConfigs[i].PerformBurnAmount, EventSig: bytes1, + Feeds: loadConfigs[i].Feeds, } encodedCheckDataStruct, err := consumerABI.Methods["_checkDataConfig"].Inputs.Pack(&checkDataStruct) require.NoError(t, err, "Error encoding check data struct") - l.Debug().Bytes("Encoded Check Data Struct", encodedCheckDataStruct).Msg("Encoded Check Data Struct") + l.Debug(). + Interface("checkDataStruct", checkDataStruct). + Str("Encoded Check Data Struct", hex.EncodeToString(encodedCheckDataStruct)).Msg("Encoded Check Data Struct") upkeepConfig := automationv2.UpkeepConfig{ UpkeepName: fmt.Sprintf("LogTriggerUpkeep-%d", i), @@ -461,7 +556,7 @@ Load Config: Str("Duration", testSetupDuration.String()). Msg("Test setup ended") - ts, err := sendSlackNotification("Started", l, &loadedTestConfig, testEnvironment.Cfg.Namespace, strconv.Itoa(*loadedTestConfig.Automation.General.NumberOfNodes), + ts, err := sendSlackNotification("Started :white_check_mark:", l, &loadedTestConfig, testEnvironment.Cfg.Namespace, strconv.Itoa(*loadedTestConfig.Automation.General.NumberOfNodes), strconv.FormatInt(startTimeTestSetup.UnixMilli(), 10), "now", []slack.Block{extraBlockWithText("\bTest Config\b\n```" + testConfig + "```")}, slack.MsgOptionBlocks()) if err != nil { @@ -513,6 +608,13 @@ Load Config: startTimeTestReport := time.Now() l.Info().Str("START_TIME", startTimeTestReport.String()).Msg("Test reporting started") + for _, gen := range p.Generators { + if len(gen.Errors()) != 0 { + l.Error().Strs("Errors", gen.Errors()).Msg("Error in load gen") + t.Fail() + } + } + upkeepDelaysFast := make([][]int64, 0) upkeepDelaysRecovery := make([][]int64, 0) @@ -686,6 +788,7 @@ Max: %d Total Perform Count: %d Perform Count Fast Execution: %d Perform Count Recovery Execution: %d +Total Expected Log Triggering Events: %d Total Log Triggering Events Emitted: %d Total Events Missed: %d Percent Missed: %f @@ -698,11 +801,22 @@ Test Duration: %s` Str("Duration", testReDuration.String()). Msg("Test reporting ended") + numberOfExpectedEvents := numberOfEventsEmittedPerSec * int64(loadDuration.Seconds()) + if numberOfEventsEmitted < numberOfExpectedEvents { + l.Error().Msg("Number of events emitted is less than expected") + t.Fail() + } testReport := fmt.Sprintf(testReportFormat, avgF, medianF, ninetyPctF, ninetyNinePctF, maximumF, avgR, medianR, ninetyPctR, ninetyNinePctR, maximumR, len(allUpkeepDelays), len(allUpkeepDelaysFast), - len(allUpkeepDelaysRecovery), numberOfEventsEmitted, eventsMissed, percentMissed, testExDuration.String()) + len(allUpkeepDelaysRecovery), numberOfExpectedEvents, numberOfEventsEmitted, eventsMissed, percentMissed, testExDuration.String()) + l.Info().Str("Test Report", testReport).Msg("Test Report prepared") + + testStatus := "Failed :x:" + if !t.Failed() { + testStatus = "Finished :white_check_mark:" + } - _, err = sendSlackNotification("Finished", l, &loadedTestConfig, testEnvironment.Cfg.Namespace, strconv.Itoa(*loadedTestConfig.Automation.General.NumberOfNodes), + _, err = sendSlackNotification(testStatus, l, &loadedTestConfig, testEnvironment.Cfg.Namespace, strconv.Itoa(*loadedTestConfig.Automation.General.NumberOfNodes), strconv.FormatInt(startTimeTestSetup.UnixMilli(), 10), strconv.FormatInt(time.Now().UnixMilli(), 10), []slack.Block{extraBlockWithText("\bTest Report\b\n```" + testReport + "```")}, slack.MsgOptionTS(ts)) if err != nil { @@ -712,7 +826,7 @@ Test Duration: %s` t.Cleanup(func() { if err = actions.TeardownRemoteSuite(t, testEnvironment.Cfg.Namespace, chainlinkNodes, nil, &loadedTestConfig, chainClient); err != nil { l.Error().Err(err).Msg("Error when tearing down remote suite") - testEnvironment.Cfg.TTL = time.Hour * 48 + testEnvironment.Cfg.TTL += time.Hour * 48 err := testEnvironment.Run() if err != nil { l.Error().Err(err).Msg("Error increasing TTL of namespace") diff --git a/integration-tests/load/automationv2_1/helpers.go b/integration-tests/load/automationv2_1/helpers.go index bd5bfe58667..00576c255e4 100644 --- a/integration-tests/load/automationv2_1/helpers.go +++ b/integration-tests/load/automationv2_1/helpers.go @@ -19,7 +19,7 @@ func sendSlackNotification(header string, l zerolog.Logger, config *tc.TestConfi startingTime string, endingTime string, extraBlocks []slack.Block, msgOption slack.MsgOption) (string, error) { slackClient := slack.New(reportModel.SlackAPIKey) - headerText := ":chainlink-keepers: Automation Load Test " + header + " :white_check_mark:" + headerText := ":chainlink-keepers: Automation Load Test " + header grafanaUrl, err := config.GetGrafanaBaseURL() if err != nil { diff --git a/integration-tests/load/functions/functions_test.go b/integration-tests/load/functions/functions_test.go index d3b82cde33b..49102bcaa66 100644 --- a/integration-tests/load/functions/functions_test.go +++ b/integration-tests/load/functions/functions_test.go @@ -16,7 +16,6 @@ func TestFunctionsLoad(t *testing.T) { ft, err := SetupLocalLoadTestEnv(&generalConfig, &generalConfig) require.NoError(t, err) - ft.EVMClient.ParallelTransactions(false) labels := map[string]string{ "branch": "functions_healthcheck", diff --git a/integration-tests/load/functions/gateway_test.go b/integration-tests/load/functions/gateway_test.go index be5d148386c..c2d5bd7c2cd 100644 --- a/integration-tests/load/functions/gateway_test.go +++ b/integration-tests/load/functions/gateway_test.go @@ -18,7 +18,6 @@ func TestGatewayLoad(t *testing.T) { require.NoError(t, err) ft, err := SetupLocalLoadTestEnv(&listConfig, &listConfig) require.NoError(t, err) - ft.EVMClient.ParallelTransactions(false) labels := map[string]string{ "branch": "gateway_healthcheck", diff --git a/integration-tests/load/functions/setup.go b/integration-tests/load/functions/setup.go index e6711907592..a6c80279bb9 100644 --- a/integration-tests/load/functions/setup.go +++ b/integration-tests/load/functions/setup.go @@ -11,21 +11,20 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/go-resty/resty/v2" "github.com/rs/zerolog/log" + "github.com/smartcontractkit/seth" "github.com/smartcontractkit/tdh2/go/tdh2/tdh2easy" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink/integration-tests/contracts" tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" "github.com/smartcontractkit/chainlink/integration-tests/types" + "github.com/smartcontractkit/chainlink/integration-tests/utils" chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" ) type FunctionsTest struct { - EVMClient blockchain.EVMClient - ContractDeployer contracts.ContractDeployer - ContractLoader contracts.ContractLoader + SethClient seth.Client LinkToken contracts.LinkToken Coordinator contracts.FunctionsCoordinator Router contracts.FunctionsRouter @@ -53,42 +52,36 @@ type S4SecretsCfg struct { func SetupLocalLoadTestEnv(globalConfig tc.GlobalTestConfig, functionsConfig types.FunctionsTestConfig) (*FunctionsTest, error) { selectedNetwork := networks.MustGetSelectedNetworkConfig(globalConfig.GetNetworkConfig())[0] - bc, err := blockchain.NewEVMClientFromNetwork(selectedNetwork, log.Logger) - if err != nil { - return nil, err - } - cd, err := contracts.NewContractDeployer(bc, log.Logger) - if err != nil { - return nil, err - } - - cl, err := contracts.NewContractLoader(bc, log.Logger) + readSethCfg := globalConfig.GetSethConfig() + sethCfg := utils.MergeSethAndEvmNetworkConfigs(log.Logger, selectedNetwork, *readSethCfg) + err := utils.ValidateSethNetworkConfig(sethCfg.Network) if err != nil { return nil, err } + seth, err := seth.NewClientWithConfig(&sethCfg) if err != nil { return nil, err } cfg := functionsConfig.GetFunctionsConfig() - lt, err := cl.LoadLINKToken(*cfg.Common.LINKTokenAddr) + lt, err := contracts.DeployLinkTokenContract(log.Logger, seth) if err != nil { return nil, err } - coord, err := cl.LoadFunctionsCoordinator(*cfg.Common.Coordinator) + coord, err := contracts.LoadFunctionsCoordinator(seth, *cfg.Common.Coordinator) if err != nil { return nil, err } - router, err := cl.LoadFunctionsRouter(*cfg.Common.Router) + router, err := contracts.LoadFunctionsRouter(log.Logger, seth, *cfg.Common.Router) if err != nil { return nil, err } var loadTestClient contracts.FunctionsLoadTestClient if cfg.Common.LoadTestClient != nil && *cfg.Common.LoadTestClient != "" { - loadTestClient, err = cl.LoadFunctionsLoadTestClient(*cfg.Common.LoadTestClient) + loadTestClient, err = contracts.LoadFunctionsLoadTestClient(seth, *cfg.Common.LoadTestClient) } else { - loadTestClient, err = cd.DeployFunctionsLoadTestClient(*cfg.Common.Router) + loadTestClient, err = contracts.DeployFunctionsLoadTestClient(seth, *cfg.Common.Router) } if err != nil { return nil, err @@ -155,9 +148,7 @@ func SetupLocalLoadTestEnv(globalConfig tc.GlobalTestConfig, functionsConfig typ Msg("Set new secret") } return &FunctionsTest{ - EVMClient: bc, - ContractDeployer: cd, - ContractLoader: cl, + SethClient: *seth, LinkToken: lt, Coordinator: coord, Router: router, diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 3dca77447b0..e08143040be 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -12,18 +12,20 @@ require ( github.com/ethereum/go-ethereum v1.13.8 github.com/go-resty/resty/v2 v2.11.0 github.com/pelletier/go-toml/v2 v2.1.1 + github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.30.0 github.com/slack-go/slack v0.12.2 - github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240311111125-22812a072c35 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240314172156-049609b8e1f9 - github.com/smartcontractkit/chainlink-testing-framework v1.26.0 + github.com/smartcontractkit/chainlink-automation v1.0.2 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240404141006-77085a02ce25 + github.com/smartcontractkit/chainlink-testing-framework v1.28.1 github.com/smartcontractkit/chainlink/integration-tests v0.0.0-20240214231432-4ad5eb95178c github.com/smartcontractkit/chainlink/v2 v2.9.0-beta0.0.20240216210048-da02459ddad8 - github.com/smartcontractkit/libocr v0.0.0-20240229181116-bfb2432a7a66 + github.com/smartcontractkit/libocr v0.0.0-20240326191951-2bbe9382d052 github.com/smartcontractkit/seth v0.1.2 github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/wasp v0.4.6 github.com/stretchr/testify v1.9.0 + github.com/wiremock/go-wiremock v1.9.0 go.uber.org/ratelimit v0.3.0 ) @@ -58,6 +60,8 @@ require ( github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/Microsoft/hcsshim v0.11.4 // indirect + github.com/NethermindEth/juno v0.3.1 // indirect + github.com/NethermindEth/starknet.go v0.6.1-0.20231218140327-915109ab5bc1 // indirect github.com/VictoriaMetrics/fastcache v1.12.1 // indirect github.com/XSAM/otelsql v0.27.0 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect @@ -69,6 +73,7 @@ require ( github.com/aws/constructs-go/constructs/v10 v10.1.255 // indirect github.com/aws/jsii-runtime-go v1.75.0 // indirect github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect + github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -131,6 +136,7 @@ require ( github.com/docker/docker v25.0.2+incompatible // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect + github.com/dominikbraun/graph v0.23.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.5.0 // indirect github.com/edsrzf/mmap-go v1.1.0 // indirect @@ -164,7 +170,7 @@ require ( github.com/go-kit/log v0.2.1 // indirect github.com/go-ldap/ldap/v3 v3.4.6 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-openapi/analysis v0.21.4 // indirect @@ -192,7 +198,7 @@ require ( github.com/golang-jwt/jwt/v5 v5.2.0 // indirect github.com/golang/glog v1.1.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/btree v1.1.2 // indirect github.com/google/gnostic v0.6.9 // indirect @@ -230,7 +236,7 @@ require ( github.com/gtank/merlin v0.1.1 // indirect github.com/gtank/ristretto255 v0.1.2 // indirect github.com/hashicorp/consul/api v1.25.1 // indirect - github.com/hashicorp/consul/sdk v0.14.1 // indirect + github.com/hashicorp/consul/sdk v0.16.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-envparse v0.1.0 // indirect @@ -255,14 +261,15 @@ require ( github.com/huin/goupnp v1.3.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/invopop/jsonschema v0.12.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.14.1 // indirect + github.com/jackc/pgconn v1.14.3 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.2 // indirect + github.com/jackc/pgproto3/v2 v2.3.3 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgtype v1.14.0 // indirect - github.com/jackc/pgx/v4 v4.18.1 // indirect + github.com/jackc/pgx/v4 v4.18.2 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect @@ -335,7 +342,6 @@ require ( github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/prometheus/alertmanager v0.26.0 // indirect @@ -361,13 +367,12 @@ require ( github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect github.com/smartcontractkit/chain-selectors v1.0.10 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 // indirect github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e // indirect - github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240213121419-1272736c2ac0 // indirect + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595 // indirect github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240227164431-18a7065e23ea // indirect github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect @@ -405,6 +410,7 @@ require ( github.com/umbracle/ethgo v0.1.3 // indirect github.com/umbracle/fastrlp v0.0.0-20220527094140-59d5dd30e722 // indirect github.com/valyala/fastjson v1.4.1 // indirect + github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xlab/treeprint v1.1.0 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect @@ -422,12 +428,12 @@ require ( go.opentelemetry.io/collector/semconv v0.87.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect - go.opentelemetry.io/otel v1.21.0 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 // indirect - go.opentelemetry.io/otel/metric v1.21.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/otel/sdk v1.21.0 // indirect - go.opentelemetry.io/otel/trace v1.21.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.starlark.net v0.0.0-20220817180228-f738f5508c12 // indirect go.uber.org/atomic v1.11.0 // indirect @@ -436,14 +442,14 @@ require ( go.uber.org/zap v1.26.0 // indirect go4.org/netipx v0.0.0-20230125063823-8449b0a6169f // indirect golang.org/x/arch v0.7.0 // indirect - golang.org/x/crypto v0.19.0 // indirect + golang.org/x/crypto v0.21.0 // indirect golang.org/x/exp v0.0.0-20240213143201-ec583247a57a // indirect golang.org/x/mod v0.15.0 // indirect golang.org/x/net v0.21.0 // indirect golang.org/x/oauth2 v0.17.0 // indirect golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.17.0 // indirect - golang.org/x/term v0.17.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/term v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.18.0 // indirect @@ -454,7 +460,7 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect google.golang.org/grpc v1.59.0 // indirect - google.golang.org/protobuf v1.32.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/guregu/null.v4 v4.0.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect @@ -479,7 +485,7 @@ require ( sigs.k8s.io/kustomize/api v0.12.1 // indirect sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) replace ( diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 21845553680..a5c62d390e1 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -148,6 +148,10 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8= github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w= +github.com/NethermindEth/juno v0.3.1 h1:AW72LiAm9gqUeCVJWvepnZcTnpU4Vkl0KzPMxS+42FA= +github.com/NethermindEth/juno v0.3.1/go.mod h1:SGbTpgGaCsxhFsKOid7Ylnz//WZ8swtILk+NbHGsk/Q= +github.com/NethermindEth/starknet.go v0.6.1-0.20231218140327-915109ab5bc1 h1:9SBvy3eZut1X+wEyAFqfb7ADGj8IQw7ZnlkMwz0YOTY= +github.com/NethermindEth/starknet.go v0.6.1-0.20231218140327-915109ab5bc1/go.mod h1:V6qrbi1+fTDCftETIT1grBXIf+TvWP/4Aois1a9EF1E= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -215,6 +219,8 @@ github.com/aws/jsii-runtime-go v1.75.0/go.mod h1:TKCyrtM0pygEPo4rDZzbMSDNCDNTSYS github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df h1:GSoSVRLoBaFpOOds6QyY1L8AX7uoY+Ln3BHc22W40X0= github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df/go.mod h1:hiVxq5OP2bUGBRNS3Z/bt/reCLFNbdcST6gISi1fiOM= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -438,6 +444,8 @@ github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6 github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucVPgCo= +github.com/dominikbraun/graph v0.23.0/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= @@ -572,8 +580,8 @@ github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A= @@ -740,8 +748,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -887,8 +895,8 @@ github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBt github.com/hashicorp/consul/api v1.25.1 h1:CqrdhYzc8XZuPnhIYZWH45toM0LB9ZeYr/gvpLVI3PE= github.com/hashicorp/consul/api v1.25.1/go.mod h1:iiLVwR/htV7mas/sy0O+XSuEnrdBUUydemjxcUrAt4g= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.14.1 h1:ZiwE2bKb+zro68sWzZ1SgHF3kRMBZ94TwOCFRF4ylPs= -github.com/hashicorp/consul/sdk v0.14.1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg= +github.com/hashicorp/consul/sdk v0.16.0 h1:SE9m0W6DEfgIVCJX7xU+iv/hUl4m/nxqMTnCdMxDpJ8= +github.com/hashicorp/consul/sdk v0.16.0/go.mod h1:7pxqqhqoaPqnBnzXD1StKed62LqJeClzVsUEy85Zr0A= github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A= github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -989,6 +997,8 @@ github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPt github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI= +github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= github.com/ionos-cloud/sdk-go/v6 v6.1.8 h1:493wE/BkZxJf7x79UCE0cYGPZoqQcPiEBALvt7uVGY0= github.com/ionos-cloud/sdk-go/v6 v6.1.8/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= @@ -1006,9 +1016,8 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= -github.com/jackc/pgconn v1.14.1 h1:smbxIaZA08n6YuxEX1sDyjV/qkbtUtkH20qLkR9MUR4= -github.com/jackc/pgconn v1.14.1/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= +github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w= +github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= @@ -1024,8 +1033,8 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.2 h1:7eY55bdBeCz1F2fTzSz69QC+pG46jYq9/jtSPiJ5nn0= -github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= +github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= @@ -1039,12 +1048,11 @@ github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08 github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0= -github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE= +github.com/jackc/pgx/v4 v4.18.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU= +github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -1453,6 +1461,8 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= @@ -1494,14 +1504,12 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/slack-go/slack v0.12.2 h1:x3OppyMyGIbbiyFhsBmpf9pwkUzMhthJMRNmNlA4LaQ= github.com/slack-go/slack v0.12.2/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= -github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= -github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCqR1LNS7aI3jT0V+xGrg= github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= -github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240311111125-22812a072c35 h1:GNhRKD3izyzAoGMXDvVUAwEuzz4Atdj3U3RH7eak5Is= -github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240311111125-22812a072c35/go.mod h1:2I0dWdYdK6jHPnSYYy7Y7Xp7L0YTnJ3KZtkhLQflsTU= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240314172156-049609b8e1f9 h1:rlvE17wHiSnrl2d42TWQ2VVx8ho8c9vgznysXj68sRU= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240314172156-049609b8e1f9/go.mod h1:/bJGelrpXvCcDCuaIgt91UN4B9YxZdK1O7VX5lzbysI= +github.com/smartcontractkit/chainlink-automation v1.0.2 h1:xsfyuswL15q2YBGQT3qn2SBz6fnSKiSW7XZ8IZQLpnI= +github.com/smartcontractkit/chainlink-automation v1.0.2/go.mod h1:RjboV0Qd7YP+To+OrzHGXaxUxoSONveCoAK2TQ1INLU= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240404141006-77085a02ce25 h1:fY2wMtlr/VQxPyVVQdi1jFvQHi0VbDnGGVXzLKOZTOY= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240404141006-77085a02ce25/go.mod h1:kstYjAGqBswdZpl7YkSPeXBDVwaY1VaR6tUMPWl8ykA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8 h1:I326nw5GwHQHsLKHwtu5Sb9EBLylC8CfUd7BFAS0jtg= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240213120401-01a23955f9f8/go.mod h1:a65NtrK4xZb01mf0dDNghPkN2wXgcqFQ55ADthVBgMc= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= @@ -1510,10 +1518,10 @@ github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 h github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8/go.mod h1:vy1L7NybTy2F/Yv7BOh+oZBa1MACD6gzd1+DkcSkfp8= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e h1:k8HS3GsAFZnxXIW3141VsQP2+EL1XrTtOi/HDt7sdBE= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240216142700-c5869534c19e/go.mod h1:JiykN+8W5TA4UD2ClrzQCVvcH3NcyLEVv7RwY0busrw= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240213121419-1272736c2ac0 h1:7m9PVtccb8/pvKTXMaGuyceFno1icRyC2SFH7KG7+70= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240213121419-1272736c2ac0/go.mod h1:SZ899lZYQ0maUulWbZg+SWqabHQ1wTbyk3jT8wJfyo8= -github.com/smartcontractkit/chainlink-testing-framework v1.26.0 h1:YlEWIqnHzFV5syEaWiL/COjpsjqvCKPZP6Xi0m+Kvhw= -github.com/smartcontractkit/chainlink-testing-framework v1.26.0/go.mod h1:gkmsafC85u6hIqWbxKjynKf4NuFuFJDRcgxIEFsSq6E= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595 h1:y6ks0HsSOhPUueOmTcoxDQ50RCS1XINlRDTemZyHjFw= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240325075535-0f7eb05ee595/go.mod h1:vV6WfnVIbK5Q1JsIru4YcTG0T1uRpLJm6t2BgCnCSsg= +github.com/smartcontractkit/chainlink-testing-framework v1.28.1 h1:B0YEbaKjAGTPa9rkSfXS+RkH1phzBFjeV6ejPVGM/Jg= +github.com/smartcontractkit/chainlink-testing-framework v1.28.1/go.mod h1:jN+HgXbriq6fKRlIqLw9F3I81aYImV6kBJkIfz0mdIA= github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240227164431-18a7065e23ea h1:ZdLmNAfKRjH8AYUvjiiDGUgiWQfq/7iNpxyTkvjx/ko= github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240227164431-18a7065e23ea/go.mod h1:gCKC9w6XpNk6jm+XIk2psrkkfxhi421N9NSiFceXW88= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= @@ -1522,8 +1530,8 @@ github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88 github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -github.com/smartcontractkit/libocr v0.0.0-20240229181116-bfb2432a7a66 h1:xsU00JB9GJxEiN6tDbqgN+fT98ySdxkUwTw6CfBXscw= -github.com/smartcontractkit/libocr v0.0.0-20240229181116-bfb2432a7a66/go.mod h1:SJEZCHgMCAzzBvo9vMV2DQ9onfEcIJCYSViyP4JI6c4= +github.com/smartcontractkit/libocr v0.0.0-20240326191951-2bbe9382d052 h1:1WFjrrVrWoQ9UpVMh7Mx4jDpzhmo1h8hFUKd9awIhIU= +github.com/smartcontractkit/libocr v0.0.0-20240326191951-2bbe9382d052/go.mod h1:SJEZCHgMCAzzBvo9vMV2DQ9onfEcIJCYSViyP4JI6c4= github.com/smartcontractkit/seth v0.1.2 h1:ImXJmniuq6yWB6b3eezjV+lkYb1GfQuaJkwRvrCfTKQ= github.com/smartcontractkit/seth v0.1.2/go.mod h1:aOaGwrIVFG/MYaLSj9UUMyE5QJnYQoAgnxm5cKfT9Ng= github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE= @@ -1665,6 +1673,10 @@ github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+ github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI= +github.com/wiremock/go-wiremock v1.9.0 h1:9xcU4/IoEfgCaH4TGhQTtiQyBh2eMtu9JB6ppWduK+E= +github.com/wiremock/go-wiremock v1.9.0/go.mod h1:/uvO0XFheyy8XetvQqm4TbNQRsGPlByeNegzLzvXs0c= +github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= +github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= @@ -1741,14 +1753,14 @@ go.opentelemetry.io/collector/pdata v1.0.0-rcv0016/go.mod h1:OdN0alYOlYhHXu6BDlG go.opentelemetry.io/collector/semconv v0.87.0 h1:BsG1jdLLRCBRlvUujk4QA86af7r/ZXnizczQpEs/gg8= go.opentelemetry.io/collector/semconv v0.87.0/go.mod h1:j/8THcqVxFna1FpvA2zYIsUperEtOaRaqoLYIN4doWw= go.opentelemetry.io/contrib v0.20.0 h1:ubFQUn0VCZ0gPwIoJfBJVpeBlyRMxu8Mm/huKWYd9p0= -go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1 h1:mMv2jG58h6ZI5t5S9QCVGdzCmAsTakMa3oxVgpSD44g= -go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1/go.mod h1:oqRuNKG0upTaDPbLVCG8AD0G2ETrfDtmh7jViy7ox6M= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.49.0 h1:1f31+6grJmV3X4lxcEvUy13i5/kfDw1nJZwhd8mA4tg= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.49.0/go.mod h1:1P/02zM3OwkX9uki+Wmxw3a5GVb6KUXRsa7m7bOC9Fg= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q= -go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= -go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= go.opentelemetry.io/otel/exporters/otlp v0.20.0 h1:PTNgq9MRmQqqJY0REVbZFvwkYOA85vbdQU/nVfxDyqg= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg= @@ -1756,14 +1768,14 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqhe go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= -go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= -go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= go.opentelemetry.io/otel/sdk/metric v1.21.0 h1:smhI5oD714d6jHE6Tie36fPx4WDFIg+Y6RfAY4ICcR0= go.opentelemetry.io/otel/sdk/metric v1.21.0/go.mod h1:FJ8RAsoPGv/wYMgBdUJXOm+6pzFY3YdljnXtv1SBE8Q= -go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= -go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= @@ -1832,11 +1844,10 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -2075,8 +2086,8 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -2087,8 +2098,8 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2323,8 +2334,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -2421,5 +2432,5 @@ sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2 sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4= sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk= sigs.k8s.io/structured-merge-diff/v4 v4.3.0/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/integration-tests/load/ocr/helper.go b/integration-tests/load/ocr/helper.go index c80cedb64fc..ad07ccd4fd4 100644 --- a/integration-tests/load/ocr/helper.go +++ b/integration-tests/load/ocr/helper.go @@ -27,11 +27,11 @@ func SetupCluster( if err != nil { return common.Address{}, err } - linkDeploymentData, err := contracts.DeployLinkTokenContract(seth) + linkContract, err := contracts.DeployLinkTokenContract(l, seth) if err != nil { return common.Address{}, err } - return linkDeploymentData.Address, nil + return common.HexToAddress(linkContract.Address()), nil } func SetupFeed( diff --git a/integration-tests/load/vrfv2/gun.go b/integration-tests/load/vrfv2/gun.go index 9bf34f70b92..71d3113e60f 100644 --- a/integration-tests/load/vrfv2/gun.go +++ b/integration-tests/load/vrfv2/gun.go @@ -8,16 +8,59 @@ import ( vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv2" - "github.com/smartcontractkit/chainlink/integration-tests/types" + vrfv2_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2" ) -/* SingleHashGun is a gun that constantly requests randomness for one feed */ +type BHSTestGun struct { + contracts *vrfcommon.VRFContracts + subIDs []uint64 + keyHash [32]byte + testConfig *vrfv2_config.Config + logger zerolog.Logger +} + +func NewBHSTestGun( + contracts *vrfcommon.VRFContracts, + keyHash [32]byte, + subIDs []uint64, + testConfig *vrfv2_config.Config, + logger zerolog.Logger, +) *BHSTestGun { + return &BHSTestGun{ + contracts: contracts, + subIDs: subIDs, + keyHash: keyHash, + testConfig: testConfig, + logger: logger, + } +} + +// Call implements example gun call, assertions on response bodies should be done here +func (m *BHSTestGun) Call(_ *wasp.Generator) *wasp.Response { + _, err := vrfv2.RequestRandomness( + m.logger, + m.contracts.VRFV2Consumers[0], + m.contracts.CoordinatorV2, + m.subIDs[0], + &vrfcommon.VRFKeyData{KeyHash: m.keyHash}, + *m.testConfig.General.MinimumConfirmations, + *m.testConfig.General.CallbackGasLimit, + *m.testConfig.General.NumberOfWords, + *m.testConfig.General.RandomnessRequestCountPerRequest, + *m.testConfig.General.RandomnessRequestCountPerRequestDeviation, + ) + //todo - might need to store randRequestBlockNumber and blockhash to verify that it was stored in BHS contract at the end of the test + if err != nil { + return &wasp.Response{Error: err.Error(), Failed: true} + } + return &wasp.Response{} +} type SingleHashGun struct { contracts *vrfcommon.VRFContracts keyHash [32]byte subIDs []uint64 - testConfig types.VRFv2TestConfig + testConfig *vrfv2_config.Config logger zerolog.Logger } @@ -25,7 +68,7 @@ func NewSingleHashGun( contracts *vrfcommon.VRFContracts, keyHash [32]byte, subIDs []uint64, - testConfig types.VRFv2TestConfig, + testConfig *vrfv2_config.Config, logger zerolog.Logger, ) *SingleHashGun { return &SingleHashGun{ @@ -41,13 +84,13 @@ func NewSingleHashGun( func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.Response { //todo - should work with multiple consumers and consumers having different keyhashes and wallets - vrfv2Config := m.testConfig.GetVRFv2Config().General + vrfv2Config := m.testConfig.General //randomly increase/decrease randomness request count per TX randomnessRequestCountPerRequest := deviateValue(*vrfv2Config.RandomnessRequestCountPerRequest, *vrfv2Config.RandomnessRequestCountPerRequestDeviation) _, err := vrfv2.RequestRandomnessAndWaitForFulfillment( m.logger, //the same consumer is used for all requests and in all subs - m.contracts.VRFV2Consumer[0], + m.contracts.VRFV2Consumers[0], m.contracts.CoordinatorV2, //randomly pick a subID from pool of subIDs m.subIDs[randInRange(0, len(m.subIDs)-1)], diff --git a/integration-tests/load/vrfv2/onchain_monitoring.go b/integration-tests/load/vrfv2/onchain_monitoring.go index 55975a7e42f..e057e7f8d23 100644 --- a/integration-tests/load/vrfv2/onchain_monitoring.go +++ b/integration-tests/load/vrfv2/onchain_monitoring.go @@ -20,11 +20,11 @@ const ( ErrLokiPush = "failed to push monitoring metrics to Loki" ) -func MonitorLoadStats(lc *wasp.LokiClient, consumer contracts.VRFv2LoadTestConsumer, labels map[string]string) { +func MonitorLoadStats(ctx context.Context, lc *wasp.LokiClient, consumer contracts.VRFv2LoadTestConsumer, labels map[string]string) { go func() { for { time.Sleep(1 * time.Second) - metrics := GetLoadTestMetrics(consumer) + metrics := GetLoadTestMetrics(ctx, consumer) SendMetricsToLoki(metrics, lc, labels) } }() @@ -47,8 +47,8 @@ func SendMetricsToLoki(metrics *contracts.VRFLoadTestMetrics, lc *wasp.LokiClien } } -func GetLoadTestMetrics(consumer contracts.VRFv2LoadTestConsumer) *contracts.VRFLoadTestMetrics { - metrics, err := consumer.GetLoadTestMetrics(context.Background()) +func GetLoadTestMetrics(ctx context.Context, consumer contracts.VRFv2LoadTestConsumer) *contracts.VRFLoadTestMetrics { + metrics, err := consumer.GetLoadTestMetrics(ctx) if err != nil { log.Error().Err(err).Msg(ErrMetrics) } diff --git a/integration-tests/load/vrfv2/vrfv2_test.go b/integration-tests/load/vrfv2/vrfv2_test.go index e99f353d149..0edf35df8fa 100644 --- a/integration-tests/load/vrfv2/vrfv2_test.go +++ b/integration-tests/load/vrfv2/vrfv2_test.go @@ -1,25 +1,21 @@ package loadvrfv2 import ( - "context" "math/big" "sync" "testing" "time" - "github.com/ethereum/go-ethereum/common" - "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/smartcontractkit/wasp" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv2" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" @@ -30,9 +26,9 @@ import ( ) var ( - env *test_env.CLClusterTestEnv + testEnv *test_env.CLClusterTestEnv vrfContracts *vrfcommon.VRFContracts - vrfKeyData *vrfcommon.VRFKeyData + vrfKey *vrfcommon.VRFKeyData subIDs []uint64 eoaWalletAddress string @@ -64,7 +60,7 @@ func TestVRFV2Performance(t *testing.T) { updatedLabels := UpdateLabels(labels, t) l.Info(). - Str("Test Type", string(testType)). + Str("Test Type", testType). Str("Test Duration", vrfv2Config.Performance.TestDuration.Duration.Truncate(time.Second).String()). Int64("RPS", *vrfv2Config.Performance.RPS). Str("RateLimitUnitDuration", vrfv2Config.Performance.RateLimitUnitDuration.String()). @@ -73,134 +69,58 @@ func TestVRFV2Performance(t *testing.T) { Bool("UseExistingEnv", *vrfv2Config.General.UseExistingEnv). Msg("Performance Test Configuration") - if *vrfv2Config.General.UseExistingEnv { - env, err = test_env.NewCLTestEnvBuilder(). - WithTestInstance(t). - WithTestConfig(&testConfig). - WithCustomCleanup( - func() { - teardown(t, vrfContracts.VRFV2Consumer[0], lc, updatedLabels, testReporter, string(testType), &testConfig) - if env.EVMClient.NetworkSimulated() { - l.Info(). - Str("Network Name", env.EVMClient.GetNetworkName()). - Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") - } else { - if *vrfv2Config.General.CancelSubsAfterTestRun { - //cancel subs and return funds to sub owner - cancelSubsAndReturnFunds(testcontext.Get(t), subIDs, l) - } - } - }). - Build() - - require.NoError(t, err, "error creating test env") - - coordinator, err := env.ContractLoader.LoadVRFCoordinatorV2(*vrfv2Config.ExistingEnvConfig.CoordinatorAddress) - require.NoError(t, err) + chainID := networks.MustGetSelectedNetworkConfig(testConfig.GetNetworkConfig())[0].ChainID + + cleanupFn := func() { + teardown(t, vrfContracts.VRFV2Consumers[0], lc, updatedLabels, testReporter, testType, &testConfig) + + evmClient, err := testEnv.GetEVMClient(chainID) + require.NoError(t, err, "error getting EVM client") - var consumers []contracts.VRFv2LoadTestConsumer - if *vrfv2Config.ExistingEnvConfig.CreateFundSubsAndAddConsumers { - linkToken, err := env.ContractLoader.LoadLINKToken(*vrfv2Config.ExistingEnvConfig.LinkAddress) - require.NoError(t, err) - consumers, err = vrfv2.DeployVRFV2Consumers(env.ContractDeployer, coordinator.Address(), 1) - require.NoError(t, err) - err = env.EVMClient.WaitForEvents() - require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) + if evmClient.NetworkSimulated() { l.Info(). - Str("Coordinator", *vrfv2Config.ExistingEnvConfig.CoordinatorAddress). - Int("Number of Subs to create", *vrfv2Config.General.NumberOfSubToCreate). - Msg("Creating and funding subscriptions, deploying and adding consumers to subs") - subIDs, err = vrfv2.CreateFundSubsAndAddConsumers( - env, - big.NewFloat(*vrfv2Config.General.SubscriptionFundingAmountLink), - linkToken, - coordinator, - consumers, - *vrfv2Config.General.NumberOfSubToCreate, - ) - require.NoError(t, err) + Str("Network Name", evmClient.GetNetworkName()). + Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { - consumer, err := env.ContractLoader.LoadVRFv2LoadTestConsumer(*vrfv2Config.ExistingEnvConfig.ConsumerAddress) - require.NoError(t, err) - consumers = append(consumers, consumer) - subIDs = append(subIDs, *vrfv2Config.ExistingEnvConfig.SubID) + if *vrfv2Config.General.CancelSubsAfterTestRun { + //cancel subs and return funds to sub owner + vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, eoaWalletAddress, subIDs, l) + } + } + if !*vrfv2Config.General.UseExistingEnv { + if err := testEnv.Cleanup(); err != nil { + l.Error().Err(err).Msg("Error cleaning up test environment") + } } + } - err = FundNodesIfNeeded(testcontext.Get(t), &testConfig, env.EVMClient, l) - require.NoError(t, err) + newEnvConfig := vrfcommon.NewEnvConfig{ + NodesToCreate: []vrfcommon.VRFNodeType{vrfcommon.VRF}, + NumberOfTxKeysToCreate: *vrfv2Config.General.NumberOfSendingKeysToCreate, + UseVRFOwner: true, + UseTestCoordinator: true, + } - vrfContracts = &vrfcommon.VRFContracts{ - CoordinatorV2: coordinator, - VRFV2Consumer: consumers, - BHS: nil, - } + testEnv, vrfContracts, vrfKey, _, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, testConfig, chainID, cleanupFn, newEnvConfig, l) + require.NoError(t, err, "error setting up VRFV2 universe") - vrfKeyData = &vrfcommon.VRFKeyData{ - VRFKey: nil, - EncodedProvingKey: [2]*big.Int{}, - KeyHash: common.HexToHash(*vrfv2Config.ExistingEnvConfig.KeyHash), - } + evmClient, err := testEnv.GetEVMClient(chainID) + require.NoError(t, err, "error getting EVM client") - } else { - network, err := actions.EthereumNetworkConfigFromConfig(l, &testConfig) - require.NoError(t, err, "Error building ethereum network config") - env, err = test_env.NewCLTestEnvBuilder(). - WithTestInstance(t). - WithTestConfig(&testConfig). - WithPrivateEthereumNetwork(network). - WithCLNodes(1). - WithFunding(big.NewFloat(*testConfig.Common.ChainlinkNodeFunding)). - WithCustomCleanup( - func() { - teardown(t, vrfContracts.VRFV2Consumer[0], lc, updatedLabels, testReporter, string(testType), &testConfig) - - if env.EVMClient.NetworkSimulated() { - l.Info(). - Str("Network Name", env.EVMClient.GetNetworkName()). - Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") - } else { - if *testConfig.VRFv2.General.CancelSubsAfterTestRun { - //cancel subs and return funds to sub owner - cancelSubsAndReturnFunds(testcontext.Get(t), subIDs, l) - } - } - if err := env.Cleanup(); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }). - Build() - - require.NoError(t, err, "error creating test env") - - env.ParallelTransactions(true) - - mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*vrfv2Config.General.LinkNativeFeedResponse)) - require.NoError(t, err, "error deploying mock ETH/LINK feed") - - linkToken, err := actions.DeployLINKToken(env.ContractDeployer) - require.NoError(t, err, "error deploying LINK contract") - - useVRFOwner := true - useTestCoordinator := true - - vrfContracts, subIDs, vrfKeyData, _, err = vrfv2.SetupVRFV2Environment( - env, - []vrfcommon.VRFNodeType{vrfcommon.VRF}, - &testConfig, - useVRFOwner, - useTestCoordinator, - linkToken, - mockETHLinkFeed, - //register proving key against EOA address in order to return funds to this address - env.EVMClient.GetDefaultWallet().Address(), - 0, - 1, - *vrfv2Config.General.NumberOfSubToCreate, - l, - ) - require.NoError(t, err, "error setting up VRF v2 env") - } - eoaWalletAddress = env.EVMClient.GetDefaultWallet().Address() + var consumers []contracts.VRFv2LoadTestConsumer + subIDs, consumers, err = vrfv2.SetupSubsAndConsumersForExistingEnv( + testEnv, + chainID, + vrfContracts.CoordinatorV2, + vrfContracts.LinkToken, + 1, + *vrfv2Config.General.NumberOfSubToCreate, + testConfig, + l, + ) + vrfContracts.VRFV2Consumers = consumers + + eoaWalletAddress = evmClient.GetDefaultWallet().Address() l.Debug().Int("Number of Subs", len(subIDs)).Msg("Subs involved in the test") for _, subID := range subIDs { @@ -208,30 +128,30 @@ func TestVRFV2Performance(t *testing.T) { require.NoError(t, err, "error getting subscription information for subscription %d", subID) vrfv2.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2) } - singleFeedConfig := &wasp.Config{ - T: t, - LoadType: wasp.RPS, - GenName: "gun", - RateLimitUnitDuration: vrfv2Config.Performance.RateLimitUnitDuration.Duration, - Gun: NewSingleHashGun( - vrfContracts, - vrfKeyData.KeyHash, - subIDs, - &testConfig, - l, - ), - Labels: labels, - LokiConfig: lokiConfig, - CallTimeout: 2 * time.Minute, - } - require.Len(t, vrfContracts.VRFV2Consumer, 1, "only one consumer should be created for Load Test") - consumer := vrfContracts.VRFV2Consumer[0] - err = consumer.ResetMetrics() - require.NoError(t, err) - MonitorLoadStats(lc, consumer, updatedLabels) // is our "job" stable at all, no memory leaks, no flaking performance under some RPS? t.Run("vrfv2 performance test", func(t *testing.T) { + require.Len(t, vrfContracts.VRFV2Consumers, 1, "only one consumer should be created for Load Test") + err = vrfContracts.VRFV2Consumers[0].ResetMetrics() + require.NoError(t, err) + MonitorLoadStats(testcontext.Get(t), lc, vrfContracts.VRFV2Consumers[0], updatedLabels) + + singleFeedConfig := &wasp.Config{ + T: t, + LoadType: wasp.RPS, + GenName: "gun", + RateLimitUnitDuration: vrfv2Config.Performance.RateLimitUnitDuration.Duration, + Gun: NewSingleHashGun( + vrfContracts, + vrfKey.KeyHash, + subIDs, + vrfv2Config, + l, + ), + Labels: labels, + LokiConfig: lokiConfig, + CallTimeout: 2 * time.Minute, + } singleFeedConfig.Schedule = wasp.Plain( *vrfv2Config.Performance.RPS, @@ -245,7 +165,7 @@ func TestVRFV2Performance(t *testing.T) { var wg sync.WaitGroup wg.Add(1) //todo - timeout should be configurable depending on the perf test type - requestCount, fulfilmentCount, err := vrfcommon.WaitForRequestCountEqualToFulfilmentCount(testcontext.Get(t), consumer, 2*time.Minute, &wg) + requestCount, fulfilmentCount, err := vrfcommon.WaitForRequestCountEqualToFulfilmentCount(testcontext.Get(t), vrfContracts.VRFV2Consumers[0], 2*time.Minute, &wg) require.NoError(t, err) wg.Wait() @@ -254,65 +174,168 @@ func TestVRFV2Performance(t *testing.T) { Interface("Fulfilment Count", fulfilmentCount). Msg("Final Request/Fulfilment Stats") }) - } -func cancelSubsAndReturnFunds(ctx context.Context, subIDs []uint64, l zerolog.Logger) { - for _, subID := range subIDs { - l.Info(). - Uint64("Returning funds from SubID", subID). - Str("Returning funds to", eoaWalletAddress). - Msg("Canceling subscription and returning funds to subscription owner") - pendingRequestsExist, err := vrfContracts.CoordinatorV2.PendingRequestsExist(ctx, subID) - if err != nil { - l.Error().Err(err).Msg("Error checking if pending requests exist") - } - if !pendingRequestsExist { - _, err := vrfContracts.CoordinatorV2.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) - if err != nil { - l.Error().Err(err).Msg("Error canceling subscription") - } - } else { - l.Error().Uint64("Sub ID", subID).Msg("Pending requests exist for subscription, cannot cancel subscription and return funds") - } +func TestVRFV2BHSPerformance(t *testing.T) { + l := logging.GetTestLogger(t) + + testType, err := tc.GetConfigurationNameFromEnv() + require.NoError(t, err) + testConfig, err := tc.GetConfig(testType, tc.VRFv2) + require.NoError(t, err) + + testReporter := &testreporters.VRFV2TestReporter{} + vrfv2Config := testConfig.VRFv2 + + cfgl := testConfig.Logging.Loki + lokiConfig := wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken) + lc, err := wasp.NewLokiClient(lokiConfig) + if err != nil { + l.Error().Err(err).Msg(ErrLokiClient) + return } -} -func FundNodesIfNeeded(ctx context.Context, vrfv2TestConfig tc.VRFv2TestConfig, client blockchain.EVMClient, l zerolog.Logger) error { - cfg := vrfv2TestConfig.GetVRFv2Config() - if cfg.ExistingEnvConfig.NodeSendingKeyFundingMin != nil && *cfg.ExistingEnvConfig.NodeSendingKeyFundingMin > 0 { - for _, sendingKey := range cfg.ExistingEnvConfig.NodeSendingKeys { - address := common.HexToAddress(sendingKey) - sendingKeyBalance, err := client.BalanceAt(ctx, address) - if err != nil { - return err + updatedLabels := UpdateLabels(labels, t) + + l.Info(). + Str("Test Type", testType). + Str("Test Duration", vrfv2Config.Performance.TestDuration.Duration.Truncate(time.Second).String()). + Int64("RPS", *vrfv2Config.Performance.RPS). + Str("RateLimitUnitDuration", vrfv2Config.Performance.RateLimitUnitDuration.String()). + Uint16("RandomnessRequestCountPerRequest", *vrfv2Config.General.RandomnessRequestCountPerRequest). + Uint16("RandomnessRequestCountPerRequestDeviation", *vrfv2Config.General.RandomnessRequestCountPerRequestDeviation). + Bool("UseExistingEnv", *vrfv2Config.General.UseExistingEnv). + Msg("Performance Test Configuration") + + chainID := networks.MustGetSelectedNetworkConfig(testConfig.GetNetworkConfig())[0].ChainID + + cleanupFn := func() { + teardown(t, vrfContracts.VRFV2Consumers[0], lc, updatedLabels, testReporter, testType, &testConfig) + + evmClient, err := testEnv.GetEVMClient(chainID) + require.NoError(t, err, "error getting EVM client") + + if evmClient.NetworkSimulated() { + l.Info(). + Str("Network Name", evmClient.GetNetworkName()). + Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") + } else { + if *vrfv2Config.General.CancelSubsAfterTestRun { + //cancel subs and return funds to sub owner + vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, eoaWalletAddress, subIDs, l) } - fundingAtLeast := conversions.EtherToWei(big.NewFloat(*cfg.ExistingEnvConfig.NodeSendingKeyFundingMin)) - fundingToSendWei := new(big.Int).Sub(fundingAtLeast, sendingKeyBalance) - fundingToSendEth := conversions.WeiToEther(fundingToSendWei) - if fundingToSendWei.Cmp(big.NewInt(0)) == 1 { - l.Info(). - Str("Sending Key", sendingKey). - Str("Sending Key Current Balance", sendingKeyBalance.String()). - Str("Should have at least", fundingAtLeast.String()). - Str("Funding Amount in ETH", fundingToSendEth.String()). - Msg("Funding Node's Sending Key") - err := actions.FundAddress(client, sendingKey, fundingToSendEth) - if err != nil { - return err - } - } else { - l.Info(). - Str("Sending Key", sendingKey). - Str("Sending Key Current Balance", sendingKeyBalance.String()). - Str("Should have at least", fundingAtLeast.String()). - Msg("Skipping Node's Sending Key funding as it has enough funds") + } + if !*vrfv2Config.General.UseExistingEnv { + if err := testEnv.Cleanup(); err != nil { + l.Error().Err(err).Msg("Error cleaning up test environment") } } } - return nil -} + newEnvConfig := vrfcommon.NewEnvConfig{ + NodesToCreate: []vrfcommon.VRFNodeType{vrfcommon.VRF}, + NumberOfTxKeysToCreate: *vrfv2Config.General.NumberOfSendingKeysToCreate, + UseVRFOwner: true, + UseTestCoordinator: true, + } + + testEnv, vrfContracts, vrfKey, _, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, testConfig, chainID, cleanupFn, newEnvConfig, l) + require.NoError(t, err, "error setting up VRFV2 universe") + + evmClient, err := testEnv.GetEVMClient(chainID) + require.NoError(t, err, "error getting EVM client") + + var consumers []contracts.VRFv2LoadTestConsumer + subIDs, consumers, err = vrfv2.SetupSubsAndConsumersForExistingEnv( + testEnv, + chainID, + vrfContracts.CoordinatorV2, + vrfContracts.LinkToken, + 1, + *vrfv2Config.General.NumberOfSubToCreate, + testConfig, + l, + ) + vrfContracts.VRFV2Consumers = consumers + + eoaWalletAddress = evmClient.GetDefaultWallet().Address() + + l.Debug().Int("Number of Subs", len(subIDs)).Msg("Subs involved in the test") + for _, subID := range subIDs { + subscription, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subID) + require.NoError(t, err, "error getting subscription information for subscription %d", subID) + vrfv2.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2) + } + + t.Run("vrfv2 and bhs performance test", func(t *testing.T) { + configCopy := testConfig.MustCopy().(tc.TestConfig) + //Underfund Subscription + configCopy.VRFv2.General.SubscriptionFundingAmountLink = ptr.Ptr(float64(0)) + consumers, subIDs, err = vrfv2.SetupNewConsumersAndSubs( + testEnv, + chainID, + vrfContracts.CoordinatorV2, + configCopy, + vrfContracts.LinkToken, + 1, + *configCopy.VRFv2.General.NumberOfSubToCreate, + l, + ) + require.NoError(t, err, "error setting up new consumers and subscriptions") + vrfContracts.VRFV2Consumers = consumers + require.Len(t, vrfContracts.VRFV2Consumers, 1, "only one consumer should be created for Load Test") + err = vrfContracts.VRFV2Consumers[0].ResetMetrics() + require.NoError(t, err, "error resetting consumer metrics") + MonitorLoadStats(testcontext.Get(t), lc, vrfContracts.VRFV2Consumers[0], updatedLabels) + + singleFeedConfig := &wasp.Config{ + T: t, + LoadType: wasp.RPS, + GenName: "gun", + RateLimitUnitDuration: configCopy.VRFv2.Performance.BHSTestRateLimitUnitDuration.Duration, + Gun: NewBHSTestGun( + vrfContracts, + vrfKey.KeyHash, + subIDs, + configCopy.VRFv2, + l, + ), + Labels: labels, + LokiConfig: lokiConfig, + CallTimeout: 2 * time.Minute, + } + + singleFeedConfig.Schedule = wasp.Plain( + *configCopy.VRFv2.Performance.BHSTestRPS, + configCopy.VRFv2.Performance.BHSTestDuration.Duration, + ) + _, err = wasp.NewProfile(). + Add(wasp.NewGenerator(singleFeedConfig)). + Run(true) + require.NoError(t, err) + + var wgBlockNumberTobe sync.WaitGroup + wgBlockNumberTobe.Add(1) + //Wait at least 256 blocks + latestBlockNumber, err := evmClient.LatestBlockNumber(testcontext.Get(t)) + require.NoError(t, err, "error getting latest block number") + _, err = actions.WaitForBlockNumberToBe(latestBlockNumber+uint64(256), evmClient, &wgBlockNumberTobe, configCopy.VRFv2.General.WaitFor256BlocksTimeout.Duration, t) + wgBlockNumberTobe.Wait() + require.NoError(t, err, "error waiting for block number to be") + err = vrfv2.FundSubscriptions(testEnv, chainID, big.NewFloat(*configCopy.VRFv2.General.SubscriptionRefundingAmountLink), vrfContracts.LinkToken, vrfContracts.CoordinatorV2, subIDs) + require.NoError(t, err, "error funding subscriptions") + var wgAllRequestsFulfilled sync.WaitGroup + wgAllRequestsFulfilled.Add(1) + requestCount, fulfilmentCount, err := vrfcommon.WaitForRequestCountEqualToFulfilmentCount(testcontext.Get(t), vrfContracts.VRFV2Consumers[0], 2*time.Minute, &wgAllRequestsFulfilled) + require.NoError(t, err) + wgAllRequestsFulfilled.Wait() + + l.Info(). + Interface("Request Count", requestCount). + Interface("Fulfilment Count", fulfilmentCount). + Msg("Final Request/Fulfilment Stats") + }) +} func teardown( t *testing.T, consumer contracts.VRFv2LoadTestConsumer, @@ -323,16 +346,18 @@ func teardown( testConfig *tc.TestConfig, ) { //send final results to Loki - metrics := GetLoadTestMetrics(consumer) + metrics := GetLoadTestMetrics(testcontext.Get(t), consumer) SendMetricsToLoki(metrics, lc, updatedLabels) //set report data for Slack notification testReporter.SetReportData( testType, - metrics.RequestCount, - metrics.FulfilmentCount, - metrics.AverageFulfillmentInMillions, - metrics.SlowestFulfillment, - metrics.FastestFulfillment, + testreporters.VRFLoadTestMetrics{ + RequestCount: metrics.RequestCount, + FulfilmentCount: metrics.FulfilmentCount, + AverageFulfillmentInMillions: metrics.AverageFulfillmentInMillions, + SlowestFulfillment: metrics.SlowestFulfillment, + FastestFulfillment: metrics.FastestFulfillment, + }, testConfig, ) diff --git a/integration-tests/load/vrfv2plus/gun.go b/integration-tests/load/vrfv2plus/gun.go index 22a56d557de..8be30afd412 100644 --- a/integration-tests/load/vrfv2plus/gun.go +++ b/integration-tests/load/vrfv2plus/gun.go @@ -11,16 +11,63 @@ import ( vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv2plus" vrfv2plus_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2plus" - "github.com/smartcontractkit/chainlink/integration-tests/types" ) -/* SingleHashGun is a gun that constantly requests randomness for one feed */ +type BHSTestGun struct { + contracts *vrfcommon.VRFContracts + keyHash [32]byte + subIDs []*big.Int + testConfig *vrfv2plus_config.Config + logger zerolog.Logger +} + +func NewBHSTestGun( + contracts *vrfcommon.VRFContracts, + keyHash [32]byte, + subIDs []*big.Int, + testConfig *vrfv2plus_config.Config, + logger zerolog.Logger, +) *BHSTestGun { + return &BHSTestGun{ + contracts: contracts, + subIDs: subIDs, + keyHash: keyHash, + testConfig: testConfig, + logger: logger, + } +} +// Call implements example gun call, assertions on response bodies should be done here +func (m *BHSTestGun) Call(_ *wasp.Generator) *wasp.Response { + vrfv2PlusConfig := m.testConfig.General + billingType, err := selectBillingType(*vrfv2PlusConfig.SubscriptionBillingType) + if err != nil { + return &wasp.Response{Error: err.Error(), Failed: true} + } + _, err = vrfv2plus.RequestRandomnessAndWaitForRequestedEvent( + //the same consumer is used for all requests and in all subs + m.contracts.VRFV2PlusConsumer[0], + m.contracts.CoordinatorV2Plus, + &vrfcommon.VRFKeyData{KeyHash: m.keyHash}, + //randomly pick a subID from pool of subIDs + m.subIDs[randInRange(0, len(m.subIDs)-1)], + billingType, + vrfv2PlusConfig, + m.logger, + ) + //todo - might need to store randRequestBlockNumber and blockhash to verify that it was stored in BHS contract at the end of the test + if err != nil { + return &wasp.Response{Error: err.Error(), Failed: true} + } + return &wasp.Response{} +} + +/* SingleHashGun is a gun that constantly requests randomness for one feed */ type SingleHashGun struct { contracts *vrfcommon.VRFContracts keyHash [32]byte subIDs []*big.Int - testConfig types.VRFv2PlusTestConfig + testConfig *vrfv2plus_config.Config logger zerolog.Logger } @@ -28,7 +75,7 @@ func NewSingleHashGun( contracts *vrfcommon.VRFContracts, keyHash [32]byte, subIDs []*big.Int, - testConfig types.VRFv2PlusTestConfig, + testConfig *vrfv2plus_config.Config, logger zerolog.Logger, ) *SingleHashGun { return &SingleHashGun{ @@ -43,15 +90,15 @@ func NewSingleHashGun( // Call implements example gun call, assertions on response bodies should be done here func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.Response { //todo - should work with multiple consumers and consumers having different keyhashes and wallets - - billingType, err := selectBillingType(*m.testConfig.GetVRFv2PlusConfig().General.SubscriptionBillingType) + vrfv2PlusConfig := m.testConfig.General + billingType, err := selectBillingType(*vrfv2PlusConfig.SubscriptionBillingType) if err != nil { return &wasp.Response{Error: err.Error(), Failed: true} } //randomly increase/decrease randomness request count per TX - reqCount := deviateValue(*m.testConfig.GetVRFv2PlusConfig().General.RandomnessRequestCountPerRequest, *m.testConfig.GetVRFv2PlusConfig().General.RandomnessRequestCountPerRequestDeviation) - m.testConfig.GetVRFv2PlusConfig().General.RandomnessRequestCountPerRequest = &reqCount + reqCount := deviateValue(*m.testConfig.General.RandomnessRequestCountPerRequest, *m.testConfig.General.RandomnessRequestCountPerRequestDeviation) + m.testConfig.General.RandomnessRequestCountPerRequest = &reqCount _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillment( //the same consumer is used for all requests and in all subs m.contracts.VRFV2PlusConsumer[0], @@ -59,9 +106,8 @@ func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.Response { &vrfcommon.VRFKeyData{KeyHash: m.keyHash}, //randomly pick a subID from pool of subIDs m.subIDs[randInRange(0, len(m.subIDs)-1)], - //randomly pick payment type billingType, - m.testConfig.GetVRFv2PlusConfig().General, + vrfv2PlusConfig, m.logger, ) if err != nil { diff --git a/integration-tests/load/vrfv2plus/onchain_monitoring.go b/integration-tests/load/vrfv2plus/onchain_monitoring.go index c911546af0c..50c0ac18a98 100644 --- a/integration-tests/load/vrfv2plus/onchain_monitoring.go +++ b/integration-tests/load/vrfv2plus/onchain_monitoring.go @@ -20,11 +20,11 @@ const ( ErrLokiPush = "failed to push monitoring metrics to Loki" ) -func MonitorLoadStats(lc *wasp.LokiClient, consumer contracts.VRFv2PlusLoadTestConsumer, labels map[string]string) { +func MonitorLoadStats(ctx context.Context, lc *wasp.LokiClient, consumer contracts.VRFv2PlusLoadTestConsumer, labels map[string]string) { go func() { for { time.Sleep(1 * time.Second) - metrics := GetLoadTestMetrics(consumer) + metrics := GetLoadTestMetrics(ctx, consumer) SendMetricsToLoki(metrics, lc, labels) } }() @@ -47,8 +47,8 @@ func SendMetricsToLoki(metrics *contracts.VRFLoadTestMetrics, lc *wasp.LokiClien } } -func GetLoadTestMetrics(consumer contracts.VRFv2PlusLoadTestConsumer) *contracts.VRFLoadTestMetrics { - metrics, err := consumer.GetLoadTestMetrics(context.Background()) +func GetLoadTestMetrics(ctx context.Context, consumer contracts.VRFv2PlusLoadTestConsumer) *contracts.VRFLoadTestMetrics { + metrics, err := consumer.GetLoadTestMetrics(ctx) if err != nil { log.Error().Err(err).Msg(ErrMetrics) } diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go index 13c694c0290..1589123c77e 100644 --- a/integration-tests/load/vrfv2plus/vrfv2plus_test.go +++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go @@ -1,37 +1,34 @@ package loadvrfv2plus import ( - "context" "math/big" "sync" "testing" "time" - "github.com/ethereum/go-ethereum/common" - "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/smartcontractkit/wasp" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" + "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv2plus" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" - "github.com/smartcontractkit/chainlink/integration-tests/actions" vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) var ( - env *test_env.CLClusterTestEnv + testEnv *test_env.CLClusterTestEnv vrfContracts *vrfcommon.VRFContracts - vrfv2PlusData *vrfcommon.VRFKeyData + vrfKey *vrfcommon.VRFKeyData subIDs []*big.Int eoaWalletAddress string @@ -53,16 +50,18 @@ func TestVRFV2PlusPerformance(t *testing.T) { vrfv2PlusConfig := testConfig.VRFv2Plus testReporter := &testreporters.VRFV2PlusTestReporter{} - lc, err := wasp.NewLokiClient(wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken)) + lokiConfig := wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken) + lc, err := wasp.NewLokiClient(lokiConfig) if err != nil { l.Error().Err(err).Msg(ErrLokiClient) return } + networkConfig := networks.MustGetSelectedNetworkConfig(testConfig.GetNetworkConfig())[0] updatedLabels := UpdateLabels(labels, t) l.Info(). - Str("Test Type", string(testType)). + Str("Test Type", testType). Str("Test Duration", vrfv2PlusConfig.Performance.TestDuration.Duration.Truncate(time.Second).String()). Int64("RPS", *vrfv2PlusConfig.Performance.RPS). Str("RateLimitUnitDuration", vrfv2PlusConfig.Performance.RateLimitUnitDuration.String()). @@ -71,132 +70,54 @@ func TestVRFV2PlusPerformance(t *testing.T) { Bool("UseExistingEnv", *vrfv2PlusConfig.General.UseExistingEnv). Msg("Performance Test Configuration") - if *vrfv2PlusConfig.General.UseExistingEnv { - - env, err = test_env.NewCLTestEnvBuilder(). - WithTestInstance(t). - WithTestConfig(&testConfig). - WithCustomCleanup( - func() { - teardown(t, vrfContracts.VRFV2PlusConsumer[0], lc, updatedLabels, testReporter, string(testType), &testConfig) - if env.EVMClient.NetworkSimulated() { - l.Info(). - Str("Network Name", env.EVMClient.GetNetworkName()). - Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") - } else { - if *testConfig.VRFv2Plus.General.CancelSubsAfterTestRun { - //cancel subs and return funds to sub owner - cancelSubsAndReturnFunds(testcontext.Get(t), subIDs, l) - } - } - }). - Build() - - require.NoError(t, err, "error creating test env") - - coordinator, err := env.ContractLoader.LoadVRFCoordinatorV2_5(*vrfv2PlusConfig.ExistingEnvConfig.CoordinatorAddress) - require.NoError(t, err) + cleanupFn := func() { + teardown(t, vrfContracts.VRFV2PlusConsumer[0], lc, updatedLabels, testReporter, testType, &testConfig) + + evmClient, err := testEnv.GetEVMClient(networkConfig.ChainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") - var consumers []contracts.VRFv2PlusLoadTestConsumer - if *testConfig.VRFv2Plus.ExistingEnvConfig.CreateFundSubsAndAddConsumers { - linkToken, err := env.ContractLoader.LoadLINKToken(*vrfv2PlusConfig.ExistingEnvConfig.LinkAddress) - require.NoError(t, err) - consumers, err = vrfv2plus.DeployVRFV2PlusConsumers(env.ContractDeployer, coordinator, 1) - require.NoError(t, err) - err = env.EVMClient.WaitForEvents() - require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) + if evmClient.NetworkSimulated() { l.Info(). - Str("Coordinator", *vrfv2PlusConfig.ExistingEnvConfig.CoordinatorAddress). - Int("Number of Subs to create", *vrfv2PlusConfig.General.NumberOfSubToCreate). - Msg("Creating and funding subscriptions, deploying and adding consumers to subs") - subIDs, err = vrfv2plus.CreateFundSubsAndAddConsumers( - env, - big.NewFloat(*testConfig.GetVRFv2PlusConfig().General.SubscriptionFundingAmountNative), - big.NewFloat(*testConfig.GetVRFv2PlusConfig().General.SubscriptionFundingAmountLink), - linkToken, - coordinator, - consumers, - *vrfv2PlusConfig.General.NumberOfSubToCreate, - ) - require.NoError(t, err) + Str("Network Name", evmClient.GetNetworkName()). + Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { - consumer, err := env.ContractLoader.LoadVRFv2PlusLoadTestConsumer(*vrfv2PlusConfig.ExistingEnvConfig.ConsumerAddress) - require.NoError(t, err) - consumers = append(consumers, consumer) - var ok bool - subID, ok := new(big.Int).SetString(*vrfv2PlusConfig.ExistingEnvConfig.SubID, 10) - require.True(t, ok) - subIDs = append(subIDs, subID) + if *testConfig.VRFv2Plus.General.CancelSubsAfterTestRun { + //cancel subs and return funds to sub owner + vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, eoaWalletAddress, subIDs, l) + } } + if !*testConfig.VRFv2Plus.General.UseExistingEnv { + if err := testEnv.Cleanup(); err != nil { + l.Error().Err(err).Msg("Error cleaning up test environment") + } + } + } - err = FundNodesIfNeeded(testcontext.Get(t), &testConfig, env.EVMClient, l) - require.NoError(t, err) + newEnvConfig := vrfcommon.NewEnvConfig{ + NodesToCreate: []vrfcommon.VRFNodeType{vrfcommon.VRF}, + NumberOfTxKeysToCreate: *vrfv2PlusConfig.General.NumberOfSendingKeysToCreate, + } - vrfContracts = &vrfcommon.VRFContracts{ - CoordinatorV2Plus: coordinator, - VRFV2PlusConsumer: consumers, - BHS: nil, - } + testEnv, vrfContracts, vrfKey, _, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, testConfig, networkConfig.ChainID, cleanupFn, newEnvConfig, l) + require.NoError(t, err, "error setting up VRFV2Plus universe") - vrfv2PlusData = &vrfcommon.VRFKeyData{ - VRFKey: nil, - EncodedProvingKey: [2]*big.Int{}, - KeyHash: common.HexToHash(*vrfv2PlusConfig.ExistingEnvConfig.KeyHash), - } + evmClient, err := testEnv.GetEVMClient(networkConfig.ChainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") - } else { - network, err := actions.EthereumNetworkConfigFromConfig(l, &testConfig) - require.NoError(t, err, "Error building ethereum network config") - env, err = test_env.NewCLTestEnvBuilder(). - WithTestInstance(t). - WithTestConfig(&testConfig). - WithPrivateEthereumNetwork(network). - WithCLNodes(1). - WithFunding(big.NewFloat(*testConfig.Common.ChainlinkNodeFunding)). - WithCustomCleanup( - func() { - teardown(t, vrfContracts.VRFV2PlusConsumer[0], lc, updatedLabels, testReporter, string(testType), &testConfig) - - if env.EVMClient.NetworkSimulated() { - l.Info(). - Str("Network Name", env.EVMClient.GetNetworkName()). - Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") - } else { - if *testConfig.VRFv2Plus.General.CancelSubsAfterTestRun { - //cancel subs and return funds to sub owner - cancelSubsAndReturnFunds(testcontext.Get(t), subIDs, l) - } - } - if err := env.Cleanup(); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }). - Build() - - require.NoError(t, err, "error creating test env") - - env.ParallelTransactions(true) - - mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*vrfv2PlusConfig.General.LinkNativeFeedResponse)) - require.NoError(t, err, "error deploying mock ETH/LINK feed") - - linkToken, err := actions.DeployLINKToken(env.ContractDeployer) - require.NoError(t, err, "error deploying LINK contract") - - vrfContracts, subIDs, vrfv2PlusData, _, err = vrfv2plus.SetupVRFV2_5Environment( - env, - []vrfcommon.VRFNodeType{vrfcommon.VRF}, - &testConfig, - linkToken, - mockETHLinkFeed, - 0, - 1, - *vrfv2PlusConfig.General.NumberOfSubToCreate, - l, - ) - require.NoError(t, err, "error setting up VRF v2_5 env") - } - eoaWalletAddress = env.EVMClient.GetDefaultWallet().Address() + var consumers []contracts.VRFv2PlusLoadTestConsumer + subIDs, consumers, err = vrfv2plus.SetupSubsAndConsumersForExistingEnv( + testEnv, + networkConfig.ChainID, + vrfContracts.CoordinatorV2Plus, + vrfContracts.LinkToken, + 1, + *vrfv2PlusConfig.General.NumberOfSubToCreate, + testConfig, + l, + ) + vrfContracts.VRFV2PlusConsumer = consumers + + eoaWalletAddress = evmClient.GetDefaultWallet().Address() l.Debug().Int("Number of Subs", len(subIDs)).Msg("Subs involved in the test") for _, subID := range subIDs { @@ -205,30 +126,30 @@ func TestVRFV2PlusPerformance(t *testing.T) { vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) } - singleFeedConfig := &wasp.Config{ - T: t, - LoadType: wasp.RPS, - GenName: "gun", - RateLimitUnitDuration: vrfv2PlusConfig.Performance.RateLimitUnitDuration.Duration, - Gun: NewSingleHashGun( - vrfContracts, - vrfv2PlusData.KeyHash, - subIDs, - &testConfig, - l, - ), - Labels: labels, - LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), - CallTimeout: 2 * time.Minute, - } - require.Len(t, vrfContracts.VRFV2PlusConsumer, 1, "only one consumer should be created for Load Test") - consumer := vrfContracts.VRFV2PlusConsumer[0] - err = consumer.ResetMetrics() - require.NoError(t, err) - MonitorLoadStats(lc, consumer, updatedLabels) - // is our "job" stable at all, no memory leaks, no flaking performance under some RPS? t.Run("vrfv2plus performance test", func(t *testing.T) { + singleFeedConfig := &wasp.Config{ + T: t, + LoadType: wasp.RPS, + GenName: "gun", + RateLimitUnitDuration: vrfv2PlusConfig.Performance.RateLimitUnitDuration.Duration, + Gun: NewSingleHashGun( + vrfContracts, + vrfKey.KeyHash, + subIDs, + vrfv2PlusConfig, + l, + ), + Labels: labels, + LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), + CallTimeout: 2 * time.Minute, + } + require.Len(t, vrfContracts.VRFV2PlusConsumer, 1, "only one consumer should be created for Load Test") + consumer := vrfContracts.VRFV2PlusConsumer[0] + err = consumer.ResetMetrics() + require.NoError(t, err) + MonitorLoadStats(testcontext.Get(t), lc, consumer, updatedLabels) + singleFeedConfig.Schedule = wasp.Plain( *vrfv2PlusConfig.Performance.RPS, vrfv2PlusConfig.Performance.TestDuration.Duration, @@ -250,63 +171,163 @@ func TestVRFV2PlusPerformance(t *testing.T) { Interface("Fulfilment Count", fulfilmentCount). Msg("Final Request/Fulfilment Stats") }) - } -func cancelSubsAndReturnFunds(ctx context.Context, subIDs []*big.Int, l zerolog.Logger) { - for _, subID := range subIDs { - l.Info(). - Str("Returning funds from SubID", subID.String()). - Str("Returning funds to", eoaWalletAddress). - Msg("Canceling subscription and returning funds to subscription owner") - pendingRequestsExist, err := vrfContracts.CoordinatorV2Plus.PendingRequestsExist(ctx, subID) - if err != nil { - l.Error().Err(err).Msg("Error checking if pending requests exist") - } - if !pendingRequestsExist { - _, err := vrfContracts.CoordinatorV2Plus.CancelSubscription(subID, common.HexToAddress(eoaWalletAddress)) - if err != nil { - l.Error().Err(err).Msg("Error canceling subscription") - } - } else { - l.Error().Str("Sub ID", subID.String()).Msg("Pending requests exist for subscription, cannot cancel subscription and return funds") - } +func TestVRFV2PlusBHSPerformance(t *testing.T) { + l := logging.GetTestLogger(t) + + testType, err := tc.GetConfigurationNameFromEnv() + require.NoError(t, err) + testConfig, err := tc.GetConfig(testType, tc.VRFv2Plus) + require.NoError(t, err) + cfgl := testConfig.Logging.Loki + + vrfv2PlusConfig := testConfig.VRFv2Plus + testReporter := &testreporters.VRFV2PlusTestReporter{} + + lokiConfig := wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken) + lc, err := wasp.NewLokiClient(lokiConfig) + if err != nil { + l.Error().Err(err).Msg(ErrLokiClient) + return } -} -func FundNodesIfNeeded(ctx context.Context, vrfv2plusTestConfig tc.VRFv2PlusTestConfig, client blockchain.EVMClient, l zerolog.Logger) error { - cfg := vrfv2plusTestConfig.GetVRFv2PlusConfig() - if cfg.ExistingEnvConfig.NodeSendingKeyFundingMin != nil && *cfg.ExistingEnvConfig.NodeSendingKeyFundingMin > 0 { - for _, sendingKey := range cfg.ExistingEnvConfig.NodeSendingKeys { - address := common.HexToAddress(sendingKey) - sendingKeyBalance, err := client.BalanceAt(ctx, address) - if err != nil { - return err + updatedLabels := UpdateLabels(labels, t) + + l.Info(). + Str("Test Type", testType). + Str("Test Duration", vrfv2PlusConfig.Performance.TestDuration.Duration.Truncate(time.Second).String()). + Int64("RPS", *vrfv2PlusConfig.Performance.RPS). + Str("RateLimitUnitDuration", vrfv2PlusConfig.Performance.RateLimitUnitDuration.String()). + Uint16("RandomnessRequestCountPerRequest", *vrfv2PlusConfig.General.RandomnessRequestCountPerRequest). + Uint16("RandomnessRequestCountPerRequestDeviation", *vrfv2PlusConfig.General.RandomnessRequestCountPerRequestDeviation). + Bool("UseExistingEnv", *vrfv2PlusConfig.General.UseExistingEnv). + Msg("Performance Test Configuration") + + chainID := networks.MustGetSelectedNetworkConfig(testConfig.GetNetworkConfig())[0].ChainID + + cleanupFn := func() { + teardown(t, vrfContracts.VRFV2PlusConsumer[0], lc, updatedLabels, testReporter, testType, &testConfig) + + evmClient, err := testEnv.GetEVMClient(chainID) + require.NoError(t, err, "error getting EVM client") + + if evmClient.NetworkSimulated() { + l.Info(). + Str("Network Name", evmClient.GetNetworkName()). + Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") + } else { + if *testConfig.VRFv2Plus.General.CancelSubsAfterTestRun { + //cancel subs and return funds to sub owner + vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, eoaWalletAddress, subIDs, l) } - fundingAtLeast := conversions.EtherToWei(big.NewFloat(*cfg.ExistingEnvConfig.NodeSendingKeyFundingMin)) - fundingToSendWei := new(big.Int).Sub(fundingAtLeast, sendingKeyBalance) - fundingToSendEth := conversions.WeiToEther(fundingToSendWei) - if fundingToSendWei.Cmp(big.NewInt(0)) == 1 { - l.Info(). - Str("Sending Key", sendingKey). - Str("Sending Key Current Balance", sendingKeyBalance.String()). - Str("Should have at least", fundingAtLeast.String()). - Str("Funding Amount in ETH", fundingToSendEth.String()). - Msg("Funding Node's Sending Key") - err := actions.FundAddress(client, sendingKey, fundingToSendEth) - if err != nil { - return err - } - } else { - l.Info(). - Str("Sending Key", sendingKey). - Str("Sending Key Current Balance", sendingKeyBalance.String()). - Str("Should have at least", fundingAtLeast.String()). - Msg("Skipping Node's Sending Key funding as it has enough funds") + } + if !*testConfig.VRFv2Plus.General.UseExistingEnv { + if err := testEnv.Cleanup(); err != nil { + l.Error().Err(err).Msg("Error cleaning up test environment") } } } - return nil + + newEnvConfig := vrfcommon.NewEnvConfig{ + NodesToCreate: []vrfcommon.VRFNodeType{vrfcommon.VRF}, + NumberOfTxKeysToCreate: *vrfv2PlusConfig.General.NumberOfSendingKeysToCreate, + } + + testEnv, vrfContracts, vrfKey, _, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, testConfig, chainID, cleanupFn, newEnvConfig, l) + require.NoError(t, err, "error setting up VRFV2Plus universe") + + evmClient, err := testEnv.GetEVMClient(chainID) + require.NoError(t, err, "error getting EVM client") + + eoaWalletAddress = evmClient.GetDefaultWallet().Address() + + l.Debug().Int("Number of Subs", len(subIDs)).Msg("Subs involved in the test") + for _, subID := range subIDs { + subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) + require.NoError(t, err, "error getting subscription information for subscription %s", subID.String()) + vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + } + + t.Run("vrfv2plus and bhs performance test", func(t *testing.T) { + configCopy := testConfig.MustCopy().(tc.TestConfig) + //Underfund Subscription + configCopy.VRFv2Plus.General.SubscriptionFundingAmountLink = ptr.Ptr(float64(0)) + consumers, underfundedSubIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + testEnv, + chainID, + vrfContracts.CoordinatorV2Plus, + configCopy, + vrfContracts.LinkToken, + 1, + *configCopy.VRFv2Plus.General.NumberOfSubToCreate, + l, + ) + require.NoError(t, err, "error setting up new consumers and subs for Load Test") + vrfContracts.VRFV2PlusConsumer = consumers + require.Len(t, vrfContracts.VRFV2PlusConsumer, 1, "only one consumer should be created for Load Test") + consumer := vrfContracts.VRFV2PlusConsumer[0] + err = consumer.ResetMetrics() + require.NoError(t, err) + MonitorLoadStats(testcontext.Get(t), lc, consumer, updatedLabels) + + singleFeedConfig := &wasp.Config{ + T: t, + LoadType: wasp.RPS, + GenName: "gun", + RateLimitUnitDuration: configCopy.VRFv2Plus.Performance.BHSTestRateLimitUnitDuration.Duration, + Gun: NewBHSTestGun( + vrfContracts, + vrfKey.KeyHash, + underfundedSubIDs, + configCopy.VRFv2Plus, + l, + ), + Labels: labels, + LokiConfig: lokiConfig, + CallTimeout: 2 * time.Minute, + } + + singleFeedConfig.Schedule = wasp.Plain( + *configCopy.VRFv2Plus.Performance.BHSTestRPS, + configCopy.VRFv2Plus.Performance.BHSTestDuration.Duration, + ) + _, err = wasp.NewProfile(). + Add(wasp.NewGenerator(singleFeedConfig)). + Run(true) + require.NoError(t, err) + + var wgBlockNumberTobe sync.WaitGroup + wgBlockNumberTobe.Add(1) + //Wait at least 256 blocks + latestBlockNumber, err := evmClient.LatestBlockNumber(testcontext.Get(t)) + require.NoError(t, err, "error getting latest block number") + _, err = actions.WaitForBlockNumberToBe(latestBlockNumber+uint64(256), evmClient, &wgBlockNumberTobe, configCopy.VRFv2Plus.General.WaitFor256BlocksTimeout.Duration, t) + wgBlockNumberTobe.Wait() + require.NoError(t, err, "error waiting for block number to be") + + err = vrfv2plus.FundSubscriptions( + testEnv, + chainID, + big.NewFloat(*configCopy.VRFv2Plus.General.SubscriptionRefundingAmountNative), + big.NewFloat(*configCopy.VRFv2Plus.General.SubscriptionRefundingAmountLink), + vrfContracts.LinkToken, + vrfContracts.CoordinatorV2Plus, + subIDs, + ) + require.NoError(t, err, "error funding subscriptions") + + var wgAllRequestsFulfilled sync.WaitGroup + wgAllRequestsFulfilled.Add(1) + requestCount, fulfilmentCount, err := vrfcommon.WaitForRequestCountEqualToFulfilmentCount(testcontext.Get(t), consumer, 2*time.Minute, &wgAllRequestsFulfilled) + require.NoError(t, err) + wgAllRequestsFulfilled.Wait() + + l.Info(). + Interface("Request Count", requestCount). + Interface("Fulfilment Count", fulfilmentCount). + Msg("Final Request/Fulfilment Stats") + }) } func teardown( @@ -319,7 +340,7 @@ func teardown( testConfig *tc.TestConfig, ) { //send final results to Loki - metrics := GetLoadTestMetrics(consumer) + metrics := GetLoadTestMetrics(testcontext.Get(t), consumer) SendMetricsToLoki(metrics, lc, updatedLabels) //set report data for Slack notification testReporter.SetReportData( @@ -330,6 +351,8 @@ func teardown( AverageFulfillmentInMillions: metrics.AverageFulfillmentInMillions, SlowestFulfillment: metrics.SlowestFulfillment, FastestFulfillment: metrics.FastestFulfillment, + P90FulfillmentBlockTime: metrics.P90FulfillmentBlockTime, + P95FulfillmentBlockTime: metrics.P95FulfillmentBlockTime, AverageResponseTimeInSecondsMillions: metrics.AverageResponseTimeInSecondsMillions, SlowestResponseTimeInSeconds: metrics.SlowestResponseTimeInSeconds, FastestResponseTimeInSeconds: metrics.FastestResponseTimeInSeconds, diff --git a/integration-tests/migration/upgrade_version_test.go b/integration-tests/migration/upgrade_version_test.go index 584a9fbc75e..47761c09e50 100644 --- a/integration-tests/migration/upgrade_version_test.go +++ b/integration-tests/migration/upgrade_version_test.go @@ -5,6 +5,8 @@ import ( "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" @@ -13,19 +15,25 @@ import ( func TestVersionUpgrade(t *testing.T) { t.Parallel() + l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Migration", tc.Node) require.NoError(t, err, "Error getting config") err = config.ChainlinkUpgradeImage.Validate() require.NoError(t, err, "Error validating upgrade image") + privateNetwork, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") + env, err := test_env.NewCLTestEnvBuilder(). WithTestConfig(&config). WithTestInstance(t). WithStandardCleanup(). - WithGeth(). + WithPrivateEthereumNetwork(privateNetwork). WithCLNodes(1). WithStandardCleanup(). + WithSeth(). Build() require.NoError(t, err) diff --git a/integration-tests/reorg/automation_reorg_test.go b/integration-tests/reorg/automation_reorg_test.go index fe87ac1aa3f..7a2215c36f0 100644 --- a/integration-tests/reorg/automation_reorg_test.go +++ b/integration-tests/reorg/automation_reorg_test.go @@ -96,6 +96,7 @@ LimitDefault = 5_000_000` FallbackLinkPrice: big.NewInt(2e18), MaxCheckDataSize: uint32(5000), MaxPerformDataSize: uint32(5000), + MaxRevertDataSize: uint32(5000), } ) diff --git a/integration-tests/scripts/buildEvmClientTestMatrixList.sh b/integration-tests/scripts/buildEvmClientTestMatrixList.sh new file mode 100755 index 00000000000..2f0e27b7fb8 --- /dev/null +++ b/integration-tests/scripts/buildEvmClientTestMatrixList.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash + +# requires a path to a json file with all the tests it should run +# requires a node label to be passed in, for example "ubuntu-latest" + +set -e + +# get this script's directory +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) + +cd "$SCRIPT_DIR"/../ || exit 1 + +JSONFILE=$1 +NODE_LABEL=$2 + +COUNTER=1 + +# Build a JSON object in the format expected by our evm-version-compatibility-tests workflow matrix +matrix_output() { + local counter=$1 + local job_name=$2 + local test_name=$3 + local node_label=$4 + local eth_client=$5 + local docker_image=$6 + local product=$7 + local counter_out=$(printf "%02d\n" $counter) + echo -n "{\"name\": \"${job_name}-${counter_out}\", \"os\": \"${node_label}\", \"product\": \"${product}\", \"eth_client\": \"${eth_client}\", \"docker_image\": \"${docker_image}\", \"run\": \"-run '^${test_name}$'\"}" +} + +# Read the JSON file and loop through 'tests' and 'run' +jq -c '.tests[]' ${JSONFILE} | while read -r test; do + testName=$(echo ${test} | jq -r '.name') + label=$(echo ${test} | jq -r '.label // empty') + effective_node_label=${label:-$NODE_LABEL} + eth_client=$(echo ${test} | jq -r '.eth_client') + docker_image=$(echo ${test} | jq -r '.docker_image') + product=$(echo ${test} | jq -r '.product') + subTests=$(echo ${test} | jq -r '.run[]?.name // empty') + output="" + + if [ $COUNTER -ne 1 ]; then + echo -n "," + fi + + # Loop through subtests, if any, and print in the desired format + if [ -n "$subTests" ]; then + subTestString="" + subTestCounter=1 + for subTest in $subTests; do + if [ $subTestCounter -ne 1 ]; then + subTestString+="|" + fi + subTestString+="${testName}\/${subTest}" + ((subTestCounter++)) + done + testName="${subTestString}" + fi + matrix_output $COUNTER "emv-node-version-compatibility-test" "${testName}" ${effective_node_label} "${eth_client}" "${docker_image}" "${product}" + ((COUNTER++)) +done > "./tmpout.json" +OUTPUT=$(cat ./tmpout.json) +echo "[${OUTPUT}]" +rm ./tmpout.json \ No newline at end of file diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index 8cdd4f25686..73a7749c4e1 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -44,22 +44,23 @@ const ( defaultAmountOfUpkeeps = 2 ) -var ( - automationDefaultRegistryConfig = contracts.KeeperRegistrySettings{ - PaymentPremiumPPB: uint32(200000000), - FlatFeeMicroLINK: uint32(0), - BlockCountPerTurn: big.NewInt(10), - CheckGasLimit: uint32(2500000), - StalenessSeconds: big.NewInt(90000), - GasCeilingMultiplier: uint16(1), - MinUpkeepSpend: big.NewInt(0), - MaxPerformGas: uint32(5000000), - FallbackGasPrice: big.NewInt(2e11), - FallbackLinkPrice: big.NewInt(2e18), - MaxCheckDataSize: uint32(5000), - MaxPerformDataSize: uint32(5000), +func automationDefaultRegistryConfig(c tc.AutomationTestConfig) contracts.KeeperRegistrySettings { + registrySettings := c.GetAutomationConfig().AutomationConfig.RegistrySettings + return contracts.KeeperRegistrySettings{ + PaymentPremiumPPB: *registrySettings.PaymentPremiumPPB, + FlatFeeMicroLINK: *registrySettings.FlatFeeMicroLINK, + CheckGasLimit: *registrySettings.CheckGasLimit, + StalenessSeconds: registrySettings.StalenessSeconds, + GasCeilingMultiplier: *registrySettings.GasCeilingMultiplier, + MinUpkeepSpend: registrySettings.MinUpkeepSpend, + MaxPerformGas: *registrySettings.MaxPerformGas, + FallbackGasPrice: registrySettings.FallbackGasPrice, + FallbackLinkPrice: registrySettings.FallbackLinkPrice, + MaxCheckDataSize: *registrySettings.MaxCheckDataSize, + MaxPerformDataSize: *registrySettings.MaxPerformDataSize, + MaxRevertDataSize: *registrySettings.MaxRevertDataSize, } -) +} func TestMain(m *testing.M) { logging.Init() @@ -120,7 +121,7 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool, automationTestConfig t isMercury := isMercuryV02 || isMercuryV03 a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, isMercuryV02, isMercuryV03, automationTestConfig, + t, registryVersion, automationDefaultRegistryConfig(automationTestConfig), isMercuryV02, isMercuryV03, automationTestConfig, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -250,7 +251,7 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { } a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, &config, + t, registryVersion, automationDefaultRegistryConfig(config), false, false, &config, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -432,7 +433,7 @@ func TestAutomationAddFunds(t *testing.T) { t.Fatal(err) } a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, &config, + t, registryVersion, automationDefaultRegistryConfig(config), false, false, &config, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -500,7 +501,7 @@ func TestAutomationPauseUnPause(t *testing.T) { t.Fatal(err) } a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, &config, + t, registryVersion, automationDefaultRegistryConfig(config), false, false, &config, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -600,7 +601,7 @@ func TestAutomationRegisterUpkeep(t *testing.T) { t.Fatal(err) } a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, &config, + t, registryVersion, automationDefaultRegistryConfig(config), false, false, &config, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -688,7 +689,7 @@ func TestAutomationPauseRegistry(t *testing.T) { t.Fatal(err) } a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, &config, + t, registryVersion, automationDefaultRegistryConfig(config), false, false, &config, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -763,7 +764,7 @@ func TestAutomationKeeperNodesDown(t *testing.T) { t.Fatal(err) } a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, &config, + t, registryVersion, automationDefaultRegistryConfig(config), false, false, &config, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -867,7 +868,7 @@ func TestAutomationPerformSimulation(t *testing.T) { t.Fatal(err) } a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, &config, + t, registryVersion, automationDefaultRegistryConfig(config), false, false, &config, ) consumersPerformance, _ := actions.DeployPerformanceConsumers( @@ -936,7 +937,7 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { t.Fatal(err) } a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, &config, + t, registryVersion, automationDefaultRegistryConfig(config), false, false, &config, ) consumersPerformance, upkeepIDs := actions.DeployPerformanceConsumers( @@ -1012,7 +1013,7 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { l.Info().Int64("Upkeep counter", existingCntInt).Msg("Upkeep counter when consistently block finished") // Now increase checkGasLimit on registry - highCheckGasLimit := automationDefaultRegistryConfig + highCheckGasLimit := automationDefaultRegistryConfig(config) highCheckGasLimit.CheckGasLimit = uint32(5000000) highCheckGasLimit.RegistryVersion = registryVersion @@ -1060,7 +1061,7 @@ func TestUpdateCheckData(t *testing.T) { } a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, &config, + t, registryVersion, automationDefaultRegistryConfig(config), false, false, &config, ) performDataChecker, upkeepIDs := actions.DeployPerformDataCheckerConsumers( @@ -1151,11 +1152,15 @@ func setupAutomationTestDocker( require.NoError(t, err) l.Debug().Msgf("Funding amount: %f", *automationTestConfig.GetCommonConfig().ChainlinkNodeFunding) clNodesCount := 5 + + privateNetwork, err := actions.EthereumNetworkConfigFromConfig(l, automationTestConfig) + require.NoError(t, err, "Error building ethereum network config") + if isMercuryV02 || isMercuryV03 { env, err = test_env.NewCLTestEnvBuilder(). WithTestInstance(t). WithTestConfig(automationTestConfig). - WithGeth(). + WithPrivateEthereumNetwork(privateNetwork). WithMockAdapter(). WithFunding(big.NewFloat(*automationTestConfig.GetCommonConfig().ChainlinkNodeFunding)). WithStandardCleanup(). @@ -1171,11 +1176,14 @@ func setupAutomationTestDocker( Password = 'nodepass'` secretsConfig = fmt.Sprintf(secretsConfig, env.MockAdapter.InternalEndpoint, env.MockAdapter.InternalEndpoint) + rpcProvider, err := env.GetRpcProvider(network.ChainID) + require.NoError(t, err, "Error getting rpc provider") + var httpUrls []string var wsUrls []string if network.Simulated { - httpUrls = []string{env.RpcProvider.PrivateHttpUrls()[0]} - wsUrls = []string{env.RpcProvider.PrivateWsUrsl()[0]} + httpUrls = []string{rpcProvider.PrivateHttpUrls()[0]} + wsUrls = []string{rpcProvider.PrivateWsUrsl()[0]} } else { httpUrls = network.HTTPURLs wsUrls = network.URLs @@ -1192,7 +1200,7 @@ func setupAutomationTestDocker( env, err = test_env.NewCLTestEnvBuilder(). WithTestInstance(t). WithTestConfig(automationTestConfig). - WithGeth(). + WithPrivateEthereumNetwork(privateNetwork). WithMockAdapter(). WithCLNodes(clNodesCount). WithCLNodeConfig(clNodeConfig). @@ -1205,37 +1213,42 @@ func setupAutomationTestDocker( env.ParallelTransactions(true) nodeClients := env.ClCluster.NodeAPIs() - a := automationv2.NewAutomationTestDocker(env.EVMClient, env.ContractDeployer, nodeClients) - a.MercuryCredentialName = "cred1" + evmClient, err := env.GetEVMClient(network.ChainID) + require.NoError(t, err, "Error getting evm client") + + a := automationv2.NewAutomationTestDocker(evmClient, env.ContractDeployer, nodeClients) + a.SetMercuryCredentialName("cred1") a.RegistrySettings = registryConfig a.RegistrarSettings = contracts.KeeperRegistrarSettings{ AutoApproveConfigType: uint8(2), AutoApproveMaxAllowed: 1000, MinLinkJuels: big.NewInt(0), } + plCfg := automationTestConfig.GetAutomationConfig().AutomationConfig.PluginConfig a.PluginConfig = ocr2keepers30config.OffchainConfig{ - TargetProbability: "0.999", - TargetInRounds: 1, - PerformLockoutWindow: 3_600_000, // Intentionally set to be higher than in prod for testing purpose - GasLimitPerReport: 10_300_000, - GasOverheadPerUpkeep: 300_000, - MinConfirmations: 0, - MaxUpkeepBatchSize: 10, + TargetProbability: *plCfg.TargetProbability, + TargetInRounds: *plCfg.TargetInRounds, + PerformLockoutWindow: *plCfg.PerformLockoutWindow, + GasLimitPerReport: *plCfg.GasLimitPerReport, + GasOverheadPerUpkeep: *plCfg.GasOverheadPerUpkeep, + MinConfirmations: *plCfg.MinConfirmations, + MaxUpkeepBatchSize: *plCfg.MaxUpkeepBatchSize, } + pubCfg := automationTestConfig.GetAutomationConfig().AutomationConfig.PublicConfig a.PublicConfig = ocr3.PublicConfig{ - DeltaProgress: 10 * time.Second, - DeltaResend: 15 * time.Second, - DeltaInitial: 500 * time.Millisecond, - DeltaRound: 1000 * time.Millisecond, - DeltaGrace: 200 * time.Millisecond, - DeltaCertifiedCommitRequest: 300 * time.Millisecond, - DeltaStage: 30 * time.Second, - RMax: 24, - MaxDurationQuery: 20 * time.Millisecond, - MaxDurationObservation: 20 * time.Millisecond, - MaxDurationShouldAcceptAttestedReport: 1200 * time.Millisecond, - MaxDurationShouldTransmitAcceptedReport: 20 * time.Millisecond, - F: 1, + DeltaProgress: *pubCfg.DeltaProgress, + DeltaResend: *pubCfg.DeltaResend, + DeltaInitial: *pubCfg.DeltaInitial, + DeltaRound: *pubCfg.DeltaRound, + DeltaGrace: *pubCfg.DeltaGrace, + DeltaCertifiedCommitRequest: *pubCfg.DeltaCertifiedCommitRequest, + DeltaStage: *pubCfg.DeltaStage, + RMax: *pubCfg.RMax, + MaxDurationQuery: *pubCfg.MaxDurationQuery, + MaxDurationObservation: *pubCfg.MaxDurationObservation, + MaxDurationShouldAcceptAttestedReport: *pubCfg.MaxDurationShouldAcceptAttestedReport, + MaxDurationShouldTransmitAcceptedReport: *pubCfg.MaxDurationShouldTransmitAcceptedReport, + F: *pubCfg.F, } a.SetupAutomationDeployment(t) diff --git a/integration-tests/smoke/cron_test.go b/integration-tests/smoke/cron_test.go index b6e04612aca..218727b7d66 100644 --- a/integration-tests/smoke/cron_test.go +++ b/integration-tests/smoke/cron_test.go @@ -11,6 +11,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" @@ -25,13 +26,17 @@ func TestCronBasic(t *testing.T) { t.Fatal(err) } + privateNetwork, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") + env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). WithTestConfig(&config). - WithGeth(). + WithPrivateEthereumNetwork(privateNetwork). WithMockAdapter(). WithCLNodes(1). WithStandardCleanup(). + WithSeth(). Build() require.NoError(t, err) @@ -77,13 +82,17 @@ func TestCronJobReplacement(t *testing.T) { t.Fatal(err) } + privateNetwork, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") + env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). WithTestConfig(&config). - WithGeth(). + WithPrivateEthereumNetwork(privateNetwork). WithMockAdapter(). WithCLNodes(1). WithStandardCleanup(). + WithSeth(). Build() require.NoError(t, err) diff --git a/integration-tests/smoke/evm_node_compatibility_test_list.json b/integration-tests/smoke/evm_node_compatibility_test_list.json new file mode 100644 index 00000000000..c14a2b54a3e --- /dev/null +++ b/integration-tests/smoke/evm_node_compatibility_test_list.json @@ -0,0 +1,214 @@ +{ + "tests": [ + { + "product": "ocr", + "name": "TestOCRBasic", + "eth_client": "geth", + "docker_image": "ethereum/client-go:latest_stable", + "label": "ubuntu-latest" + }, + { + "product": "ocr", + "name": "TestOCRBasic", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.13.0", + "label": "ubuntu-latest" + }, + { + "product": "ocr", + "name": "TestOCRBasic", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.12.0", + "label": "ubuntu-latest" + }, + { + "product": "ocr", + "name": "TestOCRBasic", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.11.0", + "label": "ubuntu-latest" + }, + { + "product": "ocr", + "name": "TestOCRBasic", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.10.0", + "label": "ubuntu-latest" + }, + { + "product": "ocr2", + "name": "TestOCRv2Request", + "eth_client": "geth", + "docker_image": "ethereum/client-go:latest_stable", + "label": "ubuntu-latest" + }, + { + "product": "ocr2", + "name": "TestOCRv2Request", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.13.0", + "label": "ubuntu-latest" + }, + { + "product": "ocr2", + "name": "TestOCRv2Request", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.12.0", + "label": "ubuntu-latest" + }, + { + "product": "ocr2", + "name": "TestOCRv2Request", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.11.0", + "label": "ubuntu-latest" + }, + { + "product": "ocr2", + "name": "TestOCRv2Request", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.10.0", + "label": "ubuntu-latest" + }, + { + "product": "vrf", + "name": "TestVRFBasic", + "eth_client": "geth", + "docker_image": "ethereum/client-go:latest_stable", + "label": "ubuntu-latest" + }, + { + "product": "vrf", + "name": "TestVRFBasic", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.13.0", + "label": "ubuntu-latest" + }, + { + "product": "vrf", + "name": "TestVRFBasic", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.12.0", + "label": "ubuntu-latest" + }, + { + "product": "vrf", + "name": "TestVRFBasic", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.11.0", + "label": "ubuntu-latest" + }, + { + "product": "vrf", + "name": "TestVRFBasic", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.10.0", + "label": "ubuntu-latest" + }, + { + "product": "vrfv2", + "name": "TestVRFv2Basic/Request Randomness", + "eth_client": "geth", + "docker_image": "ethereum/client-go:latest_stable", + "label": "ubuntu-latest" + }, + { + "product": "vrfv2", + "name": "TestVRFv2Basic/Request Randomness", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.13.0", + "label": "ubuntu-latest" + }, + { + "product": "vrfv2", + "name": "TestVRFv2Basic/Request Randomness", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.12.0", + "label": "ubuntu-latest" + }, + { + "product": "vrfv2", + "name": "TestVRFv2Basic/Request Randomness", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.11.0", + "label": "ubuntu-latest" + }, + { + "product": "vrfv2", + "name": "TestVRFv2Basic/Request Randomness", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.10.0", + "label": "ubuntu-latest" + }, + { + "product": "vrfv2plus", + "name": "TestVRFv2Plus/Link Billing", + "eth_client": "geth", + "docker_image": "ethereum/client-go:latest_stable", + "label": "ubuntu-latest" + }, + { + "product": "vrfv2plus", + "name": "TestVRFv2Plus/Link Billing", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.13.0", + "label": "ubuntu-latest" + }, + { + "product": "vrfv2plus", + "name": "TestVRFv2Plus/Link Billing", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.12.0", + "label": "ubuntu-latest" + }, + { + "product": "vrfv2plus", + "name": "TestVRFv2Plus/Link Billing", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.11.0", + "label": "ubuntu-latest" + }, + { + "product": "vrfv2plus", + "name": "TestVRFv2Plus/Link Billing", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.10.0", + "label": "ubuntu-latest" + }, + { + "product": "automation", + "name": "TestSetUpkeepTriggerConfig", + "eth_client": "geth", + "docker_image": "ethereum/client-go:latest_stable", + "label": "ubuntu-latest" + }, + { + "product": "automation", + "name": "TestSetUpkeepTriggerConfig", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.13.0", + "label": "ubuntu-latest" + }, + { + "product": "automation", + "name": "TestSetUpkeepTriggerConfig", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.12.0", + "label": "ubuntu-latest" + }, + { + "product": "automation", + "name": "TestSetUpkeepTriggerConfig", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.11.0", + "label": "ubuntu-latest" + }, + { + "product": "automation", + "name": "TestSetUpkeepTriggerConfig", + "eth_client": "geth", + "docker_image": "ethereum/client-go:v1.10.0", + "label": "ubuntu-latest" + } + ] +} \ No newline at end of file diff --git a/integration-tests/smoke/flux_test.go b/integration-tests/smoke/flux_test.go index c8cec4e385b..023dd9dae89 100644 --- a/integration-tests/smoke/flux_test.go +++ b/integration-tests/smoke/flux_test.go @@ -13,9 +13,11 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" + actions_seth "github.com/smartcontractkit/chainlink/integration-tests/actions/seth" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" @@ -31,36 +33,40 @@ func TestFluxBasic(t *testing.T) { t.Fatal(err) } + privateNetwork, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") + env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). WithTestConfig(&config). - WithGeth(). + WithPrivateEthereumNetwork(privateNetwork). WithMockAdapter(). WithCLNodes(3). WithStandardCleanup(). + WithSeth(). Build() require.NoError(t, err) nodeAddresses, err := env.ClCluster.NodeAddresses() require.NoError(t, err, "Retrieving on-chain wallet addresses for chainlink nodes shouldn't fail") - env.EVMClient.ParallelTransactions(true) + + network := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0] + sethClient, err := env.GetSethClient(network.ChainID) + require.NoError(t, err, "Error getting seth client") adapterUUID := uuid.NewString() adapterPath := fmt.Sprintf("/variable-%s", adapterUUID) err = env.MockAdapter.SetAdapterBasedIntValuePath(adapterPath, []string{http.MethodPost}, 1e5) require.NoError(t, err, "Setting mock adapter value path shouldn't fail") - lt, err := actions.DeployLINKToken(env.ContractDeployer) + lt, err := contracts.DeployLinkTokenContract(l, sethClient) require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") - fluxInstance, err := env.ContractDeployer.DeployFluxAggregatorContract(lt.Address(), contracts.DefaultFluxAggregatorOptions()) + + fluxInstance, err := contracts.DeployFluxAggregatorContract(sethClient, lt.Address(), contracts.DefaultFluxAggregatorOptions()) require.NoError(t, err, "Deploying Flux Aggregator Contract shouldn't fail") - err = env.EVMClient.WaitForEvents() - require.NoError(t, err, "Failed waiting for deployment of flux aggregator contract") err = lt.Transfer(fluxInstance.Address(), big.NewInt(1e18)) require.NoError(t, err, "Funding Flux Aggregator Contract shouldn't fail") - err = env.EVMClient.WaitForEvents() - require.NoError(t, err, "Failed waiting for funding of flux aggregator contract") err = fluxInstance.UpdateAvailableFunds() require.NoError(t, err, "Updating the available funds on the Flux Aggregator Contract shouldn't fail") @@ -79,8 +85,6 @@ func TestFluxBasic(t *testing.T) { }) require.NoError(t, err, "Setting oracle options in the Flux Aggregator contract shouldn't fail") - err = env.EVMClient.WaitForEvents() - require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") oracles, err := fluxInstance.GetOracles(testcontext.Get(t)) require.NoError(t, err, "Getting oracle details from the Flux aggregator contract shouldn't fail") l.Info().Str("Oracles", strings.Join(oracles, ",")).Msg("Oracles set") @@ -98,7 +102,7 @@ func TestFluxBasic(t *testing.T) { fluxSpec := &client.FluxMonitorJobSpec{ Name: fmt.Sprintf("flux-monitor-%s", adapterUUID), ContractAddress: fluxInstance.Address(), - EVMChainID: env.EVMClient.GetChainID().String(), + EVMChainID: fmt.Sprint(sethClient.ChainID), Threshold: 0, AbsoluteThreshold: 0, PollTimerPeriod: 15 * time.Second, // min 15s @@ -111,9 +115,7 @@ func TestFluxBasic(t *testing.T) { // initial value set is performed before jobs creation fluxRoundTimeout := 1 * time.Minute - fluxRound := contracts.NewFluxAggregatorRoundConfirmer(fluxInstance, big.NewInt(1), fluxRoundTimeout, l) - env.EVMClient.AddHeaderEventSubscription(fluxInstance.Address(), fluxRound) - err = env.EVMClient.WaitForEvents() + err = actions_seth.WatchNewFluxRound(l, sethClient, 1, fluxInstance, fluxRoundTimeout) require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") data, err := fluxInstance.GetContractData(testcontext.Get(t)) require.NoError(t, err, "Getting contract data from flux aggregator contract shouldn't fail") @@ -128,11 +130,9 @@ func TestFluxBasic(t *testing.T) { require.Equal(t, int64(3), data.AllocatedFunds.Int64(), "Expected allocated funds to be %d, but found %d", int64(3), data.AllocatedFunds.Int64()) - fluxRound = contracts.NewFluxAggregatorRoundConfirmer(fluxInstance, big.NewInt(2), fluxRoundTimeout, l) - env.EVMClient.AddHeaderEventSubscription(fluxInstance.Address(), fluxRound) err = env.MockAdapter.SetAdapterBasedIntValuePath(adapterPath, []string{http.MethodPost}, 1e10) require.NoError(t, err, "Setting value path in mock server shouldn't fail") - err = env.EVMClient.WaitForEvents() + err = actions_seth.WatchNewFluxRound(l, sethClient, 2, fluxInstance, fluxRoundTimeout) require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") data, err = fluxInstance.GetContractData(testcontext.Get(t)) require.NoError(t, err, "Getting contract data from flux aggregator contract shouldn't fail") diff --git a/integration-tests/smoke/forwarder_ocr_test.go b/integration-tests/smoke/forwarder_ocr_test.go index 60fe1db3c25..5a8e51f871f 100644 --- a/integration-tests/smoke/forwarder_ocr_test.go +++ b/integration-tests/smoke/forwarder_ocr_test.go @@ -1,16 +1,21 @@ package smoke import ( + "fmt" "math/big" "testing" + "time" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" + actions_seth "github.com/smartcontractkit/chainlink/integration-tests/actions/seth" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) @@ -24,15 +29,19 @@ func TestForwarderOCRBasic(t *testing.T) { t.Fatal(err) } + privateNetwork, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") + env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). WithTestConfig(&config). - WithGeth(). + WithPrivateEthereumNetwork(privateNetwork). WithMockAdapter(). WithForwarders(). WithCLNodes(6). WithFunding(big.NewFloat(.1)). WithStandardCleanup(). + WithSeth(). Build() require.NoError(t, err) @@ -44,42 +53,42 @@ func TestForwarderOCRBasic(t *testing.T) { workerNodeAddresses, err := actions.ChainlinkNodeAddressesLocal(workerNodes) require.NoError(t, err, "Retreiving on-chain wallet addresses for chainlink nodes shouldn't fail") - linkTokenContract, err := env.ContractDeployer.DeployLinkTokenContract() + selectedNetwork := networks.MustGetSelectedNetworkConfig(config.Network)[0] + sethClient, err := env.GetSethClient(selectedNetwork.ChainID) + require.NoError(t, err, "Error getting seth client") + + lt, err := contracts.DeployLinkTokenContract(l, sethClient) require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") - err = actions.FundChainlinkNodesLocal(workerNodes, env.EVMClient, big.NewFloat(.05)) + fundingAmount := big.NewFloat(.05) + l.Info().Str("ETH amount per node", fundingAmount.String()).Msg("Funding Chainlink nodes") + err = actions_seth.FundChainlinkNodesFromRootAddress(l, sethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(workerNodes), fundingAmount) require.NoError(t, err, "Error funding Chainlink nodes") - //nolint:staticcheck //ignore SA1019 we will migrate that test later - operators, authorizedForwarders, _ := actions.DeployForwarderContracts( - t, env.ContractDeployer, linkTokenContract, env.EVMClient, len(workerNodes), + operators, authorizedForwarders, _ := actions_seth.DeployForwarderContracts( + t, sethClient, common.HexToAddress(lt.Address()), len(workerNodes), ) for i := range workerNodes { - //nolint:staticcheck //ignore SA1019 we will migrate that test later - actions.AcceptAuthorizedReceiversOperator( - t, operators[i], authorizedForwarders[i], []common.Address{workerNodeAddresses[i]}, env.EVMClient, env.ContractLoader, + actions_seth.AcceptAuthorizedReceiversOperator( + t, l, sethClient, operators[i], authorizedForwarders[i], []common.Address{workerNodeAddresses[i]}, ) require.NoError(t, err, "Accepting Authorize Receivers on Operator shouldn't fail") - err = actions.TrackForwarderLocal(env.EVMClient, authorizedForwarders[i], workerNodes[i], l) - require.NoError(t, err) - err = env.EVMClient.WaitForEvents() + actions_seth.TrackForwarder(t, sethClient, authorizedForwarders[i], workerNodes[i]) } - ocrInstances, err := actions.DeployOCRContractsForwarderFlowLocal( + ocrInstances, err := actions_seth.DeployOCRContractsForwarderFlow( + l, + sethClient, 1, - linkTokenContract, - env.ContractDeployer, - workerNodes, + common.HexToAddress(lt.Address()), + contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(workerNodes), authorizedForwarders, - env.EVMClient, ) require.NoError(t, err, "Error deploying OCR contracts") - err = actions.CreateOCRJobsWithForwarderLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, env.EVMClient.GetChainID().String()) + err = actions.CreateOCRJobsWithForwarderLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, fmt.Sprint(sethClient.ChainID)) require.NoError(t, err, "failed to setup forwarder jobs") - err = actions.WatchNewRound(1, ocrInstances, env.EVMClient, l) - require.NoError(t, err) - err = env.EVMClient.WaitForEvents() - require.NoError(t, err, "Error waiting for events") + err = actions_seth.WatchNewOCRRound(l, sethClient, 1, contracts.V1OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), time.Duration(10*time.Minute)) + require.NoError(t, err, "error watching for new OCR round") answer, err := ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") @@ -87,10 +96,8 @@ func TestForwarderOCRBasic(t *testing.T) { err = actions.SetAllAdapterResponsesToTheSameValueLocal(10, ocrInstances, workerNodes, env.MockAdapter) require.NoError(t, err) - err = actions.WatchNewRound(2, ocrInstances, env.EVMClient, l) - require.NoError(t, err) - err = env.EVMClient.WaitForEvents() - require.NoError(t, err, "Error waiting for events") + err = actions_seth.WatchNewOCRRound(l, sethClient, 2, contracts.V1OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), time.Duration(10*time.Minute)) + require.NoError(t, err, "error watching for new OCR round") answer, err = ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) require.NoError(t, err, "Error getting latest OCR answer") diff --git a/integration-tests/smoke/forwarders_ocr2_test.go b/integration-tests/smoke/forwarders_ocr2_test.go index 7c5b988276b..ee86e8cc4b6 100644 --- a/integration-tests/smoke/forwarders_ocr2_test.go +++ b/integration-tests/smoke/forwarders_ocr2_test.go @@ -11,9 +11,11 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" + actions_seth "github.com/smartcontractkit/chainlink/integration-tests/actions/seth" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" @@ -30,10 +32,13 @@ func TestForwarderOCR2Basic(t *testing.T) { t.Fatal(err) } + privateNetwork, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") + env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). WithTestConfig(&config). - WithGeth(). + WithPrivateEthereumNetwork(privateNetwork). WithMockAdapter(). WithCLNodeConfig(node.NewConfig(node.NewBaseConfig(), node.WithOCR2(), @@ -43,36 +48,38 @@ func TestForwarderOCR2Basic(t *testing.T) { WithCLNodes(6). WithFunding(big.NewFloat(.1)). WithStandardCleanup(). + WithSeth(). Build() require.NoError(t, err) - env.ParallelTransactions(true) - nodeClients := env.ClCluster.NodeAPIs() bootstrapNode, workerNodes := nodeClients[0], nodeClients[1:] workerNodeAddresses, err := actions.ChainlinkNodeAddressesLocal(workerNodes) require.NoError(t, err, "Retreiving on-chain wallet addresses for chainlink nodes shouldn't fail") - linkTokenContract, err := env.ContractDeployer.DeployLinkTokenContract() + selectedNetwork := networks.MustGetSelectedNetworkConfig(config.Network)[0] + sethClient, err := env.GetSethClient(selectedNetwork.ChainID) + require.NoError(t, err, "Error getting seth client") + + lt, err := contracts.DeployLinkTokenContract(l, sethClient) require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") - err = actions.FundChainlinkNodesLocal(workerNodes, env.EVMClient, big.NewFloat(.05)) + fundingAmount := big.NewFloat(.05) + l.Info().Str("ETH amount per node", fundingAmount.String()).Msg("Funding Chainlink nodes") + err = actions_seth.FundChainlinkNodesFromRootAddress(l, sethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(workerNodes), fundingAmount) require.NoError(t, err, "Error funding Chainlink nodes") - //nolint:staticcheck //ignore SA1019 we will migrate that test later - operators, authorizedForwarders, _ := actions.DeployForwarderContracts( - t, env.ContractDeployer, linkTokenContract, env.EVMClient, len(workerNodes), + operators, authorizedForwarders, _ := actions_seth.DeployForwarderContracts( + t, sethClient, common.HexToAddress(lt.Address()), len(workerNodes), ) for i := range workerNodes { - //nolint:staticcheck //ignore SA1019 we will migrate that test later - actions.AcceptAuthorizedReceiversOperator(t, operators[i], authorizedForwarders[i], []common.Address{workerNodeAddresses[i]}, env.EVMClient, env.ContractLoader) - require.NoError(t, err, "Accepting Authorized Receivers on Operator shouldn't fail") - err = actions.TrackForwarderLocal(env.EVMClient, authorizedForwarders[i], workerNodes[i], l) - require.NoError(t, err, "failed to track forwarders") - err = env.EVMClient.WaitForEvents() - require.NoError(t, err, "Error waiting for events") + actions_seth.AcceptAuthorizedReceiversOperator( + t, l, sethClient, operators[i], authorizedForwarders[i], []common.Address{workerNodeAddresses[i]}, + ) + require.NoError(t, err, "Accepting Authorize Receivers on Operator shouldn't fail") + actions_seth.TrackForwarder(t, sethClient, authorizedForwarders[i], workerNodes[i]) } // Gather transmitters @@ -82,26 +89,21 @@ func TestForwarderOCR2Basic(t *testing.T) { } ocrOffchainOptions := contracts.DefaultOffChainAggregatorOptions() - ocrInstances, err := actions.DeployOCRv2Contracts(1, linkTokenContract, env.ContractDeployer, transmitters, env.EVMClient, ocrOffchainOptions) + ocrInstances, err := actions_seth.DeployOCRv2Contracts(l, sethClient, 1, common.HexToAddress(lt.Address()), transmitters, ocrOffchainOptions) require.NoError(t, err, "Error deploying OCRv2 contracts with forwarders") - err = env.EVMClient.WaitForEvents() - require.NoError(t, err, "Error waiting for events") - err = actions.CreateOCRv2JobsLocal(ocrInstances, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 5, env.EVMClient.GetChainID().Uint64(), true, false) + err = actions.CreateOCRv2JobsLocal(ocrInstances, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 5, uint64(sethClient.ChainID), true, false) require.NoError(t, err, "Error creating OCRv2 jobs with forwarders") - err = env.EVMClient.WaitForEvents() - require.NoError(t, err, "Error waiting for events") ocrv2Config, err := actions.BuildMedianOCR2ConfigLocal(workerNodes, ocrOffchainOptions) require.NoError(t, err, "Error building OCRv2 config") ocrv2Config.Transmitters = authorizedForwarders - //nolint:staticcheck //ignore SA1019 we will migrate that test later - err = actions.ConfigureOCRv2AggregatorContracts(env.EVMClient, ocrv2Config, ocrInstances) + err = actions_seth.ConfigureOCRv2AggregatorContracts(ocrv2Config, ocrInstances) require.NoError(t, err, "Error configuring OCRv2 aggregator contracts") - err = actions.WatchNewOCR2Round(1, ocrInstances, env.EVMClient, time.Minute*10, l) - require.NoError(t, err) + err = actions_seth.WatchNewOCRRound(l, sethClient, 1, contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), time.Duration(10*time.Minute)) + require.NoError(t, err, "error watching for new OCRv2 round") answer, err := ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) require.NoError(t, err, "Getting latest answer from OCRv2 contract shouldn't fail") @@ -111,9 +113,8 @@ func TestForwarderOCR2Basic(t *testing.T) { ocrRoundVal := (5 + i) % 10 err = env.MockAdapter.SetAdapterBasedIntValuePath("ocr2", []string{http.MethodGet, http.MethodPost}, ocrRoundVal) require.NoError(t, err) - err = actions.WatchNewOCR2Round(int64(i), ocrInstances, env.EVMClient, time.Minute*10, l) - require.NoError(t, err) - + err = actions_seth.WatchNewOCRRound(l, sethClient, int64(i), contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), time.Duration(10*time.Minute)) + require.NoError(t, err, "error watching for new OCRv2 round") answer, err = ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) require.NoError(t, err, "Error getting latest OCRv2 answer") require.Equal(t, int64(ocrRoundVal), answer.Int64(), fmt.Sprintf("Expected latest answer from OCRv2 contract to be %d but got %d", ocrRoundVal, answer.Int64())) diff --git a/integration-tests/smoke/keeper_test.go b/integration-tests/smoke/keeper_test.go index 0ebbc1e083d..7f2183faeac 100644 --- a/integration-tests/smoke/keeper_test.go +++ b/integration-tests/smoke/keeper_test.go @@ -9,11 +9,13 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/onsi/gomega" + "github.com/rs/zerolog" "github.com/stretchr/testify/require" commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" @@ -93,7 +95,7 @@ func TestKeeperBasicSmoke(t *testing.T) { t.Fatal(err) } - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(l, t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -174,7 +176,7 @@ func TestKeeperBlockCountPerTurn(t *testing.T) { t.Fatal(err) } - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(l, t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -283,7 +285,7 @@ func TestKeeperSimulation(t *testing.T) { t.Fatal(err) } - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(l, t, &config) registry, _, consumersPerformance, upkeepIDs := actions.DeployPerformanceKeeperContracts( t, registryVersion, @@ -360,7 +362,7 @@ func TestKeeperCheckPerformGasLimit(t *testing.T) { if err != nil { t.Fatal(err) } - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(l, t, &config) registry, _, consumersPerformance, upkeepIDs := actions.DeployPerformanceKeeperContracts( t, registryVersion, @@ -477,7 +479,7 @@ func TestKeeperRegisterUpkeep(t *testing.T) { if err != nil { t.Fatal(err) } - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(l, t, &config) registry, registrar, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -570,7 +572,7 @@ func TestKeeperAddFunds(t *testing.T) { if err != nil { t.Fatal(err) } - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(l, t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -637,7 +639,7 @@ func TestKeeperRemove(t *testing.T) { if err != nil { t.Fatal(err) } - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(l, t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -719,7 +721,7 @@ func TestKeeperPauseRegistry(t *testing.T) { if err != nil { t.Fatal(err) } - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(l, t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -784,7 +786,7 @@ func TestKeeperMigrateRegistry(t *testing.T) { if err != nil { t.Fatal(err) } - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(l, t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, ethereum.RegistryVersion_1_2, @@ -880,7 +882,7 @@ func TestKeeperNodeDown(t *testing.T) { if err != nil { t.Fatal(err) } - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(l, t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -990,7 +992,7 @@ func TestKeeperPauseUnPauseUpkeep(t *testing.T) { if err != nil { t.Fatal(err) } - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(l, t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, ethereum.RegistryVersion_1_3, @@ -1084,7 +1086,7 @@ func TestKeeperUpdateCheckData(t *testing.T) { if err != nil { t.Fatal(err) } - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(l, t, &config) registry, _, performDataChecker, upkeepIDs := actions.DeployPerformDataCheckerContracts( t, ethereum.RegistryVersion_1_3, @@ -1143,7 +1145,7 @@ func TestKeeperUpdateCheckData(t *testing.T) { }, "3m", "1s").Should(gomega.Succeed()) } -func setupKeeperTest(t *testing.T, config *tc.TestConfig) ( +func setupKeeperTest(l zerolog.Logger, t *testing.T, config *tc.TestConfig) ( blockchain.EVMClient, []*client.ChainlinkClient, contracts.ContractDeployer, @@ -1158,10 +1160,13 @@ func setupKeeperTest(t *testing.T, config *tc.TestConfig) ( clNodeConfig.Keeper.Registry.SyncInterval = &syncInterval clNodeConfig.Keeper.Registry.PerformGasOverhead = &performGasOverhead + privateNetwork, err := actions.EthereumNetworkConfigFromConfig(l, config) + require.NoError(t, err, "Error building ethereum network config") + env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). WithTestConfig(config). - WithGeth(). + WithPrivateEthereumNetwork(privateNetwork). WithCLNodes(5). WithCLNodeConfig(clNodeConfig). WithFunding(big.NewFloat(.5)). @@ -1174,10 +1179,14 @@ func setupKeeperTest(t *testing.T, config *tc.TestConfig) ( linkTokenContract, err := env.ContractDeployer.DeployLinkTokenContract() require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") - err = env.EVMClient.WaitForEvents() + network := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0] + evmClient, err := env.GetEVMClient(network.ChainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + + err = evmClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") - return env.EVMClient, env.ClCluster.NodeAPIs(), env.ContractDeployer, linkTokenContract, env + return evmClient, env.ClCluster.NodeAPIs(), env.ContractDeployer, linkTokenContract, env } func TestKeeperJobReplacement(t *testing.T) { @@ -1189,7 +1198,7 @@ func TestKeeperJobReplacement(t *testing.T) { t.Fatal(err) } - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(l, t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, diff --git a/integration-tests/smoke/log_poller_test.go b/integration-tests/smoke/log_poller_test.go index f6c349581ba..930ef4ad0e2 100644 --- a/integration-tests/smoke/log_poller_test.go +++ b/integration-tests/smoke/log_poller_test.go @@ -13,13 +13,13 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" - lp_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/log_poller" logpoller "github.com/smartcontractkit/chainlink/integration-tests/universal/log_poller" core_logger "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -107,14 +107,18 @@ func executeBasicLogPollerTest(t *testing.T) { l.Info().Msg("No duplicate filters found. OK!") - err = testEnv.EVMClient.WaitForEvents() + network := networks.MustGetSelectedNetworkConfig(testConfig.GetNetworkConfig())[0] + evmClient, err := testEnv.GetEVMClient(network.ChainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + + err = evmClient.WaitForEvents() require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") expectedFilters := logpoller.GetExpectedFilters(lpTestEnv.logEmitters, cfg) - waitForAllNodesToHaveExpectedFiltersRegisteredOrFail(ctx, l, coreLogger, t, testEnv, expectedFilters) + waitForAllNodesToHaveExpectedFiltersRegisteredOrFail(ctx, l, coreLogger, t, testEnv, &testConfig, expectedFilters) // Save block number before starting to emit events, so that we can later use it when querying logs - sb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) + sb, err := evmClient.LatestBlockNumber(testcontext.Get(t)) require.NoError(t, err, "Error getting latest block number") startBlock := int64(sb) @@ -124,7 +128,7 @@ func executeBasicLogPollerTest(t *testing.T) { // Start chaos experimnents by randomly pausing random containers (Chainlink nodes or their DBs) chaosDoneCh := make(chan error, 1) go func() { - logpoller.ExecuteChaosExperiment(l, testEnv, cfg, chaosDoneCh) + logpoller.ExecuteChaosExperiment(l, testEnv, &testConfig, chaosDoneCh) }() totalLogsEmitted, err := logpoller.ExecuteGenerator(t, cfg, lpTestEnv.logEmitters) @@ -134,7 +138,7 @@ func executeBasicLogPollerTest(t *testing.T) { expectedLogsEmitted := logpoller.GetExpectedLogCount(cfg) duration := int(endTime.Sub(startTime).Seconds()) - eb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) + eb, err := evmClient.LatestBlockNumber(testcontext.Get(t)) require.NoError(t, err, "Error getting latest block number") l.Info(). @@ -153,12 +157,10 @@ func executeBasicLogPollerTest(t *testing.T) { // as that's not trivial to do (i.e. just because chain was at block X when log emission ended it doesn't mean all events made it to that block) endBlock := int64(eb) + 10000 - // logCountWaitDuration, err := time.ParseDuration("5m") - // require.NoError(t, err, "Error parsing log count wait duration") - allNodesLogCountMatches, err := logpoller.FluentlyCheckIfAllNodesHaveLogCount("5m", startBlock, endBlock, totalLogsEmitted, expectedFilters, l, coreLogger, testEnv) + allNodesLogCountMatches, err := logpoller.FluentlyCheckIfAllNodesHaveLogCount("5m", startBlock, endBlock, totalLogsEmitted, expectedFilters, l, coreLogger, testEnv, evmClient.GetChainID().Int64()) require.NoError(t, err, "Error checking if CL nodes have expected log count") - conditionallyWaitUntilNodesHaveTheSameLogsAsEvm(l, coreLogger, t, allNodesLogCountMatches, lpTestEnv, cfg, startBlock, endBlock, "5m") + conditionallyWaitUntilNodesHaveTheSameLogsAsEvm(l, coreLogger, t, allNodesLogCountMatches, lpTestEnv, &testConfig, startBlock, endBlock, "5m") } func executeLogPollerReplay(t *testing.T, consistencyTimeout string) { @@ -180,9 +182,12 @@ func executeLogPollerReplay(t *testing.T, consistencyTimeout string) { testEnv := lpTestEnv.testEnv ctx := testcontext.Get(t) + network := networks.MustGetSelectedNetworkConfig(testConfig.GetNetworkConfig())[0] + evmClient, err := testEnv.GetEVMClient(network.ChainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") // Save block number before starting to emit events, so that we can later use it when querying logs - sb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) + sb, err := evmClient.LatestBlockNumber(testcontext.Get(t)) require.NoError(t, err, "Error getting latest block number") startBlock := int64(sb) @@ -195,17 +200,17 @@ func executeLogPollerReplay(t *testing.T, consistencyTimeout string) { duration := int(endTime.Sub(startTime).Seconds()) // Save block number after finishing to emit events, so that we can later use it when querying logs - eb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) + eb, err := evmClient.LatestBlockNumber(testcontext.Get(t)) require.NoError(t, err, "Error getting latest block number") - endBlock, err := logpoller.GetEndBlockToWaitFor(int64(eb), testEnv.EVMClient.GetChainID().Int64(), cfg) + endBlock, err := logpoller.GetEndBlockToWaitFor(int64(eb), evmClient.GetChainID().Int64(), cfg) require.NoError(t, err, "Error getting end block to wait for") l.Info().Int64("Ending Block", endBlock).Int("Total logs emitted", totalLogsEmitted).Int64("Expected total logs emitted", expectedLogsEmitted).Str("Duration", fmt.Sprintf("%d sec", duration)).Str("LPS", fmt.Sprintf("%d/sec", totalLogsEmitted/duration)).Msg("FINISHED EVENT EMISSION") // Lets make sure no logs are in DB yet expectedFilters := logpoller.GetExpectedFilters(lpTestEnv.logEmitters, cfg) - logCountMatches, err := logpoller.ClNodesHaveExpectedLogCount(startBlock, endBlock, testEnv.EVMClient.GetChainID(), 0, expectedFilters, l, coreLogger, testEnv.ClCluster) + logCountMatches, err := logpoller.ClNodesHaveExpectedLogCount(startBlock, endBlock, evmClient.GetChainID(), 0, expectedFilters, l, coreLogger, testEnv.ClCluster) require.NoError(t, err, "Error checking if CL nodes have expected log count") require.True(t, logCountMatches, "Some CL nodes already had logs in DB") l.Info().Msg("No logs were saved by CL nodes yet, as expected. Proceeding.") @@ -215,16 +220,16 @@ func executeLogPollerReplay(t *testing.T, consistencyTimeout string) { err = logpoller.RegisterFiltersAndAssertUniquness(l, lpTestEnv.registry, lpTestEnv.upkeepIDs, lpTestEnv.logEmitters, cfg, lpTestEnv.upKeepsNeeded) require.NoError(t, err, "Error registering filters") - err = testEnv.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") - waitForAllNodesToHaveExpectedFiltersRegisteredOrFail(ctx, l, coreLogger, t, testEnv, expectedFilters) + waitForAllNodesToHaveExpectedFiltersRegisteredOrFail(ctx, l, coreLogger, t, testEnv, &testConfig, expectedFilters) blockFinalisationWaitDuration := "5m" l.Warn().Str("Duration", blockFinalisationWaitDuration).Msg("Waiting for all CL nodes to have end block finalised") gom := gomega.NewGomegaWithT(t) gom.Eventually(func(g gomega.Gomega) { - hasFinalised, err := logpoller.LogPollerHasFinalisedEndBlock(endBlock, testEnv.EVMClient.GetChainID(), l, coreLogger, testEnv.ClCluster) + hasFinalised, err := logpoller.LogPollerHasFinalisedEndBlock(endBlock, evmClient.GetChainID(), l, coreLogger, testEnv.ClCluster) if err != nil { l.Warn().Err(err).Msg("Error checking if nodes have finalised end block. Retrying...") } @@ -235,7 +240,7 @@ func executeLogPollerReplay(t *testing.T, consistencyTimeout string) { l.Info().Msg("Triggering log poller's replay") for i := 1; i < len(testEnv.ClCluster.Nodes); i++ { nodeName := testEnv.ClCluster.Nodes[i].ContainerName - response, _, err := testEnv.ClCluster.Nodes[i].API.ReplayLogPollerFromBlock(startBlock, testEnv.EVMClient.GetChainID().Int64()) + response, _, err := testEnv.ClCluster.Nodes[i].API.ReplayLogPollerFromBlock(startBlock, evmClient.GetChainID().Int64()) require.NoError(t, err, "Error triggering log poller's replay on node %s", nodeName) require.Equal(t, "Replay started", response.Data.Attributes.Message, "Unexpected response message from log poller's replay") } @@ -245,10 +250,10 @@ func executeLogPollerReplay(t *testing.T, consistencyTimeout string) { l.Warn().Str("Duration", consistencyTimeout).Msg("Waiting for replay logs to be processed by all nodes") // logCountWaitDuration, err := time.ParseDuration("5m") - allNodesLogCountMatches, err := logpoller.FluentlyCheckIfAllNodesHaveLogCount("5m", startBlock, endBlock, totalLogsEmitted, expectedFilters, l, coreLogger, testEnv) + allNodesLogCountMatches, err := logpoller.FluentlyCheckIfAllNodesHaveLogCount("5m", startBlock, endBlock, totalLogsEmitted, expectedFilters, l, coreLogger, testEnv, evmClient.GetChainID().Int64()) require.NoError(t, err, "Error checking if CL nodes have expected log count") - conditionallyWaitUntilNodesHaveTheSameLogsAsEvm(l, coreLogger, t, allNodesLogCountMatches, lpTestEnv, cfg, startBlock, endBlock, "5m") + conditionallyWaitUntilNodesHaveTheSameLogsAsEvm(l, coreLogger, t, allNodesLogCountMatches, lpTestEnv, &testConfig, startBlock, endBlock, "5m") } type logPollerEnvironment struct { @@ -307,7 +312,7 @@ func prepareEnvironment(l zerolog.Logger, t *testing.T, testConfig *tc.TestConfi l.Info().Msg("No duplicate upkeep IDs found. OK!") // Deploy Log Emitter contracts - logEmitters := logpoller.UploadLogEmitterContractsAndWaitForFinalisation(l, t, testEnv, cfg) + logEmitters := logpoller.UploadLogEmitterContractsAndWaitForFinalisation(l, t, testEnv, testConfig) err = logpoller.AssertContractAddressUniquneness(logEmitters) require.NoError(t, err, "Error asserting contract addresses uniqueness") l.Info().Msg("No duplicate contract addresses found. OK!") @@ -322,8 +327,13 @@ func prepareEnvironment(l zerolog.Logger, t *testing.T, testConfig *tc.TestConfi } // waitForAllNodesToHaveExpectedFiltersRegisteredOrFail waits until all nodes have expected filters registered until timeout -func waitForAllNodesToHaveExpectedFiltersRegisteredOrFail(ctx context.Context, l zerolog.Logger, coreLogger core_logger.SugaredLogger, t *testing.T, testEnv *test_env.CLClusterTestEnv, expectedFilters []logpoller.ExpectedFilter) { +func waitForAllNodesToHaveExpectedFiltersRegisteredOrFail(ctx context.Context, l zerolog.Logger, coreLogger core_logger.SugaredLogger, t *testing.T, testEnv *test_env.CLClusterTestEnv, testConfig *tc.TestConfig, expectedFilters []logpoller.ExpectedFilter) { // Make sure that all nodes have expected filters registered before starting to emit events + + network := networks.MustGetSelectedNetworkConfig(testConfig.GetNetworkConfig())[0] + evmClient, err := testEnv.GetEVMClient(network.ChainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + gom := gomega.NewGomegaWithT(t) gom.Eventually(func(g gomega.Gomega) { hasFilters := false @@ -335,7 +345,7 @@ func waitForAllNodesToHaveExpectedFiltersRegisteredOrFail(ctx context.Context, l var message string var err error - hasFilters, message, err = logpoller.NodeHasExpectedFilters(ctx, expectedFilters, coreLogger, testEnv.EVMClient.GetChainID(), testEnv.ClCluster.Nodes[i].PostgresDb) + hasFilters, message, err = logpoller.NodeHasExpectedFilters(ctx, expectedFilters, coreLogger, evmClient.GetChainID(), testEnv.ClCluster.Nodes[i].PostgresDb) if !hasFilters || err != nil { l.Warn(). Str("Details", message). @@ -355,16 +365,20 @@ func waitForAllNodesToHaveExpectedFiltersRegisteredOrFail(ctx context.Context, l // conditionallyWaitUntilNodesHaveTheSameLogsAsEvm checks whether all CL nodes have the same number of logs as EVM node // if not, then it prints missing logs and wait for some time and checks again -func conditionallyWaitUntilNodesHaveTheSameLogsAsEvm(l zerolog.Logger, coreLogger core_logger.SugaredLogger, t *testing.T, allNodesLogCountMatches bool, lpTestEnv logPollerEnvironment, cfg *lp_config.Config, startBlock, endBlock int64, waitDuration string) { +func conditionallyWaitUntilNodesHaveTheSameLogsAsEvm(l zerolog.Logger, coreLogger core_logger.SugaredLogger, t *testing.T, allNodesLogCountMatches bool, lpTestEnv logPollerEnvironment, testConfig *tc.TestConfig, startBlock, endBlock int64, waitDuration string) { logCountWaitDuration, err := time.ParseDuration(waitDuration) require.NoError(t, err, "Error parsing log count wait duration") + network := networks.MustGetSelectedNetworkConfig(testConfig.GetNetworkConfig())[0] + evmClient, err := lpTestEnv.testEnv.GetEVMClient(network.ChainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + allNodesHaveAllExpectedLogs := false if !allNodesLogCountMatches { - missingLogs, err := logpoller.GetMissingLogs(startBlock, endBlock, lpTestEnv.logEmitters, lpTestEnv.testEnv.EVMClient, lpTestEnv.testEnv.ClCluster, l, coreLogger, cfg) + missingLogs, err := logpoller.GetMissingLogs(startBlock, endBlock, lpTestEnv.logEmitters, evmClient, lpTestEnv.testEnv.ClCluster, l, coreLogger, testConfig.LogPoller) if err == nil { if !missingLogs.IsEmpty() { - logpoller.PrintMissingLogsInfo(missingLogs, l, cfg) + logpoller.PrintMissingLogsInfo(missingLogs, l, testConfig.LogPoller) } else { allNodesHaveAllExpectedLogs = true l.Info().Msg("All CL nodes have all the logs that EVM node has") @@ -385,7 +399,7 @@ func conditionallyWaitUntilNodesHaveTheSameLogsAsEvm(l zerolog.Logger, coreLogge gom := gomega.NewGomegaWithT(t) gom.Eventually(func(g gomega.Gomega) { - missingLogs, err := logpoller.GetMissingLogs(startBlock, endBlock, lpTestEnv.logEmitters, lpTestEnv.testEnv.EVMClient, lpTestEnv.testEnv.ClCluster, l, coreLogger, cfg) + missingLogs, err := logpoller.GetMissingLogs(startBlock, endBlock, lpTestEnv.logEmitters, evmClient, lpTestEnv.testEnv.ClCluster, l, coreLogger, testConfig.LogPoller) if err != nil { l.Warn(). Err(err). @@ -393,7 +407,7 @@ func conditionallyWaitUntilNodesHaveTheSameLogsAsEvm(l zerolog.Logger, coreLogge } if !missingLogs.IsEmpty() { - logpoller.PrintMissingLogsInfo(missingLogs, l, cfg) + logpoller.PrintMissingLogsInfo(missingLogs, l, testConfig.LogPoller) } g.Expect(missingLogs.IsEmpty()).To(gomega.BeTrue(), "Some CL nodes were missing logs") }, logConsistencyWaitDuration, "10s").Should(gomega.Succeed()) diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go index 33538c1eaa4..d4f7d1e7ffd 100644 --- a/integration-tests/smoke/ocr2_test.go +++ b/integration-tests/smoke/ocr2_test.go @@ -7,10 +7,13 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/common" "github.com/rs/zerolog" + "github.com/smartcontractkit/seth" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/v2/core/config/env" @@ -43,11 +46,11 @@ func TestOCRv2Basic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - env, aggregatorContracts := prepareORCv2SmokeTestEnv(t, l, 5) + env, aggregatorContracts, sethClient := prepareORCv2SmokeTestEnv(t, l, 5) err := env.MockAdapter.SetAdapterBasedIntValuePath("ocr2", []string{http.MethodGet, http.MethodPost}, 10) require.NoError(t, err) - err = actions_seth.WatchNewRound(l, env.SethClient, 2, contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts), time.Minute*5) + err = actions_seth.WatchNewOCRRound(l, sethClient, 2, contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts), time.Minute*5) require.NoError(t, err) roundData, err := aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(2)) @@ -65,13 +68,13 @@ func TestOCRv2Request(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - env, aggregatorContracts := prepareORCv2SmokeTestEnv(t, l, 5) + _, aggregatorContracts, sethClient := prepareORCv2SmokeTestEnv(t, l, 5) // Keep the mockserver value the same and continually request new rounds for round := 2; round <= 4; round++ { err := actions_seth.StartNewRound(contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts)) require.NoError(t, err, "Error starting new OCR2 round") - err = actions_seth.WatchNewRound(l, env.SethClient, int64(round), contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts), time.Minute*5) + err = actions_seth.WatchNewOCRRound(l, sethClient, int64(round), contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts), time.Minute*5) require.NoError(t, err, "Error watching for new OCR2 round") roundData, err := aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(int64(round))) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") @@ -87,13 +90,13 @@ func TestOCRv2JobReplacement(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - env, aggregatorContracts := prepareORCv2SmokeTestEnv(t, l, 5) + env, aggregatorContracts, sethClient := prepareORCv2SmokeTestEnv(t, l, 5) nodeClients := env.ClCluster.NodeAPIs() bootstrapNode, workerNodes := nodeClients[0], nodeClients[1:] err := env.MockAdapter.SetAdapterBasedIntValuePath("ocr2", []string{http.MethodGet, http.MethodPost}, 10) require.NoError(t, err) - err = actions_seth.WatchNewRound(l, env.SethClient, 2, contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts), time.Minute*5) + err = actions_seth.WatchNewOCRRound(l, sethClient, 2, contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts), time.Minute*5) require.NoError(t, err, "Error watching for new OCR2 round") roundData, err := aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(2)) @@ -109,10 +112,10 @@ func TestOCRv2JobReplacement(t *testing.T) { err = actions.DeleteBridges(nodeClients) require.NoError(t, err) - err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 15, uint64(env.SethClient.ChainID), false, false) + err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 15, uint64(sethClient.ChainID), false, false) require.NoError(t, err, "Error creating OCRv2 jobs") - err = actions_seth.WatchNewRound(l, env.SethClient, 3, contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts), time.Minute*3) + err = actions_seth.WatchNewOCRRound(l, sethClient, 3, contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts), time.Minute*3) require.NoError(t, err, "Error watching for new OCR2 round") roundData, err = aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(3)) @@ -123,16 +126,19 @@ func TestOCRv2JobReplacement(t *testing.T) { ) } -func prepareORCv2SmokeTestEnv(t *testing.T, l zerolog.Logger, firstRoundResult int) (*test_env.CLClusterTestEnv, []contracts.OffchainAggregatorV2) { +func prepareORCv2SmokeTestEnv(t *testing.T, l zerolog.Logger, firstRoundResult int) (*test_env.CLClusterTestEnv, []contracts.OffchainAggregatorV2, *seth.Client) { config, err := tc.GetConfig("Smoke", tc.OCR2) if err != nil { t.Fatal(err) } + privateNetwork, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") + env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). WithTestConfig(&config). - WithGeth(). + WithPrivateEthereumNetwork(privateNetwork). WithMockAdapter(). WithCLNodeConfig(node.NewConfig(node.NewBaseConfig(), node.WithOCR2(), @@ -146,13 +152,17 @@ func prepareORCv2SmokeTestEnv(t *testing.T, l zerolog.Logger, firstRoundResult i Build() require.NoError(t, err) + selectedNetwork := networks.MustGetSelectedNetworkConfig(config.Network)[0] + sethClient, err := env.GetSethClient(selectedNetwork.ChainID) + require.NoError(t, err, "Error getting seth client") + nodeClients := env.ClCluster.NodeAPIs() bootstrapNode, workerNodes := nodeClients[0], nodeClients[1:] - linkDeploymentData, err := contracts.DeployLinkTokenContract(env.SethClient) + linkContract, err := contracts.DeployLinkTokenContract(l, sethClient) require.NoError(t, err, "Error deploying link token contract") - err = actions_seth.FundChainlinkNodesFromRootAddress(l, env.SethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(workerNodes), big.NewFloat(.05)) + err = actions_seth.FundChainlinkNodesFromRootAddress(l, sethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(workerNodes), big.NewFloat(.05)) require.NoError(t, err, "Error funding Chainlink nodes") // Gather transmitters @@ -166,10 +176,10 @@ func prepareORCv2SmokeTestEnv(t *testing.T, l zerolog.Logger, firstRoundResult i } ocrOffchainOptions := contracts.DefaultOffChainAggregatorOptions() - aggregatorContracts, err := actions_seth.DeployOCRv2Contracts(l, env.SethClient, 1, linkDeploymentData.Address, transmitters, ocrOffchainOptions) + aggregatorContracts, err := actions_seth.DeployOCRv2Contracts(l, sethClient, 1, common.HexToAddress(linkContract.Address()), transmitters, ocrOffchainOptions) require.NoError(t, err, "Error deploying OCRv2 aggregator contracts") - err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 5, uint64(env.SethClient.ChainID), false, false) + err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 5, uint64(sethClient.ChainID), false, false) require.NoError(t, err, "Error creating OCRv2 jobs") ocrv2Config, err := actions.BuildMedianOCR2ConfigLocal(workerNodes, ocrOffchainOptions) @@ -178,7 +188,7 @@ func prepareORCv2SmokeTestEnv(t *testing.T, l zerolog.Logger, firstRoundResult i err = actions_seth.ConfigureOCRv2AggregatorContracts(ocrv2Config, aggregatorContracts) require.NoError(t, err, "Error configuring OCRv2 aggregator contracts") - err = actions_seth.WatchNewRound(l, env.SethClient, 1, contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts), time.Minute*5) + err = actions_seth.WatchNewOCRRound(l, sethClient, 1, contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts), time.Minute*5) require.NoError(t, err, "Error watching for new OCR2 round") roundData, err := aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(1)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") @@ -187,5 +197,5 @@ func prepareORCv2SmokeTestEnv(t *testing.T, l zerolog.Logger, firstRoundResult i roundData.Answer.Int64(), ) - return env, aggregatorContracts + return env, aggregatorContracts, sethClient } diff --git a/integration-tests/smoke/ocr_test.go b/integration-tests/smoke/ocr_test.go index 8047a19a50c..29e633beb15 100644 --- a/integration-tests/smoke/ocr_test.go +++ b/integration-tests/smoke/ocr_test.go @@ -5,17 +5,19 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/common" "github.com/rs/zerolog" + "github.com/smartcontractkit/seth" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" + actions_seth "github.com/smartcontractkit/chainlink/integration-tests/actions/seth" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" - - actions_seth "github.com/smartcontractkit/chainlink/integration-tests/actions/seth" tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) @@ -27,13 +29,14 @@ func TestOCRBasic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - env, ocrInstances := prepareORCv1SmokeTestEnv(t, l, 5) + env, ocrInstances, sethClient := prepareORCv1SmokeTestEnv(t, l, 5) nodeClients := env.ClCluster.NodeAPIs() workerNodes := nodeClients[1:] err := actions.SetAllAdapterResponsesToTheSameValueLocal(10, ocrInstances, workerNodes, env.MockAdapter) require.NoError(t, err, "Error setting all adapter responses to the same value") - err = actions_seth.WatchNewRound(l, env.SethClient, 2, contracts.V1OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), time.Duration(3*time.Minute)) + + err = actions_seth.WatchNewOCRRound(l, sethClient, 2, contracts.V1OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), time.Duration(3*time.Minute)) require.NoError(t, err, ErrWatchingNewOCRRound) answer, err := ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) @@ -45,13 +48,13 @@ func TestOCRJobReplacement(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - env, ocrInstances := prepareORCv1SmokeTestEnv(t, l, 5) + env, ocrInstances, sethClient := prepareORCv1SmokeTestEnv(t, l, 5) nodeClients := env.ClCluster.NodeAPIs() bootstrapNode, workerNodes := nodeClients[0], nodeClients[1:] err := actions.SetAllAdapterResponsesToTheSameValueLocal(10, ocrInstances, workerNodes, env.MockAdapter) require.NoError(t, err, "Error setting all adapter responses to the same value") - err = actions_seth.WatchNewRound(l, env.SethClient, 2, contracts.V1OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), time.Duration(3*time.Minute)) + err = actions_seth.WatchNewOCRRound(l, sethClient, 2, contracts.V1OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), time.Duration(3*time.Minute)) require.NoError(t, err, ErrWatchingNewOCRRound) answer, err := ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) @@ -65,10 +68,10 @@ func TestOCRJobReplacement(t *testing.T) { require.NoError(t, err, "Error deleting OCR bridges") //Recreate job - err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, big.NewInt(env.SethClient.ChainID)) + err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, big.NewInt(sethClient.ChainID)) require.NoError(t, err, "Error creating OCR jobs") - err = actions_seth.WatchNewRound(l, env.SethClient, 1, contracts.V1OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), time.Duration(3*time.Minute)) + err = actions_seth.WatchNewOCRRound(l, sethClient, 1, contracts.V1OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), time.Duration(3*time.Minute)) require.NoError(t, err, ErrWatchingNewOCRRound) answer, err = ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) @@ -76,7 +79,7 @@ func TestOCRJobReplacement(t *testing.T) { require.Equal(t, int64(10), answer.Int64(), "Expected latest answer from OCR contract to be 10 but got %d", answer.Int64()) } -func prepareORCv1SmokeTestEnv(t *testing.T, l zerolog.Logger, firstRoundResult int64) (*test_env.CLClusterTestEnv, []contracts.OffchainAggregator) { +func prepareORCv1SmokeTestEnv(t *testing.T, l zerolog.Logger, firstRoundResult int64) (*test_env.CLClusterTestEnv, []contracts.OffchainAggregator, *seth.Client) { config, err := tc.GetConfig("Smoke", tc.OCR) if err != nil { t.Fatal(err) @@ -97,24 +100,28 @@ func prepareORCv1SmokeTestEnv(t *testing.T, l zerolog.Logger, firstRoundResult i Build() require.NoError(t, err) + selectedNetwork := networks.MustGetSelectedNetworkConfig(config.Network)[0] + sethClient, err := env.GetSethClient(selectedNetwork.ChainID) + require.NoError(t, err, "Error getting seth client") + nodeClients := env.ClCluster.NodeAPIs() bootstrapNode, workerNodes := nodeClients[0], nodeClients[1:] - linkDeploymentData, err := contracts.DeployLinkTokenContract(env.SethClient) + linkContract, err := contracts.DeployLinkTokenContract(l, sethClient) require.NoError(t, err, "Error deploying link token contract") - ocrInstances, err := actions_seth.DeployOCRv1Contracts(l, env.SethClient, 1, linkDeploymentData.Address, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(workerNodes)) + ocrInstances, err := actions_seth.DeployOCRv1Contracts(l, sethClient, 1, common.HexToAddress(linkContract.Address()), contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(workerNodes)) require.NoError(t, err, "Error deploying OCR contracts") - err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, big.NewInt(env.SethClient.ChainID)) + err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, big.NewInt(sethClient.ChainID)) require.NoError(t, err, "Error creating OCR jobs") - err = actions_seth.WatchNewRound(l, env.SethClient, 1, contracts.V1OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), time.Duration(3*time.Minute)) + err = actions_seth.WatchNewOCRRound(l, sethClient, 1, contracts.V1OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), time.Duration(3*time.Minute)) require.NoError(t, err, "Error watching for new OCR round") answer, err := ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") require.Equal(t, firstRoundResult, answer.Int64(), "Expected latest answer from OCR contract to be 5 but got %d", answer.Int64()) - return env, ocrInstances + return env, ocrInstances, sethClient } diff --git a/integration-tests/smoke/runlog_test.go b/integration-tests/smoke/runlog_test.go index f7f5c54069e..d255fe07235 100644 --- a/integration-tests/smoke/runlog_test.go +++ b/integration-tests/smoke/runlog_test.go @@ -12,9 +12,12 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" @@ -25,29 +28,35 @@ func TestRunLogBasic(t *testing.T) { l := logging.GetTestLogger(t) config, err := tc.GetConfig("Smoke", tc.RunLog) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err, "Error getting config") + + privateNetwork, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") env, err := test_env.NewCLTestEnvBuilder(). WithTestInstance(t). WithTestConfig(&config). - WithGeth(). + WithPrivateEthereumNetwork(privateNetwork). WithMockAdapter(). WithCLNodes(1). WithFunding(big.NewFloat(.1)). WithStandardCleanup(). + WithSeth(). Build() require.NoError(t, err) - lt, err := env.ContractDeployer.DeployLinkTokenContract() + network := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0] + sethClient, err := env.GetSethClient(network.ChainID) + require.NoError(t, err, "Error getting seth client") + + lt, err := contracts.DeployLinkTokenContract(l, sethClient) require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") - oracle, err := env.ContractDeployer.DeployOracle(lt.Address()) + + oracle, err := contracts.DeployOracle(sethClient, lt.Address()) require.NoError(t, err, "Deploying Oracle Contract shouldn't fail") - consumer, err := env.ContractDeployer.DeployAPIConsumer(lt.Address()) + consumer, err := contracts.DeployAPIConsumer(sethClient, lt.Address()) require.NoError(t, err, "Deploying Consumer Contract shouldn't fail") - err = env.EVMClient.SetDefaultWallet(0) - require.NoError(t, err, "Setting default wallet shouldn't fail") + err = lt.Transfer(consumer.Address(), big.NewInt(2e18)) require.NoError(t, err, "Transferring %d to consumer contract shouldn't fail", big.NewInt(2e18)) @@ -74,7 +83,7 @@ func TestRunLogBasic(t *testing.T) { Name: fmt.Sprintf("direct-request-%s", uuid.NewString()), MinIncomingConfirmations: "1", ContractAddress: oracle.Address(), - EVMChainID: env.EVMClient.GetChainID().String(), + EVMChainID: fmt.Sprint(sethClient.ChainID), ExternalJobID: jobUUID.String(), ObservationSource: ost, }) diff --git a/integration-tests/smoke/vrf_test.go b/integration-tests/smoke/vrf_test.go index b5badf6990b..3a28c14be00 100644 --- a/integration-tests/smoke/vrf_test.go +++ b/integration-tests/smoke/vrf_test.go @@ -8,15 +8,18 @@ import ( "github.com/google/uuid" "github.com/onsi/gomega" + "github.com/rs/zerolog" + "github.com/smartcontractkit/seth" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv1" - "github.com/smartcontractkit/chainlink/integration-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv1" "github.com/smartcontractkit/chainlink/integration-tests/client" + ethcontracts "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) @@ -24,34 +27,7 @@ import ( func TestVRFBasic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - - config, err := tc.GetConfig("Smoke", tc.VRF) - if err != nil { - t.Fatal(err) - } - - env, err := test_env.NewCLTestEnvBuilder(). - WithTestInstance(t). - WithTestConfig(&config). - WithGeth(). - WithCLNodes(1). - WithFunding(big.NewFloat(.1)). - WithStandardCleanup(). - Build() - require.NoError(t, err) - env.ParallelTransactions(true) - - lt, err := actions.DeployLINKToken(env.ContractDeployer) - require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") - contracts, err := vrfv1.DeployVRFContracts(env.ContractDeployer, env.EVMClient, lt) - require.NoError(t, err, "Deploying VRF Contracts shouldn't fail") - - err = lt.Transfer(contracts.Consumer.Address(), big.NewInt(2e18)) - require.NoError(t, err, "Funding consumer contract shouldn't fail") - _, err = env.ContractDeployer.DeployVRFContract() - require.NoError(t, err, "Deploying VRF contract shouldn't fail") - err = env.EVMClient.WaitForEvents() - require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") + env, contracts, sethClient := prepareVRFtestEnv(t, l) for _, n := range env.ClCluster.Nodes { nodeKey, err := n.API.MustCreateVRFKey() @@ -70,7 +46,7 @@ func TestVRFBasic(t *testing.T) { MinIncomingConfirmations: 1, PublicKey: pubKeyCompressed, ExternalJobID: jobUUID.String(), - EVMChainID: env.EVMClient.GetChainID().String(), + EVMChainID: fmt.Sprint(sethClient.ChainID), ObservationSource: ost, }) require.NoError(t, err, "Creating VRF Job shouldn't fail") @@ -119,33 +95,7 @@ func TestVRFBasic(t *testing.T) { func TestVRFJobReplacement(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.VRF) - if err != nil { - t.Fatal(err) - } - - env, err := test_env.NewCLTestEnvBuilder(). - WithTestInstance(t). - WithTestConfig(&config). - WithGeth(). - WithCLNodes(1). - WithFunding(big.NewFloat(.1)). - WithStandardCleanup(). - Build() - require.NoError(t, err) - env.ParallelTransactions(true) - - lt, err := actions.DeployLINKToken(env.ContractDeployer) - require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") - contracts, err := vrfv1.DeployVRFContracts(env.ContractDeployer, env.EVMClient, lt) - require.NoError(t, err, "Deploying VRF Contracts shouldn't fail") - - err = lt.Transfer(contracts.Consumer.Address(), big.NewInt(2e18)) - require.NoError(t, err, "Funding consumer contract shouldn't fail") - _, err = env.ContractDeployer.DeployVRFContract() - require.NoError(t, err, "Deploying VRF contract shouldn't fail") - err = env.EVMClient.WaitForEvents() - require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") + env, contracts, sethClient := prepareVRFtestEnv(t, l) for _, n := range env.ClCluster.Nodes { nodeKey, err := n.API.MustCreateVRFKey() @@ -164,7 +114,7 @@ func TestVRFJobReplacement(t *testing.T) { MinIncomingConfirmations: 1, PublicKey: pubKeyCompressed, ExternalJobID: jobUUID.String(), - EVMChainID: env.EVMClient.GetChainID().String(), + EVMChainID: fmt.Sprint(sethClient.ChainID), ObservationSource: ost, }) require.NoError(t, err, "Creating VRF Job shouldn't fail") @@ -213,7 +163,7 @@ func TestVRFJobReplacement(t *testing.T) { MinIncomingConfirmations: 1, PublicKey: pubKeyCompressed, ExternalJobID: jobUUID.String(), - EVMChainID: env.EVMClient.GetChainID().String(), + EVMChainID: fmt.Sprint(sethClient.ChainID), ObservationSource: ost, }) require.NoError(t, err, "Recreating VRF Job shouldn't fail") @@ -231,3 +181,38 @@ func TestVRFJobReplacement(t *testing.T) { }, timeout, "1s").Should(gomega.Succeed()) } } + +func prepareVRFtestEnv(t *testing.T, l zerolog.Logger) (*test_env.CLClusterTestEnv, *vrfv1.Contracts, *seth.Client) { + config, err := tc.GetConfig("Smoke", tc.VRF) + require.NoError(t, err, "Error getting config") + + privateNetwork, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") + + env, err := test_env.NewCLTestEnvBuilder(). + WithTestInstance(t). + WithTestConfig(&config). + WithPrivateEthereumNetwork(privateNetwork). + WithCLNodes(1). + WithFunding(big.NewFloat(.1)). + WithStandardCleanup(). + WithSeth(). + Build() + require.NoError(t, err) + + network := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0] + sethClient, err := env.GetSethClient(network.ChainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") + + lt, err := ethcontracts.DeployLinkTokenContract(l, sethClient) + require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") + contracts, err := vrfv1.DeployVRFContracts(sethClient, lt.Address()) + require.NoError(t, err, "Deploying VRF Contracts shouldn't fail") + + err = lt.Transfer(contracts.Consumer.Address(), big.NewInt(2e18)) + require.NoError(t, err, "Funding consumer contract shouldn't fail") + _, err = ethcontracts.DeployVRFv1Contract(sethClient) + require.NoError(t, err, "Deploying VRF contract shouldn't fail") + + return env, contracts, sethClient +} diff --git a/integration-tests/smoke/vrfv2_test.go b/integration-tests/smoke/vrfv2_test.go index 18a28c6ecbb..9834cd77973 100644 --- a/integration-tests/smoke/vrfv2_test.go +++ b/integration-tests/smoke/vrfv2_test.go @@ -16,6 +16,7 @@ import ( commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" @@ -30,74 +31,83 @@ import ( func TestVRFv2Basic(t *testing.T) { t.Parallel() + var ( + testEnv *test_env.CLClusterTestEnv + vrfContracts *vrfcommon.VRFContracts + subIDsForCancellingAfterTest []uint64 + defaultWalletAddress string + vrfKey *vrfcommon.VRFKeyData + nodeTypeToNodeMap map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode + ) l := logging.GetTestLogger(t) config, err := tc.GetConfig("Smoke", tc.VRFv2) require.NoError(t, err, "Error getting config") + vrfv2Config := config.VRFv2 + chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID + + cleanupFn := func() { + evmClient, err := testEnv.GetEVMClient(chainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + + if evmClient.NetworkSimulated() { + l.Info(). + Str("Network Name", evmClient.GetNetworkName()). + Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") + } else { + if *vrfv2Config.General.CancelSubsAfterTestRun { + //cancel subs and return funds to sub owner + vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + } + } + if !*vrfv2Config.General.UseExistingEnv { + if err := testEnv.Cleanup(); err != nil { + l.Error().Err(err).Msg("Error cleaning up test environment") + } + } + } + newEnvConfig := vrfcommon.NewEnvConfig{ + NodesToCreate: []vrfcommon.VRFNodeType{vrfcommon.VRF}, + NumberOfTxKeysToCreate: 0, + UseVRFOwner: false, + UseTestCoordinator: false, + } - useVRFOwner := false - useTestCoordinator := false - network, err := actions.EthereumNetworkConfigFromConfig(l, &config) - require.NoError(t, err, "Error building ethereum network config") - - env, err := test_env.NewCLTestEnvBuilder(). - WithTestInstance(t). - WithTestConfig(&config). - WithPrivateEthereumNetwork(network). - WithCLNodes(1). - WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). - WithStandardCleanup(). - Build() - require.NoError(t, err, "error creating test env") - - env.ParallelTransactions(true) - - mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*config.VRFv2.General.LinkNativeFeedResponse)) - require.NoError(t, err) - linkToken, err := actions.DeployLINKToken(env.ContractDeployer) - require.NoError(t, err) - - // register proving key against oracle address (sending key) in order to test oracleWithdraw - defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() - - numberOfTxKeysToCreate := 1 - vrfv2Contracts, subIDs, vrfv2KeyData, nodesMap, err := vrfv2.SetupVRFV2Environment( - env, - []vrfcommon.VRFNodeType{vrfcommon.VRF}, - &config, - useVRFOwner, - useTestCoordinator, - linkToken, - mockETHLinkFeed, - defaultWalletAddress, - numberOfTxKeysToCreate, - 1, - 1, - l, - ) - require.NoError(t, err, "error setting up VRF v2 env") - - subID := subIDs[0] - - subscription, err := vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subID) - require.NoError(t, err, "error getting subscription information") + testEnv, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + require.NoError(t, err, "Error setting up VRFV2 universe") + evmClient, err := testEnv.GetEVMClient(chainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") - vrfv2.LogSubDetails(l, subscription, subID, vrfv2Contracts.CoordinatorV2) + defaultWalletAddress = evmClient.GetDefaultWallet().Address() t.Run("Request Randomness", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) - subBalanceBeforeRequest := subscription.Balance + consumers, subIDsForRequestRandomness, err := vrfv2.SetupNewConsumersAndSubs( + testEnv, + chainID, + vrfContracts.CoordinatorV2, + configCopy, + vrfContracts.LinkToken, + 1, + 1, + l, + ) + require.NoError(t, err, "error setting up new consumers and subs") + subIDForRequestRandomness := subIDsForRequestRandomness[0] + subscription, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForRequestRandomness) + require.NoError(t, err, "error getting subscription information") + vrfv2.LogSubDetails(l, subscription, subIDForRequestRandomness, vrfContracts.CoordinatorV2) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDsForRequestRandomness...) - jobRunsBeforeTest, err := nodesMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodesMap[vrfcommon.VRF].Job.Data.ID) - require.NoError(t, err, "error reading job runs") + subBalanceBeforeRequest := subscription.Balance // test and assert randomWordsFulfilledEvent, err := vrfv2.RequestRandomnessAndWaitForFulfillment( l, - vrfv2Contracts.VRFV2Consumer[0], - vrfv2Contracts.CoordinatorV2, - subID, - vrfv2KeyData, + consumers[0], + vrfContracts.CoordinatorV2, + subIDForRequestRandomness, + vrfKey, *configCopy.VRFv2.General.MinimumConfirmations, *configCopy.VRFv2.General.CallbackGasLimit, *configCopy.VRFv2.General.NumberOfWords, @@ -108,45 +118,89 @@ func TestVRFv2Basic(t *testing.T) { require.NoError(t, err, "error requesting randomness and waiting for fulfilment") expectedSubBalanceJuels := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - subscription, err = vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subID) + subscription, err = vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForRequestRandomness) require.NoError(t, err, "error getting subscription information") subBalanceAfterRequest := subscription.Balance require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest) - jobRuns, err := nodesMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodesMap[vrfcommon.VRF].Job.Data.ID) - require.NoError(t, err, "error reading job runs") - require.Equal(t, len(jobRunsBeforeTest.Data)+1, len(jobRuns.Data)) - - status, err := vrfv2Contracts.VRFV2Consumer[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) + status, err := consumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") - require.Equal(t, *config.VRFv2.General.NumberOfWords, uint32(len(status.RandomWords))) + require.Equal(t, *configCopy.VRFv2.General.NumberOfWords, uint32(len(status.RandomWords))) for _, w := range status.RandomWords { l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") } }) + t.Run("CL Node VRF Job Runs", func(t *testing.T) { + configCopy := config.MustCopy().(tc.TestConfig) + consumers, subIDsForJobRuns, err := vrfv2.SetupNewConsumersAndSubs( + testEnv, + chainID, + vrfContracts.CoordinatorV2, + configCopy, + vrfContracts.LinkToken, + 1, + 1, + l, + ) + require.NoError(t, err, "error setting up new consumers and subs") + + subIDForJobRuns := subIDsForJobRuns[0] + subscription, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForJobRuns) + require.NoError(t, err, "error getting subscription information") + vrfv2.LogSubDetails(l, subscription, subIDForJobRuns, vrfContracts.CoordinatorV2) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDsForJobRuns...) + + jobRunsBeforeTest, err := nodeTypeToNodeMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodeTypeToNodeMap[vrfcommon.VRF].Job.Data.ID) + require.NoError(t, err, "error reading job runs") + + // test and assert + _, err = vrfv2.RequestRandomnessAndWaitForFulfillment( + l, + consumers[0], + vrfContracts.CoordinatorV2, + subIDForJobRuns, + vrfKey, + *configCopy.VRFv2.General.MinimumConfirmations, + *configCopy.VRFv2.General.CallbackGasLimit, + *configCopy.VRFv2.General.NumberOfWords, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, + configCopy.VRFv2.General.RandomWordsFulfilledEventTimeout.Duration, + ) + require.NoError(t, err, "error requesting randomness and waiting for fulfilment") + + jobRuns, err := nodeTypeToNodeMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodeTypeToNodeMap[vrfcommon.VRF].Job.Data.ID) + require.NoError(t, err, "error reading job runs") + require.Equal(t, len(jobRunsBeforeTest.Data)+1, len(jobRuns.Data)) + }) + t.Run("Direct Funding (VRFV2Wrapper)", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) wrapperContracts, wrapperSubID, err := vrfv2.SetupVRFV2WrapperEnvironment( - env, + testcontext.Get(t), + testEnv, + chainID, &configCopy, - linkToken, - mockETHLinkFeed, - vrfv2Contracts.CoordinatorV2, - vrfv2KeyData.KeyHash, + vrfContracts.LinkToken, + vrfContracts.MockETHLINKFeed, + vrfContracts.CoordinatorV2, + vrfKey.KeyHash, 1, ) require.NoError(t, err) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, *wrapperSubID) + wrapperConsumer := wrapperContracts.LoadTestConsumers[0] - wrapperConsumerJuelsBalanceBeforeRequest, err := linkToken.BalanceOf(testcontext.Get(t), wrapperConsumer.Address()) + wrapperConsumerJuelsBalanceBeforeRequest, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), wrapperConsumer.Address()) require.NoError(t, err, "Error getting wrapper consumer balance") - wrapperSubscription, err := vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), *wrapperSubID) + wrapperSubscription, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), *wrapperSubID) require.NoError(t, err, "Error getting subscription information") subBalanceBeforeRequest := wrapperSubscription.Balance @@ -154,9 +208,9 @@ func TestVRFv2Basic(t *testing.T) { randomWordsFulfilledEvent, err := vrfv2.DirectFundingRequestRandomnessAndWaitForFulfillment( l, wrapperConsumer, - vrfv2Contracts.CoordinatorV2, + vrfContracts.CoordinatorV2, *wrapperSubID, - vrfv2KeyData, + vrfKey, *configCopy.VRFv2.General.MinimumConfirmations, *configCopy.VRFv2.General.CallbackGasLimit, *configCopy.VRFv2.General.NumberOfWords, @@ -168,7 +222,7 @@ func TestVRFv2Basic(t *testing.T) { // Check wrapper subscription balance expectedSubBalanceJuels := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - wrapperSubscription, err = vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), *wrapperSubID) + wrapperSubscription, err = vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), *wrapperSubID) require.NoError(t, err, "Error getting subscription information") subBalanceAfterRequest := wrapperSubscription.Balance require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest) @@ -180,7 +234,7 @@ func TestVRFv2Basic(t *testing.T) { // Check wrapper consumer LINK balance expectedWrapperConsumerJuelsBalance := new(big.Int).Sub(wrapperConsumerJuelsBalanceBeforeRequest, consumerStatus.Paid) - wrapperConsumerJuelsBalanceAfterRequest, err := linkToken.BalanceOf(testcontext.Get(t), wrapperConsumer.Address()) + wrapperConsumerJuelsBalanceAfterRequest, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), wrapperConsumer.Address()) require.NoError(t, err, "Error getting wrapper consumer balance") require.Equal(t, expectedWrapperConsumerJuelsBalance, wrapperConsumerJuelsBalanceAfterRequest) @@ -207,24 +261,30 @@ func TestVRFv2Basic(t *testing.T) { t.Run("Oracle Withdraw", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) - subIDsForOracleWithDraw, err := vrfv2.CreateFundSubsAndAddConsumers( - env, - big.NewFloat(*configCopy.VRFv2.General.SubscriptionFundingAmountLink), - linkToken, - vrfv2Contracts.CoordinatorV2, - vrfv2Contracts.VRFV2Consumer, + consumers, subIDsForOracleWithDraw, err := vrfv2.SetupNewConsumersAndSubs( + testEnv, + chainID, + vrfContracts.CoordinatorV2, + configCopy, + vrfContracts.LinkToken, 1, + 1, + l, ) - require.NoError(t, err) + require.NoError(t, err, "error setting up new consumers and subs") subIDForOracleWithdraw := subIDsForOracleWithDraw[0] + subscription, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForOracleWithdraw) + require.NoError(t, err, "error getting subscription information") + vrfv2.LogSubDetails(l, subscription, subIDForOracleWithdraw, vrfContracts.CoordinatorV2) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDsForOracleWithDraw...) fulfilledEventLink, err := vrfv2.RequestRandomnessAndWaitForFulfillment( l, - vrfv2Contracts.VRFV2Consumer[0], - vrfv2Contracts.CoordinatorV2, + consumers[0], + vrfContracts.CoordinatorV2, subIDForOracleWithdraw, - vrfv2KeyData, + vrfKey, *configCopy.VRFv2.General.MinimumConfirmations, *configCopy.VRFv2.General.CallbackGasLimit, *configCopy.VRFv2.General.NumberOfWords, @@ -236,7 +296,7 @@ func TestVRFv2Basic(t *testing.T) { amountToWithdrawLink := fulfilledEventLink.Payment - defaultWalletBalanceLinkBeforeOracleWithdraw, err := linkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) + defaultWalletBalanceLinkBeforeOracleWithdraw, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) require.NoError(t, err) l.Info(). @@ -244,13 +304,13 @@ func TestVRFv2Basic(t *testing.T) { Str("Amount", amountToWithdrawLink.String()). Msg("Invoking Oracle Withdraw for LINK") - err = vrfv2Contracts.CoordinatorV2.OracleWithdraw(common.HexToAddress(defaultWalletAddress), amountToWithdrawLink) + err = vrfContracts.CoordinatorV2.OracleWithdraw(common.HexToAddress(defaultWalletAddress), amountToWithdrawLink) require.NoError(t, err, "Error withdrawing LINK from coordinator to default wallet") - err = env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - defaultWalletBalanceLinkAfterOracleWithdraw, err := linkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) + defaultWalletBalanceLinkAfterOracleWithdraw, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) require.NoError(t, err) require.Equal( @@ -263,24 +323,30 @@ func TestVRFv2Basic(t *testing.T) { t.Run("Canceling Sub And Returning Funds", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) - subIDsForCancelling, err := vrfv2.CreateFundSubsAndAddConsumers( - env, - big.NewFloat(*configCopy.VRFv2.General.SubscriptionFundingAmountLink), - linkToken, - vrfv2Contracts.CoordinatorV2, - vrfv2Contracts.VRFV2Consumer, + _, subIDsForCancelling, err := vrfv2.SetupNewConsumersAndSubs( + testEnv, + chainID, + vrfContracts.CoordinatorV2, + configCopy, + vrfContracts.LinkToken, 1, + 1, + l, ) - require.NoError(t, err) + require.NoError(t, err, "error setting up new consumers and subs") subIDForCancelling := subIDsForCancelling[0] + subscription, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForCancelling) + require.NoError(t, err, "error getting subscription information") + vrfv2.LogSubDetails(l, subscription, subIDForCancelling, vrfContracts.CoordinatorV2) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDsForCancelling...) testWalletAddress, err := actions.GenerateWallet() require.NoError(t, err) - testWalletBalanceLinkBeforeSubCancelling, err := linkToken.BalanceOf(testcontext.Get(t), testWalletAddress.String()) + testWalletBalanceLinkBeforeSubCancelling, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), testWalletAddress.String()) require.NoError(t, err) - subscriptionForCancelling, err := vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForCancelling) + subscriptionForCancelling, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForCancelling) require.NoError(t, err, "error getting subscription information") subBalanceLink := subscriptionForCancelling.Balance @@ -291,16 +357,19 @@ func TestVRFv2Basic(t *testing.T) { Str("Returning funds to", testWalletAddress.String()). Msg("Canceling subscription and returning funds to subscription owner") - tx, err := vrfv2Contracts.CoordinatorV2.CancelSubscription(subIDForCancelling, testWalletAddress) + tx, err := vrfContracts.CoordinatorV2.CancelSubscription(subIDForCancelling, testWalletAddress) require.NoError(t, err, "Error canceling subscription") - subscriptionCanceledEvent, err := vrfv2Contracts.CoordinatorV2.WaitForSubscriptionCanceledEvent([]uint64{subIDForCancelling}, time.Second*30) + subscriptionCanceledEvent, err := vrfContracts.CoordinatorV2.WaitForSubscriptionCanceledEvent([]uint64{subIDForCancelling}, time.Second*30) require.NoError(t, err, "error waiting for subscription canceled event") - - cancellationTxReceipt, err := env.EVMClient.GetTxReceipt(tx.Hash()) + cancellationTxReceipt, err := evmClient.GetTxReceipt(tx.Hash()) require.NoError(t, err, "error getting tx cancellation Tx Receipt") txGasUsed := new(big.Int).SetUint64(cancellationTxReceipt.GasUsed) + // we don't have that information for older Geth versions + if cancellationTxReceipt.EffectiveGasPrice == nil { + cancellationTxReceipt.EffectiveGasPrice = new(big.Int).SetUint64(0) + } cancellationTxFeeWei := new(big.Int).Mul(txGasUsed, cancellationTxReceipt.EffectiveGasPrice) l.Info(). @@ -317,11 +386,11 @@ func TestVRFv2Basic(t *testing.T) { require.Equal(t, subBalanceLink, subscriptionCanceledEvent.Amount, "SubscriptionCanceled event LINK amount is not equal to sub amount while canceling subscription") - testWalletBalanceLinkAfterSubCancelling, err := linkToken.BalanceOf(testcontext.Get(t), testWalletAddress.String()) + testWalletBalanceLinkAfterSubCancelling, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), testWalletAddress.String()) require.NoError(t, err) //Verify that sub was deleted from Coordinator - _, err = vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForCancelling) + _, err = vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForCancelling) require.Error(t, err, "error not occurred when trying to get deleted subscription from old Coordinator after sub migration") subFundsReturnedLinkActual := new(big.Int).Sub(testWalletBalanceLinkAfterSubCancelling, testWalletBalanceLinkBeforeSubCancelling) @@ -338,28 +407,28 @@ func TestVRFv2Basic(t *testing.T) { t.Run("Owner Canceling Sub And Returning Funds While Having Pending Requests", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) // Underfund subscription to force fulfillments to fail - configCopy.VRFv2.General.SubscriptionFundingAmountLink = ptr.Ptr(float64(0.000000000000000001)) // 1 Juel - - subIDsForCancelling, err := vrfv2.CreateFundSubsAndAddConsumers( - env, - big.NewFloat(*configCopy.VRFv2.General.SubscriptionFundingAmountLink), - linkToken, - vrfv2Contracts.CoordinatorV2, - vrfv2Contracts.VRFV2Consumer, + configCopy.VRFv2.General.SubscriptionFundingAmountLink = ptr.Ptr(float64(0)) + + consumers, subIDsForOwnerCancelling, err := vrfv2.SetupNewConsumersAndSubs( + testEnv, + chainID, + vrfContracts.CoordinatorV2, + configCopy, + vrfContracts.LinkToken, 1, + 1, + l, ) - require.NoError(t, err) - - subIDForCancelling := subIDsForCancelling[0] - - subscriptionForCancelling, err := vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForCancelling) - require.NoError(t, err, "Error getting subscription information") - - vrfv2.LogSubDetails(l, subscriptionForCancelling, subIDForCancelling, vrfv2Contracts.CoordinatorV2) + require.NoError(t, err, "error setting up new consumers and subs") + subIDForOwnerCancelling := subIDsForOwnerCancelling[0] + subscriptionForCancelling, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForOwnerCancelling) + require.NoError(t, err, "error getting subscription information") + vrfv2.LogSubDetails(l, subscriptionForCancelling, subIDForOwnerCancelling, vrfContracts.CoordinatorV2) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDsForOwnerCancelling...) // No GetActiveSubscriptionIds function available - skipping check - pendingRequestsExist, err := vrfv2Contracts.CoordinatorV2.PendingRequestsExist(testcontext.Get(t), subIDForCancelling) + pendingRequestsExist, err := vrfContracts.CoordinatorV2.PendingRequestsExist(testcontext.Get(t), subIDForOwnerCancelling) require.NoError(t, err) require.False(t, pendingRequestsExist, "Pending requests should not exist") @@ -367,10 +436,10 @@ func TestVRFv2Basic(t *testing.T) { randomWordsFulfilledEventTimeout := 5 * time.Second _, err = vrfv2.RequestRandomnessAndWaitForFulfillment( l, - vrfv2Contracts.VRFV2Consumer[0], - vrfv2Contracts.CoordinatorV2, - subIDForCancelling, - vrfv2KeyData, + consumers[0], + vrfContracts.CoordinatorV2, + subIDForOwnerCancelling, + vrfKey, *configCopy.VRFv2.General.MinimumConfirmations, *configCopy.VRFv2.General.CallbackGasLimit, *configCopy.VRFv2.General.NumberOfWords, @@ -380,34 +449,38 @@ func TestVRFv2Basic(t *testing.T) { ) require.Error(t, err, "Error should occur while waiting for fulfilment due to low sub balance") - pendingRequestsExist, err = vrfv2Contracts.CoordinatorV2.PendingRequestsExist(testcontext.Get(t), subIDForCancelling) + pendingRequestsExist, err = vrfContracts.CoordinatorV2.PendingRequestsExist(testcontext.Get(t), subIDForOwnerCancelling) require.NoError(t, err) require.True(t, pendingRequestsExist, "Pending requests should exist after unfilfulled requests due to low sub balance") - walletBalanceLinkBeforeSubCancelling, err := linkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) + walletBalanceLinkBeforeSubCancelling, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) require.NoError(t, err) - subscriptionForCancelling, err = vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForCancelling) + subscriptionForCancelling, err = vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForOwnerCancelling) require.NoError(t, err, "Error getting subscription information") subBalanceLink := subscriptionForCancelling.Balance l.Info(). Str("Subscription Amount Link", subBalanceLink.String()). - Uint64("Returning funds from SubID", subIDForCancelling). + Uint64("Returning funds from SubID", subIDForOwnerCancelling). Str("Returning funds to", defaultWalletAddress). Msg("Canceling subscription and returning funds to subscription owner") // Call OwnerCancelSubscription - tx, err := vrfv2Contracts.CoordinatorV2.OwnerCancelSubscription(subIDForCancelling) + tx, err := vrfContracts.CoordinatorV2.OwnerCancelSubscription(subIDForOwnerCancelling) require.NoError(t, err, "Error canceling subscription") - subscriptionCanceledEvent, err := vrfv2Contracts.CoordinatorV2.WaitForSubscriptionCanceledEvent([]uint64{subIDForCancelling}, time.Second*30) + subscriptionCanceledEvent, err := vrfContracts.CoordinatorV2.WaitForSubscriptionCanceledEvent([]uint64{subIDForOwnerCancelling}, time.Second*30) require.NoError(t, err, "error waiting for subscription canceled event") - cancellationTxReceipt, err := env.EVMClient.GetTxReceipt(tx.Hash()) + cancellationTxReceipt, err := evmClient.GetTxReceipt(tx.Hash()) require.NoError(t, err, "error getting tx cancellation Tx Receipt") txGasUsed := new(big.Int).SetUint64(cancellationTxReceipt.GasUsed) + // we don't have that information for older Geth versions + if cancellationTxReceipt.EffectiveGasPrice == nil { + cancellationTxReceipt.EffectiveGasPrice = new(big.Int).SetUint64(0) + } cancellationTxFeeWei := new(big.Int).Mul(txGasUsed, cancellationTxReceipt.EffectiveGasPrice) l.Info(). @@ -424,11 +497,11 @@ func TestVRFv2Basic(t *testing.T) { require.Equal(t, subBalanceLink, subscriptionCanceledEvent.Amount, "SubscriptionCanceled event LINK amount is not equal to sub amount while canceling subscription") - walletBalanceLinkAfterSubCancelling, err := linkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) + walletBalanceLinkAfterSubCancelling, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) require.NoError(t, err) // Verify that subscription was deleted from Coordinator contract - _, err = vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForCancelling) + _, err = vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForOwnerCancelling) l.Info(). Str("Expected error message", err.Error()) require.Error(t, err, "Error did not occur when fetching deleted subscription from the Coordinator after owner cancelation") @@ -451,94 +524,105 @@ func TestVRFv2Basic(t *testing.T) { func TestVRFv2MultipleSendingKeys(t *testing.T) { t.Parallel() + var ( + testEnv *test_env.CLClusterTestEnv + vrfContracts *vrfcommon.VRFContracts + subIDsForCancellingAfterTest []uint64 + defaultWalletAddress string + vrfKey *vrfcommon.VRFKeyData + nodeTypeToNodeMap map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode + ) l := logging.GetTestLogger(t) config, err := tc.GetConfig("Smoke", tc.VRFv2) if err != nil { t.Fatal(err) } + chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID + vrfv2Config := config.VRFv2 + cleanupFn := func() { + evmClient, err := testEnv.GetEVMClient(chainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + if evmClient.NetworkSimulated() { + l.Info(). + Str("Network Name", evmClient.GetNetworkName()). + Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") + } else { + if *vrfv2Config.General.CancelSubsAfterTestRun { + //cancel subs and return funds to sub owner + vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + } + } + if !*vrfv2Config.General.UseExistingEnv { + if err := testEnv.Cleanup(); err != nil { + l.Error().Err(err).Msg("Error cleaning up test environment") + } + } + } + newEnvConfig := vrfcommon.NewEnvConfig{ + NodesToCreate: []vrfcommon.VRFNodeType{vrfcommon.VRF}, + NumberOfTxKeysToCreate: 2, + UseVRFOwner: false, + UseTestCoordinator: false, + } - useVRFOwner := false - useTestCoordinator := false - - network, err := actions.EthereumNetworkConfigFromConfig(l, &config) - require.NoError(t, err, "Error building ethereum network config") - - env, err := test_env.NewCLTestEnvBuilder(). - WithTestConfig(&config). - WithTestInstance(t). - WithPrivateEthereumNetwork(network). - WithCLNodes(1). - WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). - WithStandardCleanup(). - Build() - require.NoError(t, err, "error creating test env") - - env.ParallelTransactions(true) - - mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*config.VRFv2.General.LinkNativeFeedResponse)) - require.NoError(t, err) - linkToken, err := actions.DeployLINKToken(env.ContractDeployer) - require.NoError(t, err) - - // register proving key against oracle address (sending key) in order to test oracleWithdraw - defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() - - numberOfTxKeysToCreate := 2 - vrfv2Contracts, subIDs, vrfv2KeyData, nodesMap, err := vrfv2.SetupVRFV2Environment( - env, - []vrfcommon.VRFNodeType{vrfcommon.VRF}, - &config, - useVRFOwner, - useTestCoordinator, - linkToken, - mockETHLinkFeed, - defaultWalletAddress, - numberOfTxKeysToCreate, - 1, - 1, - l, - ) - require.NoError(t, err, "error setting up VRF v2 env") + testEnv, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + require.NoError(t, err, "Error setting up VRFV2 universe") - subID := subIDs[0] + evmClient, err := testEnv.GetEVMClient(chainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + defaultWalletAddress = evmClient.GetDefaultWallet().Address() - subscription, err := vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subID) - require.NoError(t, err, "error getting subscription information") + t.Run("Request Randomness with multiple sending keys", func(t *testing.T) { + configCopy := config.MustCopy().(tc.TestConfig) - vrfv2.LogSubDetails(l, subscription, subID, vrfv2Contracts.CoordinatorV2) + consumers, subIDsForMultipleSendingKeys, err := vrfv2.SetupNewConsumersAndSubs( + testEnv, + chainID, + vrfContracts.CoordinatorV2, + configCopy, + vrfContracts.LinkToken, + 1, + 1, + l, + ) + require.NoError(t, err, "error setting up new consumers and subs") + subIDForMultipleSendingKeys := subIDsForMultipleSendingKeys[0] + subscriptionForMultipleSendingKeys, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForMultipleSendingKeys) + require.NoError(t, err, "error getting subscription information") + vrfv2.LogSubDetails(l, subscriptionForMultipleSendingKeys, subIDForMultipleSendingKeys, vrfContracts.CoordinatorV2) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDsForMultipleSendingKeys...) - t.Run("Request Randomness with multiple sending keys", func(t *testing.T) { - txKeys, _, err := nodesMap[vrfcommon.VRF].CLNode.API.ReadTxKeys("evm") + txKeys, _, err := nodeTypeToNodeMap[vrfcommon.VRF].CLNode.API.ReadTxKeys("evm") require.NoError(t, err, "error reading tx keys") - require.Equal(t, numberOfTxKeysToCreate+1, len(txKeys.Data)) + require.Equal(t, newEnvConfig.NumberOfTxKeysToCreate+1, len(txKeys.Data)) var fulfillmentTxFromAddresses []string - for i := 0; i < numberOfTxKeysToCreate+1; i++ { + for i := 0; i < newEnvConfig.NumberOfTxKeysToCreate+1; i++ { randomWordsFulfilledEvent, err := vrfv2.RequestRandomnessAndWaitForFulfillment( l, - vrfv2Contracts.VRFV2Consumer[0], - vrfv2Contracts.CoordinatorV2, - subID, - vrfv2KeyData, - *config.VRFv2.General.MinimumConfirmations, - *config.VRFv2.General.CallbackGasLimit, - *config.VRFv2.General.NumberOfWords, - *config.VRFv2.General.RandomnessRequestCountPerRequest, - *config.VRFv2.General.RandomnessRequestCountPerRequestDeviation, - config.VRFv2.General.RandomWordsFulfilledEventTimeout.Duration, + consumers[0], + vrfContracts.CoordinatorV2, + subIDForMultipleSendingKeys, + vrfKey, + *configCopy.VRFv2.General.MinimumConfirmations, + *configCopy.VRFv2.General.CallbackGasLimit, + *configCopy.VRFv2.General.NumberOfWords, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, + configCopy.VRFv2.General.RandomWordsFulfilledEventTimeout.Duration, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") //todo - move TransactionByHash to EVMClient in CTF - fulfillmentTx, _, err := actions.GetTxByHash(testcontext.Get(t), env.EVMClient, randomWordsFulfilledEvent.Raw.TxHash) + fulfillmentTx, _, err := actions.GetTxByHash(testcontext.Get(t), evmClient, randomWordsFulfilledEvent.Raw.TxHash) require.NoError(t, err, "error getting tx from hash") fulfillmentTxFromAddress, err := actions.GetTxFromAddress(fulfillmentTx) require.NoError(t, err, "error getting tx from address") fulfillmentTxFromAddresses = append(fulfillmentTxFromAddresses, fulfillmentTxFromAddress) } - require.Equal(t, numberOfTxKeysToCreate+1, len(fulfillmentTxFromAddresses)) + require.Equal(t, newEnvConfig.NumberOfTxKeysToCreate+1, len(fulfillmentTxFromAddresses)) var txKeyAddresses []string for _, txKey := range txKeys.Data { txKeyAddresses = append(txKeyAddresses, txKey.Attributes.Address) @@ -551,109 +635,117 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { func TestVRFOwner(t *testing.T) { t.Parallel() + var ( + testEnv *test_env.CLClusterTestEnv + vrfContracts *vrfcommon.VRFContracts + subIDsForCancellingAfterTest []uint64 + defaultWalletAddress string + vrfKey *vrfcommon.VRFKeyData + ) l := logging.GetTestLogger(t) config, err := tc.GetConfig("Smoke", tc.VRFv2) require.NoError(t, err, "Error getting config") + chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID + vrfv2Config := config.VRFv2 + cleanupFn := func() { + evmClient, err := testEnv.GetEVMClient(chainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + if evmClient.NetworkSimulated() { + l.Info(). + Str("Network Name", evmClient.GetNetworkName()). + Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") + } else { + if *vrfv2Config.General.CancelSubsAfterTestRun { + //cancel subs and return funds to sub owner + vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + } + } + if !*vrfv2Config.General.UseExistingEnv { + if err := testEnv.Cleanup(); err != nil { + l.Error().Err(err).Msg("Error cleaning up test environment") + } + } + } + newEnvConfig := vrfcommon.NewEnvConfig{ + NodesToCreate: []vrfcommon.VRFNodeType{vrfcommon.VRF}, + NumberOfTxKeysToCreate: 0, + UseVRFOwner: true, + UseTestCoordinator: true, + } - useVRFOwner := true - useTestCoordinator := true - network, err := actions.EthereumNetworkConfigFromConfig(l, &config) - require.NoError(t, err, "Error building ethereum network config") - - env, err := test_env.NewCLTestEnvBuilder(). - WithTestInstance(t). - WithTestConfig(&config). - WithPrivateEthereumNetwork(network). - WithCLNodes(1). - WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). - WithStandardCleanup(). - Build() - require.NoError(t, err, "error creating test env") - - env.ParallelTransactions(true) - - mockETHLinkFeed, err := env.ContractDeployer.DeployVRFMockETHLINKFeed(big.NewInt(*config.VRFv2.General.LinkNativeFeedResponse)) - - require.NoError(t, err) - linkToken, err := actions.DeployLINKToken(env.ContractDeployer) - require.NoError(t, err) - - // register proving key against oracle address (sending key) in order to test oracleWithdraw - defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() - - numberOfTxKeysToCreate := 1 - vrfv2Contracts, subIDs, vrfv2Data, _, err := vrfv2.SetupVRFV2Environment( - env, - []vrfcommon.VRFNodeType{vrfcommon.VRF}, - &config, - useVRFOwner, - useTestCoordinator, - linkToken, - mockETHLinkFeed, - defaultWalletAddress, - numberOfTxKeysToCreate, - 1, - 1, - l, - ) - require.NoError(t, err, "error setting up VRF v2 env") - - subID := subIDs[0] - - subscription, err := vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subID) - require.NoError(t, err, "error getting subscription information") + testEnv, vrfContracts, vrfKey, _, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + require.NoError(t, err, "Error setting up VRFV2 universe") - vrfv2.LogSubDetails(l, subscription, subID, vrfv2Contracts.CoordinatorV2) + evmClient, err := testEnv.GetEVMClient(chainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + defaultWalletAddress = evmClient.GetDefaultWallet().Address() t.Run("Request Randomness With Force-Fulfill", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) - vrfCoordinatorOwner, err := vrfv2Contracts.CoordinatorV2.GetOwner(testcontext.Get(t)) + consumers, subIDsForForceFulfill, err := vrfv2.SetupNewConsumersAndSubs( + testEnv, + chainID, + vrfContracts.CoordinatorV2, + configCopy, + vrfContracts.LinkToken, + 1, + 1, + l, + ) + require.NoError(t, err, "error setting up new consumers and subs") + subIDForForceFulfill := subIDsForForceFulfill[0] + subscriptionForMultipleSendingKeys, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForForceFulfill) + require.NoError(t, err, "error getting subscription information") + vrfv2.LogSubDetails(l, subscriptionForMultipleSendingKeys, subIDForForceFulfill, vrfContracts.CoordinatorV2) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDsForForceFulfill...) + + vrfCoordinatorOwner, err := vrfContracts.CoordinatorV2.GetOwner(testcontext.Get(t)) require.NoError(t, err) - require.Equal(t, vrfv2Contracts.VRFOwner.Address(), vrfCoordinatorOwner.String()) + require.Equal(t, vrfContracts.VRFOwner.Address(), vrfCoordinatorOwner.String()) - err = linkToken.Transfer( - vrfv2Contracts.VRFV2Consumer[0].Address(), + err = vrfContracts.LinkToken.Transfer( + consumers[0].Address(), conversions.EtherToWei(big.NewFloat(*configCopy.VRFv2.General.SubscriptionFundingAmountLink)), ) require.NoError(t, err, "error transferring link to consumer contract") - err = env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - consumerLinkBalance, err := linkToken.BalanceOf(testcontext.Get(t), vrfv2Contracts.VRFV2Consumer[0].Address()) + consumerLinkBalance, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), consumers[0].Address()) require.NoError(t, err, "error getting consumer link balance") l.Info(). Str("Balance", conversions.WeiToEther(consumerLinkBalance).String()). - Str("Consumer", vrfv2Contracts.VRFV2Consumer[0].Address()). + Str("Consumer", consumers[0].Address()). Msg("Consumer Link Balance") - err = mockETHLinkFeed.SetBlockTimestampDeduction(big.NewInt(3)) + err = vrfContracts.MockETHLINKFeed.SetBlockTimestampDeduction(big.NewInt(3)) require.NoError(t, err) - err = env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) // test and assert _, randFulfilledEvent, _, err := vrfv2.RequestRandomnessWithForceFulfillAndWaitForFulfillment( l, - vrfv2Contracts.VRFV2Consumer[0], - vrfv2Contracts.CoordinatorV2, - vrfv2Contracts.VRFOwner, - vrfv2Data, + consumers[0], + vrfContracts.CoordinatorV2, + vrfContracts.VRFOwner, + vrfKey, *configCopy.VRFv2.General.MinimumConfirmations, *configCopy.VRFv2.General.CallbackGasLimit, *configCopy.VRFv2.General.NumberOfWords, *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, conversions.EtherToWei(big.NewFloat(5)), - common.HexToAddress(linkToken.Address()), + common.HexToAddress(vrfContracts.LinkToken.Address()), time.Minute*2, ) require.NoError(t, err, "error requesting randomness with force-fulfillment and waiting for fulfilment") require.Equal(t, 0, randFulfilledEvent.Payment.Cmp(big.NewInt(0)), "Forced Fulfilled Randomness's Payment should be 0") - status, err := vrfv2Contracts.VRFV2Consumer[0].GetRequestStatus(testcontext.Get(t), randFulfilledEvent.RequestId) + status, err := consumers[0].GetRequestStatus(testcontext.Get(t), randFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") @@ -664,13 +756,13 @@ func TestVRFOwner(t *testing.T) { require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") } - coordinatorConfig, err := vrfv2Contracts.CoordinatorV2.GetConfig(testcontext.Get(t)) + coordinatorConfig, err := vrfContracts.CoordinatorV2.GetConfig(testcontext.Get(t)) require.NoError(t, err, "error getting coordinator config") - coordinatorFeeConfig, err := vrfv2Contracts.CoordinatorV2.GetFeeConfig(testcontext.Get(t)) + coordinatorFeeConfig, err := vrfContracts.CoordinatorV2.GetFeeConfig(testcontext.Get(t)) require.NoError(t, err, "error getting coordinator fee config") - coordinatorFallbackWeiPerUnitLinkConfig, err := vrfv2Contracts.CoordinatorV2.GetFallbackWeiPerUnitLink(testcontext.Get(t)) + coordinatorFallbackWeiPerUnitLinkConfig, err := vrfContracts.CoordinatorV2.GetFallbackWeiPerUnitLink(testcontext.Get(t)) require.NoError(t, err, "error getting coordinator FallbackWeiPerUnitLink") require.Equal(t, *configCopy.VRFv2.General.StalenessSeconds, coordinatorConfig.StalenessSeconds) @@ -684,106 +776,114 @@ func TestVRFOwner(t *testing.T) { func TestVRFV2WithBHS(t *testing.T) { t.Parallel() + var ( + testEnv *test_env.CLClusterTestEnv + vrfContracts *vrfcommon.VRFContracts + subIDsForCancellingAfterTest []uint64 + defaultWalletAddress string + vrfKey *vrfcommon.VRFKeyData + nodeTypeToNodeMap map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode + ) l := logging.GetTestLogger(t) config, err := tc.GetConfig("Smoke", tc.VRFv2) require.NoError(t, err, "Error getting config") - - useVRFOwner := true - useTestCoordinator := true - network, err := actions.EthereumNetworkConfigFromConfig(l, &config) - require.NoError(t, err, "Error building ethereum network config") - - env, err := test_env.NewCLTestEnvBuilder(). - WithTestInstance(t). - WithTestConfig(&config). - WithPrivateEthereumNetwork(network). - WithCLNodes(2). - WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). - WithStandardCleanup(). - Build() - require.NoError(t, err, "error creating test env") - - env.ParallelTransactions(true) - - mockETHLinkFeed, err := env.ContractDeployer.DeployVRFMockETHLINKFeed(big.NewInt(*config.VRFv2.General.LinkNativeFeedResponse)) - - require.NoError(t, err) - linkToken, err := actions.DeployLINKToken(env.ContractDeployer) - require.NoError(t, err) - - // register proving key against oracle address (sending key) in order to test oracleWithdraw - defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() - - //Underfund Subscription - config.VRFv2.General.SubscriptionFundingAmountLink = ptr.Ptr(float64(0.000000000000000001)) // 1 Juel + vrfv2Config := config.VRFv2 + chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID + + cleanupFn := func() { + evmClient, err := testEnv.GetEVMClient(chainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + if evmClient.NetworkSimulated() { + l.Info(). + Str("Network Name", evmClient.GetNetworkName()). + Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") + } else { + if *vrfv2Config.General.CancelSubsAfterTestRun { + //cancel subs and return funds to sub owner + vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + } + } + if !*vrfv2Config.General.UseExistingEnv { + if err := testEnv.Cleanup(); err != nil { + l.Error().Err(err).Msg("Error cleaning up test environment") + } + } + } //decrease default span for checking blockhashes for unfulfilled requests - config.VRFv2.General.BHSJobWaitBlocks = ptr.Ptr(2) - config.VRFv2.General.BHSJobLookBackBlocks = ptr.Ptr(20) - - numberOfTxKeysToCreate := 0 - vrfv2Contracts, subIDs, vrfv2KeyData, nodesMap, err := vrfv2.SetupVRFV2Environment( - env, - []vrfcommon.VRFNodeType{vrfcommon.VRF, vrfcommon.BHS}, - &config, - useVRFOwner, - useTestCoordinator, - linkToken, - mockETHLinkFeed, - defaultWalletAddress, - numberOfTxKeysToCreate, - 1, - 1, - l, - ) - require.NoError(t, err, "error setting up VRF v2 env") - - subID := subIDs[0] + vrfv2Config.General.BHSJobWaitBlocks = ptr.Ptr(2) + vrfv2Config.General.BHSJobLookBackBlocks = ptr.Ptr(20) + + newEnvConfig := vrfcommon.NewEnvConfig{ + NodesToCreate: []vrfcommon.VRFNodeType{vrfcommon.VRF, vrfcommon.BHS}, + NumberOfTxKeysToCreate: 0, + UseVRFOwner: false, + UseTestCoordinator: false, + } - subscription, err := vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subID) - require.NoError(t, err, "error getting subscription information") + testEnv, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2.SetupVRFV2Universe(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + require.NoError(t, err, "Error setting up VRFV2 universe") - vrfv2.LogSubDetails(l, subscription, subID, vrfv2Contracts.CoordinatorV2) + evmClient, err := testEnv.GetEVMClient(chainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + defaultWalletAddress = evmClient.GetDefaultWallet().Address() t.Run("BHS Job with complete E2E - wait 256 blocks to see if Rand Request is fulfilled", func(t *testing.T) { t.Skip("Skipped since should be run on-demand on live testnet due to long execution time") //BHS node should fill in blockhashes into BHS contract depending on the waitBlocks and lookBackBlocks settings configCopy := config.MustCopy().(tc.TestConfig) - _, err := vrfv2Contracts.VRFV2Consumer[0].RequestRandomness( - vrfv2KeyData.KeyHash, - subID, + + //Underfund Subscription + configCopy.VRFv2.General.SubscriptionFundingAmountLink = ptr.Ptr(float64(0)) + consumers, subIDsForBHS, err := vrfv2.SetupNewConsumersAndSubs( + testEnv, + chainID, + vrfContracts.CoordinatorV2, + configCopy, + vrfContracts.LinkToken, + 1, + 1, + l, + ) + require.NoError(t, err, "error setting up new consumers and subs") + subIDForBHS := subIDsForBHS[0] + subscriptionForBHS, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForBHS) + require.NoError(t, err, "error getting subscription information") + vrfv2.LogSubDetails(l, subscriptionForBHS, subIDForBHS, vrfContracts.CoordinatorV2) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDsForBHS...) + + randomWordsRequestedEvent, err := vrfv2.RequestRandomness( + l, + consumers[0], + vrfContracts.CoordinatorV2, + subIDForBHS, + vrfKey, *configCopy.VRFv2.General.MinimumConfirmations, *configCopy.VRFv2.General.CallbackGasLimit, *configCopy.VRFv2.General.NumberOfWords, *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, ) require.NoError(t, err, "error requesting randomness") - randomWordsRequestedEvent, err := vrfv2Contracts.CoordinatorV2.WaitForRandomWordsRequestedEvent( - [][32]byte{vrfv2KeyData.KeyHash}, - []uint64{subID}, - []common.Address{common.HexToAddress(vrfv2Contracts.VRFV2Consumer[0].Address())}, - time.Minute*1, - ) - require.NoError(t, err, "error waiting for randomness requested event") - vrfv2.LogRandomnessRequestedEvent(l, vrfv2Contracts.CoordinatorV2, randomWordsRequestedEvent) + vrfv2.LogRandomnessRequestedEvent(l, vrfContracts.CoordinatorV2, randomWordsRequestedEvent) randRequestBlockNumber := randomWordsRequestedEvent.Raw.BlockNumber var wg sync.WaitGroup wg.Add(1) //Wait at least 256 blocks - _, err = actions.WaitForBlockNumberToBe(randRequestBlockNumber+uint64(257), env.EVMClient, &wg, time.Second*260, t) + _, err = actions.WaitForBlockNumberToBe(randRequestBlockNumber+uint64(257), evmClient, &wg, time.Second*260, t) wg.Wait() require.NoError(t, err) - err = vrfv2.FundSubscriptions(env, big.NewFloat(*configCopy.VRFv2.General.SubscriptionFundingAmountLink), linkToken, vrfv2Contracts.CoordinatorV2, subIDs) + err = vrfv2.FundSubscriptions(testEnv, chainID, big.NewFloat(*configCopy.VRFv2.General.SubscriptionFundingAmountLink), vrfContracts.LinkToken, vrfContracts.CoordinatorV2, subIDsForBHS) require.NoError(t, err, "error funding subscriptions") - randomWordsFulfilledEvent, err := vrfv2Contracts.CoordinatorV2.WaitForRandomWordsFulfilledEvent( + randomWordsFulfilledEvent, err := vrfContracts.CoordinatorV2.WaitForRandomWordsFulfilledEvent( []*big.Int{randomWordsRequestedEvent.RequestId}, time.Second*30, ) require.NoError(t, err, "error waiting for randomness fulfilled event") - vrfv2.LogRandomWordsFulfilledEvent(l, vrfv2Contracts.CoordinatorV2, randomWordsFulfilledEvent) - status, err := vrfv2Contracts.VRFV2Consumer[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) + vrfv2.LogRandomWordsFulfilledEvent(l, vrfContracts.CoordinatorV2, randomWordsFulfilledEvent) + status, err := consumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") @@ -792,38 +892,54 @@ func TestVRFV2WithBHS(t *testing.T) { t.Run("BHS Job should fill in blockhashes into BHS contract for unfulfilled requests", func(t *testing.T) { //BHS node should fill in blockhashes into BHS contract depending on the waitBlocks and lookBackBlocks settings configCopy := config.MustCopy().(tc.TestConfig) - _, err := vrfv2Contracts.VRFV2Consumer[0].RequestRandomness( - vrfv2KeyData.KeyHash, - subID, + //Underfund Subscription + configCopy.VRFv2.General.SubscriptionFundingAmountLink = ptr.Ptr(float64(0)) + + consumers, subIDsForBHS, err := vrfv2.SetupNewConsumersAndSubs( + testEnv, + chainID, + vrfContracts.CoordinatorV2, + configCopy, + vrfContracts.LinkToken, + 1, + 1, + l, + ) + require.NoError(t, err, "error setting up new consumers and subs") + subIDForBHS := subIDsForBHS[0] + subscriptionForBHS, err := vrfContracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subIDForBHS) + require.NoError(t, err, "error getting subscription information") + vrfv2.LogSubDetails(l, subscriptionForBHS, subIDForBHS, vrfContracts.CoordinatorV2) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDsForBHS...) + + randomWordsRequestedEvent, err := vrfv2.RequestRandomness( + l, + consumers[0], + vrfContracts.CoordinatorV2, + subIDForBHS, + vrfKey, *configCopy.VRFv2.General.MinimumConfirmations, *configCopy.VRFv2.General.CallbackGasLimit, *configCopy.VRFv2.General.NumberOfWords, *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, ) require.NoError(t, err, "error requesting randomness") - randomWordsRequestedEvent, err := vrfv2Contracts.CoordinatorV2.WaitForRandomWordsRequestedEvent( - [][32]byte{vrfv2KeyData.KeyHash}, - []uint64{subID}, - []common.Address{common.HexToAddress(vrfv2Contracts.VRFV2Consumer[0].Address())}, - time.Minute*1, - ) - require.NoError(t, err, "error waiting for randomness requested event") - vrfv2.LogRandomnessRequestedEvent(l, vrfv2Contracts.CoordinatorV2, randomWordsRequestedEvent) randRequestBlockNumber := randomWordsRequestedEvent.Raw.BlockNumber - _, err = vrfv2Contracts.BHS.GetBlockHash(testcontext.Get(t), big.NewInt(int64(randRequestBlockNumber))) + _, err = vrfContracts.BHS.GetBlockHash(testcontext.Get(t), big.NewInt(int64(randRequestBlockNumber))) require.Error(t, err, "error not occurred when getting blockhash for a blocknumber which was not stored in BHS contract") var wg sync.WaitGroup wg.Add(1) - _, err = actions.WaitForBlockNumberToBe(randRequestBlockNumber+uint64(*config.VRFv2.General.BHSJobWaitBlocks), env.EVMClient, &wg, time.Minute*1, t) + _, err = actions.WaitForBlockNumberToBe(randRequestBlockNumber+uint64(*configCopy.VRFv2.General.BHSJobWaitBlocks), evmClient, &wg, time.Minute*1, t) wg.Wait() require.NoError(t, err, "error waiting for blocknumber to be") - err = env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - metrics, err := vrfv2Contracts.VRFV2Consumer[0].GetLoadTestMetrics(testcontext.Get(t)) + metrics, err := consumers[0].GetLoadTestMetrics(testcontext.Get(t)) require.Equal(t, 0, metrics.RequestCount.Cmp(big.NewInt(1))) require.Equal(t, 0, metrics.FulfilmentCount.Cmp(big.NewInt(0))) @@ -831,16 +947,16 @@ func TestVRFV2WithBHS(t *testing.T) { var txHash string gom := gomega.NewGomegaWithT(t) gom.Eventually(func(g gomega.Gomega) { - clNodeTxs, _, err = nodesMap[vrfcommon.BHS].CLNode.API.ReadTransactions() + clNodeTxs, _, err = nodeTypeToNodeMap[vrfcommon.BHS].CLNode.API.ReadTransactions() g.Expect(err).ShouldNot(gomega.HaveOccurred(), "error getting CL Node transactions") l.Debug().Int("Number of TXs", len(clNodeTxs.Data)).Msg("BHS Node txs") g.Expect(len(clNodeTxs.Data)).Should(gomega.BeNumerically("==", 1), "Expected 1 tx posted by BHS Node, but found %d", len(clNodeTxs.Data)) txHash = clNodeTxs.Data[0].Attributes.Hash }, "2m", "1s").Should(gomega.Succeed()) - require.Equal(t, strings.ToLower(vrfv2Contracts.BHS.Address()), strings.ToLower(clNodeTxs.Data[0].Attributes.To)) + require.Equal(t, strings.ToLower(vrfContracts.BHS.Address()), strings.ToLower(clNodeTxs.Data[0].Attributes.To)) - bhsStoreTx, _, err := actions.GetTxByHash(testcontext.Get(t), env.EVMClient, common.HexToHash(txHash)) + bhsStoreTx, _, err := actions.GetTxByHash(testcontext.Get(t), evmClient, common.HexToHash(txHash)) require.NoError(t, err, "error getting tx from hash") bhsStoreTxInputData, err := actions.DecodeTxInputData(blockhash_store.BlockhashStoreABI, bhsStoreTx.Data()) @@ -849,12 +965,12 @@ func TestVRFV2WithBHS(t *testing.T) { Msg("BHS Node's Store Blockhash for Blocknumber Method TX") require.Equal(t, randRequestBlockNumber, bhsStoreTxInputData["n"].(*big.Int).Uint64()) - err = env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) var randRequestBlockHash [32]byte gom.Eventually(func(g gomega.Gomega) { - randRequestBlockHash, err = vrfv2Contracts.BHS.GetBlockHash(testcontext.Get(t), big.NewInt(int64(randRequestBlockNumber))) + randRequestBlockHash, err = vrfContracts.BHS.GetBlockHash(testcontext.Get(t), big.NewInt(int64(randRequestBlockNumber))) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "error getting blockhash for a blocknumber which was stored in BHS contract") }, "2m", "1s").Should(gomega.Succeed()) l.Info(). diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index 32445995dd9..c5a35704b1a 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -16,6 +16,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" vrfcommon "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/common" @@ -32,72 +33,86 @@ import ( func TestVRFv2Plus(t *testing.T) { t.Parallel() + var ( + env *test_env.CLClusterTestEnv + vrfContracts *vrfcommon.VRFContracts + subIDsForCancellingAfterTest []*big.Int + defaultWalletAddress string + vrfKey *vrfcommon.VRFKeyData + nodeTypeToNodeMap map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode + ) l := logging.GetTestLogger(t) config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) - if err != nil { - t.Fatal(err) + require.NoError(t, err, "Error getting config") + vrfv2PlusConfig := config.VRFv2Plus + chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID + + cleanupFn := func() { + evmClient, err := env.GetEVMClient(chainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + + if evmClient.NetworkSimulated() { + l.Info(). + Str("Network Name", evmClient.GetNetworkName()). + Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") + } else { + if *vrfv2PlusConfig.General.CancelSubsAfterTestRun { + //cancel subs and return funds to sub owner + vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + } + } + if !*vrfv2PlusConfig.General.UseExistingEnv { + if err := env.Cleanup(); err != nil { + l.Error().Err(err).Msg("Error cleaning up test environment") + } + } + } + newEnvConfig := vrfcommon.NewEnvConfig{ + NodesToCreate: []vrfcommon.VRFNodeType{vrfcommon.VRF}, + NumberOfTxKeysToCreate: 0, + UseVRFOwner: false, + UseTestCoordinator: false, } - network, err := actions.EthereumNetworkConfigFromConfig(l, &config) - require.NoError(t, err, "Error building ethereum network config") - - env, err := test_env.NewCLTestEnvBuilder(). - WithTestInstance(t). - WithTestConfig(&config). - WithPrivateEthereumNetwork(network). - WithCLNodes(1). - WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). - WithStandardCleanup(). - Build() - require.NoError(t, err, "error creating test env") - - env.ParallelTransactions(true) - - mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*config.VRFv2Plus.General.LinkNativeFeedResponse)) - require.NoError(t, err, "error deploying mock ETH/LINK feed") - - linkToken, err := actions.DeployLINKToken(env.ContractDeployer) - require.NoError(t, err, "error deploying LINK contract") - - // default wallet address is used to test Withdraw - defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() - - numberOfTxKeysToCreate := 2 - vrfv2PlusContracts, subIDs, vrfv2PlusData, nodesMap, err := vrfv2plus.SetupVRFV2_5Environment( - env, - []vrfcommon.VRFNodeType{vrfcommon.VRF}, - &config, - linkToken, - mockETHLinkFeed, - numberOfTxKeysToCreate, - 1, - 1, - l, - ) - require.NoError(t, err, "error setting up VRF v2_5 env") - - subID := subIDs[0] + env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + require.NoError(t, err, "Error setting up VRFv2Plus universe") - subscription, err := vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) - require.NoError(t, err, "error getting subscription information") - - vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.CoordinatorV2Plus) + evmClient, err := env.GetEVMClient(chainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + defaultWalletAddress = evmClient.GetDefaultWallet().Address() t.Run("Link Billing", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) var isNativeBilling = false + consumers, subIDsForRequestRandomness, err := vrfv2plus.SetupNewConsumersAndSubs( + env, + chainID, + vrfContracts.CoordinatorV2Plus, + configCopy, + vrfContracts.LinkToken, + 1, + 1, + l, + ) + require.NoError(t, err, "error setting up new consumers and subs") + subIDForRequestRandomness := subIDsForRequestRandomness[0] + subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subIDForRequestRandomness) + require.NoError(t, err, "error getting subscription information") + vrfv2plus.LogSubDetails(l, subscription, subIDForRequestRandomness, vrfContracts.CoordinatorV2Plus) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDsForRequestRandomness...) + subBalanceBeforeRequest := subscription.Balance - jobRunsBeforeTest, err := nodesMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodesMap[vrfcommon.VRF].Job.Data.ID) + jobRunsBeforeTest, err := nodeTypeToNodeMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodeTypeToNodeMap[vrfcommon.VRF].Job.Data.ID) require.NoError(t, err, "error reading job runs") // test and assert randomWordsFulfilledEvent, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( - vrfv2PlusContracts.VRFV2PlusConsumer[0], - vrfv2PlusContracts.CoordinatorV2Plus, - vrfv2PlusData, - subID, + consumers[0], + vrfContracts.CoordinatorV2Plus, + vrfKey, + subIDForRequestRandomness, isNativeBilling, configCopy.VRFv2Plus.General, l, @@ -109,16 +124,16 @@ func TestVRFv2Plus(t *testing.T) { require.True(t, randomWordsFulfilledEvent.Success, "RandomWordsFulfilled Event's `Success` field should be true") expectedSubBalanceJuels := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - subscription, err = vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) + subscription, err = vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subIDForRequestRandomness) require.NoError(t, err, "error getting subscription information") subBalanceAfterRequest := subscription.Balance require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest) - jobRuns, err := nodesMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodesMap[vrfcommon.VRF].Job.Data.ID) + jobRuns, err := nodeTypeToNodeMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodeTypeToNodeMap[vrfcommon.VRF].Job.Data.ID) require.NoError(t, err, "error reading job runs") require.Equal(t, len(jobRunsBeforeTest.Data)+1, len(jobRuns.Data)) - status, err := vrfv2PlusContracts.VRFV2PlusConsumer[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) + status, err := consumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") @@ -133,16 +148,34 @@ func TestVRFv2Plus(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) testConfig := configCopy.VRFv2Plus.General var isNativeBilling = true + + consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + env, + chainID, + vrfContracts.CoordinatorV2Plus, + configCopy, + vrfContracts.LinkToken, + 1, + 1, + l, + ) + require.NoError(t, err, "error setting up new consumers and subs") + subID := subIDs[0] + subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) + require.NoError(t, err, "error getting subscription information") + vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) + subNativeTokenBalanceBeforeRequest := subscription.NativeBalance - jobRunsBeforeTest, err := nodesMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodesMap[vrfcommon.VRF].Job.Data.ID) + jobRunsBeforeTest, err := nodeTypeToNodeMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodeTypeToNodeMap[vrfcommon.VRF].Job.Data.ID) require.NoError(t, err, "error reading job runs") // test and assert randomWordsFulfilledEvent, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( - vrfv2PlusContracts.VRFV2PlusConsumer[0], - vrfv2PlusContracts.CoordinatorV2Plus, - vrfv2PlusData, + consumers[0], + vrfContracts.CoordinatorV2Plus, + vrfKey, subID, isNativeBilling, configCopy.VRFv2Plus.General, @@ -153,16 +186,16 @@ func TestVRFv2Plus(t *testing.T) { require.Equal(t, isNativeBilling, randomWordsFulfilledEvent.NativePayment) require.True(t, randomWordsFulfilledEvent.Success) expectedSubBalanceWei := new(big.Int).Sub(subNativeTokenBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - subscription, err = vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) + subscription, err = vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err) subBalanceAfterRequest := subscription.NativeBalance require.Equal(t, expectedSubBalanceWei, subBalanceAfterRequest) - jobRuns, err := nodesMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodesMap[vrfcommon.VRF].Job.Data.ID) + jobRuns, err := nodeTypeToNodeMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodeTypeToNodeMap[vrfcommon.VRF].Job.Data.ID) require.NoError(t, err, "error reading job runs") require.Equal(t, len(jobRunsBeforeTest.Data)+1, len(jobRuns.Data)) - status, err := vrfv2PlusContracts.VRFV2PlusConsumer[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) + status, err := consumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") @@ -176,12 +209,14 @@ func TestVRFv2Plus(t *testing.T) { t.Run("Direct Funding (VRFV2PlusWrapper)", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) wrapperContracts, wrapperSubID, err := vrfv2plus.SetupVRFV2PlusWrapperEnvironment( + testcontext.Get(t), env, + chainID, &configCopy, - linkToken, - mockETHLinkFeed, - vrfv2PlusContracts.CoordinatorV2Plus, - vrfv2PlusData.KeyHash, + vrfContracts.LinkToken, + vrfContracts.MockETHLINKFeed, + vrfContracts.CoordinatorV2Plus, + vrfKey.KeyHash, 1, ) require.NoError(t, err) @@ -191,17 +226,17 @@ func TestVRFv2Plus(t *testing.T) { testConfig := configCopy.VRFv2Plus.General var isNativeBilling = false - wrapperConsumerJuelsBalanceBeforeRequest, err := linkToken.BalanceOf(testcontext.Get(t), wrapperContracts.LoadTestConsumers[0].Address()) + wrapperConsumerJuelsBalanceBeforeRequest, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), wrapperContracts.LoadTestConsumers[0].Address()) require.NoError(t, err, "error getting wrapper consumer balance") - wrapperSubscription, err := vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), wrapperSubID) + wrapperSubscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), wrapperSubID) require.NoError(t, err, "error getting subscription information") subBalanceBeforeRequest := wrapperSubscription.Balance randomWordsFulfilledEvent, err := vrfv2plus.DirectFundingRequestRandomnessAndWaitForFulfillment( wrapperContracts.LoadTestConsumers[0], - vrfv2PlusContracts.CoordinatorV2Plus, - vrfv2PlusData, + vrfContracts.CoordinatorV2Plus, + vrfKey, wrapperSubID, isNativeBilling, configCopy.VRFv2Plus.General, @@ -210,7 +245,7 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err, "error requesting randomness and waiting for fulfilment") expectedSubBalanceJuels := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - wrapperSubscription, err = vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), wrapperSubID) + wrapperSubscription, err = vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), wrapperSubID) require.NoError(t, err, "error getting subscription information") subBalanceAfterRequest := wrapperSubscription.Balance require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest) @@ -221,7 +256,7 @@ func TestVRFv2Plus(t *testing.T) { expectedWrapperConsumerJuelsBalance := new(big.Int).Sub(wrapperConsumerJuelsBalanceBeforeRequest, consumerStatus.Paid) - wrapperConsumerJuelsBalanceAfterRequest, err := linkToken.BalanceOf(testcontext.Get(t), wrapperContracts.LoadTestConsumers[0].Address()) + wrapperConsumerJuelsBalanceAfterRequest, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), wrapperContracts.LoadTestConsumers[0].Address()) require.NoError(t, err, "error getting wrapper consumer balance") require.Equal(t, expectedWrapperConsumerJuelsBalance, wrapperConsumerJuelsBalanceAfterRequest) @@ -240,17 +275,17 @@ func TestVRFv2Plus(t *testing.T) { testConfig := configCopy.VRFv2Plus.General var isNativeBilling = true - wrapperConsumerBalanceBeforeRequestWei, err := env.EVMClient.BalanceAt(testcontext.Get(t), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) + wrapperConsumerBalanceBeforeRequestWei, err := evmClient.BalanceAt(testcontext.Get(t), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) require.NoError(t, err, "error getting wrapper consumer balance") - wrapperSubscription, err := vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), wrapperSubID) + wrapperSubscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), wrapperSubID) require.NoError(t, err, "error getting subscription information") subBalanceBeforeRequest := wrapperSubscription.NativeBalance randomWordsFulfilledEvent, err := vrfv2plus.DirectFundingRequestRandomnessAndWaitForFulfillment( wrapperContracts.LoadTestConsumers[0], - vrfv2PlusContracts.CoordinatorV2Plus, - vrfv2PlusData, + vrfContracts.CoordinatorV2Plus, + vrfKey, wrapperSubID, isNativeBilling, configCopy.VRFv2Plus.General, @@ -259,7 +294,7 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err, "error requesting randomness and waiting for fulfilment") expectedSubBalanceWei := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) - wrapperSubscription, err = vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), wrapperSubID) + wrapperSubscription, err = vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), wrapperSubID) require.NoError(t, err, "error getting subscription information") subBalanceAfterRequest := wrapperSubscription.NativeBalance require.Equal(t, expectedSubBalanceWei, subBalanceAfterRequest) @@ -270,7 +305,7 @@ func TestVRFv2Plus(t *testing.T) { expectedWrapperConsumerWeiBalance := new(big.Int).Sub(wrapperConsumerBalanceBeforeRequestWei, consumerStatus.Paid) - wrapperConsumerBalanceAfterRequestWei, err := env.EVMClient.BalanceAt(testcontext.Get(t), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) + wrapperConsumerBalanceAfterRequestWei, err := evmClient.BalanceAt(testcontext.Get(t), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) require.NoError(t, err, "error getting wrapper consumer balance") require.Equal(t, expectedWrapperConsumerWeiBalance, wrapperConsumerBalanceAfterRequestWei) @@ -287,28 +322,33 @@ func TestVRFv2Plus(t *testing.T) { }) t.Run("Canceling Sub And Returning Funds", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) - subIDsForCancelling, err := vrfv2plus.CreateFundSubsAndAddConsumers( + _, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( env, - big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountNative), - big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountLink), - linkToken, - vrfv2PlusContracts.CoordinatorV2Plus, - vrfv2PlusContracts.VRFV2PlusConsumer, + chainID, + vrfContracts.CoordinatorV2Plus, + configCopy, + vrfContracts.LinkToken, + 1, 1, + l, ) - require.NoError(t, err) - subIDForCancelling := subIDsForCancelling[0] + require.NoError(t, err, "error setting up new consumers and subs") + subID := subIDs[0] + subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) + require.NoError(t, err, "error getting subscription information") + vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) testWalletAddress, err := actions.GenerateWallet() require.NoError(t, err) - testWalletBalanceNativeBeforeSubCancelling, err := env.EVMClient.BalanceAt(testcontext.Get(t), testWalletAddress) + testWalletBalanceNativeBeforeSubCancelling, err := evmClient.BalanceAt(testcontext.Get(t), testWalletAddress) require.NoError(t, err) - testWalletBalanceLinkBeforeSubCancelling, err := linkToken.BalanceOf(testcontext.Get(t), testWalletAddress.String()) + testWalletBalanceLinkBeforeSubCancelling, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), testWalletAddress.String()) require.NoError(t, err) - subscriptionForCancelling, err := vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subIDForCancelling) + subscriptionForCancelling, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") subBalanceLink := subscriptionForCancelling.Balance @@ -316,19 +356,23 @@ func TestVRFv2Plus(t *testing.T) { l.Info(). Str("Subscription Amount Native", subBalanceNative.String()). Str("Subscription Amount Link", subBalanceLink.String()). - Str("Returning funds from SubID", subIDForCancelling.String()). + Str("Returning funds from SubID", subID.String()). Str("Returning funds to", testWalletAddress.String()). Msg("Canceling subscription and returning funds to subscription owner") - tx, err := vrfv2PlusContracts.CoordinatorV2Plus.CancelSubscription(subIDForCancelling, testWalletAddress) + tx, err := vrfContracts.CoordinatorV2Plus.CancelSubscription(subID, testWalletAddress) require.NoError(t, err, "Error canceling subscription") - subscriptionCanceledEvent, err := vrfv2PlusContracts.CoordinatorV2Plus.WaitForSubscriptionCanceledEvent(subIDForCancelling, time.Second*30) + subscriptionCanceledEvent, err := vrfContracts.CoordinatorV2Plus.WaitForSubscriptionCanceledEvent(subID, time.Second*30) require.NoError(t, err, "error waiting for subscription canceled event") - cancellationTxReceipt, err := env.EVMClient.GetTxReceipt(tx.Hash()) + cancellationTxReceipt, err := evmClient.GetTxReceipt(tx.Hash()) require.NoError(t, err, "error getting tx cancellation Tx Receipt") txGasUsed := new(big.Int).SetUint64(cancellationTxReceipt.GasUsed) + // we don't have that information for older Geth versions + if cancellationTxReceipt.EffectiveGasPrice == nil { + cancellationTxReceipt.EffectiveGasPrice = new(big.Int).SetUint64(0) + } cancellationTxFeeWei := new(big.Int).Mul(txGasUsed, cancellationTxReceipt.EffectiveGasPrice) l.Info(). @@ -347,14 +391,14 @@ func TestVRFv2Plus(t *testing.T) { require.Equal(t, subBalanceNative, subscriptionCanceledEvent.AmountNative, "SubscriptionCanceled event native amount is not equal to sub amount while canceling subscription") require.Equal(t, subBalanceLink, subscriptionCanceledEvent.AmountLink, "SubscriptionCanceled event LINK amount is not equal to sub amount while canceling subscription") - testWalletBalanceNativeAfterSubCancelling, err := env.EVMClient.BalanceAt(testcontext.Get(t), testWalletAddress) + testWalletBalanceNativeAfterSubCancelling, err := evmClient.BalanceAt(testcontext.Get(t), testWalletAddress) require.NoError(t, err) - testWalletBalanceLinkAfterSubCancelling, err := linkToken.BalanceOf(testcontext.Get(t), testWalletAddress.String()) + testWalletBalanceLinkAfterSubCancelling, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), testWalletAddress.String()) require.NoError(t, err) //Verify that sub was deleted from Coordinator - _, err = vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subIDForCancelling) + _, err = vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.Error(t, err, "error not occurred when trying to get deleted subscription from old Coordinator after sub migration") subFundsReturnedNativeActual := new(big.Int).Sub(testWalletBalanceNativeAfterSubCancelling, testWalletBalanceNativeBeforeSubCancelling) @@ -383,42 +427,40 @@ func TestVRFv2Plus(t *testing.T) { testConfig := configCopy.VRFv2Plus.General //underfund subs in order rand fulfillments to fail - testConfig.SubscriptionFundingAmountNative = ptr.Ptr(float64(0.000000000000000001)) //1 Wei - testConfig.SubscriptionFundingAmountLink = ptr.Ptr(float64(0.000000000000000001)) //1 Juels + testConfig.SubscriptionFundingAmountNative = ptr.Ptr(float64(0)) + testConfig.SubscriptionFundingAmountLink = ptr.Ptr(float64(0)) - subIDsForCancelling, err := vrfv2plus.CreateFundSubsAndAddConsumers( + consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( env, - big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountNative), - big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountLink), - linkToken, - vrfv2PlusContracts.CoordinatorV2Plus, - vrfv2PlusContracts.VRFV2PlusConsumer, + chainID, + vrfContracts.CoordinatorV2Plus, + configCopy, + vrfContracts.LinkToken, 1, + 1, + l, ) - require.NoError(t, err) - - subIDForCancelling := subIDsForCancelling[0] - - subscriptionForCancelling, err := vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subIDForCancelling) + require.NoError(t, err, "error setting up new consumers and subs") + subID := subIDs[0] + subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") - - vrfv2plus.LogSubDetails(l, subscriptionForCancelling, subIDForCancelling, vrfv2PlusContracts.CoordinatorV2Plus) - - activeSubscriptionIdsBeforeSubCancellation, err := vrfv2PlusContracts.CoordinatorV2Plus.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) + vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) + activeSubscriptionIdsBeforeSubCancellation, err := vrfContracts.CoordinatorV2Plus.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) require.NoError(t, err) - require.True(t, it_utils.BigIntSliceContains(activeSubscriptionIdsBeforeSubCancellation, subIDForCancelling)) + require.True(t, it_utils.BigIntSliceContains(activeSubscriptionIdsBeforeSubCancellation, subID)) - pendingRequestsExist, err := vrfv2PlusContracts.CoordinatorV2Plus.PendingRequestsExist(testcontext.Get(t), subIDForCancelling) + pendingRequestsExist, err := vrfContracts.CoordinatorV2Plus.PendingRequestsExist(testcontext.Get(t), subID) require.NoError(t, err) require.False(t, pendingRequestsExist, "Pending requests should not exist") configCopy.VRFv2Plus.General.RandomWordsFulfilledEventTimeout = ptr.Ptr(blockchain.StrDuration{Duration: 5 * time.Second}) _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillment( - vrfv2PlusContracts.VRFV2PlusConsumer[0], - vrfv2PlusContracts.CoordinatorV2Plus, - vrfv2PlusData, - subIDForCancelling, + consumers[0], + vrfContracts.CoordinatorV2Plus, + vrfKey, + subID, false, configCopy.VRFv2Plus.General, l, @@ -427,10 +469,10 @@ func TestVRFv2Plus(t *testing.T) { require.Error(t, err, "error should occur for waiting for fulfilment due to low sub balance") _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillment( - vrfv2PlusContracts.VRFV2PlusConsumer[0], - vrfv2PlusContracts.CoordinatorV2Plus, - vrfv2PlusData, - subIDForCancelling, + consumers[0], + vrfContracts.CoordinatorV2Plus, + vrfKey, + subID, true, configCopy.VRFv2Plus.General, l, @@ -438,17 +480,17 @@ func TestVRFv2Plus(t *testing.T) { require.Error(t, err, "error should occur for waiting for fulfilment due to low sub balance") - pendingRequestsExist, err = vrfv2PlusContracts.CoordinatorV2Plus.PendingRequestsExist(testcontext.Get(t), subIDForCancelling) + pendingRequestsExist, err = vrfContracts.CoordinatorV2Plus.PendingRequestsExist(testcontext.Get(t), subID) require.NoError(t, err) require.True(t, pendingRequestsExist, "Pending requests should exist after unfulfilled rand requests due to low sub balance") - walletBalanceNativeBeforeSubCancelling, err := env.EVMClient.BalanceAt(testcontext.Get(t), common.HexToAddress(defaultWalletAddress)) + walletBalanceNativeBeforeSubCancelling, err := evmClient.BalanceAt(testcontext.Get(t), common.HexToAddress(defaultWalletAddress)) require.NoError(t, err) - walletBalanceLinkBeforeSubCancelling, err := linkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) + walletBalanceLinkBeforeSubCancelling, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) require.NoError(t, err) - subscriptionForCancelling, err = vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subIDForCancelling) + subscriptionForCancelling, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") subBalanceLink := subscriptionForCancelling.Balance @@ -456,19 +498,23 @@ func TestVRFv2Plus(t *testing.T) { l.Info(). Str("Subscription Amount Native", subBalanceNative.String()). Str("Subscription Amount Link", subBalanceLink.String()). - Str("Returning funds from SubID", subIDForCancelling.String()). + Str("Returning funds from SubID", subID.String()). Str("Returning funds to", defaultWalletAddress). Msg("Canceling subscription and returning funds to subscription owner") - tx, err := vrfv2PlusContracts.CoordinatorV2Plus.OwnerCancelSubscription(subIDForCancelling) + tx, err := vrfContracts.CoordinatorV2Plus.OwnerCancelSubscription(subID) require.NoError(t, err, "Error canceling subscription") - subscriptionCanceledEvent, err := vrfv2PlusContracts.CoordinatorV2Plus.WaitForSubscriptionCanceledEvent(subIDForCancelling, time.Second*30) + subscriptionCanceledEvent, err := vrfContracts.CoordinatorV2Plus.WaitForSubscriptionCanceledEvent(subID, time.Second*30) require.NoError(t, err, "error waiting for subscription canceled event") - cancellationTxReceipt, err := env.EVMClient.GetTxReceipt(tx.Hash()) + cancellationTxReceipt, err := evmClient.GetTxReceipt(tx.Hash()) require.NoError(t, err, "error getting tx cancellation Tx Receipt") txGasUsed := new(big.Int).SetUint64(cancellationTxReceipt.GasUsed) + // we don't have that information for older Geth versions + if cancellationTxReceipt.EffectiveGasPrice == nil { + cancellationTxReceipt.EffectiveGasPrice = new(big.Int).SetUint64(0) + } cancellationTxFeeWei := new(big.Int).Mul(txGasUsed, cancellationTxReceipt.EffectiveGasPrice) l.Info(). @@ -487,14 +533,14 @@ func TestVRFv2Plus(t *testing.T) { require.Equal(t, subBalanceNative, subscriptionCanceledEvent.AmountNative, "SubscriptionCanceled event native amount is not equal to sub amount while canceling subscription") require.Equal(t, subBalanceLink, subscriptionCanceledEvent.AmountLink, "SubscriptionCanceled event LINK amount is not equal to sub amount while canceling subscription") - walletBalanceNativeAfterSubCancelling, err := env.EVMClient.BalanceAt(testcontext.Get(t), common.HexToAddress(defaultWalletAddress)) + walletBalanceNativeAfterSubCancelling, err := evmClient.BalanceAt(testcontext.Get(t), common.HexToAddress(defaultWalletAddress)) require.NoError(t, err) - walletBalanceLinkAfterSubCancelling, err := linkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) + walletBalanceLinkAfterSubCancelling, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) require.NoError(t, err) //Verify that sub was deleted from Coordinator - _, err = vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subIDForCancelling) + _, err = vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.Error(t, err, "error not occurred when trying to get deleted subscription from old Coordinator after sub migration") subFundsReturnedNativeActual := new(big.Int).Sub(walletBalanceNativeAfterSubCancelling, walletBalanceNativeBeforeSubCancelling) @@ -522,34 +568,39 @@ func TestVRFv2Plus(t *testing.T) { //require.Equal(t, subFundsReturnedNativeExpected, subFundsReturnedNativeActual, "Returned funds are not equal to sub balance that was cancelled") require.Equal(t, 0, subBalanceLink.Cmp(subFundsReturnedLinkActual), "Returned LINK funds are not equal to sub balance that was cancelled") - activeSubscriptionIdsAfterSubCancellation, err := vrfv2PlusContracts.CoordinatorV2Plus.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) + activeSubscriptionIdsAfterSubCancellation, err := vrfContracts.CoordinatorV2Plus.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) require.NoError(t, err, "error getting active subscription ids") require.False( t, - it_utils.BigIntSliceContains(activeSubscriptionIdsAfterSubCancellation, subIDForCancelling), + it_utils.BigIntSliceContains(activeSubscriptionIdsAfterSubCancellation, subID), "Active subscription ids should not contain sub id after sub cancellation", ) }) t.Run("Owner Withdraw", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) - subIDsForWithdraw, err := vrfv2plus.CreateFundSubsAndAddConsumers( + consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( env, - big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountNative), - big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountLink), - linkToken, - vrfv2PlusContracts.CoordinatorV2Plus, - vrfv2PlusContracts.VRFV2PlusConsumer, + chainID, + vrfContracts.CoordinatorV2Plus, + configCopy, + vrfContracts.LinkToken, + 1, 1, + l, ) - require.NoError(t, err) - subIDForWithdraw := subIDsForWithdraw[0] + require.NoError(t, err, "error setting up new consumers and subs") + subID := subIDs[0] + subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) + require.NoError(t, err, "error getting subscription information") + vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) fulfilledEventLink, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( - vrfv2PlusContracts.VRFV2PlusConsumer[0], - vrfv2PlusContracts.CoordinatorV2Plus, - vrfv2PlusData, - subIDForWithdraw, + consumers[0], + vrfContracts.CoordinatorV2Plus, + vrfKey, + subID, false, configCopy.VRFv2Plus.General, l, @@ -557,10 +608,10 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err) fulfilledEventNative, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( - vrfv2PlusContracts.VRFV2PlusConsumer[0], - vrfv2PlusContracts.CoordinatorV2Plus, - vrfv2PlusData, - subIDForWithdraw, + consumers[0], + vrfContracts.CoordinatorV2Plus, + vrfKey, + subID, true, configCopy.VRFv2Plus.General, l, @@ -568,10 +619,10 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err) amountToWithdrawLink := fulfilledEventLink.Payment - defaultWalletBalanceNativeBeforeWithdraw, err := env.EVMClient.BalanceAt(testcontext.Get(t), common.HexToAddress(defaultWalletAddress)) + defaultWalletBalanceNativeBeforeWithdraw, err := evmClient.BalanceAt(testcontext.Get(t), common.HexToAddress(defaultWalletAddress)) require.NoError(t, err) - defaultWalletBalanceLinkBeforeWithdraw, err := linkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) + defaultWalletBalanceLinkBeforeWithdraw, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) require.NoError(t, err) l.Info(). @@ -579,7 +630,7 @@ func TestVRFv2Plus(t *testing.T) { Str("Amount", amountToWithdrawLink.String()). Msg("Invoking Oracle Withdraw for LINK") - err = vrfv2PlusContracts.CoordinatorV2Plus.Withdraw( + err = vrfContracts.CoordinatorV2Plus.Withdraw( common.HexToAddress(defaultWalletAddress), ) require.NoError(t, err, "error withdrawing LINK from coordinator to default wallet") @@ -590,18 +641,18 @@ func TestVRFv2Plus(t *testing.T) { Str("Amount", amountToWithdrawNative.String()). Msg("Invoking Oracle Withdraw for Native") - err = vrfv2PlusContracts.CoordinatorV2Plus.WithdrawNative( + err = vrfContracts.CoordinatorV2Plus.WithdrawNative( common.HexToAddress(defaultWalletAddress), ) require.NoError(t, err, "error withdrawing Native tokens from coordinator to default wallet") - err = env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - defaultWalletBalanceNativeAfterWithdraw, err := env.EVMClient.BalanceAt(testcontext.Get(t), common.HexToAddress(defaultWalletAddress)) + defaultWalletBalanceNativeAfterWithdraw, err := evmClient.BalanceAt(testcontext.Get(t), common.HexToAddress(defaultWalletAddress)) require.NoError(t, err) - defaultWalletBalanceLinkAfterWithdraw, err := linkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) + defaultWalletBalanceLinkAfterWithdraw, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) require.NoError(t, err) //not possible to verify exact amount of Native/LINK returned as defaultWallet is used in other tests in parallel which might affect the balance @@ -612,69 +663,87 @@ func TestVRFv2Plus(t *testing.T) { func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { t.Parallel() + var ( + env *test_env.CLClusterTestEnv + vrfContracts *vrfcommon.VRFContracts + subIDsForCancellingAfterTest []*big.Int + defaultWalletAddress string + vrfKey *vrfcommon.VRFKeyData + nodeTypeToNodeMap map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode + ) l := logging.GetTestLogger(t) config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) - if err != nil { - t.Fatal(err) + require.NoError(t, err, "Error getting config") + vrfv2PlusConfig := config.VRFv2Plus + chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID + + cleanupFn := func() { + evmClient, err := env.GetEVMClient(chainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + + if evmClient.NetworkSimulated() { + l.Info(). + Str("Network Name", evmClient.GetNetworkName()). + Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") + } else { + if *vrfv2PlusConfig.General.CancelSubsAfterTestRun { + //cancel subs and return funds to sub owner + vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + } + } + if !*vrfv2PlusConfig.General.UseExistingEnv { + if err := env.Cleanup(); err != nil { + l.Error().Err(err).Msg("Error cleaning up test environment") + } + } + } + newEnvConfig := vrfcommon.NewEnvConfig{ + NodesToCreate: []vrfcommon.VRFNodeType{vrfcommon.VRF}, + NumberOfTxKeysToCreate: 2, + UseVRFOwner: false, + UseTestCoordinator: false, } - network, err := actions.EthereumNetworkConfigFromConfig(l, &config) - require.NoError(t, err, "Error building ethereum network config") - - env, err := test_env.NewCLTestEnvBuilder(). - WithTestInstance(t). - WithTestConfig(&config). - WithPrivateEthereumNetwork(network). - WithCLNodes(1). - WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). - WithStandardCleanup(). - Build() - require.NoError(t, err, "error creating test env") - - env.ParallelTransactions(true) - - mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*config.VRFv2Plus.General.LinkNativeFeedResponse)) - require.NoError(t, err, "error deploying mock ETH/LINK feed") - - linkToken, err := actions.DeployLINKToken(env.ContractDeployer) - require.NoError(t, err, "error deploying LINK contract") - - numberOfTxKeysToCreate := 2 - vrfv2PlusContracts, subIDs, vrfv2PlusData, nodesMap, err := vrfv2plus.SetupVRFV2_5Environment( - env, - []vrfcommon.VRFNodeType{vrfcommon.VRF}, - &config, - linkToken, - mockETHLinkFeed, - numberOfTxKeysToCreate, - 1, - 1, - l, - ) - require.NoError(t, err, "error setting up VRF v2_5 env") - - subID := subIDs[0] - - subscription, err := vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) - require.NoError(t, err, "error getting subscription information") + env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + require.NoError(t, err, "error setting up VRFV2Plus universe") - vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.CoordinatorV2Plus) + evmClient, err := env.GetEVMClient(chainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + defaultWalletAddress = evmClient.GetDefaultWallet().Address() t.Run("Request Randomness with multiple sending keys", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) var isNativeBilling = true - txKeys, _, err := nodesMap[vrfcommon.VRF].CLNode.API.ReadTxKeys("evm") + + consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + env, + chainID, + vrfContracts.CoordinatorV2Plus, + configCopy, + vrfContracts.LinkToken, + 1, + 1, + l, + ) + require.NoError(t, err, "error setting up new consumers and subs") + subID := subIDs[0] + subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) + require.NoError(t, err, "error getting subscription information") + vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) + + txKeys, _, err := nodeTypeToNodeMap[vrfcommon.VRF].CLNode.API.ReadTxKeys("evm") require.NoError(t, err, "error reading tx keys") - require.Equal(t, numberOfTxKeysToCreate+1, len(txKeys.Data)) + require.Equal(t, newEnvConfig.NumberOfTxKeysToCreate+1, len(txKeys.Data)) var fulfillmentTxFromAddresses []string - for i := 0; i < numberOfTxKeysToCreate+1; i++ { + for i := 0; i < newEnvConfig.NumberOfTxKeysToCreate+1; i++ { randomWordsFulfilledEvent, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( - vrfv2PlusContracts.VRFV2PlusConsumer[0], - vrfv2PlusContracts.CoordinatorV2Plus, - vrfv2PlusData, + consumers[0], + vrfContracts.CoordinatorV2Plus, + vrfKey, subID, isNativeBilling, configCopy.VRFv2Plus.General, @@ -683,13 +752,13 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { require.NoError(t, err, "error requesting randomness and waiting for fulfilment") //todo - move TransactionByHash to EVMClient in CTF - fulfillmentTx, _, err := actions.GetTxByHash(testcontext.Get(t), env.EVMClient, randomWordsFulfilledEvent.Raw.TxHash) + fulfillmentTx, _, err := actions.GetTxByHash(testcontext.Get(t), evmClient, randomWordsFulfilledEvent.Raw.TxHash) require.NoError(t, err, "error getting tx from hash") fulfillmentTxFromAddress, err := actions.GetTxFromAddress(fulfillmentTx) require.NoError(t, err, "error getting tx from address") fulfillmentTxFromAddresses = append(fulfillmentTxFromAddresses, fulfillmentTxFromAddress) } - require.Equal(t, numberOfTxKeysToCreate+1, len(fulfillmentTxFromAddresses)) + require.Equal(t, newEnvConfig.NumberOfTxKeysToCreate+1, len(fulfillmentTxFromAddresses)) var txKeyAddresses []string for _, txKey := range txKeys.Data { txKeyAddresses = append(txKeyAddresses, txKey.Attributes.Address) @@ -702,140 +771,159 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { func TestVRFv2PlusMigration(t *testing.T) { t.Parallel() + var ( + env *test_env.CLClusterTestEnv + vrfContracts *vrfcommon.VRFContracts + subIDsForCancellingAfterTest []*big.Int + defaultWalletAddress string + vrfKey *vrfcommon.VRFKeyData + nodeTypeToNodeMap map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode + ) l := logging.GetTestLogger(t) config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) - if err != nil { - t.Fatal(err) + require.NoError(t, err, "Error getting config") + vrfv2PlusConfig := config.VRFv2Plus + chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID + + cleanupFn := func() { + evmClient, err := env.GetEVMClient(chainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + if evmClient.NetworkSimulated() { + l.Info(). + Str("Network Name", evmClient.GetNetworkName()). + Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") + } else { + if *vrfv2PlusConfig.General.CancelSubsAfterTestRun { + //cancel subs and return funds to sub owner + vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + } + } + if !*vrfv2PlusConfig.General.UseExistingEnv { + if err := env.Cleanup(); err != nil { + l.Error().Err(err).Msg("Error cleaning up test environment") + } + } + } + newEnvConfig := vrfcommon.NewEnvConfig{ + NodesToCreate: []vrfcommon.VRFNodeType{vrfcommon.VRF}, + NumberOfTxKeysToCreate: 0, + UseVRFOwner: false, + UseTestCoordinator: false, } - network, err := actions.EthereumNetworkConfigFromConfig(l, &config) - require.NoError(t, err, "Error building ethereum network config") - - env, err := test_env.NewCLTestEnvBuilder(). - WithTestInstance(t). - WithTestConfig(&config). - WithPrivateEthereumNetwork(network). - WithCLNodes(1). - WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). - WithStandardCleanup(). - Build() - require.NoError(t, err, "error creating test env") - env.ParallelTransactions(true) - - mockETHLinkFeedAddress, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*config.VRFv2Plus.General.LinkNativeFeedResponse)) - require.NoError(t, err, "error deploying mock ETH/LINK feed") - - linkAddress, err := actions.DeployLINKToken(env.ContractDeployer) - require.NoError(t, err, "error deploying LINK contract") + env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + require.NoError(t, err, "error setting up VRFV2Plus universe") - vrfv2PlusContracts, subIDs, vrfv2PlusData, nodesMap, err := vrfv2plus.SetupVRFV2_5Environment( - env, - []vrfcommon.VRFNodeType{vrfcommon.VRF}, - &config, - linkAddress, - mockETHLinkFeedAddress, - 0, - 2, - 1, - l, - ) - require.NoError(t, err, "error setting up VRF v2_5 env") + evmClient, err := env.GetEVMClient(chainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + defaultWalletAddress = evmClient.GetDefaultWallet().Address() // Migrate subscription from old coordinator to new coordinator, verify if balances // are moved correctly and requests can be made successfully in the subscription in // new coordinator t.Run("Test migration of Subscription Billing subID", func(t *testing.T) { - subID := subIDs[0] + configCopy := config.MustCopy().(tc.TestConfig) - subscription, err := vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) + consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + env, + chainID, + vrfContracts.CoordinatorV2Plus, + configCopy, + vrfContracts.LinkToken, + 2, + 1, + l, + ) + require.NoError(t, err, "error setting up new consumers and subs") + subID := subIDs[0] + subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") + vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) - vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.CoordinatorV2Plus) - - activeSubIdsOldCoordinatorBeforeMigration, err := vrfv2PlusContracts.CoordinatorV2Plus.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) + activeSubIdsOldCoordinatorBeforeMigration, err := vrfContracts.CoordinatorV2Plus.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) require.NoError(t, err, "error occurred getting active sub ids") require.Len(t, activeSubIdsOldCoordinatorBeforeMigration, 1, "Active Sub Ids length is not equal to 1") require.Equal(t, subID, activeSubIdsOldCoordinatorBeforeMigration[0]) - oldSubscriptionBeforeMigration, err := vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) + oldSubscriptionBeforeMigration, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") //Migration Process - newCoordinator, err := env.ContractDeployer.DeployVRFCoordinatorV2PlusUpgradedVersion(vrfv2PlusContracts.BHS.Address()) + newCoordinator, err := env.ContractDeployer.DeployVRFCoordinatorV2PlusUpgradedVersion(vrfContracts.BHS.Address()) require.NoError(t, err, "error deploying VRF CoordinatorV2PlusUpgradedVersion") - err = env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - _, err = vrfv2plus.VRFV2PlusUpgradedVersionRegisterProvingKey(vrfv2PlusData.VRFKey, newCoordinator) + _, err = vrfv2plus.VRFV2PlusUpgradedVersionRegisterProvingKey(vrfKey.VRFKey, newCoordinator) require.NoError(t, err, fmt.Errorf("%s, err: %w", vrfcommon.ErrRegisteringProvingKey, err)) - vrfv2PlusConfig := config.VRFv2Plus.General err = newCoordinator.SetConfig( - *vrfv2PlusConfig.MinimumConfirmations, - *vrfv2PlusConfig.MaxGasLimitCoordinatorConfig, - *vrfv2PlusConfig.StalenessSeconds, - *vrfv2PlusConfig.GasAfterPaymentCalculation, - big.NewInt(*vrfv2PlusConfig.LinkNativeFeedResponse), - *vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, - *vrfv2PlusConfig.FulfillmentFlatFeeLinkDiscountPPM, - *vrfv2PlusConfig.NativePremiumPercentage, - *vrfv2PlusConfig.LinkPremiumPercentage, + *configCopy.VRFv2Plus.General.MinimumConfirmations, + *configCopy.VRFv2Plus.General.MaxGasLimitCoordinatorConfig, + *configCopy.VRFv2Plus.General.StalenessSeconds, + *configCopy.VRFv2Plus.General.GasAfterPaymentCalculation, + big.NewInt(*configCopy.VRFv2Plus.General.LinkNativeFeedResponse), + *configCopy.VRFv2Plus.General.FulfillmentFlatFeeNativePPM, + *configCopy.VRFv2Plus.General.FulfillmentFlatFeeLinkDiscountPPM, + *configCopy.VRFv2Plus.General.NativePremiumPercentage, + *configCopy.VRFv2Plus.General.LinkPremiumPercentage, ) require.NoError(t, err) - err = newCoordinator.SetLINKAndLINKNativeFeed(linkAddress.Address(), mockETHLinkFeedAddress.Address()) + err = newCoordinator.SetLINKAndLINKNativeFeed(vrfContracts.LinkToken.Address(), vrfContracts.MockETHLINKFeed.Address()) require.NoError(t, err, vrfv2plus.ErrSetLinkNativeLinkFeed) - err = env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) vrfJobSpecConfig := vrfcommon.VRFJobSpecConfig{ - ForwardingAllowed: *vrfv2PlusConfig.VRFJobForwardingAllowed, + ForwardingAllowed: *configCopy.VRFv2Plus.General.VRFJobForwardingAllowed, CoordinatorAddress: newCoordinator.Address(), - FromAddresses: nodesMap[vrfcommon.VRF].TXKeyAddressStrings, - EVMChainID: env.EVMClient.GetChainID().String(), - MinIncomingConfirmations: int(*vrfv2PlusConfig.MinimumConfirmations), - PublicKey: vrfv2PlusData.VRFKey.Data.ID, - EstimateGasMultiplier: *vrfv2PlusConfig.VRFJobEstimateGasMultiplier, - BatchFulfillmentEnabled: *vrfv2PlusConfig.VRFJobBatchFulfillmentEnabled, - BatchFulfillmentGasMultiplier: *vrfv2PlusConfig.VRFJobBatchFulfillmentGasMultiplier, - PollPeriod: vrfv2PlusConfig.VRFJobPollPeriod.Duration, - RequestTimeout: vrfv2PlusConfig.VRFJobRequestTimeout.Duration, + FromAddresses: nodeTypeToNodeMap[vrfcommon.VRF].TXKeyAddressStrings, + EVMChainID: fmt.Sprint(chainID), + MinIncomingConfirmations: int(*configCopy.VRFv2Plus.General.MinimumConfirmations), + PublicKey: vrfKey.VRFKey.Data.ID, + EstimateGasMultiplier: *configCopy.VRFv2Plus.General.VRFJobEstimateGasMultiplier, + BatchFulfillmentEnabled: *configCopy.VRFv2Plus.General.VRFJobBatchFulfillmentEnabled, + BatchFulfillmentGasMultiplier: *configCopy.VRFv2Plus.General.VRFJobBatchFulfillmentGasMultiplier, + PollPeriod: configCopy.VRFv2Plus.General.VRFJobPollPeriod.Duration, + RequestTimeout: configCopy.VRFv2Plus.General.VRFJobRequestTimeout.Duration, } _, err = vrfv2plus.CreateVRFV2PlusJob( - nodesMap[vrfcommon.VRF].CLNode.API, + nodeTypeToNodeMap[vrfcommon.VRF].CLNode.API, vrfJobSpecConfig, ) require.NoError(t, err, vrfv2plus.ErrCreateVRFV2PlusJobs) - err = vrfv2PlusContracts.CoordinatorV2Plus.RegisterMigratableCoordinator(newCoordinator.Address()) + err = vrfContracts.CoordinatorV2Plus.RegisterMigratableCoordinator(newCoordinator.Address()) require.NoError(t, err, "error registering migratable coordinator") - err = env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - oldCoordinatorLinkTotalBalanceBeforeMigration, oldCoordinatorEthTotalBalanceBeforeMigration, err := vrfv2plus.GetCoordinatorTotalBalance(vrfv2PlusContracts.CoordinatorV2Plus) + oldCoordinatorLinkTotalBalanceBeforeMigration, oldCoordinatorEthTotalBalanceBeforeMigration, err := vrfv2plus.GetCoordinatorTotalBalance(vrfContracts.CoordinatorV2Plus) require.NoError(t, err) migratedCoordinatorLinkTotalBalanceBeforeMigration, migratedCoordinatorEthTotalBalanceBeforeMigration, err := vrfv2plus.GetUpgradedCoordinatorTotalBalance(newCoordinator) require.NoError(t, err) - err = env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - err = vrfv2PlusContracts.CoordinatorV2Plus.Migrate(subID, newCoordinator.Address()) + err = vrfContracts.CoordinatorV2Plus.Migrate(subID, newCoordinator.Address()) - require.NoError(t, err, "error migrating sub id ", subID.String(), " from ", vrfv2PlusContracts.CoordinatorV2Plus.Address(), " to new Coordinator address ", newCoordinator.Address()) - migrationCompletedEvent, err := vrfv2PlusContracts.CoordinatorV2Plus.WaitForMigrationCompletedEvent(time.Minute * 1) + require.NoError(t, err, "error migrating sub id ", subID.String(), " from ", vrfContracts.CoordinatorV2Plus.Address(), " to new Coordinator address ", newCoordinator.Address()) + migrationCompletedEvent, err := vrfContracts.CoordinatorV2Plus.WaitForMigrationCompletedEvent(time.Minute * 1) require.NoError(t, err, "error waiting for MigrationCompleted event") - err = env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - vrfv2plus.LogMigrationCompletedEvent(l, migrationCompletedEvent, vrfv2PlusContracts) + vrfv2plus.LogMigrationCompletedEvent(l, migrationCompletedEvent, vrfContracts) - oldCoordinatorLinkTotalBalanceAfterMigration, oldCoordinatorEthTotalBalanceAfterMigration, err := vrfv2plus.GetCoordinatorTotalBalance(vrfv2PlusContracts.CoordinatorV2Plus) + oldCoordinatorLinkTotalBalanceAfterMigration, oldCoordinatorEthTotalBalanceAfterMigration, err := vrfv2plus.GetCoordinatorTotalBalance(vrfContracts.CoordinatorV2Plus) require.NoError(t, err) migratedCoordinatorLinkTotalBalanceAfterMigration, migratedCoordinatorEthTotalBalanceAfterMigration, err := vrfv2plus.GetUpgradedCoordinatorTotalBalance(newCoordinator) @@ -847,7 +935,7 @@ func TestVRFv2PlusMigration(t *testing.T) { vrfv2plus.LogSubDetailsAfterMigration(l, newCoordinator, subID, migratedSubscription) //Verify that Coordinators were updated in Consumers - for _, consumer := range vrfv2PlusContracts.VRFV2PlusConsumer { + for _, consumer := range consumers { coordinatorAddressInConsumerAfterMigration, err := consumer.GetCoordinator(testcontext.Get(t)) require.NoError(t, err, "error getting Coordinator from Consumer contract") require.Equal(t, newCoordinator.Address(), coordinatorAddressInConsumerAfterMigration.String()) @@ -860,14 +948,14 @@ func TestVRFv2PlusMigration(t *testing.T) { //Verify old and migrated subs require.Equal(t, oldSubscriptionBeforeMigration.NativeBalance, migratedSubscription.NativeBalance) require.Equal(t, oldSubscriptionBeforeMigration.Balance, migratedSubscription.Balance) - require.Equal(t, oldSubscriptionBeforeMigration.Owner, migratedSubscription.Owner) + require.Equal(t, oldSubscriptionBeforeMigration.SubOwner, migratedSubscription.SubOwner) require.Equal(t, oldSubscriptionBeforeMigration.Consumers, migratedSubscription.Consumers) //Verify that old sub was deleted from old Coordinator - _, err = vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) + _, err = vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.Error(t, err, "error not occurred when trying to get deleted subscription from old Coordinator after sub migration") - _, err = vrfv2PlusContracts.CoordinatorV2Plus.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) + _, err = vrfContracts.CoordinatorV2Plus.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) // If (subscription billing), numActiveSub should be 0 after migration in oldCoordinator require.Error(t, err, "error not occurred getting active sub ids. Should occur since it should revert when sub id array is empty") @@ -889,24 +977,24 @@ func TestVRFv2PlusMigration(t *testing.T) { //Verify rand requests fulfills with Link Token billing _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillmentUpgraded( - vrfv2PlusContracts.VRFV2PlusConsumer[0], + consumers[0], newCoordinator, - vrfv2PlusData, + vrfKey, subID, false, - config.VRFv2Plus.General, + configCopy.VRFv2Plus.General, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") //Verify rand requests fulfills with Native Token billing _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillmentUpgraded( - vrfv2PlusContracts.VRFV2PlusConsumer[1], + consumers[1], newCoordinator, - vrfv2PlusData, + vrfKey, subID, true, - config.VRFv2Plus.General, + configCopy.VRFv2Plus.General, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -917,108 +1005,110 @@ func TestVRFv2PlusMigration(t *testing.T) { // new coordinator t.Run("Test migration of direct billing using VRFV2PlusWrapper subID", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) + wrapperContracts, wrapperSubID, err := vrfv2plus.SetupVRFV2PlusWrapperEnvironment( + testcontext.Get(t), env, + chainID, &configCopy, - linkAddress, - mockETHLinkFeedAddress, - vrfv2PlusContracts.CoordinatorV2Plus, - vrfv2PlusData.KeyHash, + vrfContracts.LinkToken, + vrfContracts.MockETHLINKFeed, + vrfContracts.CoordinatorV2Plus, + vrfKey.KeyHash, 1, ) require.NoError(t, err) subID := wrapperSubID - subscription, err := vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) + subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") - vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.CoordinatorV2Plus) + vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) - activeSubIdsOldCoordinatorBeforeMigration, err := vrfv2PlusContracts.CoordinatorV2Plus.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) + activeSubIdsOldCoordinatorBeforeMigration, err := vrfContracts.CoordinatorV2Plus.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) require.NoError(t, err, "error occurred getting active sub ids") require.Len(t, activeSubIdsOldCoordinatorBeforeMigration, 1, "Active Sub Ids length is not equal to 1") activeSubID := activeSubIdsOldCoordinatorBeforeMigration[0] require.Equal(t, subID, activeSubID) - oldSubscriptionBeforeMigration, err := vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) + oldSubscriptionBeforeMigration, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") //Migration Process - newCoordinator, err := env.ContractDeployer.DeployVRFCoordinatorV2PlusUpgradedVersion(vrfv2PlusContracts.BHS.Address()) + newCoordinator, err := env.ContractDeployer.DeployVRFCoordinatorV2PlusUpgradedVersion(vrfContracts.BHS.Address()) require.NoError(t, err, "error deploying VRF CoordinatorV2PlusUpgradedVersion") - err = env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - _, err = vrfv2plus.VRFV2PlusUpgradedVersionRegisterProvingKey(vrfv2PlusData.VRFKey, newCoordinator) + _, err = vrfv2plus.VRFV2PlusUpgradedVersionRegisterProvingKey(vrfKey.VRFKey, newCoordinator) require.NoError(t, err, fmt.Errorf("%s, err: %w", vrfcommon.ErrRegisteringProvingKey, err)) - vrfv2PlusConfig := config.VRFv2Plus.General err = newCoordinator.SetConfig( - *vrfv2PlusConfig.MinimumConfirmations, - *vrfv2PlusConfig.MaxGasLimitCoordinatorConfig, - *vrfv2PlusConfig.StalenessSeconds, - *vrfv2PlusConfig.GasAfterPaymentCalculation, - big.NewInt(*vrfv2PlusConfig.LinkNativeFeedResponse), - *vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, - *vrfv2PlusConfig.FulfillmentFlatFeeLinkDiscountPPM, - *vrfv2PlusConfig.NativePremiumPercentage, - *vrfv2PlusConfig.LinkPremiumPercentage, + *configCopy.VRFv2Plus.General.MinimumConfirmations, + *configCopy.VRFv2Plus.General.MaxGasLimitCoordinatorConfig, + *configCopy.VRFv2Plus.General.StalenessSeconds, + *configCopy.VRFv2Plus.General.GasAfterPaymentCalculation, + big.NewInt(*configCopy.VRFv2Plus.General.LinkNativeFeedResponse), + *configCopy.VRFv2Plus.General.FulfillmentFlatFeeNativePPM, + *configCopy.VRFv2Plus.General.FulfillmentFlatFeeLinkDiscountPPM, + *configCopy.VRFv2Plus.General.NativePremiumPercentage, + *configCopy.VRFv2Plus.General.LinkPremiumPercentage, ) require.NoError(t, err) - err = newCoordinator.SetLINKAndLINKNativeFeed(linkAddress.Address(), mockETHLinkFeedAddress.Address()) + err = newCoordinator.SetLINKAndLINKNativeFeed(vrfContracts.LinkToken.Address(), vrfContracts.MockETHLINKFeed.Address()) require.NoError(t, err, vrfv2plus.ErrSetLinkNativeLinkFeed) - err = env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) vrfJobSpecConfig := vrfcommon.VRFJobSpecConfig{ - ForwardingAllowed: *vrfv2PlusConfig.VRFJobForwardingAllowed, + ForwardingAllowed: *configCopy.VRFv2Plus.General.VRFJobForwardingAllowed, CoordinatorAddress: newCoordinator.Address(), - FromAddresses: nodesMap[vrfcommon.VRF].TXKeyAddressStrings, - EVMChainID: env.EVMClient.GetChainID().String(), - MinIncomingConfirmations: int(*vrfv2PlusConfig.MinimumConfirmations), - PublicKey: vrfv2PlusData.VRFKey.Data.ID, - EstimateGasMultiplier: *vrfv2PlusConfig.VRFJobEstimateGasMultiplier, - BatchFulfillmentEnabled: *vrfv2PlusConfig.VRFJobBatchFulfillmentEnabled, - BatchFulfillmentGasMultiplier: *vrfv2PlusConfig.VRFJobBatchFulfillmentGasMultiplier, - PollPeriod: vrfv2PlusConfig.VRFJobPollPeriod.Duration, - RequestTimeout: vrfv2PlusConfig.VRFJobRequestTimeout.Duration, + FromAddresses: nodeTypeToNodeMap[vrfcommon.VRF].TXKeyAddressStrings, + EVMChainID: fmt.Sprint(chainID), + MinIncomingConfirmations: int(*configCopy.VRFv2Plus.General.MinimumConfirmations), + PublicKey: vrfKey.VRFKey.Data.ID, + EstimateGasMultiplier: *configCopy.VRFv2Plus.General.VRFJobEstimateGasMultiplier, + BatchFulfillmentEnabled: *configCopy.VRFv2Plus.General.VRFJobBatchFulfillmentEnabled, + BatchFulfillmentGasMultiplier: *configCopy.VRFv2Plus.General.VRFJobBatchFulfillmentGasMultiplier, + PollPeriod: configCopy.VRFv2Plus.General.VRFJobPollPeriod.Duration, + RequestTimeout: configCopy.VRFv2Plus.General.VRFJobRequestTimeout.Duration, } _, err = vrfv2plus.CreateVRFV2PlusJob( - nodesMap[vrfcommon.VRF].CLNode.API, + nodeTypeToNodeMap[vrfcommon.VRF].CLNode.API, vrfJobSpecConfig, ) require.NoError(t, err, vrfv2plus.ErrCreateVRFV2PlusJobs) - err = vrfv2PlusContracts.CoordinatorV2Plus.RegisterMigratableCoordinator(newCoordinator.Address()) + err = vrfContracts.CoordinatorV2Plus.RegisterMigratableCoordinator(newCoordinator.Address()) require.NoError(t, err, "error registering migratable coordinator") - err = env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - oldCoordinatorLinkTotalBalanceBeforeMigration, oldCoordinatorEthTotalBalanceBeforeMigration, err := vrfv2plus.GetCoordinatorTotalBalance(vrfv2PlusContracts.CoordinatorV2Plus) + oldCoordinatorLinkTotalBalanceBeforeMigration, oldCoordinatorEthTotalBalanceBeforeMigration, err := vrfv2plus.GetCoordinatorTotalBalance(vrfContracts.CoordinatorV2Plus) require.NoError(t, err) migratedCoordinatorLinkTotalBalanceBeforeMigration, migratedCoordinatorEthTotalBalanceBeforeMigration, err := vrfv2plus.GetUpgradedCoordinatorTotalBalance(newCoordinator) require.NoError(t, err) - err = env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - // Migrate sub using VRFV2PlusWrapper's migrate method - err = wrapperContracts.VRFV2PlusWrapper.Migrate(common.HexToAddress(newCoordinator.Address())) + // Migrate wrapper's sub using coordinator's migrate method + err = vrfContracts.CoordinatorV2Plus.Migrate(subID, newCoordinator.Address()) - require.NoError(t, err, "error migrating sub id ", subID.String(), " from ", vrfv2PlusContracts.CoordinatorV2Plus.Address(), " to new Coordinator address ", newCoordinator.Address()) - migrationCompletedEvent, err := vrfv2PlusContracts.CoordinatorV2Plus.WaitForMigrationCompletedEvent(time.Minute * 1) + require.NoError(t, err, "error migrating sub id ", subID.String(), " from ", vrfContracts.CoordinatorV2Plus.Address(), " to new Coordinator address ", newCoordinator.Address()) + migrationCompletedEvent, err := vrfContracts.CoordinatorV2Plus.WaitForMigrationCompletedEvent(time.Minute * 1) require.NoError(t, err, "error waiting for MigrationCompleted event") - err = env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) - vrfv2plus.LogMigrationCompletedEvent(l, migrationCompletedEvent, vrfv2PlusContracts) + vrfv2plus.LogMigrationCompletedEvent(l, migrationCompletedEvent, vrfContracts) - oldCoordinatorLinkTotalBalanceAfterMigration, oldCoordinatorEthTotalBalanceAfterMigration, err := vrfv2plus.GetCoordinatorTotalBalance(vrfv2PlusContracts.CoordinatorV2Plus) + oldCoordinatorLinkTotalBalanceAfterMigration, oldCoordinatorEthTotalBalanceAfterMigration, err := vrfv2plus.GetCoordinatorTotalBalance(vrfContracts.CoordinatorV2Plus) require.NoError(t, err) migratedCoordinatorLinkTotalBalanceAfterMigration, migratedCoordinatorEthTotalBalanceAfterMigration, err := vrfv2plus.GetUpgradedCoordinatorTotalBalance(newCoordinator) @@ -1041,14 +1131,14 @@ func TestVRFv2PlusMigration(t *testing.T) { //Verify old and migrated subs require.Equal(t, oldSubscriptionBeforeMigration.NativeBalance, migratedSubscription.NativeBalance) require.Equal(t, oldSubscriptionBeforeMigration.Balance, migratedSubscription.Balance) - require.Equal(t, oldSubscriptionBeforeMigration.Owner, migratedSubscription.Owner) + require.Equal(t, oldSubscriptionBeforeMigration.SubOwner, migratedSubscription.SubOwner) require.Equal(t, oldSubscriptionBeforeMigration.Consumers, migratedSubscription.Consumers) //Verify that old sub was deleted from old Coordinator - _, err = vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) + _, err = vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.Error(t, err, "error not occurred when trying to get deleted subscription from old Coordinator after sub migration") - _, err = vrfv2PlusContracts.CoordinatorV2Plus.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) + _, err = vrfContracts.CoordinatorV2Plus.GetActiveSubscriptionIds(testcontext.Get(t), big.NewInt(0), big.NewInt(0)) // If (subscription billing) or (direct billing and numActiveSubs is 0 before this test) -> numActiveSub should be 0 after migration in oldCoordinator require.Error(t, err, "error not occurred getting active sub ids. Should occur since it should revert when sub id array is empty") @@ -1073,7 +1163,7 @@ func TestVRFv2PlusMigration(t *testing.T) { randomWordsFulfilledEvent, err := vrfv2plus.DirectFundingRequestRandomnessAndWaitForFulfillmentUpgraded( wrapperContracts.LoadTestConsumers[0], newCoordinator, - vrfv2PlusData, + vrfKey, subID, isNativeBilling, configCopy.VRFv2Plus.General, @@ -1089,7 +1179,7 @@ func TestVRFv2PlusMigration(t *testing.T) { randomWordsFulfilledEvent, err = vrfv2plus.DirectFundingRequestRandomnessAndWaitForFulfillmentUpgraded( wrapperContracts.LoadTestConsumers[0], newCoordinator, - vrfv2PlusData, + vrfKey, subID, isNativeBilling, configCopy.VRFv2Plus.General, @@ -1104,68 +1194,86 @@ func TestVRFv2PlusMigration(t *testing.T) { func TestVRFV2PlusWithBHS(t *testing.T) { t.Parallel() + var ( + env *test_env.CLClusterTestEnv + vrfContracts *vrfcommon.VRFContracts + subIDsForCancellingAfterTest []*big.Int + defaultWalletAddress string + vrfKey *vrfcommon.VRFKeyData + nodeTypeToNodeMap map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode + ) l := logging.GetTestLogger(t) config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) require.NoError(t, err, "Error getting config") - - network, err := actions.EthereumNetworkConfigFromConfig(l, &config) - require.NoError(t, err, "Error building ethereum network config") - - env, err := test_env.NewCLTestEnvBuilder(). - WithTestInstance(t). - WithTestConfig(&config). - WithPrivateEthereumNetwork(network). - WithCLNodes(2). - WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). - WithStandardCleanup(). - Build() - require.NoError(t, err, "error creating test env") - - env.ParallelTransactions(true) - - mockETHLinkFeed, err := env.ContractDeployer.DeployVRFMockETHLINKFeed(big.NewInt(*config.VRFv2Plus.General.LinkNativeFeedResponse)) - - require.NoError(t, err) - linkToken, err := actions.DeployLINKToken(env.ContractDeployer) - require.NoError(t, err) - - //Underfund Subscription - config.VRFv2Plus.General.SubscriptionFundingAmountLink = ptr.Ptr(float64(0.000000000000000001)) // 1 Juel + vrfv2PlusConfig := config.VRFv2Plus + chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID + + cleanupFn := func() { + evmClient, err := env.GetEVMClient(chainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + if evmClient.NetworkSimulated() { + l.Info(). + Str("Network Name", evmClient.GetNetworkName()). + Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") + } else { + if *vrfv2PlusConfig.General.CancelSubsAfterTestRun { + //cancel subs and return funds to sub owner + vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + } + } + if !*vrfv2PlusConfig.General.UseExistingEnv { + if err := env.Cleanup(); err != nil { + l.Error().Err(err).Msg("Error cleaning up test environment") + } + } + } //decrease default span for checking blockhashes for unfulfilled requests - config.VRFv2Plus.General.BHSJobWaitBlocks = ptr.Ptr(2) - config.VRFv2Plus.General.BHSJobLookBackBlocks = ptr.Ptr(20) + vrfv2PlusConfig.General.BHSJobWaitBlocks = ptr.Ptr(2) + vrfv2PlusConfig.General.BHSJobLookBackBlocks = ptr.Ptr(20) + + newEnvConfig := vrfcommon.NewEnvConfig{ + NodesToCreate: []vrfcommon.VRFNodeType{vrfcommon.VRF, vrfcommon.BHS}, + NumberOfTxKeysToCreate: 0, + UseVRFOwner: false, + UseTestCoordinator: false, + } - numberOfTxKeysToCreate := 0 - vrfContracts, subIDs, vrfKeyData, nodesMap, err := vrfv2plus.SetupVRFV2_5Environment( - env, - []vrfcommon.VRFNodeType{vrfcommon.VRF, vrfcommon.BHS}, - &config, - linkToken, - mockETHLinkFeed, - numberOfTxKeysToCreate, - 1, - 2, - l, - ) - require.NoError(t, err, "error setting up VRF v2_5 env") + env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + require.NoError(t, err, "error setting up VRFV2Plus universe") + + evmClient, err := env.GetEVMClient(chainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + defaultWalletAddress = evmClient.GetDefaultWallet().Address() var isNativeBilling = true t.Run("BHS Job with complete E2E - wait 256 blocks to see if Rand Request is fulfilled", func(t *testing.T) { t.Skip("Skipped since should be run on-demand on live testnet due to long execution time") + configCopy := config.MustCopy().(tc.TestConfig) + //Underfund Subscription + configCopy.VRFv2Plus.General.SubscriptionFundingAmountLink = ptr.Ptr(float64(0)) + configCopy.VRFv2Plus.General.SubscriptionFundingAmountNative = ptr.Ptr(float64(0)) + consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + env, + chainID, + vrfContracts.CoordinatorV2Plus, + configCopy, + vrfContracts.LinkToken, + 1, + 1, + l, + ) + require.NoError(t, err, "error setting up new consumers and subs") subID := subIDs[0] - subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") - vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) - //BHS node should fill in blockhashes into BHS contract depending on the waitBlocks and lookBackBlocks settings - configCopy := config.MustCopy().(tc.TestConfig) - _, err = vrfContracts.VRFV2PlusConsumer[0].RequestRandomness( - vrfKeyData.KeyHash, + _, err = consumers[0].RequestRandomness( + vrfKey.KeyHash, subID, *configCopy.VRFv2Plus.General.MinimumConfirmations, *configCopy.VRFv2Plus.General.CallbackGasLimit, @@ -1176,9 +1284,9 @@ func TestVRFV2PlusWithBHS(t *testing.T) { require.NoError(t, err, "error requesting randomness") randomWordsRequestedEvent, err := vrfContracts.CoordinatorV2Plus.WaitForRandomWordsRequestedEvent( - [][32]byte{vrfKeyData.KeyHash}, + [][32]byte{vrfKey.KeyHash}, []*big.Int{subID}, - []common.Address{common.HexToAddress(vrfContracts.VRFV2PlusConsumer[0].Address())}, + []common.Address{common.HexToAddress(consumers[0].Address())}, time.Minute*1, ) require.NoError(t, err, "error waiting for randomness requested event") @@ -1187,14 +1295,15 @@ func TestVRFV2PlusWithBHS(t *testing.T) { var wg sync.WaitGroup wg.Add(1) //Wait at least 256 blocks - _, err = actions.WaitForBlockNumberToBe(randRequestBlockNumber+uint64(257), env.EVMClient, &wg, time.Second*260, t) + _, err = actions.WaitForBlockNumberToBe(randRequestBlockNumber+uint64(257), evmClient, &wg, time.Second*260, t) wg.Wait() require.NoError(t, err) err = vrfv2plus.FundSubscriptions( env, - big.NewFloat(*configCopy.VRFv2Plus.General.SubscriptionFundingAmountNative), - big.NewFloat(*configCopy.VRFv2Plus.General.SubscriptionFundingAmountLink), - linkToken, + chainID, + big.NewFloat(*configCopy.VRFv2Plus.General.SubscriptionRefundingAmountNative), + big.NewFloat(*configCopy.VRFv2Plus.General.SubscriptionRefundingAmountLink), + vrfContracts.LinkToken, vrfContracts.CoordinatorV2Plus, subIDs, ) @@ -1206,7 +1315,7 @@ func TestVRFV2PlusWithBHS(t *testing.T) { ) require.NoError(t, err, "error waiting for randomness fulfilled event") vrfv2plus.LogRandomWordsFulfilledEvent(l, vrfContracts.CoordinatorV2Plus, randomWordsFulfilledEvent, isNativeBilling) - status, err := vrfContracts.VRFV2PlusConsumer[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) + status, err := consumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") @@ -1222,17 +1331,31 @@ func TestVRFV2PlusWithBHS(t *testing.T) { }) t.Run("BHS Job should fill in blockhashes into BHS contract for unfulfilled requests", func(t *testing.T) { - subID := subIDs[1] + configCopy := config.MustCopy().(tc.TestConfig) + //Underfund Subscription + configCopy.VRFv2Plus.General.SubscriptionFundingAmountLink = ptr.Ptr(float64(0)) + configCopy.VRFv2Plus.General.SubscriptionFundingAmountNative = ptr.Ptr(float64(0)) + consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + env, + chainID, + vrfContracts.CoordinatorV2Plus, + configCopy, + vrfContracts.LinkToken, + 1, + 1, + l, + ) + require.NoError(t, err, "error setting up new consumers and subs") + subID := subIDs[0] subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") - vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) //BHS node should fill in blockhashes into BHS contract depending on the waitBlocks and lookBackBlocks settings - configCopy := config.MustCopy().(tc.TestConfig) - _, err = vrfContracts.VRFV2PlusConsumer[0].RequestRandomness( - vrfKeyData.KeyHash, + _, err = consumers[0].RequestRandomness( + vrfKey.KeyHash, subID, *configCopy.VRFv2Plus.General.MinimumConfirmations, *configCopy.VRFv2Plus.General.CallbackGasLimit, @@ -1243,9 +1366,9 @@ func TestVRFV2PlusWithBHS(t *testing.T) { require.NoError(t, err, "error requesting randomness") randomWordsRequestedEvent, err := vrfContracts.CoordinatorV2Plus.WaitForRandomWordsRequestedEvent( - [][32]byte{vrfKeyData.KeyHash}, + [][32]byte{vrfKey.KeyHash}, []*big.Int{subID}, - []common.Address{common.HexToAddress(vrfContracts.VRFV2PlusConsumer[0].Address())}, + []common.Address{common.HexToAddress(consumers[0].Address())}, time.Minute*1, ) require.NoError(t, err, "error waiting for randomness requested event") @@ -1256,18 +1379,18 @@ func TestVRFV2PlusWithBHS(t *testing.T) { var wg sync.WaitGroup wg.Add(1) - _, err = actions.WaitForBlockNumberToBe(randRequestBlockNumber+uint64(*config.VRFv2Plus.General.BHSJobWaitBlocks+10), env.EVMClient, &wg, time.Minute*1, t) + _, err = actions.WaitForBlockNumberToBe(randRequestBlockNumber+uint64(*configCopy.VRFv2Plus.General.BHSJobWaitBlocks+10), evmClient, &wg, time.Minute*1, t) wg.Wait() require.NoError(t, err, "error waiting for blocknumber to be") - err = env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) var clNodeTxs *client.TransactionsData var txHash string gom := gomega.NewGomegaWithT(t) gom.Eventually(func(g gomega.Gomega) { - clNodeTxs, _, err = nodesMap[vrfcommon.BHS].CLNode.API.ReadTransactions() + clNodeTxs, _, err = nodeTypeToNodeMap[vrfcommon.BHS].CLNode.API.ReadTransactions() g.Expect(err).ShouldNot(gomega.HaveOccurred(), "error getting CL Node transactions") l.Debug().Int("Number of TXs", len(clNodeTxs.Data)).Msg("BHS Node txs") g.Expect(len(clNodeTxs.Data)).Should(gomega.BeNumerically("==", 1), "Expected 1 tx posted by BHS Node, but found %d", len(clNodeTxs.Data)) @@ -1276,7 +1399,7 @@ func TestVRFV2PlusWithBHS(t *testing.T) { require.Equal(t, strings.ToLower(vrfContracts.BHS.Address()), strings.ToLower(clNodeTxs.Data[0].Attributes.To)) - bhsStoreTx, _, err := actions.GetTxByHash(testcontext.Get(t), env.EVMClient, common.HexToHash(txHash)) + bhsStoreTx, _, err := actions.GetTxByHash(testcontext.Get(t), evmClient, common.HexToHash(txHash)) require.NoError(t, err, "error getting tx from hash") bhsStoreTxInputData, err := actions.DecodeTxInputData(blockhash_store.BlockhashStoreABI, bhsStoreTx.Data()) @@ -1285,7 +1408,7 @@ func TestVRFV2PlusWithBHS(t *testing.T) { Msg("BHS Node's Store Blockhash for Blocknumber Method TX") require.Equal(t, randRequestBlockNumber, bhsStoreTxInputData["n"].(*big.Int).Uint64()) - err = env.EVMClient.WaitForEvents() + err = evmClient.WaitForEvents() require.NoError(t, err, vrfcommon.ErrWaitTXsComplete) var randRequestBlockHash [32]byte @@ -1301,116 +1424,272 @@ func TestVRFV2PlusWithBHS(t *testing.T) { }) } -func TestVRFv2PlusReplayAfterTimeout(t *testing.T) { +func TestVRFV2PlusWithBHF(t *testing.T) { t.Parallel() + var ( + env *test_env.CLClusterTestEnv + vrfContracts *vrfcommon.VRFContracts + subIDsForCancellingAfterTest []*big.Int + defaultWalletAddress string + vrfKey *vrfcommon.VRFKeyData + nodeTypeToNodeMap map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode + ) l := logging.GetTestLogger(t) config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) - if err != nil { - t.Fatal(err) + require.NoError(t, err, "Error getting config") + vrfv2PlusConfig := config.VRFv2Plus + + chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID + + cleanupFn := func() { + evmClient, err := env.GetEVMClient(chainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + if evmClient.NetworkSimulated() { + l.Info(). + Str("Network Name", evmClient.GetNetworkName()). + Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") + } else { + if *vrfv2PlusConfig.General.CancelSubsAfterTestRun { + //cancel subs and return funds to sub owner + vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + } + } + if !*vrfv2PlusConfig.General.UseExistingEnv { + if err := env.Cleanup(); err != nil { + l.Error().Err(err).Msg("Error cleaning up test environment") + } + } } - network, err := actions.EthereumNetworkConfigFromConfig(l, &config) - require.NoError(t, err, "Error building ethereum network config") + // BHF job config + config.VRFv2Plus.General.BHFJobWaitBlocks = ptr.Ptr(260) + config.VRFv2Plus.General.BHFJobLookBackBlocks = ptr.Ptr(500) + config.VRFv2Plus.General.BHFJobPollPeriod = ptr.Ptr(blockchain.StrDuration{Duration: time.Second * 30}) + config.VRFv2Plus.General.BHFJobRunTimeout = ptr.Ptr(blockchain.StrDuration{Duration: time.Minute * 24}) + + newEnvConfig := vrfcommon.NewEnvConfig{ + NodesToCreate: []vrfcommon.VRFNodeType{vrfcommon.VRF, vrfcommon.BHF}, + NumberOfTxKeysToCreate: 0, + UseVRFOwner: false, + UseTestCoordinator: false, + } - env, err := test_env.NewCLTestEnvBuilder(). - WithTestInstance(t). - WithTestConfig(&config). - WithPrivateEthereumNetwork(network). - WithCLNodes(1). - WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). - WithStandardCleanup(). - Build() - require.NoError(t, err, "error creating test env") + env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse( + testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + require.NoError(t, err) + evmClient, err := env.GetEVMClient(chainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + defaultWalletAddress = evmClient.GetDefaultWallet().Address() - env.ParallelTransactions(true) + var isNativeBilling = true + t.Run("BHF Job with complete E2E - wait 256 blocks to see if Rand Request is fulfilled", func(t *testing.T) { + // t.Skip("Skipped since should be run on-demand on live testnet due to long execution time") + configCopy := config.MustCopy().(tc.TestConfig) + // Underfund Subscription + configCopy.VRFv2Plus.General.SubscriptionFundingAmountLink = ptr.Ptr(float64(0)) + configCopy.VRFv2Plus.General.SubscriptionFundingAmountNative = ptr.Ptr(float64(0)) - mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*config.VRFv2Plus.General.LinkNativeFeedResponse)) - require.NoError(t, err, "error deploying mock ETH/LINK feed") + consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + env, + chainID, + vrfContracts.CoordinatorV2Plus, + configCopy, + vrfContracts.LinkToken, + 1, + 1, + l, + ) + require.NoError(t, err, "error setting up new consumers and subs") + subID := subIDs[0] + subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) + require.NoError(t, err, "error getting subscription information") + vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) - linkToken, err := actions.DeployLINKToken(env.ContractDeployer) - require.NoError(t, err, "error deploying LINK contract") + _, err = consumers[0].RequestRandomness( + vrfKey.KeyHash, + subID, + *configCopy.VRFv2Plus.General.MinimumConfirmations, + *configCopy.VRFv2Plus.General.CallbackGasLimit, + isNativeBilling, + *configCopy.VRFv2Plus.General.NumberOfWords, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + ) + require.NoError(t, err, "error requesting randomness") + + randomWordsRequestedEvent, err := vrfContracts.CoordinatorV2Plus.WaitForRandomWordsRequestedEvent( + [][32]byte{vrfKey.KeyHash}, + []*big.Int{subID}, + []common.Address{common.HexToAddress(consumers[0].Address())}, + time.Minute*1, + ) + require.NoError(t, err, "error waiting for randomness requested event") + vrfv2plus.LogRandomnessRequestedEvent(l, vrfContracts.CoordinatorV2Plus, randomWordsRequestedEvent, isNativeBilling) + randRequestBlockNumber := randomWordsRequestedEvent.Raw.BlockNumber + var wg sync.WaitGroup + wg.Add(1) + //Wait at least 260 blocks + _, err = actions.WaitForBlockNumberToBe(randRequestBlockNumber+uint64(260), evmClient, &wg, time.Second*262, t) + wg.Wait() + require.NoError(t, err) + l.Info().Float64("SubscriptionFundingAmountNative", *configCopy.VRFv2Plus.General.SubscriptionRefundingAmountNative). + Float64("SubscriptionFundingAmountLink", *configCopy.VRFv2Plus.General.SubscriptionRefundingAmountLink). + Msg("Funding subscription") + err = vrfv2plus.FundSubscriptions( + env, + chainID, + big.NewFloat(*configCopy.VRFv2Plus.General.SubscriptionRefundingAmountNative), + big.NewFloat(*configCopy.VRFv2Plus.General.SubscriptionRefundingAmountLink), + vrfContracts.LinkToken, + vrfContracts.CoordinatorV2Plus, + subIDs, + ) + require.NoError(t, err, "error funding subscriptions") + randomWordsFulfilledEvent, err := vrfContracts.CoordinatorV2Plus.WaitForRandomWordsFulfilledEvent( + []*big.Int{subID}, + []*big.Int{randomWordsRequestedEvent.RequestId}, + time.Minute*2, + ) + require.NoError(t, err, "error waiting for randomness fulfilled event") + vrfv2plus.LogRandomWordsFulfilledEvent(l, vrfContracts.CoordinatorV2Plus, randomWordsFulfilledEvent, isNativeBilling) + status, err := consumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) + require.NoError(t, err, "error getting rand request status") + require.True(t, status.Fulfilled) + l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") + + clNodeTxs, _, err := nodeTypeToNodeMap[vrfcommon.BHF].CLNode.API.ReadTransactions() + require.NoError(t, err, "error fetching txns from BHF node") + batchBHSTxFound := false + for _, tx := range clNodeTxs.Data { + if strings.EqualFold(tx.Attributes.To, vrfContracts.BatchBHS.Address()) { + batchBHSTxFound = true + } + } + require.True(t, batchBHSTxFound) + + randRequestBlockHash, err := vrfContracts.BHS.GetBlockHash(testcontext.Get(t), big.NewInt(int64(randRequestBlockNumber))) + require.NoError(t, err, "error getting blockhash for a blocknumber which was stored in BHS contract") + + l.Info(). + Str("Randomness Request's Blockhash", randomWordsRequestedEvent.Raw.BlockHash.String()). + Str("Block Hash stored by BHS contract", fmt.Sprintf("0x%x", randRequestBlockHash)). + Msg("BHS Contract's stored Blockhash for Randomness Request") + require.Equal(t, 0, randomWordsRequestedEvent.Raw.BlockHash.Cmp(randRequestBlockHash)) + }) +} + +func TestVRFv2PlusReplayAfterTimeout(t *testing.T) { + t.Parallel() + var ( + env *test_env.CLClusterTestEnv + vrfContracts *vrfcommon.VRFContracts + subIDsForCancellingAfterTest []*big.Int + defaultWalletAddress string + vrfKey *vrfcommon.VRFKeyData + nodeTypeToNodeMap map[vrfcommon.VRFNodeType]*vrfcommon.VRFNode + ) + l := logging.GetTestLogger(t) + + config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) + require.NoError(t, err, "Error getting config") + vrfv2PlusConfig := config.VRFv2Plus + chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID + + cleanupFn := func() { + evmClient, err := env.GetEVMClient(chainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + if evmClient.NetworkSimulated() { + l.Info(). + Str("Network Name", evmClient.GetNetworkName()). + Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") + } else { + if *vrfv2PlusConfig.General.CancelSubsAfterTestRun { + //cancel subs and return funds to sub owner + vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + } + } + if !*vrfv2PlusConfig.General.UseExistingEnv { + if err := env.Cleanup(); err != nil { + l.Error().Err(err).Msg("Error cleaning up test environment") + } + } + } + newEnvConfig := vrfcommon.NewEnvConfig{ + NodesToCreate: []vrfcommon.VRFNodeType{vrfcommon.VRF}, + NumberOfTxKeysToCreate: 0, + UseVRFOwner: false, + UseTestCoordinator: false, + } // 1. Add job spec with requestTimeout = 5 seconds - timeout := time.Duration(time.Second * 5) - numberOfTxKeysToCreate := 0 + timeout := time.Second * 5 config.VRFv2Plus.General.VRFJobRequestTimeout = ptr.Ptr(blockchain.StrDuration{Duration: timeout}) config.VRFv2Plus.General.SubscriptionFundingAmountLink = ptr.Ptr(float64(0)) config.VRFv2Plus.General.SubscriptionFundingAmountNative = ptr.Ptr(float64(0)) - vrfv2PlusContracts, subIDs, vrfv2PlusData, nodesMap, err := vrfv2plus.SetupVRFV2_5Environment( - env, - []vrfcommon.VRFNodeType{vrfcommon.VRF}, - &config, - linkToken, - mockETHLinkFeed, - numberOfTxKeysToCreate, - 2, - 1, - l, - ) - require.NoError(t, err, "error setting up VRF v2_5 env") - subID := subIDs[0] - - subscription, err := vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) - require.NoError(t, err, "error getting subscription information") + env, vrfContracts, vrfKey, nodeTypeToNodeMap, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + require.NoError(t, err, "error setting up VRFV2Plus universe") - vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.CoordinatorV2Plus) + evmClient, err := env.GetEVMClient(chainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + defaultWalletAddress = evmClient.GetDefaultWallet().Address() t.Run("Timed out request fulfilled after node restart with replay", func(t *testing.T) { configCopy := config.MustCopy().(tc.TestConfig) var isNativeBilling = false - // 2. create request but without fulfilment - e.g. simulation failure (insufficient balance in the sub, ) - vrfv2plus.LogRandRequest( + consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( + env, + chainID, + vrfContracts.CoordinatorV2Plus, + configCopy, + vrfContracts.LinkToken, + 2, + 1, l, - vrfv2PlusContracts.VRFV2PlusConsumer[0].Address(), - vrfv2PlusContracts.CoordinatorV2Plus.Address(), - subID, - isNativeBilling, - vrfv2PlusData.KeyHash, - configCopy.VRFv2Plus.General, ) - _, err = vrfv2PlusContracts.VRFV2PlusConsumer[0].RequestRandomness( - vrfv2PlusData.KeyHash, + require.NoError(t, err, "error setting up new consumers and subs") + subID := subIDs[0] + subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) + require.NoError(t, err, "error getting subscription information") + vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) + + // 2. create request but without fulfilment - e.g. simulation failure (insufficient balance in the sub, ) + initialReqRandomWordsRequestedEvent, err := vrfv2plus.RequestRandomnessAndWaitForRequestedEvent( + consumers[0], + vrfContracts.CoordinatorV2Plus, + vrfKey, subID, - *configCopy.VRFv2Plus.General.MinimumConfirmations, - *configCopy.VRFv2Plus.General.CallbackGasLimit, isNativeBilling, - *configCopy.VRFv2Plus.General.NumberOfWords, - *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, - ) - require.NoError(t, err, "error requesting randomness") - initialReqRandomWordsRequestedEvent, err := vrfv2PlusContracts.CoordinatorV2Plus.WaitForRandomWordsRequestedEvent( - [][32]byte{vrfv2PlusData.KeyHash}, - []*big.Int{subID}, - []common.Address{common.HexToAddress(vrfv2PlusContracts.VRFV2PlusConsumer[0].Address())}, - time.Minute*1, + configCopy.VRFv2Plus.General, + l, ) - require.NoError(t, err, "error waiting for initial request RandomWordsRequestedEvent") + require.NoError(t, err, "error requesting randomness and waiting for requested event") // 3. create new request in a subscription with balance and wait for fulfilment - // TODO: We need this to be parametrized, since these tests will be run on live testnets as well. - fundingLinkAmt := big.NewFloat(5) - fundingNativeAmt := big.NewFloat(0.1) + fundingLinkAmt := big.NewFloat(*configCopy.VRFv2Plus.General.SubscriptionRefundingAmountLink) + fundingNativeAmt := big.NewFloat(*configCopy.VRFv2Plus.General.SubscriptionRefundingAmountNative) l.Info(). - Str("Coordinator", vrfv2PlusContracts.CoordinatorV2Plus.Address()). + Str("Coordinator", vrfContracts.CoordinatorV2Plus.Address()). Int("Number of Subs to create", 1). Msg("Creating and funding subscriptions, adding consumers") fundedSubIDs, err := vrfv2plus.CreateFundSubsAndAddConsumers( env, + chainID, fundingLinkAmt, fundingNativeAmt, - linkToken, - vrfv2PlusContracts.CoordinatorV2Plus, - []contracts.VRFv2PlusLoadTestConsumer{vrfv2PlusContracts.VRFV2PlusConsumer[1]}, + vrfContracts.LinkToken, + vrfContracts.CoordinatorV2Plus, + []contracts.VRFv2PlusLoadTestConsumer{consumers[1]}, 1, ) require.NoError(t, err, "error creating funded sub in replay test") randomWordsFulfilledEvent, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( - vrfv2PlusContracts.VRFV2PlusConsumer[1], - vrfv2PlusContracts.CoordinatorV2Plus, - vrfv2PlusData, + consumers[1], + vrfContracts.CoordinatorV2Plus, + vrfKey, fundedSubIDs[0], isNativeBilling, configCopy.VRFv2Plus.General, @@ -1425,46 +1704,47 @@ func TestVRFv2PlusReplayAfterTimeout(t *testing.T) { // 5. fund sub so that node can fulfill request err = vrfv2plus.FundSubscriptions( env, + chainID, fundingLinkAmt, fundingNativeAmt, - linkToken, - vrfv2PlusContracts.CoordinatorV2Plus, + vrfContracts.LinkToken, + vrfContracts.CoordinatorV2Plus, []*big.Int{subID}, ) require.NoError(t, err, "error funding subs after request timeout") // 6. no fulfilment should happen since timeout+1 seconds passed in the job - pendingReqExists, err := vrfv2PlusContracts.CoordinatorV2Plus.PendingRequestsExist(testcontext.Get(t), subID) + pendingReqExists, err := vrfContracts.CoordinatorV2Plus.PendingRequestsExist(testcontext.Get(t), subID) require.NoError(t, err, "error fetching PendingRequestsExist from coordinator") require.True(t, pendingReqExists, "pendingRequest must exist since subID was underfunded till request timeout") // 7. remove job and add new job with requestTimeout = 1 hour - vrfNode, exists := nodesMap[vrfcommon.VRF] + vrfNode, exists := nodeTypeToNodeMap[vrfcommon.VRF] require.True(t, exists, "VRF Node does not exist") resp, err := vrfNode.CLNode.API.DeleteJob(vrfNode.Job.Data.ID) require.NoError(t, err, "error deleting job after timeout") require.Equal(t, resp.StatusCode, 204) - chainID := env.EVMClient.GetChainID() - config.VRFv2Plus.General.VRFJobRequestTimeout = ptr.Ptr(blockchain.StrDuration{Duration: time.Duration(time.Hour * 1)}) + configCopy.VRFv2Plus.General.VRFJobRequestTimeout = ptr.Ptr(blockchain.StrDuration{Duration: time.Duration(time.Hour * 1)}) vrfJobSpecConfig := vrfcommon.VRFJobSpecConfig{ - ForwardingAllowed: *config.VRFv2Plus.General.VRFJobForwardingAllowed, - CoordinatorAddress: vrfv2PlusContracts.CoordinatorV2Plus.Address(), + ForwardingAllowed: *configCopy.VRFv2Plus.General.VRFJobForwardingAllowed, + CoordinatorAddress: vrfContracts.CoordinatorV2Plus.Address(), FromAddresses: vrfNode.TXKeyAddressStrings, - EVMChainID: chainID.String(), - MinIncomingConfirmations: int(*config.VRFv2Plus.General.MinimumConfirmations), - PublicKey: vrfv2PlusData.PubKeyCompressed, - EstimateGasMultiplier: *config.VRFv2Plus.General.VRFJobEstimateGasMultiplier, - BatchFulfillmentEnabled: *config.VRFv2Plus.General.VRFJobBatchFulfillmentEnabled, - BatchFulfillmentGasMultiplier: *config.VRFv2Plus.General.VRFJobBatchFulfillmentGasMultiplier, - PollPeriod: config.VRFv2Plus.General.VRFJobPollPeriod.Duration, - RequestTimeout: config.VRFv2Plus.General.VRFJobRequestTimeout.Duration, - SimulationBlock: config.VRFv2Plus.General.VRFJobSimulationBlock, + EVMChainID: fmt.Sprint(chainID), + MinIncomingConfirmations: int(*configCopy.VRFv2Plus.General.MinimumConfirmations), + PublicKey: vrfKey.PubKeyCompressed, + EstimateGasMultiplier: *configCopy.VRFv2Plus.General.VRFJobEstimateGasMultiplier, + BatchFulfillmentEnabled: *configCopy.VRFv2Plus.General.VRFJobBatchFulfillmentEnabled, + BatchFulfillmentGasMultiplier: *configCopy.VRFv2Plus.General.VRFJobBatchFulfillmentGasMultiplier, + PollPeriod: configCopy.VRFv2Plus.General.VRFJobPollPeriod.Duration, + RequestTimeout: configCopy.VRFv2Plus.General.VRFJobRequestTimeout.Duration, + SimulationBlock: configCopy.VRFv2Plus.General.VRFJobSimulationBlock, VRFOwnerConfig: nil, } go func() { - l.Info().Msg("Creating VRFV2 Plus Job with higher timeout (1hr)") + l.Info(). + Msg("Creating VRFV2 Plus Job with higher timeout (1hr)") job, err := vrfv2plus.CreateVRFV2PlusJob( vrfNode.CLNode.API, vrfJobSpecConfig, @@ -1477,7 +1757,7 @@ func TestVRFv2PlusReplayAfterTimeout(t *testing.T) { l.Info().Str("reqID", initialReqRandomWordsRequestedEvent.RequestId.String()). Str("subID", subID.String()). Msg("Waiting for initalReqRandomWordsFulfilledEvent") - initalReqRandomWordsFulfilledEvent, err := vrfv2PlusContracts.CoordinatorV2Plus.WaitForRandomWordsFulfilledEvent( + initalReqRandomWordsFulfilledEvent, err := vrfContracts.CoordinatorV2Plus.WaitForRandomWordsFulfilledEvent( []*big.Int{subID}, []*big.Int{initialReqRandomWordsRequestedEvent.RequestId}, configCopy.VRFv2Plus.General.RandomWordsFulfilledEventTimeout.Duration, @@ -1490,7 +1770,7 @@ func TestVRFv2PlusReplayAfterTimeout(t *testing.T) { require.True(t, initalReqRandomWordsFulfilledEvent.Success, "RandomWordsFulfilled Event's `Success` field should be true") // Get request status - status, err := vrfv2PlusContracts.VRFV2PlusConsumer[0].GetRequestStatus(testcontext.Get(t), initalReqRandomWordsFulfilledEvent.RequestId) + status, err := consumers[0].GetRequestStatus(testcontext.Get(t), initalReqRandomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) l.Info().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") @@ -1499,71 +1779,83 @@ func TestVRFv2PlusReplayAfterTimeout(t *testing.T) { func TestVRFv2PlusPendingBlockSimulationAndZeroConfirmationDelays(t *testing.T) { t.Parallel() + var ( + env *test_env.CLClusterTestEnv + vrfContracts *vrfcommon.VRFContracts + subIDsForCancellingAfterTest []*big.Int + defaultWalletAddress string + vrfKey *vrfcommon.VRFKeyData + ) l := logging.GetTestLogger(t) config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) - if err != nil { - t.Fatal(err) + require.NoError(t, err, "Error getting config") + vrfv2PlusConfig := config.VRFv2Plus + chainID := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0].ChainID + + cleanupFn := func() { + evmClient, err := env.GetEVMClient(chainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + if evmClient.NetworkSimulated() { + l.Info(). + Str("Network Name", evmClient.GetNetworkName()). + Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") + } else { + if *vrfv2PlusConfig.General.CancelSubsAfterTestRun { + //cancel subs and return funds to sub owner + vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, defaultWalletAddress, subIDsForCancellingAfterTest, l) + } + } + if !*vrfv2PlusConfig.General.UseExistingEnv { + if err := env.Cleanup(); err != nil { + l.Error().Err(err).Msg("Error cleaning up test environment") + } + } + } + newEnvConfig := vrfcommon.NewEnvConfig{ + NodesToCreate: []vrfcommon.VRFNodeType{vrfcommon.VRF}, + NumberOfTxKeysToCreate: 0, + UseVRFOwner: false, + UseTestCoordinator: false, } // override config with minConf = 0 and use pending block for simulation config.VRFv2Plus.General.MinimumConfirmations = ptr.Ptr[uint16](0) config.VRFv2Plus.General.VRFJobSimulationBlock = ptr.Ptr[string]("pending") - network, err := actions.EthereumNetworkConfigFromConfig(l, &config) - require.NoError(t, err, "Error building ethereum network config") - - env, err := test_env.NewCLTestEnvBuilder(). - WithTestInstance(t). - WithTestConfig(&config). - WithPrivateEthereumNetwork(network). - WithCLNodes(1). - WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). - WithStandardCleanup(). - Build() - require.NoError(t, err, "error creating test env") - - env.ParallelTransactions(true) - - mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*config.VRFv2Plus.General.LinkNativeFeedResponse)) - require.NoError(t, err, "error deploying mock ETH/LINK feed") + env, vrfContracts, vrfKey, _, err = vrfv2plus.SetupVRFV2PlusUniverse(testcontext.Get(t), t, config, chainID, cleanupFn, newEnvConfig, l) + require.NoError(t, err, "error setting up VRFV2Plus universe") - linkToken, err := actions.DeployLINKToken(env.ContractDeployer) - require.NoError(t, err, "error deploying LINK contract") + evmClient, err := env.GetEVMClient(chainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + defaultWalletAddress = evmClient.GetDefaultWallet().Address() - numberOfTxKeysToCreate := 2 - vrfv2PlusContracts, subIDs, vrfv2PlusData, nodesMap, err := vrfv2plus.SetupVRFV2_5Environment( + consumers, subIDs, err := vrfv2plus.SetupNewConsumersAndSubs( env, - []vrfcommon.VRFNodeType{vrfcommon.VRF}, - &config, - linkToken, - mockETHLinkFeed, - numberOfTxKeysToCreate, + chainID, + vrfContracts.CoordinatorV2Plus, + config, + vrfContracts.LinkToken, 1, 1, l, ) - require.NoError(t, err, "error setting up VRF v2_5 env") - + require.NoError(t, err, "error setting up new consumers and subs") subID := subIDs[0] - - subscription, err := vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) + subscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) require.NoError(t, err, "error getting subscription information") - - vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.CoordinatorV2Plus) + vrfv2plus.LogSubDetails(l, subscription, subID, vrfContracts.CoordinatorV2Plus) + subIDsForCancellingAfterTest = append(subIDsForCancellingAfterTest, subIDs...) var isNativeBilling = true - jobRunsBeforeTest, err := nodesMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodesMap[vrfcommon.VRF].Job.Data.ID) - require.NoError(t, err, "error reading job runs") - l.Info().Uint16("minimumConfirmationDelay", *config.VRFv2Plus.General.MinimumConfirmations).Msg("Minimum Confirmation Delay") // test and assert randomWordsFulfilledEvent, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( - vrfv2PlusContracts.VRFV2PlusConsumer[0], - vrfv2PlusContracts.CoordinatorV2Plus, - vrfv2PlusData, + consumers[0], + vrfContracts.CoordinatorV2Plus, + vrfKey, subID, isNativeBilling, config.VRFv2Plus.General, @@ -1571,12 +1863,8 @@ func TestVRFv2PlusPendingBlockSimulationAndZeroConfirmationDelays(t *testing.T) ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") - jobRuns, err := nodesMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodesMap[vrfcommon.VRF].Job.Data.ID) - require.NoError(t, err, "error reading job runs") - require.Equal(t, len(jobRunsBeforeTest.Data)+1, len(jobRuns.Data)) - - status, err := vrfv2PlusContracts.VRFV2PlusConsumer[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) + status, err := consumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) require.NoError(t, err, "error getting rand request status") require.True(t, status.Fulfilled) - l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") + l.Info().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") } diff --git a/integration-tests/testconfig/README.md b/integration-tests/testconfig/README.md index a86531551ff..fd985c316e2 100644 --- a/integration-tests/testconfig/README.md +++ b/integration-tests/testconfig/README.md @@ -3,6 +3,7 @@ ## Introduction Final implementation has undergone minor adjustments in comparison to the approach by Adam Hamric, Anindita Ghosh, and Sergey Kudasov stated in the ADR. The primary changes are as follows: + * `TEST_LOG_LEVEL` remains an environment variable, pending the release of version 2. * `TEST_TYPE` is also kept as an environment variable to facilitate dynamic configuration selection by some tests. * TOML configuration of Chainlink nodes themselves has not been added, awaiting version 2. @@ -15,6 +16,7 @@ The `testconfig` package serves as a centralized resource for accessing configur ## Configuration and Overrides The order of precedence for overrides is as follows: + * Environment variable `BASE64_CONFIG_OVERRIDE` * File `overrides.toml` * Product-specific file, e.g., `[product_name].toml` @@ -119,6 +121,7 @@ Finally `default.toml` file is envisioned to contain fundamental and universally GitHub workflows in this repository have been updated to dynamically generate and utilize base64-encoded TOML configurations derived from user inputs or environment variables. For local execution or remote Kubernetes runners, users must manually supply certain variables, which cannot be embedded in configuration files due to their sensitive or dynamic nature. Essential variables might include: + * Chainlink image and version * Test duration for specific tests (e.g., load, soak) * Configuration specific to Loki (mandatory for certain tests) @@ -127,19 +130,25 @@ Essential variables might include: For local testing, it is advisable to place these variables in the `overrides.toml` file. For Kubernetes or remote runners, the process involves creating a TOML file with the necessary values, encoding it in base64, and setting the result as the `BASE64_CONFIG_OVERRIDE` environment variable. ## Embeded config + Because Go automatically excludes TOML files during the compilation of binaries, we must take deliberate steps to include our configuration files in the compiled binary. This can be accomplished by using a custom build tag `-o embed`. Implementing this tag will incorporate all the default configurations located in the `./testconfig` folder directly into the binary. Therefore, when executing tests from the binary, you'll only need to supply the `overrides.toml` file. This file should list only the settings you wish to modify; all other configurations will be sourced from the embedded configurations. You can access these embedded configurations [here](.integration-tests/testconfig/configs_embed.go). ## To bear in mind + ### Validation failures + When the system encounters even a single setting related to a specific product or configuration within the configurations, it triggers a comprehensive validation of the entire configuration for that product. This approach is based on the assumption that if any configuration for a given product is specified, the entire set of configurations for that product must be complete and valid. This is particularly crucial when dealing with the `overrides.toml` file, where it's easy to overlook the need to comment out or adjust values when switching between configurations for different products. Essentially, the presence of any specific configuration detail necessitates that all relevant configurations for that product be fully defined and correct to prevent validation errors. ## Possible nil pointers + If no configuration values are set for a product or its logging parameters, the system won't perform validation checks. This can lead to a 'nil pointer exception' error if you attempt to access a configuration property later on. This situation arises because we use pointers to facilitate optional overrides; accessing an unset (nil) pointer will cause an error. To avoid such issues, especially when general validations might not cover every scenario, it's crucial for users to ensure that all necessary configuration options are explicitly set. Additionally, it's highly recommended to implement test-specific validations to confirm that all required values for a particular test are indeed established. This proactive approach helps prevent runtime errors and ensures smooth test execution. ## Contributing + It's crucial to incorporate all new test configuration settings directly into the TOML configuration files, steering clear of using environment variables for this purpose. Our goal is to centralize all configuration details, including examples, within the same package. This approach simplifies the process of understanding the available configuration options and identifying the appropriate values to use for each setting. ## Reusing TestConfig in other projects + To ensure the cleanliness and simplicity of your project's configuration, it's advised against using the `testconfig` code as a direct library in other projects. The reason is that much of this code is tailored specifically to its current application, which might not align with the requirements of your project. Your project might not necessitate any overrides or could perhaps benefit from a simpler configuration approach. However, if you find a need to utilize some methods from this project, the recommended practice is to implement the required interfaces within your project's configuration package, rather than directly copying and pasting code. For instance, if you aim to incorporate a setup action similar to the `SetupVRFV2Environment` for VRFv2, like the one shown below: @@ -164,5 +173,6 @@ func SetupVRFV2Environment( You should not replicate the entire `TestConfig` structure. Instead, create an implementation of the `types.VRFv2TestConfig` interface in your project and use that as the parameter. This approach allows you to maintain a streamlined and focused configuration package in your project. ## Known Issues/Limitations + * Duplicate file names in different locations may lead to unpredictable configurations being selected. * The use of pointer fields for optional configuration elements necessitates careful handling, especially for programmatic modifications, to avoid unintended consequences. The `MustCopy()` function is recommended for creating deep copies of configurations for isolated modifications. Unfortunately some of the custom types are not copied at all, you need to set them manually. It's true for example for `blockchain.StrDuration` type. diff --git a/integration-tests/testconfig/automation/automation.toml b/integration-tests/testconfig/automation/automation.toml index 58b95f9b4cc..a774a622123 100644 --- a/integration-tests/testconfig/automation/automation.toml +++ b/integration-tests/testconfig/automation/automation.toml @@ -2,6 +2,52 @@ [Common] chainlink_node_funding = 0.5 +# smoke test specific overrodes +[Smoke.Automation.AutomationConfig] +use_log_buffer_v1=false + +[Smoke.Automation.AutomationConfig.PublicConfig] +delta_progress=10_000_000_000 +delta_resend=15_000_000_000 +delta_initial=500_000_000 +delta_round=1_000_000_000 +delta_grace=200_000_000 +delta_certified_commit_request=300_000_000 +delta_stage=30_000_000_000 +r_max=24 +f=1 +max_duration_query=20_000_000 +max_duration_observation=20_000_000 +max_duration_should_accept_attested_report=1_200_000_000 +max_duration_should_transmit_accepted_report=20_000_000 + +[Smoke.Automation.AutomationConfig.PluginConfig] +perform_lockout_window=3_600_000 +target_probability="0.999" +target_in_rounds=1 +min_confirmations=0 +gas_limit_per_report=10_300_000 +gas_overhead_per_upkeep=300_000 +max_upkeep_batch_size=10 + +[Smoke.Automation.AutomationConfig.PluginConfig.LogProviderConfig] +block_rate=1 +log_limit=2 + +[Smoke.Automation.AutomationConfig.RegistrySettings] +payment_premium_ppb=200_000_000 +flat_fee_micro_link=0 +check_gas_limit=2_500_000 +staleness_seconds=90000 +gas_ceiling_multiplier=1 +max_perform_gas=5_000_000 +min_upkeep_spend=0 +fallback_gas_price=200_000_000_000 +fallback_link_price=2_000_000_000_000_000_000 +max_check_data_size=5_000 +max_perform_data_size=5_000 +max_revert_data_size=5_000 + # reorg test specific overrides [Reorg.Automation] [Reorg.Automation.General] @@ -25,6 +71,9 @@ spec_type="minimum" chainlink_node_log_level="info" use_prometheus=false +[Load.Automation.DataStreams] +enabled=false + [[Load.Automation.Load]] number_of_upkeeps=5 number_of_events = 1 @@ -34,6 +83,8 @@ check_burn_amount = 0 perform_burn_amount = 0 upkeep_gas_limit = 1000000 shared_trigger = false +is_streams_lookup = false +feeds = ["0x000200"] [[Load.Automation.Load]] number_of_upkeeps=5 @@ -44,6 +95,53 @@ check_burn_amount = 0 perform_burn_amount = 0 upkeep_gas_limit = 1000000 shared_trigger = true +is_streams_lookup = false +feeds = ["0x000200"] + +[Load.Automation.AutomationConfig] +use_log_buffer_v1=false + +[Load.Automation.AutomationConfig.PublicConfig] +delta_progress=10_000_000_000 +delta_resend=15_000_000_000 +delta_initial=500_000_000 +delta_round=1_000_000_000 +delta_grace=200_000_000 +delta_certified_commit_request=300_000_000 +delta_stage=15_000_000_000 +r_max=24 +f=1 +max_duration_query=20_000_000 +max_duration_observation=20_000_000 +max_duration_should_accept_attested_report=1_200_000_000 +max_duration_should_transmit_accepted_report=20_000_000 + +[Load.Automation.AutomationConfig.PluginConfig] +perform_lockout_window=80_000 +target_probability="0.999" +target_in_rounds=1 +min_confirmations=0 +gas_limit_per_report=10_300_000 +gas_overhead_per_upkeep=300_000 +max_upkeep_batch_size=10 + +[Load.Automation.AutomationConfig.PluginConfig.LogProviderConfig] +block_rate=1 +log_limit=2 + +[Load.Automation.AutomationConfig.RegistrySettings] +payment_premium_ppb=0 +flat_fee_micro_link=40000 +check_gas_limit=45_000_000 +staleness_seconds=90_000 +gas_ceiling_multiplier=2 +max_perform_gas=5_000_000 +min_upkeep_spend=0 +fallback_gas_price=200_000_000_000 +fallback_link_price=2_000_000_000_000_000_000 +max_check_data_size=5_000 +max_perform_data_size=5_000 +max_revert_data_size=5_000 [Load.Pyroscope] enabled=false \ No newline at end of file diff --git a/integration-tests/testconfig/automation/config.go b/integration-tests/testconfig/automation/config.go index 4431a640d0d..103f963d881 100644 --- a/integration-tests/testconfig/automation/config.go +++ b/integration-tests/testconfig/automation/config.go @@ -3,11 +3,14 @@ package automation import ( "errors" "math/big" + "time" ) type Config struct { - General *General `toml:"General"` - Load []Load `toml:"Load"` + General *General `toml:"General"` + Load []Load `toml:"Load"` + DataStreams *DataStreams `toml:"DataStreams"` + AutomationConfig *AutomationConfig `toml:"AutomationConfig"` } func (c *Config) Validate() error { @@ -23,6 +26,17 @@ func (c *Config) Validate() error { } } } + if c.DataStreams != nil { + if err := c.DataStreams.Validate(); err != nil { + return err + } + } + + if c.AutomationConfig != nil { + if err := c.AutomationConfig.Validate(); err != nil { + return err + } + } return nil } @@ -65,6 +79,8 @@ type Load struct { PerformBurnAmount *big.Int `toml:"perform_burn_amount"` SharedTrigger *bool `toml:"shared_trigger"` UpkeepGasLimit *uint32 `toml:"upkeep_gas_limit"` + IsStreamsLookup *bool `toml:"is_streams_lookup"` + Feeds []string `toml:"feeds"` } func (c *Load) Validate() error { @@ -86,6 +102,243 @@ func (c *Load) Validate() error { if c.PerformBurnAmount == nil || c.PerformBurnAmount.Cmp(big.NewInt(0)) < 0 { return errors.New("perform_burn_amount must be set to a non-negative integer") } + if c.SharedTrigger == nil { + return errors.New("shared_trigger must be set") + } + if c.UpkeepGasLimit == nil || *c.UpkeepGasLimit < 1 { + return errors.New("upkeep_gas_limit must be set to a positive integer") + } + if c.IsStreamsLookup == nil { + return errors.New("is_streams_lookup must be set") + } + if *c.IsStreamsLookup { + if len(c.Feeds) == 0 { + return errors.New("feeds must be set") + } + } return nil } + +type DataStreams struct { + Enabled *bool `toml:"enabled"` + URL *string `toml:"url"` + Username *string `toml:"username"` + Password *string `toml:"password"` + DefaultFeedID *string `toml:"default_feed_id"` +} + +func (c *DataStreams) Validate() error { + if c.Enabled != nil && *c.Enabled { + if c.URL == nil { + return errors.New("data_streams_url must be set") + } + if c.Username == nil { + return errors.New("data_streams_username must be set") + } + if c.Password == nil { + return errors.New("data_streams_password must be set") + } + if c.DefaultFeedID == nil { + return errors.New("data_streams_feed_id must be set") + } + } else { + c.Enabled = new(bool) + *c.Enabled = false + } + return nil +} + +type AutomationConfig struct { + PluginConfig *PluginConfig `toml:"PluginConfig"` + PublicConfig *PublicConfig `toml:"PublicConfig"` + RegistrySettings *RegistrySettings `toml:"RegistrySettings"` + UseLogBufferV1 *bool `toml:"use_log_buffer_v1"` +} + +func (c *AutomationConfig) Validate() error { + if err := c.PluginConfig.Validate(); err != nil { + return err + } + if err := c.PublicConfig.Validate(); err != nil { + return err + } + if err := c.RegistrySettings.Validate(); err != nil { + return err + } + if c.UseLogBufferV1 == nil { + return errors.New("use_log_buffer_v1 must be set") + } + return nil +} + +type PluginConfig struct { + PerformLockoutWindow *int64 `toml:"perform_lockout_window"` + TargetProbability *string `toml:"target_probability"` + TargetInRounds *int `toml:"target_in_rounds"` + MinConfirmations *int `toml:"min_confirmations"` + GasLimitPerReport *uint32 `toml:"gas_limit_per_report"` + GasOverheadPerUpkeep *uint32 `toml:"gas_overhead_per_upkeep"` + MaxUpkeepBatchSize *int `toml:"max_upkeep_batch_size"` + LogProviderConfig *LogProviderConfig `toml:"LogProviderConfig"` +} + +type LogProviderConfig struct { + BlockRate *uint32 `toml:"block_rate"` + LogLimit *uint32 `toml:"log_limit"` +} + +func (c *PluginConfig) Validate() error { + if err := c.LogProviderConfig.Validate(); err != nil { + return err + } + if c.PerformLockoutWindow == nil || *c.PerformLockoutWindow < 0 { + return errors.New("perform_lockout_window must be set to a non-negative integer") + } + if c.TargetProbability == nil || *c.TargetProbability == "" { + return errors.New("target_probability must be set") + } + if c.TargetInRounds == nil || *c.TargetInRounds < 1 { + return errors.New("target_in_rounds must be set to a positive integer") + } + if c.MinConfirmations == nil || *c.MinConfirmations < 0 { + return errors.New("min_confirmations must be set to a non-negative integer") + } + if c.GasLimitPerReport == nil || *c.GasLimitPerReport < 1 { + return errors.New("gas_limit_per_report must be set to a positive integer") + } + if c.GasOverheadPerUpkeep == nil || *c.GasOverheadPerUpkeep < 1 { + return errors.New("gas_overhead_per_upkeep must be set to a positive integer") + } + if c.MaxUpkeepBatchSize == nil || *c.MaxUpkeepBatchSize < 1 { + return errors.New("max_upkeep_batch_size must be set to a positive integer") + } + return nil + +} + +func (c *LogProviderConfig) Validate() error { + if c.BlockRate == nil || *c.BlockRate < 1 { + return errors.New("block_rate must be set to a positive integer") + } + if c.LogLimit == nil || *c.LogLimit < 1 { + return errors.New("log_limit must be set to a positive integer") + } + return nil + +} + +type PublicConfig struct { + DeltaProgress *time.Duration `toml:"delta_progress"` + DeltaResend *time.Duration `toml:"delta_resend"` + DeltaInitial *time.Duration `toml:"delta_initial"` + DeltaRound *time.Duration `toml:"delta_round"` + DeltaGrace *time.Duration `toml:"delta_grace"` + DeltaCertifiedCommitRequest *time.Duration `toml:"delta_certified_commit_request"` + DeltaStage *time.Duration `toml:"delta_stage"` + RMax *uint64 `toml:"r_max"` + F *int `toml:"f"` + MaxDurationQuery *time.Duration `toml:"max_duration_query"` + MaxDurationObservation *time.Duration `toml:"max_duration_observation"` + MaxDurationShouldAcceptAttestedReport *time.Duration `toml:"max_duration_should_accept_attested_report"` + MaxDurationShouldTransmitAcceptedReport *time.Duration `toml:"max_duration_should_transmit_accepted_report"` +} + +func (c *PublicConfig) Validate() error { + if c.DeltaProgress == nil || *c.DeltaProgress < 0 { + return errors.New("delta_progress must be set to a non-negative duration") + } + if c.DeltaResend == nil || *c.DeltaResend < 0 { + return errors.New("delta_resend must be set to a non-negative duration") + } + if c.DeltaInitial == nil || *c.DeltaInitial < 0 { + return errors.New("delta_initial must be set to a non-negative duration") + } + if c.DeltaRound == nil || *c.DeltaRound < 0 { + return errors.New("delta_round must be set to a non-negative duration") + } + if c.DeltaGrace == nil || *c.DeltaGrace < 0 { + return errors.New("delta_grace must be set to a non-negative duration") + } + if c.DeltaCertifiedCommitRequest == nil || *c.DeltaCertifiedCommitRequest < 0 { + return errors.New("delta_certified_commit_request must be set to a non-negative duration") + } + if c.DeltaStage == nil || *c.DeltaStage < 0 { + return errors.New("delta_stage must be set to a non-negative duration") + } + if c.RMax == nil || *c.RMax < 1 { + return errors.New("r_max must be set to a positive integer") + } + if c.F == nil || *c.F < 1 { + return errors.New("f must be set to a positive integer") + } + if c.MaxDurationQuery == nil || *c.MaxDurationQuery < 0 { + return errors.New("max_duration_query must be set to a non-negative duration") + } + if c.MaxDurationObservation == nil || *c.MaxDurationObservation < 0 { + return errors.New("max_duration_observation must be set to a non-negative duration") + } + if c.MaxDurationShouldAcceptAttestedReport == nil || *c.MaxDurationShouldAcceptAttestedReport < 0 { + return errors.New("max_duration_should_accept_attested_report must be set to a non-negative duration") + } + if c.MaxDurationShouldTransmitAcceptedReport == nil || *c.MaxDurationShouldTransmitAcceptedReport < 0 { + return errors.New("max_duration_should_transmit_accepted_report must be set to a non-negative duration") + } + return nil + +} + +type RegistrySettings struct { + PaymentPremiumPPB *uint32 `toml:"payment_premium_ppb"` + FlatFeeMicroLINK *uint32 `toml:"flat_fee_micro_link"` + CheckGasLimit *uint32 `toml:"check_gas_limit"` + StalenessSeconds *big.Int `toml:"staleness_seconds"` + GasCeilingMultiplier *uint16 `toml:"gas_ceiling_multiplier"` + MaxPerformGas *uint32 `toml:"max_perform_gas"` + MinUpkeepSpend *big.Int `toml:"min_upkeep_spend"` + FallbackGasPrice *big.Int `toml:"fallback_gas_price"` + FallbackLinkPrice *big.Int `toml:"fallback_link_price"` + MaxCheckDataSize *uint32 `toml:"max_check_data_size"` + MaxPerformDataSize *uint32 `toml:"max_perform_data_size"` + MaxRevertDataSize *uint32 `toml:"max_revert_data_size"` +} + +func (c *RegistrySettings) Validate() error { + if c.PaymentPremiumPPB == nil { + return errors.New("payment_premium_ppb must be set to a non-negative integer") + } + if c.FlatFeeMicroLINK == nil { + return errors.New("flat_fee_micro_link must be set to a non-negative integer") + } + if c.CheckGasLimit == nil || *c.CheckGasLimit < 1 { + return errors.New("check_gas_limit must be set to a positive integer") + } + if c.StalenessSeconds == nil || c.StalenessSeconds.Cmp(big.NewInt(0)) < 0 { + return errors.New("staleness_seconds must be set to a non-negative integer") + } + if c.GasCeilingMultiplier == nil { + return errors.New("gas_ceiling_multiplier must be set to a non-negative integer") + } + if c.MaxPerformGas == nil || *c.MaxPerformGas < 1 { + return errors.New("max_perform_gas must be set to a positive integer") + } + if c.MinUpkeepSpend == nil || c.MinUpkeepSpend.Cmp(big.NewInt(0)) < 0 { + return errors.New("min_upkeep_spend must be set to a non-negative integer") + } + if c.FallbackGasPrice == nil || c.FallbackGasPrice.Cmp(big.NewInt(0)) < 0 { + return errors.New("fallback_gas_price must be set to a non-negative integer") + } + if c.FallbackLinkPrice == nil || c.FallbackLinkPrice.Cmp(big.NewInt(0)) < 0 { + return errors.New("fallback_link_price must be set to a non-negative integer") + } + if c.MaxCheckDataSize == nil || *c.MaxCheckDataSize < 1 { + return errors.New("max_check_data_size must be set to a positive integer") + } + if c.MaxPerformDataSize == nil || *c.MaxPerformDataSize < 1 { + return errors.New("max_perform_data_size must be set to a positive integer") + } + if c.MaxRevertDataSize == nil || *c.MaxRevertDataSize < 1 { + return errors.New("max_revert_data_size must be set to a positive integer") + } + return nil +} diff --git a/integration-tests/testconfig/common/vrf/common.go b/integration-tests/testconfig/common/vrf/common.go index ca6f44f27c0..97c413207b1 100644 --- a/integration-tests/testconfig/common/vrf/common.go +++ b/integration-tests/testconfig/common/vrf/common.go @@ -40,6 +40,10 @@ type PerformanceConfig struct { TestDuration *blockchain.StrDuration `toml:"test_duration"` RPS *int64 `toml:"rps"` RateLimitUnitDuration *blockchain.StrDuration `toml:"rate_limit_unit_duration"` + + BHSTestDuration *blockchain.StrDuration `toml:"bhs_test_duration"` + BHSTestRPS *int64 `toml:"bhs_test_rps"` + BHSTestRateLimitUnitDuration *blockchain.StrDuration `toml:"bhs_test_rate_limit_unit_duration"` } func (c *PerformanceConfig) Validate() error { @@ -52,6 +56,15 @@ func (c *PerformanceConfig) Validate() error { if c.RateLimitUnitDuration == nil { return errors.New("rate_limit_unit_duration must be set ") } + if c.BHSTestDuration == nil || c.BHSTestDuration.Duration == 0 { + return errors.New("bhs_test_duration must be set to a positive value") + } + if c.BHSTestRPS == nil || *c.BHSTestRPS == 0 { + return errors.New("bhs_test_rps must be set to a positive value") + } + if c.BHSTestRateLimitUnitDuration == nil { + return errors.New("bhs_test_rate_limit_unit_duration must be set ") + } return nil } @@ -119,25 +132,28 @@ func (c *Funding) Validate() error { } type General struct { - UseExistingEnv *bool `toml:"use_existing_env"` - CancelSubsAfterTestRun *bool `toml:"cancel_subs_after_test_run"` - CLNodeMaxGasPriceGWei *int64 `toml:"cl_node_max_gas_price_gwei"` // Max gas price in GWei for the chainlink node - LinkNativeFeedResponse *int64 `toml:"link_native_feed_response"` // Response of the LINK/ETH feed - MinimumConfirmations *uint16 `toml:"minimum_confirmations"` // Minimum number of confirmations for the VRF Coordinator - SubscriptionFundingAmountLink *float64 `toml:"subscription_funding_amount_link"` // Amount of LINK to fund the subscription with - NumberOfWords *uint32 `toml:"number_of_words"` // Number of words to request - CallbackGasLimit *uint32 `toml:"callback_gas_limit"` // Gas limit for the callback - MaxGasLimitCoordinatorConfig *uint32 `toml:"max_gas_limit_coordinator_config"` // Max gas limit for the VRF Coordinator config - FallbackWeiPerUnitLink *int64 `toml:"fallback_wei_per_unit_link"` // Fallback wei per unit LINK for the VRF Coordinator config - StalenessSeconds *uint32 `toml:"staleness_seconds"` // Staleness in seconds for the VRF Coordinator config - GasAfterPaymentCalculation *uint32 `toml:"gas_after_payment_calculation"` // Gas after payment calculation for the VRF Coordinator - - NumberOfSubToCreate *int `toml:"number_of_sub_to_create"` // Number of subscriptions to create + UseExistingEnv *bool `toml:"use_existing_env"` + CancelSubsAfterTestRun *bool `toml:"cancel_subs_after_test_run"` + CLNodeMaxGasPriceGWei *int64 `toml:"cl_node_max_gas_price_gwei"` // Max gas price in GWei for the chainlink node + LinkNativeFeedResponse *int64 `toml:"link_native_feed_response"` // Response of the LINK/ETH feed + MinimumConfirmations *uint16 `toml:"minimum_confirmations"` // Minimum number of confirmations for the VRF Coordinator + SubscriptionFundingAmountLink *float64 `toml:"subscription_funding_amount_link"` // Amount of LINK to fund the subscription with + SubscriptionRefundingAmountLink *float64 `toml:"subscription_refunding_amount_link"` // Amount of LINK to fund the subscription with + NumberOfWords *uint32 `toml:"number_of_words"` // Number of words to request + CallbackGasLimit *uint32 `toml:"callback_gas_limit"` // Gas limit for the callback + MaxGasLimitCoordinatorConfig *uint32 `toml:"max_gas_limit_coordinator_config"` // Max gas limit for the VRF Coordinator config + FallbackWeiPerUnitLink *int64 `toml:"fallback_wei_per_unit_link"` // Fallback wei per unit LINK for the VRF Coordinator config + StalenessSeconds *uint32 `toml:"staleness_seconds"` // Staleness in seconds for the VRF Coordinator config + GasAfterPaymentCalculation *uint32 `toml:"gas_after_payment_calculation"` // Gas after payment calculation for the VRF Coordinator + + NumberOfSubToCreate *int `toml:"number_of_sub_to_create"` // Number of subscriptions to create + NumberOfSendingKeysToCreate *int `toml:"number_of_sending_keys_to_create"` // Number of sending keys to create RandomnessRequestCountPerRequest *uint16 `toml:"randomness_request_count_per_request"` // How many randomness requests to send per request RandomnessRequestCountPerRequestDeviation *uint16 `toml:"randomness_request_count_per_request_deviation"` // How many randomness requests to send per request RandomWordsFulfilledEventTimeout *blockchain.StrDuration `toml:"random_words_fulfilled_event_timeout"` // How long to wait for the RandomWordsFulfilled event to be emitted + WaitFor256BlocksTimeout *blockchain.StrDuration `toml:"wait_for_256_blocks_timeout"` // How long to wait for 256 blocks to be mined // Wrapper Config WrapperGasOverhead *uint32 `toml:"wrapped_gas_overhead"` @@ -161,6 +177,12 @@ type General struct { BHSJobLookBackBlocks *int `toml:"bhs_job_lookback_blocks"` BHSJobPollPeriod *blockchain.StrDuration `toml:"bhs_job_poll_period"` BHSJobRunTimeout *blockchain.StrDuration `toml:"bhs_job_run_timeout"` + + //BHF Job Config + BHFJobWaitBlocks *int `toml:"bhf_job_wait_blocks"` + BHFJobLookBackBlocks *int `toml:"bhf_job_lookback_blocks"` + BHFJobPollPeriod *blockchain.StrDuration `toml:"bhf_job_poll_period"` + BHFJobRunTimeout *blockchain.StrDuration `toml:"bhf_job_run_timeout"` } func (c *General) Validate() error { @@ -168,7 +190,7 @@ func (c *General) Validate() error { return errors.New("use_existing_env must not be nil") } if c.CLNodeMaxGasPriceGWei == nil || *c.CLNodeMaxGasPriceGWei == 0 { - return errors.New("max_gas_price_gwei must be set to a positive value") + return errors.New("cl_node_max_gas_price_gwei must be set to a positive value") } if c.LinkNativeFeedResponse == nil || *c.LinkNativeFeedResponse == 0 { return errors.New("link_native_feed_response must be set to a positive value") @@ -179,6 +201,9 @@ func (c *General) Validate() error { if c.SubscriptionFundingAmountLink == nil || *c.SubscriptionFundingAmountLink < 0 { return errors.New("subscription_funding_amount_link must be set to non-negative value") } + if c.SubscriptionRefundingAmountLink == nil || *c.SubscriptionRefundingAmountLink < 0 { + return errors.New("subscription_refunding_amount_link must be set to non-negative value") + } if c.NumberOfWords == nil || *c.NumberOfWords == 0 { return errors.New("number_of_words must be set to a positive value") } @@ -200,6 +225,11 @@ func (c *General) Validate() error { if c.NumberOfSubToCreate == nil || *c.NumberOfSubToCreate == 0 { return errors.New("number_of_sub_to_create must be set to a positive value") } + + if c.NumberOfSendingKeysToCreate == nil || *c.NumberOfSendingKeysToCreate < 0 { + return errors.New("number_of_sending_keys_to_create must be set to 0 or a positive value") + } + if c.RandomnessRequestCountPerRequest == nil || *c.RandomnessRequestCountPerRequest == 0 { return errors.New("randomness_request_count_per_request must be set to a positive value") } @@ -209,6 +239,9 @@ func (c *General) Validate() error { if c.RandomWordsFulfilledEventTimeout == nil || c.RandomWordsFulfilledEventTimeout.Duration == 0 { return errors.New("random_words_fulfilled_event_timeout must be set to a positive value") } + if c.WaitFor256BlocksTimeout == nil || c.WaitFor256BlocksTimeout.Duration == 0 { + return errors.New("wait_for_256_blocks_timeout must be set to a positive value") + } if c.WrapperGasOverhead == nil { return errors.New("wrapped_gas_overhead must be set to a non-negative value") } diff --git a/integration-tests/testconfig/default.toml b/integration-tests/testconfig/default.toml index 1bcb4b3350c..d334eaa3c13 100644 --- a/integration-tests/testconfig/default.toml +++ b/integration-tests/testconfig/default.toml @@ -8,12 +8,14 @@ log_producer_retry_limit=10 [ChainlinkImage] postgres_version="15.6" +image="public.ecr.aws/chainlink/chainlink" +version="2.9.1" [Network] selected_networks=["simulated"] [PrivateEthereumNetwork] -consensus_type="pow" +ethereum_version="eth1" execution_layer="geth" [PrivateEthereumNetwork.EthereumChainConfig] diff --git a/integration-tests/testconfig/log_poller/log_poller.toml b/integration-tests/testconfig/log_poller/log_poller.toml index 89d2f07b4e3..5ead6c91e9c 100644 --- a/integration-tests/testconfig/log_poller/log_poller.toml +++ b/integration-tests/testconfig/log_poller/log_poller.toml @@ -1,3 +1,11 @@ +[PrivateEthereumNetwork] +ethereum_version="eth2" +consensus_layer="prysm" + +[PrivateEthereumNetwork.EthereumChainConfig] +seconds_per_slot=4 +slots_per_epoch=2 + # product defaults [LogPoller] [LogPoller.General] diff --git a/integration-tests/testconfig/testconfig.go b/integration-tests/testconfig/testconfig.go index ee3ce21d3db..097315c2e98 100644 --- a/integration-tests/testconfig/testconfig.go +++ b/integration-tests/testconfig/testconfig.go @@ -68,6 +68,10 @@ type KeeperTestConfig interface { GetKeeperConfig() *keeper_config.Config } +type AutomationTestConfig interface { + GetAutomationConfig() *a_config.Config +} + type OcrTestConfig interface { GetOCRConfig() *ocr_config.Config } @@ -210,6 +214,10 @@ func (c TestConfig) GetKeeperConfig() *keeper_config.Config { return c.Keeper } +func (c TestConfig) GetAutomationConfig() *a_config.Config { + return c.Automation +} + func (c TestConfig) GetOCRConfig() *ocr_config.Config { return c.OCR } diff --git a/integration-tests/testconfig/vrfv2/vrfv2.toml b/integration-tests/testconfig/vrfv2/vrfv2.toml index 3ce3135b3aa..6d92e2fd6b0 100644 --- a/integration-tests/testconfig/vrfv2/vrfv2.toml +++ b/integration-tests/testconfig/vrfv2/vrfv2.toml @@ -7,6 +7,7 @@ chainlink_node_funding = 0.1 cancel_subs_after_test_run = true use_existing_env = false subscription_funding_amount_link = 5.0 +subscription_refunding_amount_link = 5.0 cl_node_max_gas_price_gwei = 10 link_native_feed_response = 1000000000000000000 @@ -28,9 +29,11 @@ reqs_for_tier_3 = 0 reqs_for_tier_4 = 0 reqs_for_tier_5 = 0 number_of_sub_to_create = 1 +number_of_sending_keys_to_create = 0 randomness_request_count_per_request = 1 randomness_request_count_per_request_deviation = 0 random_words_fulfilled_event_timeout = "2m" +wait_for_256_blocks_timeout = "10m" wrapped_gas_overhead = 50000 coordinator_gas_overhead = 52000 wrapper_premium_percentage = 25 @@ -52,7 +55,6 @@ bhs_job_lookback_blocks = 250 bhs_job_poll_period = "1s" bhs_job_run_timeout = "24h" - # PERFORMANCE test specific config [VRFv2.ExistingEnv] @@ -69,6 +71,22 @@ node_sending_keys = [ "" ] +[VRFv2.Performance] +test_duration = "10s" +rate_limit_unit_duration = "3s" +rps = 1 +bhs_test_duration = "10s" +bhs_test_rate_limit_unit_duration = "3s" +bhs_test_rps = 1 + +[Smoke.VRFv2.Performance] +test_duration = "10s" +rate_limit_unit_duration = "3s" +rps = 1 +bhs_test_duration = "10s" +bhs_test_rate_limit_unit_duration = "3s" +bhs_test_rps = 1 + #SOAK TEST CONFIG [Soak.Common] chainlink_node_funding = 0.1 @@ -77,12 +95,16 @@ chainlink_node_funding = 0.1 randomness_request_count_per_request = 1 # amount of randomness requests to make per one TX request randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting number_of_sub_to_create = 1 +number_of_sending_keys_to_create = 0 subscription_funding_amount_link = 5.0 [Soak.VRFv2.Performance] test_duration = "1m" rate_limit_unit_duration = "3s" rps = 1 +bhs_test_duration = "1m" +bhs_test_rate_limit_unit_duration = "3s" +bhs_test_rps = 1 # LOAD TEST CONFIG [Load.Common] @@ -92,13 +114,16 @@ chainlink_node_funding = 0.1 randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting number_of_sub_to_create = 1 +number_of_sending_keys_to_create = 0 subscription_funding_amount_link = 5.0 [Load.VRFv2.Performance] test_duration = "2m" rate_limit_unit_duration = "3s" rps = 1 - +bhs_test_duration = "1m" +bhs_test_rate_limit_unit_duration = "3s" +bhs_test_rps = 1 # STRESS TEST CONFIG [Stress.Common] @@ -108,9 +133,13 @@ chainlink_node_funding = 0.1 randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting number_of_sub_to_create = 1 +number_of_sending_keys_to_create = 0 subscription_funding_amount_link = 5.0 [Stress.VRFv2.Performance] test_duration = "2m" rate_limit_unit_duration = "3s" rps = 1 +bhs_test_duration = "1m" +bhs_test_rate_limit_unit_duration = "3s" +bhs_test_rps = 1 diff --git a/integration-tests/testconfig/vrfv2plus/config.go b/integration-tests/testconfig/vrfv2plus/config.go index fe05dbd9d18..b87bef6a836 100644 --- a/integration-tests/testconfig/vrfv2plus/config.go +++ b/integration-tests/testconfig/vrfv2plus/config.go @@ -43,6 +43,7 @@ type General struct { *vrf_common_config.General SubscriptionBillingType *string `toml:"subscription_billing_type"` // Billing type for the subscription SubscriptionFundingAmountNative *float64 `toml:"subscription_funding_amount_native"` // Amount of LINK to fund the subscription with + SubscriptionRefundingAmountNative *float64 `toml:"subscription_refunding_amount_native"` // Amount of LINK to fund the subscription with FulfillmentFlatFeeNativePPM *uint32 `toml:"fulfillment_flat_fee_native_ppm"` // Flat fee in ppm for native currency for the VRF Coordinator config FulfillmentFlatFeeLinkPPM *uint32 `toml:"fulfillment_flat_fee_link_ppm"` // Flat fee in ppm for LINK for the VRF Coordinator config FulfillmentFlatFeeLinkDiscountPPM *uint32 `toml:"fulfillment_flat_fee_link_discount_ppm"` // Flat fee discount in ppm for LINK for the VRF Coordinator config @@ -60,6 +61,9 @@ func (c *General) Validate() error { if c.SubscriptionFundingAmountNative == nil || *c.SubscriptionFundingAmountNative <= 0 { return errors.New("subscription_funding_amount_native must be greater than 0") } + if c.SubscriptionRefundingAmountNative == nil || *c.SubscriptionRefundingAmountNative <= 0 { + return errors.New("subscription_refunding_amount_native must be greater than 0") + } if c.FulfillmentFlatFeeNativePPM == nil { return errors.New("fulfillment_flat_fee_native_ppm must not be nil") } diff --git a/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml b/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml index 96b1a3f7224..5acf9c1839f 100644 --- a/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml +++ b/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml @@ -9,6 +9,9 @@ use_existing_env = false subscription_funding_amount_link = 5.0 subscription_funding_amount_native=1 +subscription_refunding_amount_link = 5.0 +subscription_refunding_amount_native = 1 + cl_node_max_gas_price_gwei = 10 link_native_feed_response = 1000000000000000000 minimum_confirmations = 3 @@ -21,9 +24,11 @@ fallback_wei_per_unit_link = 60000000000000000 staleness_seconds = 86400 gas_after_payment_calculation = 33825 number_of_sub_to_create = 1 +number_of_sending_keys_to_create = 0 randomness_request_count_per_request = 1 randomness_request_count_per_request_deviation = 0 random_words_fulfilled_event_timeout = "2m" +wait_for_256_blocks_timeout = "10m" wrapped_gas_overhead = 50000 coordinator_gas_overhead = 52000 wrapper_premium_percentage = 25 @@ -62,6 +67,22 @@ link_address = "" node_sending_key_funding_min = 1 node_sending_keys = [] +[VRFv2Plus.Performance] +test_duration = "10s" +rate_limit_unit_duration = "3s" +rps = 1 +bhs_test_duration = "10s" +bhs_test_rate_limit_unit_duration = "3s" +bhs_test_rps = 1 + +[Smoke.VRFv2.Performance] +test_duration = "10s" +rate_limit_unit_duration = "3s" +rps = 1 +bhs_test_duration = "10s" +bhs_test_rate_limit_unit_duration = "3s" +bhs_test_rps = 1 + #SOAK TEST CONFIG [Soak.Common] chainlink_node_funding = 0.1 @@ -70,6 +91,7 @@ chainlink_node_funding = 0.1 randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting number_of_sub_to_create = 1 +number_of_sending_keys_to_create = 0 subscription_funding_amount_link = 5.0 subscription_funding_amount_native=1 @@ -77,6 +99,9 @@ subscription_funding_amount_native=1 test_duration = "2m" rate_limit_unit_duration = "3s" rps = 1 +bhs_test_duration = "1m" +bhs_test_rate_limit_unit_duration = "3s" +bhs_test_rps = 1 # LOAD TEST CONFIG [Load.Common] @@ -86,6 +111,7 @@ chainlink_node_funding = 0.1 randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting number_of_sub_to_create = 1 +number_of_sending_keys_to_create = 0 subscription_funding_amount_link = 5.0 subscription_funding_amount_native=1 @@ -93,7 +119,9 @@ subscription_funding_amount_native=1 test_duration = "2m" rate_limit_unit_duration = "3s" rps = 1 - +bhs_test_duration = "1m" +bhs_test_rate_limit_unit_duration = "3s" +bhs_test_rps = 1 # STRESS TEST CONFIG [Stress.Common] @@ -103,6 +131,7 @@ chainlink_node_funding = 0.1 randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting number_of_sub_to_create = 1 +number_of_sending_keys_to_create = 0 subscription_funding_amount_link = 5.0 subscription_funding_amount_native=1 @@ -110,3 +139,7 @@ subscription_funding_amount_native=1 test_duration = "2m" rate_limit_unit_duration = "3s" rps = 1 +bhs_test_duration = "1m" +bhs_test_rate_limit_unit_duration = "3s" +bhs_test_rps = 1 + diff --git a/integration-tests/testreporters/vrfv2.go b/integration-tests/testreporters/vrfv2.go index d94c66abc59..5f4e9dcc1fc 100644 --- a/integration-tests/testreporters/vrfv2.go +++ b/integration-tests/testreporters/vrfv2.go @@ -2,7 +2,6 @@ package testreporters import ( "fmt" - "math/big" "strings" "testing" "time" @@ -14,30 +13,18 @@ import ( ) type VRFV2TestReporter struct { - TestType string - RequestCount *big.Int - FulfilmentCount *big.Int - AverageFulfillmentInMillions *big.Int - SlowestFulfillment *big.Int - FastestFulfillment *big.Int - VRFv2TestConfig types.VRFv2TestConfig + TestType string + LoadTestMetrics VRFLoadTestMetrics + VRFv2TestConfig types.VRFv2TestConfig } func (o *VRFV2TestReporter) SetReportData( testType string, - RequestCount *big.Int, - FulfilmentCount *big.Int, - AverageFulfillmentInMillions *big.Int, - SlowestFulfillment *big.Int, - FastestFulfillment *big.Int, + metrics VRFLoadTestMetrics, vrfv2TestConfig types.VRFv2TestConfig, ) { o.TestType = testType - o.RequestCount = RequestCount - o.FulfilmentCount = FulfilmentCount - o.AverageFulfillmentInMillions = AverageFulfillmentInMillions - o.SlowestFulfillment = SlowestFulfillment - o.FastestFulfillment = FastestFulfillment + o.LoadTestMetrics = metrics o.VRFv2TestConfig = vrfv2TestConfig } @@ -54,13 +41,7 @@ func (o *VRFV2TestReporter) SendSlackNotification(t *testing.T, slackClient *sla } perfCfg := o.VRFv2TestConfig.GetVRFv2Config().Performance - var sb strings.Builder - for _, n := range o.VRFv2TestConfig.GetNetworkConfig().SelectedNetworks { - sb.WriteString(n) - sb.WriteString(", ") - } - - messageBlocks := testreporters.SlackNotifyBlocks(headerText, sb.String(), []string{ + messageBlocks := testreporters.SlackNotifyBlocks(headerText, strings.Join(o.VRFv2TestConfig.GetNetworkConfig().SelectedNetworks, ","), []string{ fmt.Sprintf( "Summary\n"+ "Perf Test Type: %s\n"+ @@ -78,11 +59,11 @@ func (o *VRFV2TestReporter) SendSlackNotification(t *testing.T, slackClient *sla o.TestType, perfCfg.TestDuration.Duration.Truncate(time.Second).String(), *o.VRFv2TestConfig.GetVRFv2Config().General.UseExistingEnv, - o.RequestCount.String(), - o.FulfilmentCount.String(), - o.AverageFulfillmentInMillions.String(), - o.SlowestFulfillment.String(), - o.FastestFulfillment.String(), + o.LoadTestMetrics.RequestCount.String(), + o.LoadTestMetrics.FulfilmentCount.String(), + o.LoadTestMetrics.AverageFulfillmentInMillions.String(), + o.LoadTestMetrics.SlowestFulfillment.String(), + o.LoadTestMetrics.FastestFulfillment.String(), *perfCfg.RPS, perfCfg.RateLimitUnitDuration.String(), *o.VRFv2TestConfig.GetVRFv2Config().General.RandomnessRequestCountPerRequest, diff --git a/integration-tests/testreporters/vrfv2plus.go b/integration-tests/testreporters/vrfv2plus.go index ddbf1f35e24..cb65b0f3d40 100644 --- a/integration-tests/testreporters/vrfv2plus.go +++ b/integration-tests/testreporters/vrfv2plus.go @@ -20,12 +20,15 @@ type VRFV2PlusTestReporter struct { VRFv2PlusTestConfig types.VRFv2PlusTestConfig } +// todo - fix import cycle to avoid struct duplicate type VRFLoadTestMetrics struct { RequestCount *big.Int FulfilmentCount *big.Int AverageFulfillmentInMillions *big.Int SlowestFulfillment *big.Int FastestFulfillment *big.Int + P90FulfillmentBlockTime float64 + P95FulfillmentBlockTime float64 AverageResponseTimeInSecondsMillions *big.Int SlowestResponseTimeInSeconds *big.Int FastestResponseTimeInSeconds *big.Int @@ -53,7 +56,7 @@ func (o *VRFV2PlusTestReporter) SendSlackNotification(t *testing.T, slackClient headerText = fmt.Sprintf(":x: VRF V2 Plus %s Test FAILED :x:", o.TestType) } - vrfv2lusConfig := o.VRFv2PlusTestConfig.GetVRFv2PlusConfig().Performance + perfCfg := o.VRFv2PlusTestConfig.GetVRFv2PlusConfig().Performance messageBlocks := testreporters.SlackNotifyBlocks(headerText, strings.Join(vtfv2PlusTestConfig.GetNetworkConfig().SelectedNetworks, ","), []string{ fmt.Sprintf( "Summary\n"+ @@ -64,6 +67,8 @@ func (o *VRFV2PlusTestReporter) SendSlackNotification(t *testing.T, slackClient "Fulfilment Count: %s\n"+ "AverageFulfillmentInMillions (blocks): %s\n"+ "Slowest Fulfillment (blocks): %s\n"+ + "P90 Fulfillment (blocks): %f\n"+ + "P95 Fulfillment (blocks): %f\n"+ "Fastest Fulfillment (blocks): %s \n"+ "AverageFulfillmentInMillions (seconds): %s\n"+ "Slowest Fulfillment (seconds): %s\n"+ @@ -73,18 +78,20 @@ func (o *VRFV2PlusTestReporter) SendSlackNotification(t *testing.T, slackClient "RandomnessRequestCountPerRequest: %d\n"+ "RandomnessRequestCountPerRequestDeviation: %d\n", o.TestType, - vrfv2lusConfig.TestDuration.Duration.Truncate(time.Second).String(), + perfCfg.TestDuration.Duration.Truncate(time.Second).String(), *o.VRFv2PlusTestConfig.GetVRFv2PlusConfig().General.UseExistingEnv, o.LoadTestMetrics.RequestCount.String(), o.LoadTestMetrics.FulfilmentCount.String(), o.LoadTestMetrics.AverageFulfillmentInMillions.String(), o.LoadTestMetrics.SlowestFulfillment.String(), + o.LoadTestMetrics.P90FulfillmentBlockTime, + o.LoadTestMetrics.P95FulfillmentBlockTime, o.LoadTestMetrics.FastestFulfillment.String(), o.LoadTestMetrics.AverageResponseTimeInSecondsMillions.String(), o.LoadTestMetrics.SlowestResponseTimeInSeconds.String(), o.LoadTestMetrics.FastestResponseTimeInSeconds.String(), - *vrfv2lusConfig.RPS, - vrfv2lusConfig.RateLimitUnitDuration.String(), + *perfCfg.RPS, + perfCfg.RateLimitUnitDuration.String(), *o.VRFv2PlusTestConfig.GetVRFv2PlusConfig().General.RandomnessRequestCountPerRequest, *o.VRFv2PlusTestConfig.GetVRFv2PlusConfig().General.RandomnessRequestCountPerRequestDeviation, ), diff --git a/integration-tests/testsetups/ocr.go b/integration-tests/testsetups/ocr.go index 14e337a43b2..d30797ac507 100644 --- a/integration-tests/testsetups/ocr.go +++ b/integration-tests/testsetups/ocr.go @@ -185,8 +185,7 @@ func (o *OCRSoakTest) Setup(ocrTestConfig tt.OcrTestConfig) { o.mockServer, err = ctfClient.ConnectMockServer(o.testEnvironment) require.NoError(o.t, err, "Creating mockserver clients shouldn't fail") - // Deploy LINK - linkDeploymentData, err := contracts.DeployLinkTokenContract(seth) + linkContract, err := contracts.DeployLinkTokenContract(o.log, seth) require.NoError(o.t, err, "Error deploying LINK contract") // Fund Chainlink nodes, excluding the bootstrap node @@ -199,7 +198,7 @@ func (o *OCRSoakTest) Setup(ocrTestConfig tt.OcrTestConfig) { if o.OperatorForwarderFlow { var operators []common.Address operators, forwarders, _ = actions_seth.DeployForwarderContracts( - o.t, o.seth, linkDeploymentData, len(o.workerNodes), + o.t, o.seth, common.HexToAddress(linkContract.Address()), len(o.workerNodes), ) require.Equal(o.t, len(o.workerNodes), len(operators), "Number of operators should match number of nodes") require.Equal(o.t, len(o.workerNodes), len(forwarders), "Number of authorized forwarders should match number of nodes") @@ -218,7 +217,7 @@ func (o *OCRSoakTest) Setup(ocrTestConfig tt.OcrTestConfig) { o.log, o.seth, *o.Config.OCR.Soak.NumberOfContracts, - linkDeploymentData.Address, + common.HexToAddress(linkContract.Address()), contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(o.workerNodes), forwarders, ) @@ -228,7 +227,7 @@ func (o *OCRSoakTest) Setup(ocrTestConfig tt.OcrTestConfig) { o.log, seth, *o.Config.OCR.Soak.NumberOfContracts, - linkDeploymentData.Address, + common.HexToAddress(linkContract.Address()), contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(o.workerNodes), ) require.NoError(o.t, err) @@ -253,7 +252,7 @@ func (o *OCRSoakTest) Setup(ocrTestConfig tt.OcrTestConfig) { o.log, o.seth, *ocrTestConfig.GetOCRConfig().Soak.NumberOfContracts, - linkDeploymentData.Address, + common.HexToAddress(linkContract.Address()), transmitters, ocrOffchainOptions, ) diff --git a/integration-tests/types/config/node/core.go b/integration-tests/types/config/node/core.go index 024a05f63e4..23efdf13a8b 100644 --- a/integration-tests/types/config/node/core.go +++ b/integration-tests/types/config/node/core.go @@ -18,10 +18,10 @@ import ( it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -214,7 +214,7 @@ func WithVRFv2EVMEstimator(addresses []string, maxGasPriceGWei int64) NodeConfig var keySpecicifArr []evmcfg.KeySpecific for _, addr := range addresses { keySpecicifArr = append(keySpecicifArr, evmcfg.KeySpecific{ - Key: ptr.Ptr(ethkey.EIP55Address(addr)), + Key: ptr.Ptr(types.EIP55Address(addr)), GasEstimator: evmcfg.KeySpecificGasEstimator{ PriceMax: est, }, diff --git a/integration-tests/types/testconfigs.go b/integration-tests/types/testconfigs.go index cb36a1d3e8b..cfebf0a3c7a 100644 --- a/integration-tests/types/testconfigs.go +++ b/integration-tests/types/testconfigs.go @@ -27,6 +27,7 @@ type AutomationTestConfig interface { tc.GlobalTestConfig tc.CommonTestConfig tc.UpgradeableChainlinkTestConfig + tc.AutomationTestConfig } type KeeperBenchmarkTestConfig interface { diff --git a/integration-tests/universal/log_poller/helpers.go b/integration-tests/universal/log_poller/helpers.go index 66c63030704..4759818d11c 100644 --- a/integration-tests/universal/log_poller/helpers.go +++ b/integration-tests/universal/log_poller/helpers.go @@ -893,7 +893,7 @@ type PauseData struct { var ChaosPauses = []PauseData{} // chaosPauseSyncFn pauses ranom container of the provided type for a random amount of time between 5 and 20 seconds -func chaosPauseSyncFn(l zerolog.Logger, testEnv *test_env.CLClusterTestEnv, targetComponent string) ChaosPauseData { +func chaosPauseSyncFn(l zerolog.Logger, testEnv *test_env.CLClusterTestEnv, testConfig *tc.TestConfig, targetComponent string) ChaosPauseData { rand.New(rand.NewSource(time.Now().UnixNano())) randomNode := testEnv.ClCluster.Nodes[rand.Intn(len(testEnv.ClCluster.Nodes)-1)+1] @@ -908,8 +908,15 @@ func chaosPauseSyncFn(l zerolog.Logger, testEnv *test_env.CLClusterTestEnv, targ return ChaosPauseData{Err: fmt.Errorf("unknown component %s", targetComponent)} } - ctx := context.Background() - pauseStartBlock, err := testEnv.EVMClient.LatestBlockNumber(ctx) + network := networks.MustGetSelectedNetworkConfig(testConfig.GetNetworkConfig())[0] + evmClient, err := testEnv.GetEVMClient(network.ChainID) + if err != nil { + return ChaosPauseData{Err: err} + } + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + pauseStartBlock, err := evmClient.LatestBlockNumber(ctx) if err != nil { return ChaosPauseData{Err: err} } @@ -922,7 +929,10 @@ func chaosPauseSyncFn(l zerolog.Logger, testEnv *test_env.CLClusterTestEnv, targ } l.Info().Str("Container", component.ContainerName).Msg("Component unpaused") - pauseEndBlock, err := testEnv.EVMClient.LatestBlockNumber(ctx) + ctx, cancel = context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + pauseEndBlock, err := evmClient.LatestBlockNumber(ctx) if err != nil { return ChaosPauseData{Err: err} } @@ -941,20 +951,20 @@ type ChaosPauseData struct { } // ExecuteChaosExperiment executes the configured chaos experiment, which consist of pausing CL node or Postgres containers -func ExecuteChaosExperiment(l zerolog.Logger, testEnv *test_env.CLClusterTestEnv, cfg *lp_config.Config, errorCh chan error) { - if cfg.ChaosConfig == nil || *cfg.ChaosConfig.ExperimentCount == 0 { +func ExecuteChaosExperiment(l zerolog.Logger, testEnv *test_env.CLClusterTestEnv, testConfig *tc.TestConfig, errorCh chan error) { + if testConfig == nil || testConfig.LogPoller.ChaosConfig == nil || *testConfig.LogPoller.ChaosConfig.ExperimentCount == 0 { errorCh <- nil return } - chaosChan := make(chan ChaosPauseData, *cfg.ChaosConfig.ExperimentCount) + chaosChan := make(chan ChaosPauseData, *testConfig.LogPoller.ChaosConfig.ExperimentCount) wg := &sync.WaitGroup{} go func() { // if we wanted to have more than 1 container paused, we'd need to make sure we aren't trying to pause an already paused one guardChan := make(chan struct{}, 1) - for i := 0; i < *cfg.ChaosConfig.ExperimentCount; i++ { + for i := 0; i < *testConfig.LogPoller.ChaosConfig.ExperimentCount; i++ { i := i wg.Add(1) guardChan <- struct{}{} @@ -963,9 +973,9 @@ func ExecuteChaosExperiment(l zerolog.Logger, testEnv *test_env.CLClusterTestEnv <-guardChan wg.Done() current := i + 1 - l.Info().Str("Current/Total", fmt.Sprintf("%d/%d", current, cfg.ChaosConfig.ExperimentCount)).Msg("Done with experiment") + l.Info().Str("Current/Total", fmt.Sprintf("%d/%d", current, testConfig.LogPoller.ChaosConfig.ExperimentCount)).Msg("Done with experiment") }() - chaosChan <- chaosPauseSyncFn(l, testEnv, *cfg.ChaosConfig.TargetComponent) + chaosChan <- chaosPauseSyncFn(l, testEnv, testConfig, *testConfig.LogPoller.ChaosConfig.TargetComponent) time.Sleep(10 * time.Second) }() } @@ -1115,22 +1125,13 @@ func SetupLogPollerTestDocker( return network } - ethBuilder := ctf_test_env.NewEthereumNetworkBuilder() - cfg, err := ethBuilder. - WithConsensusType(ctf_test_env.ConsensusType_PoS). - WithConsensusLayer(ctf_test_env.ConsensusLayer_Prysm). - WithExecutionLayer(ctf_test_env.ExecutionLayer_Geth). - WithEthereumChainConfig(ctf_test_env.EthereumChainConfig{ - SecondsPerSlot: 4, - SlotsPerEpoch: 2, - }). - Build() + privateNetwork, err := actions.EthereumNetworkConfigFromConfig(l, testConfig) require.NoError(t, err, "Error building ethereum network config") env, err = test_env.NewCLTestEnvBuilder(). WithTestConfig(testConfig). WithTestInstance(t). - WithPrivateEthereumNetwork(cfg). + WithPrivateEthereumNetwork(privateNetwork). WithCLNodes(clNodesCount). WithCLNodeConfig(clNodeConfig). WithFunding(big.NewFloat(chainlinkNodeFunding)). @@ -1161,7 +1162,10 @@ func SetupLogPollerTestDocker( } require.NoError(t, err, "Error loading/deploying LINK token") - linkBalance, err := env.EVMClient.BalanceAt(context.Background(), common.HexToAddress(linkToken.Address())) + evmClient, err := env.GetEVMClient(network.ChainID) + require.NoError(t, err, "Getting EVM client shouldn't fail") + + linkBalance, err := evmClient.BalanceAt(context.Background(), common.HexToAddress(linkToken.Address())) require.NoError(t, err, "Error getting LINK balance") l.Info().Str("Balance", big.NewInt(0).Div(linkBalance, big.NewInt(1e18)).String()).Msg("LINK balance") @@ -1177,7 +1181,7 @@ func SetupLogPollerTestDocker( registryConfig, linkToken, env.ContractDeployer, - env.EVMClient, + evmClient, ) // Fund the registry with LINK @@ -1190,28 +1194,33 @@ func SetupLogPollerTestDocker( require.NoError(t, err, "Error building OCR config vars") err = registry.SetConfigTypeSafe(ocrConfig) require.NoError(t, err, "Registry config should be set successfully") - require.NoError(t, env.EVMClient.WaitForEvents(), "Waiting for config to be set") + require.NoError(t, evmClient.WaitForEvents(), "Waiting for config to be set") - return env.EVMClient, nodeClients, env.ContractDeployer, linkToken, registry, registrar, env + return evmClient, nodeClients, env.ContractDeployer, linkToken, registry, registrar, env } // UploadLogEmitterContractsAndWaitForFinalisation uploads the configured number of log emitter contracts and waits for the upload blocks to be finalised -func UploadLogEmitterContractsAndWaitForFinalisation(l zerolog.Logger, t *testing.T, testEnv *test_env.CLClusterTestEnv, cfg *lp_config.Config) []*contracts.LogEmitter { +func UploadLogEmitterContractsAndWaitForFinalisation(l zerolog.Logger, t *testing.T, testEnv *test_env.CLClusterTestEnv, testConfig *tc.TestConfig) []*contracts.LogEmitter { logEmitters := make([]*contracts.LogEmitter, 0) - for i := 0; i < *cfg.General.Contracts; i++ { + for i := 0; i < *testConfig.LogPoller.General.Contracts; i++ { logEmitter, err := testEnv.ContractDeployer.DeployLogEmitterContract() logEmitters = append(logEmitters, &logEmitter) require.NoError(t, err, "Error deploying log emitter contract") l.Info().Str("Contract address", logEmitter.Address().Hex()).Msg("Log emitter contract deployed") time.Sleep(200 * time.Millisecond) } - afterUploadBlock, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) + + network := networks.MustGetSelectedNetworkConfig(testConfig.GetNetworkConfig())[0] + evmClient, err := testEnv.GetEVMClient(network.ChainID) + require.NoError(t, err, "Error getting EVM client") + + afterUploadBlock, err := evmClient.LatestBlockNumber(testcontext.Get(t)) require.NoError(t, err, "Error getting latest block number") gom := gomega.NewGomegaWithT(t) gom.Eventually(func(g gomega.Gomega) { targetBlockNumber := int64(afterUploadBlock + 1) - finalized, err := testEnv.EVMClient.GetLatestFinalizedBlockHeader(testcontext.Get(t)) + finalized, err := evmClient.GetLatestFinalizedBlockHeader(testcontext.Get(t)) if err != nil { l.Warn().Err(err).Msg("Error checking if contract were uploaded. Retrying...") return @@ -1296,7 +1305,7 @@ func RegisterFiltersAndAssertUniquness(l zerolog.Logger, registry contracts.Keep // FluentlyCheckIfAllNodesHaveLogCount checks if all CL nodes have the expected log count for the provided block range and expected filters // It will retry until the provided duration is reached or until all nodes have the expected log count -func FluentlyCheckIfAllNodesHaveLogCount(duration string, startBlock, endBlock int64, expectedLogCount int, expectedFilters []ExpectedFilter, l zerolog.Logger, coreLogger core_logger.SugaredLogger, testEnv *test_env.CLClusterTestEnv) (bool, error) { +func FluentlyCheckIfAllNodesHaveLogCount(duration string, startBlock, endBlock int64, expectedLogCount int, expectedFilters []ExpectedFilter, l zerolog.Logger, coreLogger core_logger.SugaredLogger, testEnv *test_env.CLClusterTestEnv, chainId int64) (bool, error) { logCountWaitDuration, err := time.ParseDuration(duration) if err != nil { return false, err @@ -1306,7 +1315,7 @@ func FluentlyCheckIfAllNodesHaveLogCount(duration string, startBlock, endBlock i // not using gomega here, because I want to see which logs were missing allNodesLogCountMatches := false for time.Now().Before(endTime) { - logCountMatches, clErr := ClNodesHaveExpectedLogCount(startBlock, endBlock, testEnv.EVMClient.GetChainID(), expectedLogCount, expectedFilters, l, coreLogger, testEnv.ClCluster) + logCountMatches, clErr := ClNodesHaveExpectedLogCount(startBlock, endBlock, big.NewInt(chainId), expectedLogCount, expectedFilters, l, coreLogger, testEnv.ClCluster) if clErr != nil { l.Warn(). Err(clErr). diff --git a/integration-tests/wrappers/contract_caller.go b/integration-tests/wrappers/contract_caller.go new file mode 100644 index 00000000000..4be76ee74a1 --- /dev/null +++ b/integration-tests/wrappers/contract_caller.go @@ -0,0 +1,130 @@ +package wrappers + +import ( + "context" + "math/big" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/smartcontractkit/seth" + + evmClient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" +) + +// WrappedContractBackend is a wrapper around the go-ethereum ContractBackend interface. It's a thin wrapper +// around the go-ethereum/ethclient.Client, which replaces only CallContract and PendingCallContract calls with +// methods that send data both in "input" and "data" field for backwards compatibility with older clients. Other methods +// are passed through to the underlying client. +type WrappedContractBackend struct { + evmClient blockchain.EVMClient + sethClient *seth.Client +} + +// MustNewWrappedContractBackend creates a new WrappedContractBackend with the given clients +func MustNewWrappedContractBackend(evmClient blockchain.EVMClient, sethClient *seth.Client) *WrappedContractBackend { + if evmClient == nil && sethClient == nil { + panic("Must provide at least one client") + } + + return &WrappedContractBackend{ + evmClient: evmClient, + sethClient: sethClient, + } +} + +func (w *WrappedContractBackend) getGethClient() *ethclient.Client { + if w.sethClient != nil { + return w.sethClient.Client + } + + if w.evmClient != nil { + return w.evmClient.GetEthClient() + } + + panic("No client found") +} + +func (w *WrappedContractBackend) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) { + client := w.getGethClient() + return client.CodeAt(ctx, contract, blockNumber) +} + +func (w *WrappedContractBackend) PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error) { + client := w.getGethClient() + return client.PendingCodeAt(ctx, contract) +} + +func (w *WrappedContractBackend) CodeAtHash(ctx context.Context, contract common.Address, blockHash common.Hash) ([]byte, error) { + client := w.getGethClient() + return client.CodeAtHash(ctx, contract, blockHash) +} + +func (w *WrappedContractBackend) CallContractAtHash(ctx context.Context, call ethereum.CallMsg, blockHash common.Hash) ([]byte, error) { + client := w.getGethClient() + return client.CallContractAtHash(ctx, call, blockHash) +} + +func (w *WrappedContractBackend) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { + client := w.getGethClient() + return client.HeaderByNumber(ctx, number) +} + +func (w *WrappedContractBackend) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { + client := w.getGethClient() + return client.PendingNonceAt(ctx, account) +} + +func (w *WrappedContractBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) { + client := w.getGethClient() + return client.SuggestGasPrice(ctx) +} + +func (w *WrappedContractBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { + client := w.getGethClient() + return client.SuggestGasTipCap(ctx) +} + +func (w *WrappedContractBackend) EstimateGas(ctx context.Context, call ethereum.CallMsg) (gas uint64, err error) { + client := w.getGethClient() + return client.EstimateGas(ctx, call) +} + +func (w *WrappedContractBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error { + client := w.getGethClient() + return client.SendTransaction(ctx, tx) +} + +func (w *WrappedContractBackend) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) { + client := w.getGethClient() + return client.FilterLogs(ctx, query) +} + +func (w *WrappedContractBackend) SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { + client := w.getGethClient() + return client.SubscribeFilterLogs(ctx, query, ch) +} + +func (w *WrappedContractBackend) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { + var hex hexutil.Bytes + client := w.getGethClient() + err := client.Client().CallContext(ctx, &hex, "eth_call", evmClient.ToBackwardCompatibleCallArg(msg), evmClient.ToBackwardCompatibleBlockNumArg(blockNumber)) + if err != nil { + return nil, err + } + return hex, nil +} + +func (w *WrappedContractBackend) PendingCallContract(ctx context.Context, msg ethereum.CallMsg) ([]byte, error) { + var hex hexutil.Bytes + client := w.getGethClient() + err := client.Client().CallContext(ctx, &hex, "eth_call", evmClient.ToBackwardCompatibleCallArg(msg), "pending") + if err != nil { + return nil, err + } + return hex, nil +} diff --git a/main_test.go b/main_test.go index 15b17e32654..51707f0d9fb 100644 --- a/main_test.go +++ b/main_test.go @@ -53,7 +53,7 @@ func TestScripts(t *testing.T) { Dir: path, Setup: commonEnv, ContinueOnError: true, - //UpdateScripts: true, // uncomment to update golden files + // UpdateScripts: true, // uncomment to update golden files }) }) return nil diff --git a/operator_ui/TAG b/operator_ui/TAG index c9093a07542..c97c524af7a 100644 --- a/operator_ui/TAG +++ b/operator_ui/TAG @@ -1 +1 @@ -v0.8.0-a2b54a2 +v0.8.0-ee9e3a3 \ No newline at end of file diff --git a/plugins/loop_registry.go b/plugins/loop_registry.go index a2fcd8ef379..b796ddf87ee 100644 --- a/plugins/loop_registry.go +++ b/plugins/loop_registry.go @@ -70,6 +70,23 @@ func (m *LoopRegistry) Register(id string) (*RegisteredLoop, error) { return m.registry[id], nil } +// Unregister remove a loop from the registry +// Safe for concurrent use. +func (m *LoopRegistry) Unregister(id string) { + m.mu.Lock() + defer m.mu.Unlock() + + loop, exists := m.registry[id] + if !exists { + m.lggr.Debugf("Trying to unregistered a loop that is not registered %q", id) + return + } + + freeport.Return([]int{loop.EnvCfg.PrometheusPort}) + delete(m.registry, id) + m.lggr.Debugf("Unregistered loopp %q", id) +} + // Return slice sorted by plugin name. Safe for concurrent use. func (m *LoopRegistry) List() []*RegisteredLoop { var registeredLoops []*RegisteredLoop diff --git a/plugins/medianpoc/data_source.go b/plugins/medianpoc/data_source.go index 92d4b04ba6c..060dddc2938 100644 --- a/plugins/medianpoc/data_source.go +++ b/plugins/medianpoc/data_source.go @@ -53,7 +53,7 @@ func (d *DataSource) Observe(ctx context.Context, reportTimestamp ocrtypes.Repor return nil, fmt.Errorf("pipeline execution failed: %w", finalResult.Error) } - asDecimal, err := utils.ToDecimal(finalResult.Value) + asDecimal, err := utils.ToDecimal(finalResult.Value.Val) if err != nil { return nil, errors.New("cannot convert observation to decimal") } diff --git a/plugins/medianpoc/data_source_test.go b/plugins/medianpoc/data_source_test.go index 9977daef3d0..e9d95b01b02 100644 --- a/plugins/medianpoc/data_source_test.go +++ b/plugins/medianpoc/data_source_test.go @@ -11,6 +11,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -34,7 +35,7 @@ func (m *mockPipelineRunner) ExecuteRun(ctx context.Context, spec string, vars t func TestDataSource(t *testing.T) { lggr := logger.TestLogger(t) - expect := int64(3) + expect := jsonserializable.JSONSerializable{Val: int64(3), Valid: true} pr := &mockPipelineRunner{ results: types.TaskResults{ { @@ -47,7 +48,7 @@ func TestDataSource(t *testing.T) { }, { TaskValue: types.TaskValue{ - Value: int(4), + Value: jsonserializable.JSONSerializable{Val: int64(4), Valid: true}, Error: nil, IsTerminal: false, }, @@ -63,9 +64,10 @@ func TestDataSource(t *testing.T) { } res, err := ds.Observe(tests.Context(t), ocrtypes.ReportTimestamp{}) require.NoError(t, err) - assert.Equal(t, big.NewInt(expect), res) + expectBN := big.NewInt(expect.Val.(int64)) + assert.Equal(t, expectBN, res) assert.Equal(t, spec, pr.spec) - assert.Equal(t, big.NewInt(expect), ds.current.LatestAnswer) + assert.Equal(t, expectBN, ds.current.LatestAnswer) } func TestDataSource_ResultErrors(t *testing.T) { @@ -94,7 +96,7 @@ func TestDataSource_ResultErrors(t *testing.T) { func TestDataSource_ResultNotAnInt(t *testing.T) { lggr := logger.TestLogger(t) - expect := "string-result" + expect := jsonserializable.JSONSerializable{Val: "string-result", Valid: true} pr := &mockPipelineRunner{ results: types.TaskResults{ { diff --git a/plugins/medianpoc/plugin.go b/plugins/medianpoc/plugin.go index fdf409b588f..76fb4651260 100644 --- a/plugins/medianpoc/plugin.go +++ b/plugins/medianpoc/plugin.go @@ -6,7 +6,6 @@ import ( "fmt" "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -30,6 +29,12 @@ type Plugin struct { reportingplugins.MedianProviderServer } +func (p *Plugin) NewValidationService(ctx context.Context) (types.ValidationService, error) { + s := &reportingPluginValidationService{lggr: p.Logger} + p.SubService(s) + return s, nil +} + type pipelineSpec struct { Name string `json:"name"` Spec string `json:"spec"` @@ -59,6 +64,7 @@ func (p *Plugin) NewReportingPluginFactory( pipelineRunner types.PipelineRunnerService, telemetry types.TelemetryClient, errorLog types.ErrorLog, + keyValueStore types.KeyValueStore, ) (types.ReportingPluginFactory, error) { f, err := p.newFactory(ctx, config, provider, pipelineRunner, telemetry, errorLog) if err != nil { @@ -129,3 +135,37 @@ func (r *reportingPluginFactoryService) Close() error { func (r *reportingPluginFactoryService) HealthReport() map[string]error { return map[string]error{r.Name(): r.Healthy()} } + +type reportingPluginValidationService struct { + services.StateMachine + lggr logger.Logger +} + +func (r *reportingPluginValidationService) ValidateConfig(ctx context.Context, config map[string]interface{}) error { + tt, ok := config["telemetryType"] + if !ok { + return fmt.Errorf("expected telemtry type") + } + telemetryType, ok := tt.(string) + if !ok { + return fmt.Errorf("expected telemtry type to be of type string but got %T", tt) + } + if telemetryType != "median" { + return fmt.Errorf("expected telemtry type to be median but got %q", telemetryType) + } + + return nil +} +func (r *reportingPluginValidationService) Name() string { return r.lggr.Name() } + +func (r *reportingPluginValidationService) Start(ctx context.Context) error { + return r.StartOnce("ValidationService", func() error { return nil }) +} + +func (r *reportingPluginValidationService) Close() error { + return r.StopOnce("ValidationService", func() error { return nil }) +} + +func (r *reportingPluginValidationService) HealthReport() map[string]error { + return map[string]error{r.Name(): r.Healthy()} +} diff --git a/plugins/registrar.go b/plugins/registrar.go index 90300b738b6..2a82f2a6204 100644 --- a/plugins/registrar.go +++ b/plugins/registrar.go @@ -9,20 +9,23 @@ import ( // RegistrarConfig generates contains static configuration inher type RegistrarConfig interface { RegisterLOOP(config CmdConfig) (func() *exec.Cmd, loop.GRPCOpts, error) + UnregisterLOOP(ID string) } type registarConfig struct { grpcOpts loop.GRPCOpts loopRegistrationFn func(loopId string) (*RegisteredLoop, error) + loopUnregisterFn func(loopId string) } // NewRegistrarConfig creates a RegistarConfig // loopRegistrationFn must act as a global registry function of LOOPs and must be idempotent. // The [func() *exec.Cmd] for a LOOP should be generated by calling [RegistrarConfig.RegisterLOOP] -func NewRegistrarConfig(grpcOpts loop.GRPCOpts, loopRegistrationFn func(loopId string) (*RegisteredLoop, error)) RegistrarConfig { +func NewRegistrarConfig(grpcOpts loop.GRPCOpts, loopRegistrationFn func(loopId string) (*RegisteredLoop, error), loopUnregisterFn func(loopId string)) RegistrarConfig { return ®istarConfig{ grpcOpts: grpcOpts, loopRegistrationFn: loopRegistrationFn, + loopUnregisterFn: loopUnregisterFn, } } @@ -34,3 +37,7 @@ func (pc *registarConfig) RegisterLOOP(cfg CmdConfig) (func() *exec.Cmd, loop.GR } return cmdFn, pc.grpcOpts, nil } + +func (pc *registarConfig) UnregisterLOOP(ID string) { + pc.loopUnregisterFn(ID) +} diff --git a/sonar-project.properties b/sonar-project.properties index 80f0ae7601b..616d7883e19 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -59,6 +59,7 @@ sonar.cpd.exclusions=\ integration-tests/contracts/ethereum_contracts_seth.go,\ integration-tests/contracts/ethereum_contracts_seth.go,\ integration-tests/actions/seth/actions.go +dashboard/** # Tests' root folder, inclusions (tests to check and count) and exclusions sonar.tests=. diff --git a/testdata/scripts/node/validate/default.txtar b/testdata/scripts/node/validate/default.txtar index dcf9c4dc154..dd3af5f91b6 100644 --- a/testdata/scripts/node/validate/default.txtar +++ b/testdata/scripts/node/validate/default.txtar @@ -25,7 +25,7 @@ DefaultLockTimeout = '15s' DefaultQueryTimeout = '10s' LogQueries = false MaxIdleConns = 10 -MaxOpenConns = 20 +MaxOpenConns = 100 MigrateOnStartup = true [Database.Backup] @@ -128,6 +128,7 @@ MaxSuccessfulRuns = 10000 ReaperInterval = '1h0m0s' ReaperThreshold = '24h0m0s' ResultWriteQueueDepth = 100 +VerboseLogging = true [JobPipeline.HTTPRequest] DefaultTimeout = '15s' diff --git a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar index 1f3ccefe51e..15a476460da 100644 --- a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar @@ -69,7 +69,7 @@ DefaultLockTimeout = '15s' DefaultQueryTimeout = '10s' LogQueries = false MaxIdleConns = 10 -MaxOpenConns = 20 +MaxOpenConns = 100 MigrateOnStartup = true [Database.Backup] @@ -172,6 +172,7 @@ MaxSuccessfulRuns = 10000 ReaperInterval = '1h0m0s' ReaperThreshold = '24h0m0s' ResultWriteQueueDepth = 100 +VerboseLogging = true [JobPipeline.HTTPRequest] DefaultTimeout = '15s' @@ -368,6 +369,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [EVM.OCR] ContractConfirmations = 4 @@ -379,7 +381,7 @@ ObservationGracePeriod = '1s' [EVM.OCR2] [EVM.OCR2.Automation] -GasLimit = 5400000 +GasLimit = 10500000 [[EVM.Nodes]] Name = 'fake' diff --git a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar index 1b72a05a311..cc8b4577bfb 100644 --- a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar @@ -69,7 +69,7 @@ DefaultLockTimeout = '15s' DefaultQueryTimeout = '10s' LogQueries = false MaxIdleConns = 10 -MaxOpenConns = 20 +MaxOpenConns = 100 MigrateOnStartup = true [Database.Backup] @@ -172,6 +172,7 @@ MaxSuccessfulRuns = 10000 ReaperInterval = '1h0m0s' ReaperThreshold = '24h0m0s' ResultWriteQueueDepth = 100 +VerboseLogging = true [JobPipeline.HTTPRequest] DefaultTimeout = '15s' @@ -368,6 +369,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [EVM.OCR] ContractConfirmations = 4 @@ -379,7 +381,7 @@ ObservationGracePeriod = '1s' [EVM.OCR2] [EVM.OCR2.Automation] -GasLimit = 5400000 +GasLimit = 10500000 [[EVM.Nodes]] Name = 'fake' diff --git a/testdata/scripts/node/validate/disk-based-logging.txtar b/testdata/scripts/node/validate/disk-based-logging.txtar index 0110db3f373..c578d200923 100644 --- a/testdata/scripts/node/validate/disk-based-logging.txtar +++ b/testdata/scripts/node/validate/disk-based-logging.txtar @@ -69,7 +69,7 @@ DefaultLockTimeout = '15s' DefaultQueryTimeout = '10s' LogQueries = false MaxIdleConns = 10 -MaxOpenConns = 20 +MaxOpenConns = 100 MigrateOnStartup = true [Database.Backup] @@ -172,6 +172,7 @@ MaxSuccessfulRuns = 10000 ReaperInterval = '1h0m0s' ReaperThreshold = '24h0m0s' ResultWriteQueueDepth = 100 +VerboseLogging = true [JobPipeline.HTTPRequest] DefaultTimeout = '15s' @@ -368,6 +369,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [EVM.OCR] ContractConfirmations = 4 @@ -379,7 +381,7 @@ ObservationGracePeriod = '1s' [EVM.OCR2] [EVM.OCR2.Automation] -GasLimit = 5400000 +GasLimit = 10500000 [[EVM.Nodes]] Name = 'fake' diff --git a/testdata/scripts/node/validate/invalid-ocr-p2p.txtar b/testdata/scripts/node/validate/invalid-ocr-p2p.txtar index 438d94be93b..91ae520532d 100644 --- a/testdata/scripts/node/validate/invalid-ocr-p2p.txtar +++ b/testdata/scripts/node/validate/invalid-ocr-p2p.txtar @@ -54,7 +54,7 @@ DefaultLockTimeout = '15s' DefaultQueryTimeout = '10s' LogQueries = false MaxIdleConns = 10 -MaxOpenConns = 20 +MaxOpenConns = 100 MigrateOnStartup = true [Database.Backup] @@ -157,6 +157,7 @@ MaxSuccessfulRuns = 10000 ReaperInterval = '1h0m0s' ReaperThreshold = '24h0m0s' ResultWriteQueueDepth = 100 +VerboseLogging = true [JobPipeline.HTTPRequest] DefaultTimeout = '15s' diff --git a/testdata/scripts/node/validate/invalid.txtar b/testdata/scripts/node/validate/invalid.txtar index 3c6b514de90..a5e4b766b6e 100644 --- a/testdata/scripts/node/validate/invalid.txtar +++ b/testdata/scripts/node/validate/invalid.txtar @@ -59,7 +59,7 @@ DefaultLockTimeout = '15s' DefaultQueryTimeout = '10s' LogQueries = false MaxIdleConns = 10 -MaxOpenConns = 20 +MaxOpenConns = 100 MigrateOnStartup = true [Database.Backup] @@ -162,6 +162,7 @@ MaxSuccessfulRuns = 10000 ReaperInterval = '1h0m0s' ReaperThreshold = '24h0m0s' ResultWriteQueueDepth = 100 +VerboseLogging = true [JobPipeline.HTTPRequest] DefaultTimeout = '15s' @@ -358,6 +359,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [EVM.OCR] ContractConfirmations = 4 @@ -369,7 +371,7 @@ ObservationGracePeriod = '1s' [EVM.OCR2] [EVM.OCR2.Automation] -GasLimit = 5400000 +GasLimit = 10500000 [[EVM.Nodes]] Name = 'fake' diff --git a/testdata/scripts/node/validate/valid.txtar b/testdata/scripts/node/validate/valid.txtar index 07bf48bb084..c220d7f2e5f 100644 --- a/testdata/scripts/node/validate/valid.txtar +++ b/testdata/scripts/node/validate/valid.txtar @@ -66,7 +66,7 @@ DefaultLockTimeout = '15s' DefaultQueryTimeout = '10s' LogQueries = false MaxIdleConns = 10 -MaxOpenConns = 20 +MaxOpenConns = 100 MigrateOnStartup = true [Database.Backup] @@ -169,6 +169,7 @@ MaxSuccessfulRuns = 10000 ReaperInterval = '1h0m0s' ReaperThreshold = '24h0m0s' ResultWriteQueueDepth = 100 +VerboseLogging = true [JobPipeline.HTTPRequest] DefaultTimeout = '15s' @@ -365,6 +366,7 @@ SelectionMode = 'HighestHead' SyncThreshold = 5 LeaseDuration = '0s' NodeIsSyncingEnabled = false +FinalizedBlockPollInterval = '5s' [EVM.OCR] ContractConfirmations = 4 @@ -376,7 +378,7 @@ ObservationGracePeriod = '1s' [EVM.OCR2] [EVM.OCR2.Automation] -GasLimit = 5400000 +GasLimit = 10500000 [[EVM.Nodes]] Name = 'fake' diff --git a/testdata/scripts/node/validate/warnings.txtar b/testdata/scripts/node/validate/warnings.txtar index bd84ced5f82..018aaf95f4c 100644 --- a/testdata/scripts/node/validate/warnings.txtar +++ b/testdata/scripts/node/validate/warnings.txtar @@ -48,7 +48,7 @@ DefaultLockTimeout = '15s' DefaultQueryTimeout = '10s' LogQueries = false MaxIdleConns = 10 -MaxOpenConns = 20 +MaxOpenConns = 100 MigrateOnStartup = true [Database.Backup] @@ -151,6 +151,7 @@ MaxSuccessfulRuns = 10000 ReaperInterval = '1h0m0s' ReaperThreshold = '24h0m0s' ResultWriteQueueDepth = 100 +VerboseLogging = true [JobPipeline.HTTPRequest] DefaultTimeout = '15s' diff --git a/tools/bin/goreleaser_utils b/tools/bin/goreleaser_utils index 99eaddb35b9..4e1b3ffc4db 100755 --- a/tools/bin/goreleaser_utils +++ b/tools/bin/goreleaser_utils @@ -1,5 +1,5 @@ #!/usr/bin/env bash -set -x +set -xe # get machine / kernel name @@ -64,13 +64,13 @@ before_hook() { # MOVE PLUGINS HERE gobin=$(go env GOPATH)/bin - install_local_plugins "linux" "amd64" "$gobin"/linux_amd64 - install_remote_plugins "linux" "amd64" "$gobin"/linux_amd64 + install_local_plugins "linux" "amd64" "$gobin"/linux_amd64/ + install_remote_plugins "linux" "amd64" "$gobin"/linux_amd64/ mkdir -p "$lib_path/linux_amd64/plugins" cp "$gobin"/linux_amd64/chainlink* "$lib_path/linux_amd64/plugins" - install_local_plugins "linux" "arm64" "$gobin"/linux_arm64 - install_remote_plugins "linux" "arm64" "$gobin"/linux_arm64 + install_local_plugins "linux" "arm64" "$gobin"/linux_arm64/ + install_remote_plugins "linux" "arm64" "$gobin"/linux_arm64/ mkdir -p "$lib_path/linux_arm64/plugins" cp "$gobin"/linux_arm64/chainlink* "$lib_path/linux_arm64/plugins" } @@ -79,9 +79,10 @@ install_local_plugins() { local -r goos=$1 local -r goarch=$2 local -r gobin=$3 - - GOBIN=$gobin GOARCH=$goarch GOOS=$goos make install-medianpoc - GOBIN=$gobin GOARCH=$goarch GOOS=$goos make install-install-ocr3-capability + ldf="$(./tools/bin/ldflags)" + ldflags=(-ldflags "$ldf") + GOARCH=$goarch GOOS=$goos go build -o $gobin "${ldflags[@]}" ./plugins/cmd/chainlink-medianpoc + GOARCH=$goarch GOOS=$goos go build -o $gobin "${ldflags[@]}" ./plugins/cmd/chainlink-ocr3-capability } get_remote_plugin_paths() { @@ -105,9 +106,10 @@ install_remote_plugins() { local -r goos=$1 local -r goarch=$2 local -r gobin=$(go env GOPATH)/bin + ldflags=(-ldflags "$(./tools/bin/ldflags)") for plugin in $(get_remote_plugin_paths); do - GOBIN=$gobin GOARCH=$goarch GOOS=$goos go install "$plugin" + GOARCH=$goarch GOOS=$goos go build -o $gobin "${ldflags[@]}" "$plugin" done } diff --git a/tools/ci/check_solc_hashes b/tools/ci/check_solc_hashes index 0fe7d091f13..d846591a72b 100755 --- a/tools/ci/check_solc_hashes +++ b/tools/ci/check_solc_hashes @@ -6,39 +6,13 @@ set -e -SOLC_6_6_LOCAL_PATH="$HOME/.solc-select/artifacts/solc-0.6.6/solc-0.6.6" -SOLC_7_6_LOCAL_PATH="$HOME/.solc-select/artifacts/solc-0.7.6/solc-0.7.6" SOLC_8_6_LOCAL_PATH="$HOME/.solc-select/artifacts/solc-0.8.6/solc-0.8.6" -SOLC_8_15_LOCAL_PATH="$HOME/.solc-select/artifacts/solc-0.8.15/solc-0.8.15" - -SOLC_6_6_LOCAL_SHA=`sha256sum -b $SOLC_6_6_LOCAL_PATH | cut -d " " -f1` -SOLC_6_6_EXPECTED_SHA="5d8cd4e0cc02e9946497db68c06d56326a78ff95a21c9265cfedb819a10a539d" - -SOLC_7_6_LOCAL_SHA=`sha256sum -b $SOLC_7_6_LOCAL_PATH | cut -d " " -f1` -SOLC_7_6_EXPECTED_SHA="bd69ea85427bf2f4da74cb426ad951dd78db9dfdd01d791208eccc2d4958a6bb" SOLC_8_6_LOCAL_SHA=`sha256sum -b $SOLC_8_6_LOCAL_PATH | cut -d " " -f1` SOLC_8_6_EXPECTED_SHA="abd5c4f3f262bc3ed7951b968c63f98e83f66d9a5c3568ab306eac49250aec3e" -SOLC_8_15_LOCAL_SHA=`sha256sum -b $SOLC_8_15_LOCAL_PATH | cut -d " " -f1` -SOLC_8_15_EXPECTED_SHA="5189155ce322d57fb75e8518d9b39139627edea4fb25b5f0ebed0391c52e74cc" - -if [ "$SOLC_6_6_LOCAL_SHA" != "$SOLC_6_6_EXPECTED_SHA" ]; then - printf "solc 0.6.6 did not match checksum.\nGot '$SOLC_6_6_LOCAL_SHA'\nExpected '$SOLC_6_6_EXPECTED_SHA']\n" - exit 1 -fi - -if [ "$SOLC_7_6_LOCAL_SHA" != "$SOLC_7_6_EXPECTED_SHA" ]; then - printf "solc 0.7.6 did not match checksum.\nGot '$SOLC_7_6_LOCAL_SHA'\nExpected '$SOLC_7_6_EXPECTED_SHA'\n" - exit 1 -fi - if [ "$SOLC_8_6_LOCAL_SHA" != "$SOLC_8_6_EXPECTED_SHA" ]; then printf "solc 0.8.6 did not match checksum.\nGot '$SOLC_8_6_LOCAL_SHA'\nExpected '$SOLC_8_6_EXPECTED_SHA'\n" exit 1 fi -if [ "$SOLC_8_15_LOCAL_SHA" != "$SOLC_8_15_EXPECTED_SHA" ]; then - printf "solc 0.8.15 did not match checksum.\nGot '$SOLC_8_15_LOCAL_SHA'\nExpected '$SOLC_8_15_EXPECTED_SHA'\n" - exit 1 -fi